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