Automate pod cluster node ip retrieval
[integration.git] / test / vcpe / vcpecommon.py
1 import json
2 import logging
3 import os
4 import pickle
5 import re
6 import sys
7
8 import ipaddress
9 import mysql.connector
10 import requests
11 import commands
12 import time
13 from kubernetes import client, config
14
15 class VcpeCommon:
16     #############################################################################################
17     #     Start: configurations that you must change for a new ONAP installation
18     external_net_addr = '10.12.0.0'
19     external_net_prefix_len = 16
20     #############################################################################################
21     # set the openstack cloud access credentials here
22     oom_mode = True
23
24     cloud = {
25         '--os-auth-url': 'http://10.12.25.2:5000',
26         '--os-username': 'kxi',
27         '--os-user-domain-id': 'default',
28         '--os-project-domain-id': 'default',
29         '--os-tenant-id': 'bc43d50ffcb84750bac0c1707a9a765b' if oom_mode else '1e097c6713e74fd7ac8e4295e605ee1e',
30         '--os-region-name': 'RegionOne',
31         '--os-password': 'n3JhGMGuDzD8',
32         '--os-project-domain-name': 'Integration-SB-03' if oom_mode else 'Integration-SB-07',
33         '--os-identity-api-version': '3'
34     }
35
36     common_preload_config = {
37         'oam_onap_net': 'oam_network_2No2' if oom_mode else 'oam_onap_lAky',
38         'oam_onap_subnet': 'oam_network_2No2' if oom_mode else 'oam_onap_lAky',
39         'public_net': 'external',
40         'public_net_id': '971040b2-7059-49dc-b220-4fab50cb2ad4'
41     }
42     sdnc_controller_pod = 'dev-sdnc-sdnc-0'
43
44     #############################################################################################
45
46     template_variable_symbol = '${'
47     cpe_vm_prefix = 'zdcpe'
48     #############################################################################################
49     # preloading network config
50     #  key=network role
51     #  value = [subnet_start_ip, subnet_gateway_ip]
52     preload_network_config = {
53         'cpe_public': ['10.2.0.2', '10.2.0.1'],
54         'cpe_signal': ['10.4.0.2', '10.4.0.1'],
55         'brg_bng': ['10.3.0.2', '10.3.0.1'],
56         'bng_mux': ['10.1.0.10', '10.1.0.1'],
57         'mux_gw': ['10.5.0.10', '10.5.0.1']
58     }
59
60     dcae_ves_collector_name = 'dcae-bootstrap'
61     global_subscriber_id = 'SDN-ETHERNET-INTERNET'
62     project_name = 'Project-Demonstration'
63     owning_entity_id = '520cc603-a3c4-4ec2-9ef4-ca70facd79c0'
64     owning_entity_name = 'OE-Demonstration1'
65
66     def __init__(self, extra_host_names=None):
67         self.logger = logging.getLogger(__name__)
68         self.logger.info('Initializing configuration')
69
70         # CHANGEME: vgw_VfModuleModelInvariantUuid is in rescust service csar, look in service-VcpesvcRescust1118-template.yml for groups vgw module metadata. TODO: read this value automcatically
71         self.vgw_VfModuleModelInvariantUuid = '26d6a718-17b2-4ba8-8691-c44343b2ecd2'
72         # CHANGEME: OOM: this is the address that the brg and bng will nat for sdnc access - 10.0.0.x address of k8 host for sdnc-0 container
73         self.sdnc_oam_ip = self.get_pod_node_oam_ip('sdnc-sdnc-0')
74         # CHANGEME: OOM: this is a k8s host external IP, e.g. oom-k8s-01 IP 
75         self.oom_so_sdnc_aai_ip = self.get_pod_node_public_ip('sdnc-sdnc-0')
76         # CHANGEME: OOM: this is a k8s host external IP, e.g. oom-k8s-01 IP
77         self.oom_dcae_ves_collector = self.get_pod_node_public_ip('sdnc-sdnc-0')
78         # CHANGEME: OOM: this is a k8s host external IP, e.g. oom-k8s-01 IP
79         self.mr_ip_addr = self.get_pod_node_public_ip('sdnc-sdnc-0')
80         self.mr_ip_port = '30227'
81         self.so_nbi_port = '30277' if self.oom_mode else '8080'
82         self.sdnc_preloading_port = '30202' if self.oom_mode else '8282'
83         self.aai_query_port = '30233' if self.oom_mode else '8443'
84         self.sniro_port = '30288' if self.oom_mode else '8080'
85
86         self.host_names = ['so', 'sdnc', 'robot', 'aai-inst1', self.dcae_ves_collector_name]
87         if extra_host_names:
88             self.host_names.extend(extra_host_names)
89         # get IP addresses
90         self.hosts = self.get_vm_ip(self.host_names, self.external_net_addr, self.external_net_prefix_len)
91         # this is the keyword used to name vgw stack, must not be used in other stacks
92         self.vgw_name_keyword = 'base_vcpe_vgw'
93         # this is the file that will keep the index of last assigned SO name
94         self.vgw_vfmod_name_index_file= '__var/vgw_vfmod_name_index'
95         self.svc_instance_uuid_file = '__var/svc_instance_uuid'
96         self.preload_dict_file = '__var/preload_dict'
97         self.vgmux_vnf_name_file = '__var/vgmux_vnf_name'
98         self.product_family_id = 'f9457e8c-4afd-45da-9389-46acd9bf5116'
99         self.custom_product_family_id = 'a9a77d5a-123e-4ca2-9eb9-0b015d2ee0fb'
100         self.instance_name_prefix = {
101             'service': 'vcpe_svc',
102             'network': 'vcpe_net',
103             'vnf': 'vcpe_vnf',
104             'vfmodule': 'vcpe_vfmodule'
105         }
106         self.aai_userpass = 'AAI', 'AAI'
107         self.pub_key = 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDKXDgoo3+WOqcUG8/5uUbk81+yczgwC4Y8ywTmuQqbNxlY1oQ0YxdMUqUnhitSXs5S/yRuAVOYHwGg2mCs20oAINrP+mxBI544AMIb9itPjCtgqtE2EWo6MmnFGbHB4Sx3XioE7F4VPsh7japsIwzOjbrQe+Mua1TGQ5d4nfEOQaaglXLLPFfuc7WbhbJbK6Q7rHqZfRcOwAMXgDoBqlyqKeiKwnumddo2RyNT8ljYmvB6buz7KnMinzo7qB0uktVT05FH9Rg0CTWH5norlG5qXgP2aukL0gk1ph8iAt7uYLf1ktp+LJI2gaF6L0/qli9EmVCSLr1uJ38Q8CBflhkh'
108         self.os_tenant_id = self.cloud['--os-tenant-id']
109         self.os_region_name = self.cloud['--os-region-name']
110         self.common_preload_config['pub_key'] = self.pub_key
111         self.sniro_url = 'http://' + self.hosts['robot'] + ':' + self.sniro_port + '/__admin/mappings'
112         self.sniro_headers = {'Content-Type': 'application/json', 'Accept': 'application/json'}
113         self.homing_solution = 'sniro'  # value is either 'sniro' or 'oof'
114 #        self.homing_solution = 'oof'
115         self.customer_location_used_by_oof = {
116             "customerLatitude": "32.897480",
117             "customerLongitude": "-97.040443",
118             "customerName": "some_company"
119         }
120
121         #############################################################################################
122         # SDNC urls
123         self.sdnc_userpass = 'admin', 'Kp8bJ4SXszM0WXlhak3eHlcse2gAw84vaoGGmJvUy2U'
124         self.sdnc_db_name = 'sdnctl'
125         self.sdnc_db_user = 'sdnctl'
126         self.sdnc_db_pass = 'gamma'
127         self.sdnc_db_port = '32774'
128         self.sdnc_headers = {'Content-Type': 'application/json', 'Accept': 'application/json'}
129         self.sdnc_preload_network_url = 'http://' + self.hosts['sdnc'] + \
130                                         ':' + self.sdnc_preloading_port + '/restconf/operations/VNF-API:preload-network-topology-operation'
131         self.sdnc_preload_vnf_url = 'http://' + self.hosts['sdnc'] + \
132                                     ':' + self.sdnc_preloading_port + '/restconf/operations/VNF-API:preload-vnf-topology-operation'
133         self.sdnc_preload_gra_url = 'http://' + self.hosts['sdnc'] + \
134                                     ':' + self.sdnc_preloading_port + '/restconf/operations/GENERIC-RESOURCE-API:preload-vf-module-topology-operation'
135         self.sdnc_ar_cleanup_url = 'http://' + self.hosts['sdnc'] + ':' + self.sdnc_preloading_port + \
136                                    '/restconf/config/GENERIC-RESOURCE-API:'
137
138         #############################################################################################
139         # SO urls, note: do NOT add a '/' at the end of the url
140         self.so_req_api_url = {'v4': 'http://' + self.hosts['so'] + ':' + self.so_nbi_port + '/onap/so/infra/serviceInstantiation/v7/serviceInstances',
141                            'v5': 'http://' + self.hosts['so'] + ':' + self.so_nbi_port + '/onap/so/infra/serviceInstantiation/v7/serviceInstances'}
142         self.so_check_progress_api_url = 'http://' + self.hosts['so'] + ':' + self.so_nbi_port + '/onap/so/infra/orchestrationRequests/v6'
143         self.so_userpass = 'InfraPortalClient', 'password1$'
144         self.so_headers = {'Content-Type': 'application/json', 'Accept': 'application/json'}
145         self.so_db_name = 'catalogdb'
146         self.so_db_user = 'root'
147         self.so_db_pass = 'password'
148         self.so_db_port = '30252' if self.oom_mode else '32769'
149
150         self.vpp_inf_url = 'http://{0}:8183/restconf/config/ietf-interfaces:interfaces'
151         self.vpp_api_headers = {'Content-Type': 'application/json', 'Accept': 'application/json'}
152         self.vpp_api_userpass = ('admin', 'admin')
153         self.vpp_ves_url= 'http://{0}:8183/restconf/config/vesagent:vesagent'
154
155     def headbridge(self, openstack_stack_name, svc_instance_uuid):
156         """
157         Add vserver information to AAI
158         """
159         self.logger.info('Adding vServer information to AAI for {0}'.format(openstack_stack_name))
160         if not self.oom_mode:
161             cmd = '/opt/demo.sh heatbridge {0} {1} vCPE'.format(openstack_stack_name, svc_instance_uuid)
162             ret = commands.getstatusoutput("ssh -i onap_dev root@{0} '{1}'".format(self.hosts['robot'], cmd))
163             self.logger.debug('%s', ret)
164         else:
165             print('To add vGMUX vserver info to AAI, do the following:')
166             print('- ssh to rancher')
167             print('- sudo su -')
168             print('- cd /root/oom/kubernetes/robot')
169             print('- ./demo-k8s.sh onap heatbridge {0} {1} vCPE'.format(openstack_stack_name, svc_instance_uuid))
170
171     def get_brg_mac_from_sdnc(self):
172         """
173         Check table DHCP_MAP in the SDNC DB. Find the newly instantiated BRG MAC address.
174         Note that there might be multiple BRGs, the most recently instantiated BRG always has the largest IP address.
175         """
176         cnx = mysql.connector.connect(user=self.sdnc_db_user, password=self.sdnc_db_pass, database=self.sdnc_db_name,
177                                       host=self.hosts['sdnc'], port=self.sdnc_db_port)
178         cursor = cnx.cursor()
179         query = "SELECT * from DHCP_MAP"
180         cursor.execute(query)
181
182         self.logger.debug('DHCP_MAP table in SDNC')
183         mac_recent = None
184         host = -1
185         for mac, ip in cursor:
186             self.logger.debug(mac + ':' + ip)
187             this_host = int(ip.split('.')[-1])
188             if host < this_host:
189                 host = this_host
190                 mac_recent = mac
191
192         cnx.close()
193
194         assert mac_recent
195         return mac_recent
196
197     def execute_cmds_sdnc_db(self, cmds):
198         self.execute_cmds_db(cmds, self.sdnc_db_user, self.sdnc_db_pass, self.sdnc_db_name,
199                              self.hosts['sdnc'], self.sdnc_db_port)
200
201     def execute_cmds_so_db(self, cmds):
202         self.execute_cmds_db(cmds, self.so_db_user, self.so_db_pass, self.so_db_name,
203                              self.hosts['so'], self.so_db_port)
204
205     def execute_cmds_db(self, cmds, dbuser, dbpass, dbname, host, port):
206         cnx = mysql.connector.connect(user=dbuser, password=dbpass, database=dbname, host=host, port=port)
207         cursor = cnx.cursor()
208         for cmd in cmds:
209             self.logger.debug(cmd)
210             cursor.execute(cmd)
211             self.logger.debug('%s', cursor)
212         cnx.commit()
213         cursor.close()
214         cnx.close()
215
216     def find_file(self, file_name_keyword, file_ext, search_dir):
217         """
218         :param file_name_keyword:  keyword used to look for the csar file, case insensitive matching, e.g, infra
219         :param file_ext: e.g., csar, json
220         :param search_dir path to search
221         :return: path name of the file
222         """
223         file_name_keyword = file_name_keyword.lower()
224         file_ext = file_ext.lower()
225         if not file_ext.startswith('.'):
226             file_ext = '.' + file_ext
227
228         filenamepath = None
229         for file_name in os.listdir(search_dir):
230             file_name_lower = file_name.lower()
231             if file_name_keyword in file_name_lower and file_name_lower.endswith(file_ext):
232                 if filenamepath:
233                     self.logger.error('Multiple files found for *{0}*.{1} in '
234                                       'directory {2}'.format(file_name_keyword, file_ext, search_dir))
235                     sys.exit()
236                 filenamepath = os.path.abspath(os.path.join(search_dir, file_name))
237
238         if filenamepath:
239             return filenamepath
240         else:
241             self.logger.error("Cannot find *{0}*{1} in directory {2}".format(file_name_keyword, file_ext, search_dir))
242             sys.exit()
243
244     @staticmethod
245     def network_name_to_subnet_name(network_name):
246         """
247         :param network_name: example: vcpe_net_cpe_signal_201711281221
248         :return: vcpe_net_cpe_signal_subnet_201711281221
249         """
250         fields = network_name.split('_')
251         fields.insert(-1, 'subnet')
252         return '_'.join(fields)
253
254     def set_network_name(self, network_name):
255         param = ' '.join([k + ' ' + v for k, v in self.cloud.items()])
256         openstackcmd = 'openstack ' + param
257         cmd = ' '.join([openstackcmd, 'network set --name', network_name, 'ONAP-NW1'])
258         os.popen(cmd)
259
260     def set_subnet_name(self, network_name):
261         """
262         Example: network_name =  vcpe_net_cpe_signal_201711281221
263         set subnet name to vcpe_net_cpe_signal_subnet_201711281221
264         :return:
265         """
266         param = ' '.join([k + ' ' + v for k, v in self.cloud.items()])
267         openstackcmd = 'openstack ' + param
268
269         # expected results: | subnets | subnet_id |
270         subnet_info = os.popen(openstackcmd + ' network show ' + network_name + ' |grep subnets').read().split('|')
271         if len(subnet_info) > 2 and subnet_info[1].strip() == 'subnets':
272             subnet_id = subnet_info[2].strip()
273             subnet_name = self.network_name_to_subnet_name(network_name)
274             cmd = ' '.join([openstackcmd, 'subnet set --name', subnet_name, subnet_id])
275             os.popen(cmd)
276             self.logger.info("Subnet name set to: " + subnet_name)
277             return True
278         else:
279             self.logger.error("Can't get subnet info from network name: " + network_name)
280             return False
281
282     def is_node_in_aai(self, node_type, node_uuid):
283         key = None
284         search_node_type = None
285         if node_type == 'service':
286             search_node_type = 'service-instance'
287             key = 'service-instance-id'
288         elif node_type == 'vnf':
289             search_node_type = 'generic-vnf'
290             key = 'vnf-id'
291         else:
292             logging.error('Invalid node_type: ' + node_type)
293             sys.exit()
294
295         url = 'https://{0}:{1}/aai/v11/search/nodes-query?search-node-type={2}&filter={3}:EQUALS:{4}'.format(
296             self.hosts['aai-inst1'], self.aai_query_port, search_node_type, key, node_uuid)
297
298         headers = {'Content-Type': 'application/json', 'Accept': 'application/json', 'X-FromAppID': 'vCPE-Robot', 'X-TransactionId': 'get_aai_subscr'}
299         requests.packages.urllib3.disable_warnings()
300         r = requests.get(url, headers=headers, auth=self.aai_userpass, verify=False)
301         response = r.json()
302         self.logger.debug('aai query: ' + url)
303         self.logger.debug('aai response:\n' + json.dumps(response, indent=4, sort_keys=True))
304         return 'result-data' in response
305
306     @staticmethod
307     def extract_ip_from_str(net_addr, net_addr_len, sz):
308         """
309         :param net_addr:  e.g. 10.5.12.0
310         :param net_addr_len: e.g. 24
311         :param sz: a string
312         :return: the first IP address matching the network, e.g. 10.5.12.3
313         """
314         network = ipaddress.ip_network(unicode('{0}/{1}'.format(net_addr, net_addr_len)), strict=False)
315         ip_list = re.findall(r'[0-9]+(?:\.[0-9]+){3}', sz)
316         for ip in ip_list:
317             this_net = ipaddress.ip_network(unicode('{0}/{1}'.format(ip, net_addr_len)), strict=False)
318             if this_net == network:
319                 return str(ip)
320         return None
321
322     def get_pod_node_oam_ip(self, pod):
323         """
324         :Assuming kubectl is available and configured by default config (~/.kube/config) 
325         :param pod: pod name substring, e.g. 'sdnc-sdnc-0'
326         :return pod's cluster node oam ip (10.0.0.0/16)
327         """
328         ret = None
329         config.load_kube_config()
330         api = client.CoreV1Api()
331         kslogger = logging.getLogger('kubernetes')
332         kslogger.setLevel(logging.INFO)
333         res = api.list_pod_for_all_namespaces()
334         for i in res.items:
335             if pod in i.metadata.name:
336                 self.logger.debug("found %s\t%s\t%s", i.metadata.name, i.status.host_ip, i.spec.node_name)
337                 ret = i.status.host_ip
338                 break
339
340         if ret is None:
341             ret = raw_input("Enter sdnc-sdnc-0 pod cluster node OAM IP address(10.0.0.0/16): ")
342         return ret
343
344     def get_pod_node_public_ip(self, pod):
345         """
346         :Assuming kubectl is available and configured by default config (~/.kube/config) 
347         :param pod: pod name substring, e.g. 'sdnc-sdnc-0'
348         :return pod's cluster node public ip (i.e. 10.12.0.0/16)
349         """
350         ret = None
351         config.load_kube_config()
352         api = client.CoreV1Api()
353         kslogger = logging.getLogger('kubernetes')
354         kslogger.setLevel(logging.INFO)
355         res = api.list_pod_for_all_namespaces()
356         for i in res.items:
357             if pod in i.metadata.name:
358                 self.logger.debug("found node %s public ip: %s", i.spec.node_name, self.get_vm_ip([i.spec.node_name])[i.spec.node_name])
359                 ret = self.get_vm_ip([i.spec.node_name])[i.spec.node_name]
360                 break
361
362         if ret is None:
363             ret = raw_input("Enter sdnc-sdnc-0 pod cluster node public IP address(i.e. 10.12.0.0/16): ")
364         return ret
365
366     def get_vm_ip(self, keywords, net_addr=None, net_addr_len=None):
367         """
368         :param keywords: list of keywords to search for vm, e.g. ['bng', 'gmux', 'brg']
369         :param net_addr: e.g. 10.12.5.0
370         :param net_addr_len: e.g. 24
371         :return: dictionary {keyword: ip}
372         """
373         if not net_addr:
374             net_addr = self.external_net_addr
375
376         if not net_addr_len:
377             net_addr_len = self.external_net_prefix_len
378
379         param = ' '.join([k + ' ' + v for k, v in self.cloud.items() if 'identity' not in k])
380         openstackcmd = 'nova ' + param + ' list'
381         self.logger.debug(openstackcmd)
382
383         results = os.popen(openstackcmd).read()
384         all_vm_ip_dict = self.extract_vm_ip_as_dict(results, net_addr, net_addr_len)
385         latest_vm_list = self.remove_old_vms(all_vm_ip_dict.keys(), self.cpe_vm_prefix)
386         latest_vm_ip_dict = {vm: all_vm_ip_dict[vm] for vm in latest_vm_list}
387         ip_dict = self.select_subset_vm_ip(latest_vm_ip_dict, keywords)
388         if self.oom_mode:
389             ip_dict.update(self.get_oom_onap_vm_ip(keywords))
390
391         if len(ip_dict) != len(keywords):
392             self.logger.error('Cannot find all desired IP addresses for %s.', keywords)
393             self.logger.error(json.dumps(ip_dict, indent=4, sort_keys=True))
394             self.logger.error('Temporarily continue.. remember to check back vcpecommon.py line: 396')
395 #            sys.exit()
396         return ip_dict
397
398     def get_oom_onap_vm_ip(self, keywords):
399         vm_ip = {}
400         onap_vm_list = set(['so', 'sdnc', 'aai-inst1', 'robot', self.dcae_ves_collector_name])
401         for vm in keywords:
402             if vm in onap_vm_list:
403                 vm_ip[vm] = self.oom_so_sdnc_aai_ip
404         return vm_ip
405
406     def extract_vm_ip_as_dict(self, novalist_results, net_addr, net_addr_len):
407         vm_ip_dict = {}
408         for line in novalist_results.split('\n'):
409             fields = line.split('|')
410             if len(fields) == 8:
411                 vm_name = fields[2]
412                 ip_info = fields[-2]
413                 ip = self.extract_ip_from_str(net_addr, net_addr_len, ip_info)
414                 vm_ip_dict[vm_name] = ip
415
416         return vm_ip_dict
417
418     def remove_old_vms(self, vm_list, prefix):
419         """
420         For vms with format name_timestamp, only keep the one with the latest timestamp.
421         E.g.,
422             zdcpe1cpe01brgemu01_201805222148        (drop this)
423             zdcpe1cpe01brgemu01_201805222229        (keep this)
424             zdcpe1cpe01gw01_201805162201
425         """
426         new_vm_list = []
427         same_type_vm_dict = {}
428         for vm in vm_list:
429             fields = vm.split('_')
430             if vm.startswith(prefix) and len(fields) == 2 and len(fields[-1]) == len('201805222148') and fields[-1].isdigit():
431                 if vm > same_type_vm_dict.get(fields[0], '0'):
432                     same_type_vm_dict[fields[0]] = vm
433             else:
434                 new_vm_list.append(vm)
435
436         new_vm_list.extend(same_type_vm_dict.values())
437         return new_vm_list
438
439     def select_subset_vm_ip(self, all_vm_ip_dict, vm_name_keyword_list):
440         vm_ip_dict = {}
441         for keyword in vm_name_keyword_list:
442             for vm, ip in all_vm_ip_dict.items():
443                 if keyword in vm:
444                     vm_ip_dict[keyword] = ip
445                     break
446         return vm_ip_dict
447
448     def del_vgmux_ves_mode(self):
449         url = self.vpp_ves_url.format(self.hosts['mux']) + '/mode'
450         r = requests.delete(url, headers=self.vpp_api_headers, auth=self.vpp_api_userpass)
451         self.logger.debug('%s', r)
452
453     def del_vgmux_ves_collector(self):
454         url = self.vpp_ves_url.format(self.hosts['mux']) + '/config'
455         r = requests.delete(url, headers=self.vpp_api_headers, auth=self.vpp_api_userpass)
456         self.logger.debug('%s', r)
457
458     def set_vgmux_ves_collector(self ):
459         url = self.vpp_ves_url.format(self.hosts['mux'])
460         data = {'config':
461                     {'server-addr': self.hosts[self.dcae_ves_collector_name],
462                      'server-port': '30235' if self.oom_mode else '8081',
463                      'read-interval': '10',
464                      'is-add':'1'
465                      }
466                 }
467         r = requests.post(url, headers=self.vpp_api_headers, auth=self.vpp_api_userpass, json=data)
468         self.logger.debug('%s', r)
469
470     def set_vgmux_packet_loss_rate(self, lossrate, vg_vnf_instance_name):
471         url = self.vpp_ves_url.format(self.hosts['mux'])
472         data = {"mode":
473                     {"working-mode": "demo",
474                      "base-packet-loss": str(lossrate),
475                      "source-name": vg_vnf_instance_name
476                      }
477                 }
478         r = requests.post(url, headers=self.vpp_api_headers, auth=self.vpp_api_userpass, json=data)
479         self.logger.debug('%s', r)
480
481         # return all the VxLAN interface names of BRG or vGMUX based on the IP address
482     def get_vxlan_interfaces(self, ip, print_info=False):
483         url = self.vpp_inf_url.format(ip)
484         self.logger.debug('url is this: %s', url)
485         r = requests.get(url, headers=self.vpp_api_headers, auth=self.vpp_api_userpass)
486         data = r.json()['interfaces']['interface']
487         if print_info:
488             for inf in data:
489                 if 'name' in inf and 'type' in inf and inf['type'] == 'v3po:vxlan-tunnel':
490                     print(json.dumps(inf, indent=4, sort_keys=True))
491
492         return [inf['name'] for inf in data if 'name' in inf and 'type' in inf and inf['type'] == 'v3po:vxlan-tunnel']
493
494     # delete all VxLAN interfaces of each hosts
495     def delete_vxlan_interfaces(self, host_dic):
496         for host, ip in host_dic.items():
497             deleted = False
498             self.logger.info('{0}: Getting VxLAN interfaces'.format(host))
499             inf_list = self.get_vxlan_interfaces(ip)
500             for inf in inf_list:
501                 deleted = True
502                 time.sleep(2)
503                 self.logger.info("{0}: Deleting VxLAN crossconnect {1}".format(host, inf))
504                 url = self.vpp_inf_url.format(ip) + '/interface/' + inf + '/v3po:l2'
505                 requests.delete(url, headers=self.vpp_api_headers, auth=self.vpp_api_userpass)
506
507             for inf in inf_list:
508                 deleted = True
509                 time.sleep(2)
510                 self.logger.info("{0}: Deleting VxLAN interface {1}".format(host, inf))
511                 url = self.vpp_inf_url.format(ip) + '/interface/' + inf
512                 requests.delete(url, headers=self.vpp_api_headers, auth=self.vpp_api_userpass)
513
514             if len(self.get_vxlan_interfaces(ip)) > 0:
515                 self.logger.error("Error deleting VxLAN from {0}, try to restart the VM, IP is {1}.".format(host, ip))
516                 return False
517
518             if not deleted:
519                 self.logger.info("{0}: no VxLAN interface found, nothing to delete".format(host))
520         return True
521
522     @staticmethod
523     def save_object(obj, filepathname):
524         with open(filepathname, 'wb') as fout:
525             pickle.dump(obj, fout)
526
527     @staticmethod
528     def load_object(filepathname):
529         with open(filepathname, 'rb') as fin:
530             return pickle.load(fin)
531
532     @staticmethod
533     def increase_ip_address_or_vni_in_template(vnf_template_file, vnf_parameter_name_list):
534         with open(vnf_template_file) as json_input:
535             json_data = json.load(json_input)
536             param_list = json_data['VNF-API:input']['VNF-API:vnf-topology-information']['VNF-API:vnf-parameters']
537             for param in param_list:
538                 if param['vnf-parameter-name'] in vnf_parameter_name_list:
539                     ipaddr_or_vni = param['vnf-parameter-value'].split('.')
540                     number = int(ipaddr_or_vni[-1])
541                     if 254 == number:
542                         number = 10
543                     else:
544                         number = number + 1
545                     ipaddr_or_vni[-1] = str(number)
546                     param['vnf-parameter-value'] = '.'.join(ipaddr_or_vni)
547
548         assert json_data is not None
549         with open(vnf_template_file, 'w') as json_output:
550             json.dump(json_data, json_output, indent=4, sort_keys=True)
551
552     def save_preload_data(self, preload_data):
553         self.save_object(preload_data, self.preload_dict_file)
554
555     def load_preload_data(self):
556         return self.load_object(self.preload_dict_file)
557
558     def save_vgmux_vnf_name(self, vgmux_vnf_name):
559         self.save_object(vgmux_vnf_name, self.vgmux_vnf_name_file)
560
561     def load_vgmux_vnf_name(self):
562         return self.load_object(self.vgmux_vnf_name_file)
563