blob: 62c036c8324be4e5b3476deadc0e78d5d2fc3be9 [file] [log] [blame]
Bartek Grzybowskifbbdbec2019-09-25 16:37:05 +02001#!/usr/bin/env python
Kang Xi11d278c2018-04-06 16:56:04 -04002
3import requests
4import json
5import sys
6from datetime import datetime
Kang Xi11d278c2018-04-06 16:56:04 -04007import csar_parser
8import logging
9import base64
10
11
12class Preload:
13 def __init__(self, vcpecommon):
14 self.logger = logging.getLogger(__name__)
Yang Xu1b31a1d2019-06-26 01:50:15 -040015 self.logger.setLevel(logging.DEBUG)
Kang Xi11d278c2018-04-06 16:56:04 -040016 self.vcpecommon = vcpecommon
17
18 def replace(self, sz, replace_dict):
19 for old_string, new_string in replace_dict.items():
20 sz = sz.replace(old_string, new_string)
21 if self.vcpecommon.template_variable_symbol in sz:
22 self.logger.error('Error! Cannot find a value to replace ' + sz)
23 return sz
24
25 def generate_json(self, template_file, replace_dict):
26 with open(template_file) as json_input:
27 json_data = json.load(json_input)
28 stk = [json_data]
Bartek Grzybowski23f22e82020-03-05 13:21:59 +010029 while stk:
Kang Xi11d278c2018-04-06 16:56:04 -040030 data = stk.pop()
31 for k, v in data.items():
32 if type(v) is dict:
33 stk.append(v)
34 elif type(v) is list:
35 stk.extend(v)
Bartek Grzybowski4be94a62020-03-05 11:41:08 +010036 elif type(v) is str or type(v) is unicode: # pylint: disable=E0602
Kang Xi11d278c2018-04-06 16:56:04 -040037 if self.vcpecommon.template_variable_symbol in v:
38 data[k] = self.replace(v, replace_dict)
39 else:
40 self.logger.warning('Unexpected line in template: %s. Look for value %s', template_file, v)
41 return json_data
42
43 def reset_sniro(self):
44 self.logger.debug('Clearing SNIRO data')
45 r = requests.post(self.vcpecommon.sniro_url + '/reset', headers=self.vcpecommon.sniro_headers)
46 if 2 != r.status_code / 100:
47 self.logger.debug(r.content)
48 self.logger.error('Clearing SNIRO date failed.')
Bartek Grzybowski68d93c22019-10-30 10:55:55 +010049 sys.exit(1)
Kang Xi11d278c2018-04-06 16:56:04 -040050
51 def preload_sniro(self, template_sniro_data, template_sniro_request, tunnelxconn_ar_name, vgw_name, vbrg_ar_name,
52 vgmux_svc_instance_uuid, vbrg_svc_instance_uuid):
53 self.reset_sniro()
54 self.logger.info('Preloading SNIRO for homing service')
55 replace_dict = {'${tunnelxconn_ar_name}': tunnelxconn_ar_name,
56 '${vgw_name}': vgw_name,
57 '${brg_ar_name}': vbrg_ar_name,
58 '${vgmux_svc_instance_uuid}': vgmux_svc_instance_uuid,
59 '${vbrg_svc_instance_uuid}': vbrg_svc_instance_uuid
60 }
61 sniro_data = self.generate_json(template_sniro_data, replace_dict)
62 self.logger.debug('SNIRO data:')
63 self.logger.debug(json.dumps(sniro_data, indent=4, sort_keys=True))
64
65 base64_sniro_data = base64.b64encode(json.dumps(sniro_data))
66 self.logger.debug('SNIRO data: 64')
67 self.logger.debug(base64_sniro_data)
68 replace_dict = {'${base64_sniro_data}': base64_sniro_data, '${sniro_ip}': self.vcpecommon.hosts['robot']}
69 sniro_request = self.generate_json(template_sniro_request, replace_dict)
70 self.logger.debug('SNIRO request:')
71 self.logger.debug(json.dumps(sniro_request, indent=4, sort_keys=True))
72
73 r = requests.post(self.vcpecommon.sniro_url, headers=self.vcpecommon.sniro_headers, json=sniro_request)
74 if 2 != r.status_code / 100:
75 response = r.json()
76 self.logger.debug(json.dumps(response, indent=4, sort_keys=True))
77 self.logger.error('SNIRO preloading failed.')
Bartek Grzybowski68d93c22019-10-30 10:55:55 +010078 sys.exit(1)
Kang Xi11d278c2018-04-06 16:56:04 -040079
80 return True
81
82 def preload_network(self, template_file, network_role, subnet_start_ip, subnet_gateway, common_dict, name_suffix):
83 """
84 :param template_file:
85 :param network_role: cpe_signal, cpe_public, brg_bng, bng_mux, mux_gw
86 :param subnet_start_ip:
87 :param subnet_gateway:
88 :param name_suffix: e.g. '201711201311'
89 :return:
90 """
91 network_name = '_'.join([self.vcpecommon.instance_name_prefix['network'], network_role.lower(), name_suffix])
92 subnet_name = self.vcpecommon.network_name_to_subnet_name(network_name)
93 common_dict['${' + network_role+'_net}'] = network_name
94 common_dict['${' + network_role+'_subnet}'] = subnet_name
95 replace_dict = {'${network_role}': network_role,
96 '${service_type}': 'vCPE',
97 '${network_type}': 'Generic NeutronNet',
98 '${network_name}': network_name,
99 '${subnet_start_ip}': subnet_start_ip,
100 '${subnet_gateway}': subnet_gateway
101 }
102 self.logger.info('Preloading network ' + network_role)
Brian Freeman9b3d6ca2019-11-06 13:22:53 -0500103 self.logger.info('template_file:' + template_file)
104 if 'networkgra' in template_file:
Bartek Grzybowski3d3d3c22020-03-05 10:28:03 +0100105 return self.preload(template_file, replace_dict, self.vcpecommon.sdnc_preload_network_gra_url)
Brian Freeman9b3d6ca2019-11-06 13:22:53 -0500106 else:
Bartek Grzybowski3d3d3c22020-03-05 10:28:03 +0100107 return self.preload(template_file, replace_dict, self.vcpecommon.sdnc_preload_network_url)
Kang Xi11d278c2018-04-06 16:56:04 -0400108
109 def preload(self, template_file, replace_dict, url):
Brian Freeman9b3d6ca2019-11-06 13:22:53 -0500110 self.logger.debug('tempalte_file:'+ template_file)
Kang Xi11d278c2018-04-06 16:56:04 -0400111 json_data = self.generate_json(template_file, replace_dict)
112 self.logger.debug(json.dumps(json_data, indent=4, sort_keys=True))
Brian Freeman383a3e82019-10-03 15:25:39 -0500113 r = requests.post(url, headers=self.vcpecommon.sdnc_headers, auth=self.vcpecommon.sdnc_userpass, json=json_data, verify=False)
Kang Xi11d278c2018-04-06 16:56:04 -0400114 response = r.json()
115 if int(response.get('output', {}).get('response-code', 0)) != 200:
116 self.logger.debug(json.dumps(response, indent=4, sort_keys=True))
117 self.logger.error('Preloading failed.')
118 return False
119 return True
120
121 def preload_vgw(self, template_file, brg_mac, commont_dict, name_suffix):
122 replace_dict = {'${brg_mac}': brg_mac,
123 '${suffix}': name_suffix
124 }
125 replace_dict.update(commont_dict)
126 self.logger.info('Preloading vGW')
127 return self.preload(template_file, replace_dict, self.vcpecommon.sdnc_preload_vnf_url)
128
Brian Freeman81f6e9e2018-11-11 22:36:20 -0500129 def preload_vgw_gra(self, template_file, brg_mac, commont_dict, name_suffix, vgw_vfmod_name_index):
130 replace_dict = {'${brg_mac}': brg_mac,
Brian Freemana605bc72018-11-12 10:50:30 -0500131 '${suffix}': name_suffix,
Brian Freeman81f6e9e2018-11-11 22:36:20 -0500132 '${vgw_vfmod_name_index}': vgw_vfmod_name_index
133 }
134 replace_dict.update(commont_dict)
135 self.logger.info('Preloading vGW-GRA')
Yang Xu63a0afd2018-11-20 16:01:01 -0500136 return self.preload(template_file, replace_dict, self.vcpecommon.sdnc_preload_gra_url)
Brian Freeman81f6e9e2018-11-11 22:36:20 -0500137
Brian Freeman9b3d6ca2019-11-06 13:22:53 -0500138 def preload_vfmodule(self, template_file, service_instance_id, vnf_model, vfmodule_model, common_dict, name_suffix , gra_api_flag):
Kang Xi11d278c2018-04-06 16:56:04 -0400139 """
140 :param template_file:
141 :param service_instance_id:
142 :param vnf_model: parsing results from csar_parser
143 :param vfmodule_model: parsing results from csar_parser
144 :param common_dict:
145 :param name_suffix:
146 :return:
147 """
148
149 # examples:
150 # vfmodule_model['modelCustomizationName']: "Vspinfra111601..base_vcpe_infra..module-0",
151 # vnf_model['modelCustomizationName']: "vspinfra111601 0",
152
153 vfmodule_name = '_'.join([self.vcpecommon.instance_name_prefix['vfmodule'],
154 vfmodule_model['modelCustomizationName'].split('..')[0].lower(), name_suffix])
155
156 # vnf_type and generic_vnf_type are identical
157 replace_dict = {'${vnf_type}': vfmodule_model['modelCustomizationName'],
158 '${generic_vnf_type}': vfmodule_model['modelCustomizationName'],
159 '${service_type}': service_instance_id,
160 '${generic_vnf_name}': vnf_model['modelCustomizationName'],
161 '${vnf_name}': vfmodule_name,
Brian Freemanb2056652018-11-19 15:36:37 -0500162 '${mr_ip_addr}': self.vcpecommon.mr_ip_addr,
163 '${mr_ip_port}': self.vcpecommon.mr_ip_port,
Yang Xu63a0afd2018-11-20 16:01:01 -0500164 '${sdnc_oam_ip}': self.vcpecommon.sdnc_oam_ip,
Kang Xi11d278c2018-04-06 16:56:04 -0400165 '${suffix}': name_suffix}
166 replace_dict.update(common_dict)
167 self.logger.info('Preloading VF Module ' + vfmodule_name)
Bartek Grzybowski3d3d3c22020-03-05 10:28:03 +0100168 if gra_api_flag:
169 return self.preload(template_file, replace_dict, self.vcpecommon.sdnc_preload_gra_url)
Brian Freeman9b3d6ca2019-11-06 13:22:53 -0500170 else:
Bartek Grzybowski3d3d3c22020-03-05 10:28:03 +0100171 return self.preload(template_file, replace_dict, self.vcpecommon.sdnc_preload_vnf_url)
Kang Xi11d278c2018-04-06 16:56:04 -0400172
173 def preload_all_networks(self, template_file, name_suffix):
174 common_dict = {'${' + k + '}': v for k, v in self.vcpecommon.common_preload_config.items()}
175 for network, v in self.vcpecommon.preload_network_config.items():
176 subnet_start_ip, subnet_gateway_ip = v
177 if not self.preload_network(template_file, network, subnet_start_ip, subnet_gateway_ip,
178 common_dict, name_suffix):
179 return None
180 return common_dict
181
Bartek Grzybowski6358aa32019-10-30 13:46:43 +0100182 def aai_region_query(self, req_method, json=None, verify=False):
183 """
184 Perform actual AAI API request for region
185 :param req_method: request method ({'get','put'})
186 :param json: Json payload
187 :param verify: SSL verify mode
188 :return:
189 """
190 url, headers, auth = (self.vcpecommon.aai_region_query_url,
191 self.vcpecommon.aai_headers,
192 self.vcpecommon.aai_userpass)
193 try:
194 if req_method == 'get':
195 request = requests.get(url, headers=headers, auth=auth,
196 verify=verify)
197 elif req_method == 'put':
198 request = requests.put(url, headers=headers, auth=auth,
199 verify=verify, json=json)
200 else:
201 raise requests.exceptions.RequestException
202 except requests.exceptions.RequestException as e:
203 self.logger.error("Error connecting to AAI API. Error details: " + str(e.message))
204 return False
205 try:
206 assert request.status_code == 200
207 except AssertionError:
208 self.logger.error('AAI request failed. API returned http code ' + str(request.status_code))
209 return False
210 try:
211 return request.json()
212 except ValueError as e:
213 if req_method == 'get':
214 self.logger.error('Unable to parse AAI response: ' + e.message)
215 return False
216 elif req_method == 'put':
217 return request.ok
218 else:
219 return False
220
221 def preload_aai_data(self, template_aai_region_data):
222 """
223 Update aai region data with identity-url
224 :param template_aai_region_data: path to region data template
225 :return:
226 """
227 request = self.aai_region_query('get')
228 if request:
229 # Check if identity-url already updated (for idempotency)
230 self.logger.debug("Regiond data acquired from AAI:\n" + json.dumps(request,indent=4))
231 try:
232 assert request['identity-url']
233 except KeyError:
234 pass
235 else:
236 self.logger.info('Identity-url already present in {0} data, not updating'.format(self.vcpecommon.cloud['--os-region-name']))
237 return
238
239 # Get resource_version and relationship_list from region data
240 resource_version = request['resource-version']
241 relationship_list = request['relationship-list']
242
243 replace_dict = {'${identity-url}': self.vcpecommon.cloud['--os-auth-url'],
244 '${identity_api_version}': self.vcpecommon.cloud['--os-identity-api-version'],
245 '${region_name}': self.vcpecommon.cloud['--os-region-name'],
246 '${resource_version}': resource_version
247 }
248 json_data = self.generate_json(template_aai_region_data, replace_dict)
249 json_data['relationship-list'] = relationship_list
250 self.logger.debug('Region update payload:\n' + json.dumps(json_data,indent=4))
251 else:
252 sys.exit(1)
253
254 # Update region data
255 request = self.aai_region_query('put', json_data)
256 if request:
257 self.logger.info('Successully updated identity-url in {0} '
258 'region'.format(self.vcpecommon.cloud['--os-region-name']))
259 else:
260 sys.exit(1)
261
Kang Xi11d278c2018-04-06 16:56:04 -0400262 def test(self):
263 # this is for testing purpose
264 name_suffix = datetime.now().strftime('%Y%m%d%H%M')
Bartek Grzybowski9afc5c72019-12-13 10:27:38 +0100265 preloader = Preload(self.vcpecommon)
Kang Xi11d278c2018-04-06 16:56:04 -0400266
267 network_dict = {'${' + k + '}': v for k, v in self.vcpecommon.common_preload_config.items()}
268 template_file = 'preload_templates/template.network.json'
269 for k, v in self.vcpecommon.preload_network_config.items():
270 if not preloader.preload_network(template_file, k, v[0], v[1], network_dict, name_suffix):
271 break
272
273 print('---------------------------------------------------------------')
274 print('Network related replacement dictionary:')
275 print(json.dumps(network_dict, indent=4, sort_keys=True))
276 print('---------------------------------------------------------------')
277
278 keys = ['infra', 'bng', 'gmux', 'brg']
279 for key in keys:
Brian Freeman9b3d6ca2019-11-06 13:22:53 -0500280 key_vnf= key + "_"
281 key_gra = key + "gra_"
Kang Xi11d278c2018-04-06 16:56:04 -0400282 csar_file = self.vcpecommon.find_file(key, 'csar', 'csar')
Brian Freeman9b3d6ca2019-11-06 13:22:53 -0500283 template_file = self.vcpecommon.find_file(key_vnf, 'json', 'preload_templates')
284 template_file_gra = self.vcpecommon.find_file(key_gra, 'json', 'preload_templates')
285 if csar_file and template_file and template_file_gra:
Kang Xi11d278c2018-04-06 16:56:04 -0400286 parser = csar_parser.CsarParser()
287 parser.parse_csar(csar_file)
288 service_instance_id = 'test112233'
Brian Freeman9b3d6ca2019-11-06 13:22:53 -0500289 # preload both VNF-API and GRA-API
Kang Xi11d278c2018-04-06 16:56:04 -0400290 preloader.preload_vfmodule(template_file, service_instance_id, parser.vnf_models[0],
Brian Freeman9b3d6ca2019-11-06 13:22:53 -0500291 parser.vfmodule_models[0], network_dict, name_suffix, False)
292 preloader.preload_vfmodule(template_file_gra, service_instance_id, parser.vnf_models[0],
293 parser.vfmodule_models[0], network_dict, name_suffix, True)
294
Kang Xi11d278c2018-04-06 16:56:04 -0400295
296 def test_sniro(self):
297 template_sniro_data = self.vcpecommon.find_file('sniro_data', 'json', 'preload_templates')
298 template_sniro_request = self.vcpecommon.find_file('sniro_request', 'json', 'preload_templates')
299
300 vcperescust_csar = self.vcpecommon.find_file('rescust', 'csar', 'csar')
301 parser = csar_parser.CsarParser()
302 parser.parse_csar(vcperescust_csar)
303 tunnelxconn_ar_name = None
304 brg_ar_name = None
305 vgw_name = None
306 for model in parser.vnf_models:
307 if 'tunnel' in model['modelCustomizationName']:
308 tunnelxconn_ar_name = model['modelCustomizationName']
309 elif 'brg' in model['modelCustomizationName']:
310 brg_ar_name = model['modelCustomizationName']
311 elif 'vgw' in model['modelCustomizationName']:
312 vgw_name = model['modelCustomizationName']
313
314 if not (tunnelxconn_ar_name and brg_ar_name and vgw_name):
315 self.logger.error('Cannot find all names from %s.', vcperescust_csar)
Bartek Grzybowski68d93c22019-10-30 10:55:55 +0100316 sys.exit(1)
Kang Xi11d278c2018-04-06 16:56:04 -0400317
318 vgmux_svc_instance_uuid = '88888888888888'
319 vbrg_svc_instance_uuid = '999999999999999'
320
321 self.preload_sniro(template_sniro_data, template_sniro_request, tunnelxconn_ar_name, vgw_name, brg_ar_name,
322 vgmux_svc_instance_uuid, vbrg_svc_instance_uuid)