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