Download vCPE service csar from SDC
[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 = ['sdc', '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         # SDC urls
135         self.sdc_get_request_userpass = 'vid','Kp8bJ4SXszM0WXlhak3eHlcse2gAw84vaoGGmJvUy2U'
136         self.sdc_get_request_headers = {'X-ECOMP-InstanceID': 'VID'}
137         self.sdc_port = '30205'
138         self.sdc_url_prefix = 'http://' + self.hosts['sdc'] + ':' + self.sdc_port
139         self.sdc_service_list_url = self.sdc_url_prefix + '/sdc/v1/catalog/services'
140
141         #############################################################################################
142         # SDNC urls
143         self.sdnc_userpass = 'admin', 'Kp8bJ4SXszM0WXlhak3eHlcse2gAw84vaoGGmJvUy2U'
144         self.sdnc_db_name = 'sdnctl'
145         self.sdnc_db_user = 'sdnctl'
146         self.sdnc_db_pass = 'gamma'
147         self.sdnc_db_port = '32774'
148         self.sdnc_headers = {'Content-Type': 'application/json', 'Accept': 'application/json'}
149         self.sdnc_preload_network_url = 'http://' + self.hosts['sdnc'] + \
150                                         ':' + self.sdnc_preloading_port + '/restconf/operations/VNF-API:preload-network-topology-operation'
151         self.sdnc_preload_vnf_url = 'http://' + self.hosts['sdnc'] + \
152                                     ':' + self.sdnc_preloading_port + '/restconf/operations/VNF-API:preload-vnf-topology-operation'
153         self.sdnc_preload_gra_url = 'http://' + self.hosts['sdnc'] + \
154                                     ':' + self.sdnc_preloading_port + '/restconf/operations/GENERIC-RESOURCE-API:preload-vf-module-topology-operation'
155         self.sdnc_ar_cleanup_url = 'http://' + self.hosts['sdnc'] + ':' + self.sdnc_preloading_port + \
156                                    '/restconf/config/GENERIC-RESOURCE-API:'
157
158         #############################################################################################
159         # SO urls, note: do NOT add a '/' at the end of the url
160         self.so_req_api_url = {'v4': 'http://' + self.hosts['so'] + ':' + self.so_nbi_port + '/onap/so/infra/serviceInstantiation/v7/serviceInstances',
161                            'v5': 'http://' + self.hosts['so'] + ':' + self.so_nbi_port + '/onap/so/infra/serviceInstantiation/v7/serviceInstances'}
162         self.so_check_progress_api_url = 'http://' + self.hosts['so'] + ':' + self.so_nbi_port + '/onap/so/infra/orchestrationRequests/v6'
163         self.so_userpass = 'InfraPortalClient', 'password1$'
164         self.so_headers = {'Content-Type': 'application/json', 'Accept': 'application/json'}
165         self.so_db_name = 'catalogdb'
166         self.so_db_user = 'root'
167         self.so_db_pass = 'password'
168         self.so_db_port = '30252' if self.oom_mode else '32769'
169
170         self.vpp_inf_url = 'http://{0}:8183/restconf/config/ietf-interfaces:interfaces'
171         self.vpp_api_headers = {'Content-Type': 'application/json', 'Accept': 'application/json'}
172         self.vpp_api_userpass = ('admin', 'admin')
173         self.vpp_ves_url= 'http://{0}:8183/restconf/config/vesagent:vesagent'
174
175     def headbridge(self, openstack_stack_name, svc_instance_uuid):
176         """
177         Add vserver information to AAI
178         """
179         self.logger.info('Adding vServer information to AAI for {0}'.format(openstack_stack_name))
180         if not self.oom_mode:
181             cmd = '/opt/demo.sh heatbridge {0} {1} vCPE'.format(openstack_stack_name, svc_instance_uuid)
182             ret = commands.getstatusoutput("ssh -i onap_dev root@{0} '{1}'".format(self.hosts['robot'], cmd))
183             self.logger.debug('%s', ret)
184         else:
185             print('To add vGMUX vserver info to AAI, do the following:')
186             print('- ssh to rancher')
187             print('- sudo su -')
188             print('- cd /root/oom/kubernetes/robot')
189             print('- ./demo-k8s.sh onap heatbridge {0} {1} vCPE'.format(openstack_stack_name, svc_instance_uuid))
190
191     def get_brg_mac_from_sdnc(self):
192         """
193         Check table DHCP_MAP in the SDNC DB. Find the newly instantiated BRG MAC address.
194         Note that there might be multiple BRGs, the most recently instantiated BRG always has the largest IP address.
195         """
196         cnx = mysql.connector.connect(user=self.sdnc_db_user, password=self.sdnc_db_pass, database=self.sdnc_db_name,
197                                       host=self.hosts['sdnc'], port=self.sdnc_db_port)
198         cursor = cnx.cursor()
199         query = "SELECT * from DHCP_MAP"
200         cursor.execute(query)
201
202         self.logger.debug('DHCP_MAP table in SDNC')
203         mac_recent = None
204         host = -1
205         for mac, ip in cursor:
206             self.logger.debug(mac + ':' + ip)
207             this_host = int(ip.split('.')[-1])
208             if host < this_host:
209                 host = this_host
210                 mac_recent = mac
211
212         cnx.close()
213
214         assert mac_recent
215         return mac_recent
216
217     def execute_cmds_sdnc_db(self, cmds):
218         self.execute_cmds_db(cmds, self.sdnc_db_user, self.sdnc_db_pass, self.sdnc_db_name,
219                              self.hosts['sdnc'], self.sdnc_db_port)
220
221     def execute_cmds_so_db(self, cmds):
222         self.execute_cmds_db(cmds, self.so_db_user, self.so_db_pass, self.so_db_name,
223                              self.hosts['so'], self.so_db_port)
224
225     def execute_cmds_db(self, cmds, dbuser, dbpass, dbname, host, port):
226         cnx = mysql.connector.connect(user=dbuser, password=dbpass, database=dbname, host=host, port=port)
227         cursor = cnx.cursor()
228         for cmd in cmds:
229             self.logger.debug(cmd)
230             cursor.execute(cmd)
231             self.logger.debug('%s', cursor)
232         cnx.commit()
233         cursor.close()
234         cnx.close()
235
236     def find_file(self, file_name_keyword, file_ext, search_dir):
237         """
238         :param file_name_keyword:  keyword used to look for the csar file, case insensitive matching, e.g, infra
239         :param file_ext: e.g., csar, json
240         :param search_dir path to search
241         :return: path name of the file
242         """
243         file_name_keyword = file_name_keyword.lower()
244         file_ext = file_ext.lower()
245         if not file_ext.startswith('.'):
246             file_ext = '.' + file_ext
247
248         filenamepath = None
249         for file_name in os.listdir(search_dir):
250             file_name_lower = file_name.lower()
251             if file_name_keyword in file_name_lower and file_name_lower.endswith(file_ext):
252                 if filenamepath:
253                     self.logger.error('Multiple files found for *{0}*.{1} in '
254                                       'directory {2}'.format(file_name_keyword, file_ext, search_dir))
255                     sys.exit()
256                 filenamepath = os.path.abspath(os.path.join(search_dir, file_name))
257
258         if filenamepath:
259             return filenamepath
260         else:
261             self.logger.error("Cannot find *{0}*{1} in directory {2}".format(file_name_keyword, file_ext, search_dir))
262             sys.exit()
263
264     @staticmethod
265     def network_name_to_subnet_name(network_name):
266         """
267         :param network_name: example: vcpe_net_cpe_signal_201711281221
268         :return: vcpe_net_cpe_signal_subnet_201711281221
269         """
270         fields = network_name.split('_')
271         fields.insert(-1, 'subnet')
272         return '_'.join(fields)
273
274     def set_network_name(self, network_name):
275         param = ' '.join([k + ' ' + v for k, v in self.cloud.items()])
276         openstackcmd = 'openstack ' + param
277         cmd = ' '.join([openstackcmd, 'network set --name', network_name, 'ONAP-NW1'])
278         os.popen(cmd)
279
280     def set_subnet_name(self, network_name):
281         """
282         Example: network_name =  vcpe_net_cpe_signal_201711281221
283         set subnet name to vcpe_net_cpe_signal_subnet_201711281221
284         :return:
285         """
286         param = ' '.join([k + ' ' + v for k, v in self.cloud.items()])
287         openstackcmd = 'openstack ' + param
288
289         # expected results: | subnets | subnet_id |
290         subnet_info = os.popen(openstackcmd + ' network show ' + network_name + ' |grep subnets').read().split('|')
291         if len(subnet_info) > 2 and subnet_info[1].strip() == 'subnets':
292             subnet_id = subnet_info[2].strip()
293             subnet_name = self.network_name_to_subnet_name(network_name)
294             cmd = ' '.join([openstackcmd, 'subnet set --name', subnet_name, subnet_id])
295             os.popen(cmd)
296             self.logger.info("Subnet name set to: " + subnet_name)
297             return True
298         else:
299             self.logger.error("Can't get subnet info from network name: " + network_name)
300             return False
301
302     def is_node_in_aai(self, node_type, node_uuid):
303         key = None
304         search_node_type = None
305         if node_type == 'service':
306             search_node_type = 'service-instance'
307             key = 'service-instance-id'
308         elif node_type == 'vnf':
309             search_node_type = 'generic-vnf'
310             key = 'vnf-id'
311         else:
312             logging.error('Invalid node_type: ' + node_type)
313             sys.exit()
314
315         url = 'https://{0}:{1}/aai/v11/search/nodes-query?search-node-type={2}&filter={3}:EQUALS:{4}'.format(
316             self.hosts['aai-inst1'], self.aai_query_port, search_node_type, key, node_uuid)
317
318         headers = {'Content-Type': 'application/json', 'Accept': 'application/json', 'X-FromAppID': 'vCPE-Robot', 'X-TransactionId': 'get_aai_subscr'}
319         requests.packages.urllib3.disable_warnings()
320         r = requests.get(url, headers=headers, auth=self.aai_userpass, verify=False)
321         response = r.json()
322         self.logger.debug('aai query: ' + url)
323         self.logger.debug('aai response:\n' + json.dumps(response, indent=4, sort_keys=True))
324         return 'result-data' in response
325
326     @staticmethod
327     def extract_ip_from_str(net_addr, net_addr_len, sz):
328         """
329         :param net_addr:  e.g. 10.5.12.0
330         :param net_addr_len: e.g. 24
331         :param sz: a string
332         :return: the first IP address matching the network, e.g. 10.5.12.3
333         """
334         network = ipaddress.ip_network(unicode('{0}/{1}'.format(net_addr, net_addr_len)), strict=False)
335         ip_list = re.findall(r'[0-9]+(?:\.[0-9]+){3}', sz)
336         for ip in ip_list:
337             this_net = ipaddress.ip_network(unicode('{0}/{1}'.format(ip, net_addr_len)), strict=False)
338             if this_net == network:
339                 return str(ip)
340         return None
341
342     def get_pod_node_oam_ip(self, pod):
343         """
344         :Assuming kubectl is available and configured by default config (~/.kube/config) 
345         :param pod: pod name substring, e.g. 'sdnc-sdnc-0'
346         :return pod's cluster node oam ip (10.0.0.0/16)
347         """
348         ret = None
349         config.load_kube_config()
350         api = client.CoreV1Api()
351         kslogger = logging.getLogger('kubernetes')
352         kslogger.setLevel(logging.INFO)
353         res = api.list_pod_for_all_namespaces()
354         for i in res.items:
355             if pod in i.metadata.name:
356                 self.logger.debug("found {0}\t{1}\t{2}".format(i.metadata.name, i.status.host_ip, i.spec.node_name))
357                 ret = i.status.host_ip
358                 break
359
360         if ret is None:
361             ret = raw_input("Enter sdnc-sdnc-0 pod cluster node OAM IP address(10.0.0.0/16): ")
362         return ret
363
364     def get_pod_node_public_ip(self, pod):
365         """
366         :Assuming kubectl is available and configured by default config (~/.kube/config) 
367         :param pod: pod name substring, e.g. 'sdnc-sdnc-0'
368         :return pod's cluster node public ip (i.e. 10.12.0.0/16)
369         """
370         ret = None
371         config.load_kube_config()
372         api = client.CoreV1Api()
373         kslogger = logging.getLogger('kubernetes')
374         kslogger.setLevel(logging.INFO)
375         res = api.list_pod_for_all_namespaces()
376         for i in res.items:
377             if pod in i.metadata.name:
378                 ret = self.get_vm_public_ip_by_nova(i.spec.node_name)
379                 self.logger.debug("found node {0} public ip: {1}".format(i.spec.node_name, ret))
380                 break
381
382         if ret is None:
383             ret = raw_input("Enter sdnc-sdnc-0 pod cluster node public IP address(i.e. 10.12.0.0/16): ")
384         return ret
385
386     def get_vm_public_ip_by_nova(self, vm):
387         """
388         This method uses openstack nova api to retrieve vm public ip
389         :param vm: vm name
390         :return vm public ip
391         """
392         subnet = IPNetwork('{0}/{1}'.format(self.external_net_addr, self.external_net_prefix_len))
393         nova = openstackclient.Client(2, self.cloud['--os-username'], self.cloud['--os-password'], self.cloud['--os-tenant-id'], self.cloud['--os-auth-url']) 
394         for i in nova.servers.list():
395             if i.name == vm:
396                 for k, v in i.networks.items():
397                     for ip in v:
398                         if IPAddress(ip) in subnet:
399                             return ip
400         return None
401
402     def get_vm_ip(self, keywords, net_addr=None, net_addr_len=None):
403         """
404         :param keywords: list of keywords to search for vm, e.g. ['bng', 'gmux', 'brg']
405         :param net_addr: e.g. 10.12.5.0
406         :param net_addr_len: e.g. 24
407         :return: dictionary {keyword: ip}
408         """
409         if not net_addr:
410             net_addr = self.external_net_addr
411
412         if not net_addr_len:
413             net_addr_len = self.external_net_prefix_len
414
415         param = ' '.join([k + ' ' + v for k, v in self.cloud.items() if 'identity' not in k])
416         openstackcmd = 'nova ' + param + ' list'
417         self.logger.debug(openstackcmd)
418
419         results = os.popen(openstackcmd).read()
420         all_vm_ip_dict = self.extract_vm_ip_as_dict(results, net_addr, net_addr_len)
421         latest_vm_list = self.remove_old_vms(all_vm_ip_dict.keys(), self.cpe_vm_prefix)
422         latest_vm_ip_dict = {vm: all_vm_ip_dict[vm] for vm in latest_vm_list}
423         ip_dict = self.select_subset_vm_ip(latest_vm_ip_dict, keywords)
424         if self.oom_mode:
425             ip_dict.update(self.get_oom_onap_vm_ip(keywords))
426
427         if len(ip_dict) != len(keywords):
428             self.logger.error('Cannot find all desired IP addresses for %s.', keywords)
429             self.logger.error(json.dumps(ip_dict, indent=4, sort_keys=True))
430             self.logger.error('Temporarily continue.. remember to check back vcpecommon.py line: 396')
431 #            sys.exit()
432         return ip_dict
433
434     def get_oom_onap_vm_ip(self, keywords):
435         vm_ip = {}
436         onap_vm_list = set(['sdc', 'so', 'sdnc', 'aai-inst1', 'robot', self.dcae_ves_collector_name])
437         for vm in keywords:
438             if vm in onap_vm_list:
439                 vm_ip[vm] = self.oom_so_sdnc_aai_ip
440         return vm_ip
441
442     def extract_vm_ip_as_dict(self, novalist_results, net_addr, net_addr_len):
443         vm_ip_dict = {}
444         for line in novalist_results.split('\n'):
445             fields = line.split('|')
446             if len(fields) == 8:
447                 vm_name = fields[2]
448                 ip_info = fields[-2]
449                 ip = self.extract_ip_from_str(net_addr, net_addr_len, ip_info)
450                 vm_ip_dict[vm_name] = ip
451
452         return vm_ip_dict
453
454     def remove_old_vms(self, vm_list, prefix):
455         """
456         For vms with format name_timestamp, only keep the one with the latest timestamp.
457         E.g.,
458             zdcpe1cpe01brgemu01_201805222148        (drop this)
459             zdcpe1cpe01brgemu01_201805222229        (keep this)
460             zdcpe1cpe01gw01_201805162201
461         """
462         new_vm_list = []
463         same_type_vm_dict = {}
464         for vm in vm_list:
465             fields = vm.split('_')
466             if vm.startswith(prefix) and len(fields) == 2 and len(fields[-1]) == len('201805222148') and fields[-1].isdigit():
467                 if vm > same_type_vm_dict.get(fields[0], '0'):
468                     same_type_vm_dict[fields[0]] = vm
469             else:
470                 new_vm_list.append(vm)
471
472         new_vm_list.extend(same_type_vm_dict.values())
473         return new_vm_list
474
475     def select_subset_vm_ip(self, all_vm_ip_dict, vm_name_keyword_list):
476         vm_ip_dict = {}
477         for keyword in vm_name_keyword_list:
478             for vm, ip in all_vm_ip_dict.items():
479                 if keyword in vm:
480                     vm_ip_dict[keyword] = ip
481                     break
482         return vm_ip_dict
483
484     def del_vgmux_ves_mode(self):
485         url = self.vpp_ves_url.format(self.hosts['mux']) + '/mode'
486         r = requests.delete(url, headers=self.vpp_api_headers, auth=self.vpp_api_userpass)
487         self.logger.debug('%s', r)
488
489     def del_vgmux_ves_collector(self):
490         url = self.vpp_ves_url.format(self.hosts['mux']) + '/config'
491         r = requests.delete(url, headers=self.vpp_api_headers, auth=self.vpp_api_userpass)
492         self.logger.debug('%s', r)
493
494     def set_vgmux_ves_collector(self ):
495         url = self.vpp_ves_url.format(self.hosts['mux'])
496         data = {'config':
497                     {'server-addr': self.hosts[self.dcae_ves_collector_name],
498                      'server-port': '30235' if self.oom_mode else '8081',
499                      'read-interval': '10',
500                      'is-add':'1'
501                      }
502                 }
503         r = requests.post(url, headers=self.vpp_api_headers, auth=self.vpp_api_userpass, json=data)
504         self.logger.debug('%s', r)
505
506     def set_vgmux_packet_loss_rate(self, lossrate, vg_vnf_instance_name):
507         url = self.vpp_ves_url.format(self.hosts['mux'])
508         data = {"mode":
509                     {"working-mode": "demo",
510                      "base-packet-loss": str(lossrate),
511                      "source-name": vg_vnf_instance_name
512                      }
513                 }
514         r = requests.post(url, headers=self.vpp_api_headers, auth=self.vpp_api_userpass, json=data)
515         self.logger.debug('%s', r)
516
517         # return all the VxLAN interface names of BRG or vGMUX based on the IP address
518     def get_vxlan_interfaces(self, ip, print_info=False):
519         url = self.vpp_inf_url.format(ip)
520         self.logger.debug('url is this: %s', url)
521         r = requests.get(url, headers=self.vpp_api_headers, auth=self.vpp_api_userpass)
522         data = r.json()['interfaces']['interface']
523         if print_info:
524             for inf in data:
525                 if 'name' in inf and 'type' in inf and inf['type'] == 'v3po:vxlan-tunnel':
526                     print(json.dumps(inf, indent=4, sort_keys=True))
527
528         return [inf['name'] for inf in data if 'name' in inf and 'type' in inf and inf['type'] == 'v3po:vxlan-tunnel']
529
530     # delete all VxLAN interfaces of each hosts
531     def delete_vxlan_interfaces(self, host_dic):
532         for host, ip in host_dic.items():
533             deleted = False
534             self.logger.info('{0}: Getting VxLAN interfaces'.format(host))
535             inf_list = self.get_vxlan_interfaces(ip)
536             for inf in inf_list:
537                 deleted = True
538                 time.sleep(2)
539                 self.logger.info("{0}: Deleting VxLAN crossconnect {1}".format(host, inf))
540                 url = self.vpp_inf_url.format(ip) + '/interface/' + inf + '/v3po:l2'
541                 requests.delete(url, headers=self.vpp_api_headers, auth=self.vpp_api_userpass)
542
543             for inf in inf_list:
544                 deleted = True
545                 time.sleep(2)
546                 self.logger.info("{0}: Deleting VxLAN interface {1}".format(host, inf))
547                 url = self.vpp_inf_url.format(ip) + '/interface/' + inf
548                 requests.delete(url, headers=self.vpp_api_headers, auth=self.vpp_api_userpass)
549
550             if len(self.get_vxlan_interfaces(ip)) > 0:
551                 self.logger.error("Error deleting VxLAN from {0}, try to restart the VM, IP is {1}.".format(host, ip))
552                 return False
553
554             if not deleted:
555                 self.logger.info("{0}: no VxLAN interface found, nothing to delete".format(host))
556         return True
557
558     @staticmethod
559     def save_object(obj, filepathname):
560         with open(filepathname, 'wb') as fout:
561             pickle.dump(obj, fout)
562
563     @staticmethod
564     def load_object(filepathname):
565         with open(filepathname, 'rb') as fin:
566             return pickle.load(fin)
567
568     @staticmethod
569     def increase_ip_address_or_vni_in_template(vnf_template_file, vnf_parameter_name_list):
570         with open(vnf_template_file) as json_input:
571             json_data = json.load(json_input)
572             param_list = json_data['VNF-API:input']['VNF-API:vnf-topology-information']['VNF-API:vnf-parameters']
573             for param in param_list:
574                 if param['vnf-parameter-name'] in vnf_parameter_name_list:
575                     ipaddr_or_vni = param['vnf-parameter-value'].split('.')
576                     number = int(ipaddr_or_vni[-1])
577                     if 254 == number:
578                         number = 10
579                     else:
580                         number = number + 1
581                     ipaddr_or_vni[-1] = str(number)
582                     param['vnf-parameter-value'] = '.'.join(ipaddr_or_vni)
583
584         assert json_data is not None
585         with open(vnf_template_file, 'w') as json_output:
586             json.dump(json_data, json_output, indent=4, sort_keys=True)
587
588     def save_preload_data(self, preload_data):
589         self.save_object(preload_data, self.preload_dict_file)
590
591     def load_preload_data(self):
592         return self.load_object(self.preload_dict_file)
593
594     def save_vgmux_vnf_name(self, vgmux_vnf_name):
595         self.save_object(vgmux_vnf_name, self.vgmux_vnf_name_file)
596
597     def load_vgmux_vnf_name(self):
598         return self.load_object(self.vgmux_vnf_name_file)
599