2 # ============LICENSE_START====================================================
3 # org.onap.vvp/validation-scripts
4 # ===================================================================
5 # Copyright © 2019 AT&T Intellectual Property. All rights reserved.
6 # ===================================================================
8 # Unless otherwise specified, all software contained herein is licensed
9 # under the Apache License, Version 2.0 (the "License");
10 # you may not use this software except in compliance with the License.
11 # You may obtain a copy of the License at
13 # http://www.apache.org/licenses/LICENSE-2.0
15 # Unless required by applicable law or agreed to in writing, software
16 # distributed under the License is distributed on an "AS IS" BASIS,
17 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 # See the License for the specific language governing permissions and
19 # limitations under the License.
23 # Unless otherwise specified, all documentation contained herein is licensed
24 # under the Creative Commons License, Attribution 4.0 Intl. (the "License");
25 # you may not use this documentation except in compliance with the License.
26 # You may obtain a copy of the License at
28 # https://creativecommons.org/licenses/by/4.0/
30 # Unless required by applicable law or agreed to in writing, documentation
31 # distributed under the License is distributed on an "AS IS" BASIS,
32 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
33 # See the License for the specific language governing permissions and
34 # limitations under the License.
36 # ============LICENSE_END============================================
40 from abc import ABC, abstractmethod
45 def get_json_template(template_dir, template_name):
46 template_name = template_name + ".json"
47 with open(os.path.join(template_dir, template_name)) as f:
48 return json.loads(f.read())
51 def get_or_create_template(template_dir, key, value, sequence, template_name):
53 Search a sequence of dicts where a given key matches value. If
54 found, then it returns that item. If not, then it loads the
55 template identified by template_name, adds it ot the sequence, and
59 if item[key] == value:
61 new_template = get_json_template(template_dir, template_name)
62 sequence.append(new_template)
66 def yield_by_count(sequence):
68 Iterates through sequence and yields each item according to its __count__
69 attribute. If an item has a __count__ of it will be returned 3 times
70 before advancing to the next item in the sequence.
72 :param sequence: sequence of dicts (must contain __count__)
73 :returns: generator of tuple key, value pairs
75 for key, value in sequence.items():
76 for i in range(value["__count__"]):
82 Optionally used by the preload generator to wrap items in the preload
83 that need to be replaced by end users
86 return "VALUE FOR: {}".format(param) if param else ""
89 class AbstractPreloadGenerator(ABC):
91 All preload generators must inherit from this class and implement the
94 Preload generators are automatically discovered at runtime via a plugin
95 architecture. The system path is scanned looking for modules with the name
96 preload_*, then all non-abstract classes that inherit from AbstractPreloadGenerator
97 are registered as preload plugins
100 :param vnf: Instance of Vnf that contains the preload data
101 :param base_output_dir: Base directory to house the preloads. All preloads
102 must be written to a subdirectory under this directory
105 def __init__(self, vnf, base_output_dir, preload_env):
106 self.preload_env = preload_env
108 self.current_module = None
109 self.current_module_env = {}
110 self.base_output_dir = base_output_dir
115 def format_name(cls):
117 String name to identify the format (ex: VN-API, GR-API)
119 raise NotImplementedError()
123 def output_sub_dir(cls):
125 String sub-directory name that will appear under ``base_output_dir``
127 raise NotImplementedError()
131 def supports_output_passing(cls):
133 Some preload methods allow automatically mapping output parameters in the
134 base module to the input parameter of other modules. This means these
135 that the incremental modules do not need these base module outputs in their
138 At this time, VNF-API does not support output parameter passing, but
141 If this is true, then the generator will call Vnf#filter_output_params
142 after the preload module for the base module has been created
144 raise NotImplementedError()
147 def generate_module(self, module, output_dir):
149 Create the preloads and write them to ``output_dir``. This
150 method is responsible for generating the content of the preload and
151 writing the file to disk.
153 raise NotImplementedError()
156 # handle the base module first
157 print("\nGenerating {} preloads".format(self.format_name()))
158 self.generate_environments(self.vnf.base_module)
159 if self.supports_output_passing():
160 self.vnf.filter_base_outputs()
161 for mod in self.vnf.incremental_modules:
162 self.generate_environments(mod)
164 def replace(self, param_name, alt_message=None, single=False):
165 value = self.get_param(param_name, single)
168 return alt_message or replace(param_name)
170 def generate_environments(self, module):
172 Generate a preload for the given module in all available environments
173 in the ``self.preload_env``. This will invoke the abstract
174 generate_module once for each available environment **and** an
175 empty environment to create a blank template.
177 :param module: module to generate for
179 print("\nGenerating Preloads for {}".format(module))
181 print("... generating blank template")
182 self.current_module = module
183 self.current_module_env = {}
185 blank_preload_dir = self.make_preload_dir(self.base_output_dir)
186 self.generate_module(module, blank_preload_dir)
187 self.generate_preload_env(module, blank_preload_dir)
189 for env in self.preload_env.environments:
190 output_dir = self.make_preload_dir(env.base_dir / "preloads")
192 "... generating preload for env ({}) to {}".format(
197 self.current_module = module
198 self.current_module_env = env.get_module(module.label)
199 self.generate_module(module, output_dir)
200 self.current_module = None
201 self.current_module_env = None
203 def make_preload_dir(self, base_dir):
204 path = os.path.join(base_dir, self.output_sub_dir())
205 if not os.path.exists(path):
206 os.makedirs(path, exist_ok=True)
209 def generate_preload_env(self, module, blank_preload_dir):
211 Create a .env template suitable for completing and using for
212 preload generation from env files.
214 output_dir = os.path.join(blank_preload_dir, "preload_env")
215 output_file = os.path.join(output_dir, "{}.env".format(module.vnf_name))
216 if not os.path.exists(output_dir):
217 os.makedirs(output_dir, exist_ok=True)
218 with open(output_file, "w") as f:
219 yaml.dump(module.env_template, f)
221 def get_param(self, param_name, single):
223 Retrieves the value for the given param if it exists. If requesting a
224 single item, and the parameter is tied to a list then only one item from
225 the list will be returned. For each subsequent call with the same parameter
226 it will iterate/rotate through the values in that list. If single is False
227 then the full list will be returned.
229 :param param_name: name of the parameter
230 :param single: If True returns single value from lists otherwises the full
231 list. This has no effect on non-list values
233 value = self.env_cache.get(param_name)
235 value = self.current_module_env.get(param_name)
236 if isinstance(value, list):
238 self.env_cache[param_name] = value
239 if value and single and isinstance(value, list):