[VVP] Support pluggable data sources for preload data
[vvp/validation-scripts.git] / ice_validator / preload_grapi / grapi_generator.py
1 # -*- coding: utf8 -*-
2 # ============LICENSE_START====================================================
3 # org.onap.vvp/validation-scripts
4 # ===================================================================
5 # Copyright © 2019 AT&T Intellectual Property. All rights reserved.
6 # ===================================================================
7 #
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
12 #
13 #             http://www.apache.org/licenses/LICENSE-2.0
14 #
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.
20 #
21 #
22 #
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
27 #
28 #             https://creativecommons.org/licenses/by/4.0/
29 #
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.
35 #
36 # ============LICENSE_END============================================
37 import json
38 import os
39 from pathlib import Path
40 from typing import Mapping
41
42 from preload.data import AbstractPreloadInstance
43 from preload.generator import (
44     get_json_template,
45     get_or_create_template,
46     AbstractPreloadGenerator,
47 )
48 from preload.model import VnfModule, Port
49
50 THIS_DIR = os.path.dirname(os.path.abspath(__file__))
51 DATA_DIR = os.path.join(THIS_DIR, "grapi_data")
52
53
54 def get_or_create_network_template(network, vm_networks):
55     """
56     If the network role already exists in vm_networks, then
57     return that otherwise create a blank template and return that
58     """
59     return get_or_create_template(
60         DATA_DIR, "network-role", network, vm_networks, "vm-network"
61     )
62
63
64 class GrApiPreloadGenerator(AbstractPreloadGenerator):
65     @classmethod
66     def supports_output_passing(cls):
67         return True
68
69     @classmethod
70     def format_name(cls):
71         return "GR-API"
72
73     @classmethod
74     def output_sub_dir(cls):
75         return "grapi"
76
77     def generate_module(
78         self,
79         vnf_module: VnfModule,
80         preload_data: AbstractPreloadInstance,
81         output_dir: Path,
82     ):
83         self.module_incomplete = False
84         template = get_json_template(DATA_DIR, "preload_template")
85         self._populate(template, preload_data, vnf_module)
86         incomplete = (
87             "_incomplete"
88             if preload_data.flag_incompletes and self.module_incomplete
89             else ""
90         )
91         filename = "{}{}.json".format(preload_data.preload_basename, incomplete)
92         outfile = output_dir.joinpath(filename)
93         with outfile.open("w") as f:
94             json.dump(template, f, indent=4)
95
96     def _populate(
97         self,
98         template: Mapping,
99         preload_data: AbstractPreloadInstance,
100         vnf_module: VnfModule,
101     ):
102         self._add_vnf_metadata(template, preload_data)
103         self._add_availability_zones(template, preload_data, vnf_module)
104         self._add_vnf_networks(template, preload_data, vnf_module)
105         self._add_vms(template, preload_data, vnf_module)
106         self._add_parameters(template, preload_data, vnf_module)
107
108     def _add_vnf_metadata(self, template: Mapping, preload: AbstractPreloadInstance):
109         topology = template["input"]["preload-vf-module-topology-information"]
110         vnf_meta = topology["vnf-topology-identifier-structure"]
111         vnf_meta["vnf-name"] = self.normalize(preload.vnf_name, "vnf_name")
112         vnf_meta["vnf-type"] = self.normalize(
113             preload.vnf_type,
114             "vnf-type",
115             "VALUE FOR: Concatenation of <Service Name>/"
116             "<VF Instance Name> MUST MATCH SDC",
117         )
118         module_meta = topology["vf-module-topology"]["vf-module-topology-identifier"]
119         module_meta["vf-module-name"] = self.normalize(
120             preload.vf_module_name, "vf_module_name"
121         )
122         module_meta["vf-module-type"] = self.normalize(
123             preload.vf_module_model_name,
124             "vf-module-model-name",
125             "VALUE FOR: <vfModuleModelName> from CSAR or SDC",
126         )
127
128     def _add_availability_zones(
129         self, template: Mapping, preload: AbstractPreloadInstance, vnf_module: VnfModule
130     ):
131         zones = template["input"]["preload-vf-module-topology-information"][
132             "vnf-resource-assignments"
133         ]["availability-zones"]["availability-zone"]
134         for i, zone_param in enumerate(vnf_module.availability_zones):
135             zone = preload.get_availability_zone(i, zone_param)
136             zones.append(self.normalize(zone, zone_param, index=i))
137
138     def _add_vnf_networks(
139         self, template: Mapping, preload: AbstractPreloadInstance, vnf_module: VnfModule
140     ):
141         networks = template["input"]["preload-vf-module-topology-information"][
142             "vnf-resource-assignments"
143         ]["vnf-networks"]["vnf-network"]
144         for network in vnf_module.networks:
145             network_data = {
146                 "network-role": network.network_role,
147                 "network-name": self.normalize(
148                     preload.get_network_name(network.network_role, network.name_param),
149                     network.name_param,
150                     "VALUE FOR: network name of {}".format(network.name_param),
151                 ),
152             }
153             if network.subnet_params:
154                 network_data["subnets-data"] = {"subnet-data": []}
155                 subnet_data = network_data["subnets-data"]["subnet-data"]
156                 for subnet in network.subnet_params:
157                     data = {}
158                     subnet_id = preload.get_subnet_id(
159                         network.network_role, subnet.ip_version, subnet.param_name
160                     )
161                     if subnet_id:
162                         data["subnet-id"] = self.normalize(subnet_id, subnet.param_name)
163                     else:
164                         subnet_name = preload.get_subnet_name(
165                             network.network_role, subnet.ip_version, ""
166                         )
167                         data["subnet-name"] = self.normalize(
168                             subnet_name,
169                             subnet.param_name,
170                             alt_message="VALUE FOR: name of {}".format(
171                                 subnet.param_name
172                             ),
173                         )
174                     subnet_data.append(data)
175             networks.append(network_data)
176
177     def add_floating_ips(
178         self, network_template: dict, port: Port, preload: AbstractPreloadInstance
179     ):
180         for ip in port.floating_ips:
181             key = "floating-ip-v4" if ip.ip_version == 4 else "floating-ip-v6"
182             ips = network_template["floating-ips"][key]
183             value = self.normalize(
184                 preload.get_floating_ip(
185                     port.vm.vm_type, port.network.network_role, ip.ip_version, ip.param
186                 ),
187                 ip.param,
188             )
189             ips.append(value)
190
191     def add_fixed_ips(
192         self, network_template: dict, port: Port, preload: AbstractPreloadInstance
193     ):
194         items = network_template["network-information-items"][
195             "network-information-item"
196         ]
197         ipv4s = next(item for item in items if item["ip-version"] == "4")
198         ipv6s = next(item for item in items if item["ip-version"] == "6")
199         if port.uses_dhcp:
200             ipv4s["use-dhcp"] = "Y"
201             ipv6s["use-dhcp"] = "Y"
202         for index, ip in port.fixed_ips_with_index:
203             target = ipv4s if ip.ip_version == 4 else ipv6s
204             ips = target["network-ips"]["network-ip"]
205             if ip.param not in ips:
206                 ips.append(
207                     self.normalize(
208                         preload.get_fixed_ip(
209                             port.vm.vm_type,
210                             port.network.network_role,
211                             ip.ip_version,
212                             index,
213                             ip.param,
214                         ),
215                         ip.param,
216                         index=index
217                     )
218                 )
219             target["ip-count"] += 1
220
221     def _add_vms(
222         self, template: Mapping, preload: AbstractPreloadInstance, vnf_module: VnfModule
223     ):
224         vms = template["input"]["preload-vf-module-topology-information"][
225             "vf-module-topology"
226         ]["vf-module-assignments"]["vms"]["vm"]
227         for vm in vnf_module.virtual_machine_types:
228             vm_template = get_json_template(DATA_DIR, "vm")
229             vms.append(vm_template)
230             vm_template["vm-type"] = vm.vm_type
231             for i, param in enumerate(sorted(vm.names)):
232                 name = preload.get_vm_name(vm.vm_type, i, param)
233                 value = self.normalize(name, param, index=i)
234                 vm_template["vm-names"]["vm-name"].append(value)
235             vm_template["vm-count"] = vm.vm_count
236             vm_networks = vm_template["vm-networks"]["vm-network"]
237             for port in vm.ports:
238                 role = port.network.network_role
239                 network_template = get_or_create_network_template(role, vm_networks)
240                 network_template["network-role"] = role
241                 network_template["network-role-tag"] = role
242                 self.add_fixed_ips(network_template, port, preload)
243                 self.add_floating_ips(network_template, port, preload)
244
245     def _add_parameters(
246         self, template: Mapping, preload: AbstractPreloadInstance, vnf_module: VnfModule
247     ):
248         params = [
249             {
250                 "name": key,
251                 "value": self.normalize(preload.get_vnf_parameter(key, value), key),
252             }
253             for key, value in vnf_module.preload_parameters.items()
254         ]
255         for key, value in preload.get_additional_parameters().items():
256             params.append(
257                 {
258                     "name": key,
259                     "value": value,
260                 }
261             )
262
263         template["input"]["preload-vf-module-topology-information"][
264             "vf-module-topology"
265         ]["vf-module-parameters"]["param"].extend(params)