blob: f5e1b30466b5b9b905319a8cf4aefbac0b196940 [file] [log] [blame]
Kang Xi11d278c2018-04-06 16:56:04 -04001import json
2import logging
3import os
4import pickle
5import re
6import sys
7
8import ipaddress
9import mysql.connector
10import requests
11import commands
12import time
13
14
15class 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
Yang Xu75b0f5e2018-11-14 14:04:20 -050022 oom_mode = True
Kang Xi0e0a1d62018-07-23 16:53:54 -040023
Kang Xi11d278c2018-04-06 16:56:04 -040024 cloud = {
25 '--os-auth-url': 'http://10.12.25.2:5000',
Kang Xi268b74d2018-05-23 15:53:42 -040026 '--os-username': 'kxi',
Kang Xi11d278c2018-04-06 16:56:04 -040027 '--os-user-domain-id': 'default',
28 '--os-project-domain-id': 'default',
Yang Xu75b0f5e2018-11-14 14:04:20 -050029 '--os-tenant-id': 'b8ad3842ab3642f7bf3fbe4e4d3b9f86' if oom_mode else '1e097c6713e74fd7ac8e4295e605ee1e',
Kang Xi11d278c2018-04-06 16:56:04 -040030 '--os-region-name': 'RegionOne',
Kang Xi268b74d2018-05-23 15:53:42 -040031 '--os-password': 'n3JhGMGuDzD8',
Yang Xu75b0f5e2018-11-14 14:04:20 -050032 '--os-project-domain-name': 'Integration-SB-05' if oom_mode else 'Integration-SB-07',
Kang Xi11d278c2018-04-06 16:56:04 -040033 '--os-identity-api-version': '3'
34 }
35
36 common_preload_config = {
Kang Xi0e0a1d62018-07-23 16:53:54 -040037 'oam_onap_net': 'oam_network_0qV7' if oom_mode else 'oam_onap_lAky',
38 'oam_onap_subnet': 'oam_network_0qV7' if oom_mode else 'oam_onap_lAky',
Kang Xi11d278c2018-04-06 16:56:04 -040039 'public_net': 'external',
40 'public_net_id': '971040b2-7059-49dc-b220-4fab50cb2ad4'
41 }
Yang Xu75b0f5e2018-11-14 14:04:20 -050042 sdnc_controller_pod = 'dev-sdnc-sdnc-0'
43
Kang Xi11d278c2018-04-06 16:56:04 -040044 #############################################################################################
45
46 template_variable_symbol = '${'
Kang Xi6c762392018-05-30 09:27:34 -040047 cpe_vm_prefix = 'zdcpe'
Kang Xi11d278c2018-04-06 16:56:04 -040048 #############################################################################################
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
Kang Xi268b74d2018-05-23 15:53:42 -040060 dcae_ves_collector_name = 'dcae-bootstrap'
Kang Xi11d278c2018-04-06 16:56:04 -040061 global_subscriber_id = 'SDN-ETHERNET-INTERNET'
Kang Xi268b74d2018-05-23 15:53:42 -040062 project_name = 'Project-Demonstration'
63 owning_entity_id = '520cc603-a3c4-4ec2-9ef4-ca70facd79c0'
64 owning_entity_name = 'OE-Demonstration'
Kang Xi11d278c2018-04-06 16:56:04 -040065
66 def __init__(self, extra_host_names=None):
67 self.logger = logging.getLogger(__name__)
68 self.logger.info('Initializing configuration')
69
Brian Freeman8076a872018-11-13 11:34:48 -050070 # OOM: this is the address that the brg and bng will nat for config of brg - 10.0.0.x address of k8 host for sdnc
Yang Xuadf57ae2018-11-14 14:33:29 -050071 self.sdnc_brg_bng_ip = self.get_pod_node_oam_ip(self.sdnc_controller_pod)[1]
Brian Freeman8076a872018-11-13 11:34:48 -050072 # OOM: this is a k8 host external IP
Kang Xi0e0a1d62018-07-23 16:53:54 -040073 self.oom_so_sdnc_aai_ip = '10.12.5.18'
Brian Freeman8076a872018-11-13 11:34:48 -050074 # OOM: this is a k8 host external IP can be same as oom_so_sdnc_aai_ip
Kang Xi0e0a1d62018-07-23 16:53:54 -040075 self.oom_dcae_ves_collector = '10.12.5.18'
Brian Freeman8076a872018-11-13 11:34:48 -050076 # OOM: this is a k8 host external IP can be same as oom_so_sdnc_aai_ip
77 self.mr_ip_addr = '10.12.5.18'
78 self.mr_ip_port = '30227'
Brian Freemana605bc72018-11-12 10:50:30 -050079 self.so_nbi_port = '30277' if self.oom_mode else '8080'
Kang Xi0e0a1d62018-07-23 16:53:54 -040080 self.sdnc_preloading_port = '30202' if self.oom_mode else '8282'
81 self.aai_query_port = '30233' if self.oom_mode else '8443'
82 self.sniro_port = '30288' if self.oom_mode else '8080'
83
Kang Xi268b74d2018-05-23 15:53:42 -040084 self.host_names = ['so', 'sdnc', 'robot', 'aai-inst1', self.dcae_ves_collector_name]
Kang Xi11d278c2018-04-06 16:56:04 -040085 if extra_host_names:
86 self.host_names.extend(extra_host_names)
87 # get IP addresses
88 self.hosts = self.get_vm_ip(self.host_names, self.external_net_addr, self.external_net_prefix_len)
89 # this is the keyword used to name vgw stack, must not be used in other stacks
90 self.vgw_name_keyword = 'base_vcpe_vgw'
Brian Freeman81f6e9e2018-11-11 22:36:20 -050091 # this is the file that will keep the index of last assigned SO name
92 self.vgw_vfmod_name_index_file= '__var/vgw_vfmod_name_index'
Kang Xi11d278c2018-04-06 16:56:04 -040093 self.svc_instance_uuid_file = '__var/svc_instance_uuid'
94 self.preload_dict_file = '__var/preload_dict'
95 self.vgmux_vnf_name_file = '__var/vgmux_vnf_name'
96 self.product_family_id = 'f9457e8c-4afd-45da-9389-46acd9bf5116'
97 self.custom_product_family_id = 'a9a77d5a-123e-4ca2-9eb9-0b015d2ee0fb'
98 self.instance_name_prefix = {
99 'service': 'vcpe_svc',
100 'network': 'vcpe_net',
101 'vnf': 'vcpe_vnf',
102 'vfmodule': 'vcpe_vfmodule'
103 }
104 self.aai_userpass = 'AAI', 'AAI'
105 self.pub_key = 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDKXDgoo3+WOqcUG8/5uUbk81+yczgwC4Y8ywTmuQqbNxlY1oQ0YxdMUqUnhitSXs5S/yRuAVOYHwGg2mCs20oAINrP+mxBI544AMIb9itPjCtgqtE2EWo6MmnFGbHB4Sx3XioE7F4VPsh7japsIwzOjbrQe+Mua1TGQ5d4nfEOQaaglXLLPFfuc7WbhbJbK6Q7rHqZfRcOwAMXgDoBqlyqKeiKwnumddo2RyNT8ljYmvB6buz7KnMinzo7qB0uktVT05FH9Rg0CTWH5norlG5qXgP2aukL0gk1ph8iAt7uYLf1ktp+LJI2gaF6L0/qli9EmVCSLr1uJ38Q8CBflhkh'
106 self.os_tenant_id = self.cloud['--os-tenant-id']
107 self.os_region_name = self.cloud['--os-region-name']
108 self.common_preload_config['pub_key'] = self.pub_key
Kang Xi0e0a1d62018-07-23 16:53:54 -0400109 self.sniro_url = 'http://' + self.hosts['robot'] + ':' + self.sniro_port + '/__admin/mappings'
Kang Xi11d278c2018-04-06 16:56:04 -0400110 self.sniro_headers = {'Content-Type': 'application/json', 'Accept': 'application/json'}
Kang Xi268b74d2018-05-23 15:53:42 -0400111 self.homing_solution = 'sniro' # value is either 'sniro' or 'oof'
112# self.homing_solution = 'oof'
113 self.customer_location_used_by_oof = {
114 "customerLatitude": "32.897480",
115 "customerLongitude": "-97.040443",
116 "customerName": "some_company"
117 }
Kang Xi11d278c2018-04-06 16:56:04 -0400118
119 #############################################################################################
120 # SDNC urls
121 self.sdnc_userpass = 'admin', 'Kp8bJ4SXszM0WXlhak3eHlcse2gAw84vaoGGmJvUy2U'
122 self.sdnc_db_name = 'sdnctl'
123 self.sdnc_db_user = 'sdnctl'
124 self.sdnc_db_pass = 'gamma'
Kang Xi268b74d2018-05-23 15:53:42 -0400125 self.sdnc_db_port = '32774'
Kang Xi11d278c2018-04-06 16:56:04 -0400126 self.sdnc_headers = {'Content-Type': 'application/json', 'Accept': 'application/json'}
127 self.sdnc_preload_network_url = 'http://' + self.hosts['sdnc'] + \
Kang Xi0e0a1d62018-07-23 16:53:54 -0400128 ':' + self.sdnc_preloading_port + '/restconf/operations/VNF-API:preload-network-topology-operation'
Kang Xi11d278c2018-04-06 16:56:04 -0400129 self.sdnc_preload_vnf_url = 'http://' + self.hosts['sdnc'] + \
Kang Xi0e0a1d62018-07-23 16:53:54 -0400130 ':' + self.sdnc_preloading_port + '/restconf/operations/VNF-API:preload-vnf-topology-operation'
Brian Freeman81f6e9e2018-11-11 22:36:20 -0500131 self.sdnc_preload_gra_url = 'http://' + self.hosts['sdnc'] + \
132 ':' + self.sdnc_preloading_port + '/restconf/operations/GENERIC-RESOURCE-API:preload-vf-module-topology-operation'
Kang Xi0e0a1d62018-07-23 16:53:54 -0400133 self.sdnc_ar_cleanup_url = 'http://' + self.hosts['sdnc'] + ':' + self.sdnc_preloading_port + \
134 '/restconf/config/GENERIC-RESOURCE-API:'
Kang Xi11d278c2018-04-06 16:56:04 -0400135
136 #############################################################################################
137 # SO urls, note: do NOT add a '/' at the end of the url
Brian Freemana605bc72018-11-12 10:50:30 -0500138 self.so_req_api_url = {'v4': 'http://' + self.hosts['so'] + ':' + self.so_nbi_port + '/onap/so/infra/serviceInstantiation/v7/serviceInstances',
139 'v5': 'http://' + self.hosts['so'] + ':' + self.so_nbi_port + '/onap/so/infraserviceInstantiation/v7/serviceInstances'}
140 self.so_check_progress_api_url = 'http://' + self.hosts['so'] + ':' + self.so_nbi_port + '/onap/so/infra/orchestrationRequests/v6'
Kang Xi11d278c2018-04-06 16:56:04 -0400141 self.so_userpass = 'InfraPortalClient', 'password1$'
142 self.so_headers = {'Content-Type': 'application/json', 'Accept': 'application/json'}
Brian Freemana605bc72018-11-12 10:50:30 -0500143 self.so_db_name = 'catalogdb'
Kang Xi11d278c2018-04-06 16:56:04 -0400144 self.so_db_user = 'root'
145 self.so_db_pass = 'password'
Kang Xi0e0a1d62018-07-23 16:53:54 -0400146 self.so_db_port = '30252' if self.oom_mode else '32769'
Kang Xi11d278c2018-04-06 16:56:04 -0400147
148 self.vpp_inf_url = 'http://{0}:8183/restconf/config/ietf-interfaces:interfaces'
149 self.vpp_api_headers = {'Content-Type': 'application/json', 'Accept': 'application/json'}
150 self.vpp_api_userpass = ('admin', 'admin')
151 self.vpp_ves_url= 'http://{0}:8183/restconf/config/vesagent:vesagent'
152
153 def headbridge(self, openstack_stack_name, svc_instance_uuid):
154 """
155 Add vserver information to AAI
156 """
157 self.logger.info('Adding vServer information to AAI for {0}'.format(openstack_stack_name))
Kang Xi0e0a1d62018-07-23 16:53:54 -0400158 if not self.oom_mode:
159 cmd = '/opt/demo.sh heatbridge {0} {1} vCPE'.format(openstack_stack_name, svc_instance_uuid)
160 ret = commands.getstatusoutput("ssh -i onap_dev root@{0} '{1}'".format(self.hosts['robot'], cmd))
161 self.logger.debug('%s', ret)
162 else:
163 print('To add vGMUX vserver info to AAI, do the following:')
164 print('- ssh to rancher')
165 print('- sudo su -')
166 print('- cd /root/oom/kubernetes/robot')
167 print('- ./demo-k8s.sh onap heatbridge {0} {1} vCPE'.format(openstack_stack_name, svc_instance_uuid))
Kang Xi11d278c2018-04-06 16:56:04 -0400168
169 def get_brg_mac_from_sdnc(self):
170 """
Kang Xi6c762392018-05-30 09:27:34 -0400171 Check table DHCP_MAP in the SDNC DB. Find the newly instantiated BRG MAC address.
172 Note that there might be multiple BRGs, the most recently instantiated BRG always has the largest IP address.
Kang Xi11d278c2018-04-06 16:56:04 -0400173 """
174 cnx = mysql.connector.connect(user=self.sdnc_db_user, password=self.sdnc_db_pass, database=self.sdnc_db_name,
175 host=self.hosts['sdnc'], port=self.sdnc_db_port)
176 cursor = cnx.cursor()
177 query = "SELECT * from DHCP_MAP"
178 cursor.execute(query)
179
180 self.logger.debug('DHCP_MAP table in SDNC')
Kang Xi6c762392018-05-30 09:27:34 -0400181 mac_recent = None
182 host = -1
Kang Xi11d278c2018-04-06 16:56:04 -0400183 for mac, ip in cursor:
Kang Xi11d278c2018-04-06 16:56:04 -0400184 self.logger.debug(mac + ':' + ip)
Kang Xi6c762392018-05-30 09:27:34 -0400185 this_host = int(ip.split('.')[-1])
186 if host < this_host:
187 host = this_host
188 mac_recent = mac
Kang Xi11d278c2018-04-06 16:56:04 -0400189
190 cnx.close()
191
Kang Xi6c762392018-05-30 09:27:34 -0400192 assert mac_recent
193 return mac_recent
Kang Xi11d278c2018-04-06 16:56:04 -0400194
Kang Xi6c762392018-05-30 09:27:34 -0400195 def execute_cmds_sdnc_db(self, cmds):
196 self.execute_cmds_db(cmds, self.sdnc_db_user, self.sdnc_db_pass, self.sdnc_db_name,
197 self.hosts['sdnc'], self.sdnc_db_port)
Kang Xi11d278c2018-04-06 16:56:04 -0400198
Kang Xi6c762392018-05-30 09:27:34 -0400199 def execute_cmds_so_db(self, cmds):
200 self.execute_cmds_db(cmds, self.so_db_user, self.so_db_pass, self.so_db_name,
201 self.hosts['so'], self.so_db_port)
202
203 def execute_cmds_db(self, cmds, dbuser, dbpass, dbname, host, port):
204 cnx = mysql.connector.connect(user=dbuser, password=dbpass, database=dbname, host=host, port=port)
Kang Xi11d278c2018-04-06 16:56:04 -0400205 cursor = cnx.cursor()
206 for cmd in cmds:
207 self.logger.debug(cmd)
208 cursor.execute(cmd)
209 self.logger.debug('%s', cursor)
210 cnx.commit()
211 cursor.close()
212 cnx.close()
213
214 def find_file(self, file_name_keyword, file_ext, search_dir):
215 """
216 :param file_name_keyword: keyword used to look for the csar file, case insensitive matching, e.g, infra
217 :param file_ext: e.g., csar, json
218 :param search_dir path to search
219 :return: path name of the file
220 """
221 file_name_keyword = file_name_keyword.lower()
222 file_ext = file_ext.lower()
223 if not file_ext.startswith('.'):
224 file_ext = '.' + file_ext
225
226 filenamepath = None
227 for file_name in os.listdir(search_dir):
228 file_name_lower = file_name.lower()
229 if file_name_keyword in file_name_lower and file_name_lower.endswith(file_ext):
230 if filenamepath:
231 self.logger.error('Multiple files found for *{0}*.{1} in '
232 'directory {2}'.format(file_name_keyword, file_ext, search_dir))
233 sys.exit()
234 filenamepath = os.path.abspath(os.path.join(search_dir, file_name))
235
236 if filenamepath:
237 return filenamepath
238 else:
239 self.logger.error("Cannot find *{0}*{1} in directory {2}".format(file_name_keyword, file_ext, search_dir))
240 sys.exit()
241
242 @staticmethod
243 def network_name_to_subnet_name(network_name):
244 """
245 :param network_name: example: vcpe_net_cpe_signal_201711281221
246 :return: vcpe_net_cpe_signal_subnet_201711281221
247 """
248 fields = network_name.split('_')
249 fields.insert(-1, 'subnet')
250 return '_'.join(fields)
251
252 def set_network_name(self, network_name):
253 param = ' '.join([k + ' ' + v for k, v in self.cloud.items()])
254 openstackcmd = 'openstack ' + param
255 cmd = ' '.join([openstackcmd, 'network set --name', network_name, 'ONAP-NW1'])
256 os.popen(cmd)
257
258 def set_subnet_name(self, network_name):
259 """
260 Example: network_name = vcpe_net_cpe_signal_201711281221
261 set subnet name to vcpe_net_cpe_signal_subnet_201711281221
262 :return:
263 """
264 param = ' '.join([k + ' ' + v for k, v in self.cloud.items()])
265 openstackcmd = 'openstack ' + param
266
267 # expected results: | subnets | subnet_id |
268 subnet_info = os.popen(openstackcmd + ' network show ' + network_name + ' |grep subnets').read().split('|')
269 if len(subnet_info) > 2 and subnet_info[1].strip() == 'subnets':
270 subnet_id = subnet_info[2].strip()
271 subnet_name = self.network_name_to_subnet_name(network_name)
272 cmd = ' '.join([openstackcmd, 'subnet set --name', subnet_name, subnet_id])
273 os.popen(cmd)
274 self.logger.info("Subnet name set to: " + subnet_name)
275 return True
276 else:
277 self.logger.error("Can't get subnet info from network name: " + network_name)
278 return False
279
280 def is_node_in_aai(self, node_type, node_uuid):
281 key = None
282 search_node_type = None
283 if node_type == 'service':
284 search_node_type = 'service-instance'
285 key = 'service-instance-id'
286 elif node_type == 'vnf':
287 search_node_type = 'generic-vnf'
288 key = 'vnf-id'
289 else:
290 logging.error('Invalid node_type: ' + node_type)
291 sys.exit()
292
Kang Xi0e0a1d62018-07-23 16:53:54 -0400293 url = 'https://{0}:{1}/aai/v11/search/nodes-query?search-node-type={2}&filter={3}:EQUALS:{4}'.format(
294 self.hosts['aai-inst1'], self.aai_query_port, search_node_type, key, node_uuid)
Kang Xi11d278c2018-04-06 16:56:04 -0400295
Kang Xi268b74d2018-05-23 15:53:42 -0400296 headers = {'Content-Type': 'application/json', 'Accept': 'application/json', 'X-FromAppID': 'vCPE-Robot', 'X-TransactionId': 'get_aai_subscr'}
Kang Xi11d278c2018-04-06 16:56:04 -0400297 requests.packages.urllib3.disable_warnings()
298 r = requests.get(url, headers=headers, auth=self.aai_userpass, verify=False)
299 response = r.json()
300 self.logger.debug('aai query: ' + url)
301 self.logger.debug('aai response:\n' + json.dumps(response, indent=4, sort_keys=True))
302 return 'result-data' in response
303
304 @staticmethod
305 def extract_ip_from_str(net_addr, net_addr_len, sz):
306 """
307 :param net_addr: e.g. 10.5.12.0
308 :param net_addr_len: e.g. 24
309 :param sz: a string
310 :return: the first IP address matching the network, e.g. 10.5.12.3
311 """
312 network = ipaddress.ip_network(unicode('{0}/{1}'.format(net_addr, net_addr_len)), strict=False)
313 ip_list = re.findall(r'[0-9]+(?:\.[0-9]+){3}', sz)
314 for ip in ip_list:
315 this_net = ipaddress.ip_network(unicode('{0}/{1}'.format(ip, net_addr_len)), strict=False)
316 if this_net == network:
317 return str(ip)
318 return None
319
Yang Xu75b0f5e2018-11-14 14:04:20 -0500320 def get_pod_node_oam_ip(self, pod):
321 """
322 :Assuming kubectl is available
323 :param pod: pod name as a string, e.g. 'dev-sdnc-sdnc-0'
324 :return pod's node oam ip (10.0.0.0/16)
325 """
326 cmd = "kubectl -n onap describe pod {0} |grep Node:|cut -d'/' -f2".format(pod)
327 ret = commands.getstatusoutput(cmd)
328 self.logger.debug("cmd = %s, ret = %s", cmd, ret)
329 return ret
330
Kang Xi11d278c2018-04-06 16:56:04 -0400331 def get_vm_ip(self, keywords, net_addr=None, net_addr_len=None):
332 """
333 :param keywords: list of keywords to search for vm, e.g. ['bng', 'gmux', 'brg']
334 :param net_addr: e.g. 10.12.5.0
335 :param net_addr_len: e.g. 24
336 :return: dictionary {keyword: ip}
337 """
338 if not net_addr:
339 net_addr = self.external_net_addr
340
341 if not net_addr_len:
342 net_addr_len = self.external_net_prefix_len
343
344 param = ' '.join([k + ' ' + v for k, v in self.cloud.items() if 'identity' not in k])
345 openstackcmd = 'nova ' + param + ' list'
346 self.logger.debug(openstackcmd)
347
Kang Xi11d278c2018-04-06 16:56:04 -0400348 results = os.popen(openstackcmd).read()
Kang Xi6c762392018-05-30 09:27:34 -0400349 all_vm_ip_dict = self.extract_vm_ip_as_dict(results, net_addr, net_addr_len)
350 latest_vm_list = self.remove_old_vms(all_vm_ip_dict.keys(), self.cpe_vm_prefix)
351 latest_vm_ip_dict = {vm: all_vm_ip_dict[vm] for vm in latest_vm_list}
352 ip_dict = self.select_subset_vm_ip(latest_vm_ip_dict, keywords)
Kang Xi0e0a1d62018-07-23 16:53:54 -0400353 if self.oom_mode:
354 ip_dict.update(self.get_oom_onap_vm_ip(keywords))
Kang Xi6c762392018-05-30 09:27:34 -0400355
Kang Xi11d278c2018-04-06 16:56:04 -0400356 if len(ip_dict) != len(keywords):
357 self.logger.error('Cannot find all desired IP addresses for %s.', keywords)
358 self.logger.error(json.dumps(ip_dict, indent=4, sort_keys=True))
Kang Xi268b74d2018-05-23 15:53:42 -0400359 self.logger.error('Temporarily continue.. remember to check back vcpecommon.py line: 316')
360# sys.exit()
Kang Xi11d278c2018-04-06 16:56:04 -0400361 return ip_dict
362
Kang Xi0e0a1d62018-07-23 16:53:54 -0400363 def get_oom_onap_vm_ip(self, keywords):
364 vm_ip = {}
365 onap_vm_list = set(['so', 'sdnc', 'aai-inst1', 'robot', self.dcae_ves_collector_name])
366 for vm in keywords:
367 if vm in onap_vm_list:
368 vm_ip[vm] = self.oom_so_sdnc_aai_ip
369 return vm_ip
370
Kang Xi6c762392018-05-30 09:27:34 -0400371 def extract_vm_ip_as_dict(self, novalist_results, net_addr, net_addr_len):
372 vm_ip_dict = {}
373 for line in novalist_results.split('\n'):
374 fields = line.split('|')
375 if len(fields) == 8:
376 vm_name = fields[2]
377 ip_info = fields[-2]
378 ip = self.extract_ip_from_str(net_addr, net_addr_len, ip_info)
379 vm_ip_dict[vm_name] = ip
380
381 return vm_ip_dict
382
383 def remove_old_vms(self, vm_list, prefix):
384 """
385 For vms with format name_timestamp, only keep the one with the latest timestamp.
386 E.g.,
387 zdcpe1cpe01brgemu01_201805222148 (drop this)
388 zdcpe1cpe01brgemu01_201805222229 (keep this)
389 zdcpe1cpe01gw01_201805162201
390 """
391 new_vm_list = []
392 same_type_vm_dict = {}
393 for vm in vm_list:
394 fields = vm.split('_')
395 if vm.startswith(prefix) and len(fields) == 2 and len(fields[-1]) == len('201805222148') and fields[-1].isdigit():
396 if vm > same_type_vm_dict.get(fields[0], '0'):
397 same_type_vm_dict[fields[0]] = vm
398 else:
399 new_vm_list.append(vm)
400
401 new_vm_list.extend(same_type_vm_dict.values())
402 return new_vm_list
403
404 def select_subset_vm_ip(self, all_vm_ip_dict, vm_name_keyword_list):
405 vm_ip_dict = {}
406 for keyword in vm_name_keyword_list:
407 for vm, ip in all_vm_ip_dict.items():
408 if keyword in vm:
409 vm_ip_dict[keyword] = ip
410 break
411 return vm_ip_dict
412
Kang Xi11d278c2018-04-06 16:56:04 -0400413 def del_vgmux_ves_mode(self):
414 url = self.vpp_ves_url.format(self.hosts['mux']) + '/mode'
415 r = requests.delete(url, headers=self.vpp_api_headers, auth=self.vpp_api_userpass)
416 self.logger.debug('%s', r)
417
418 def del_vgmux_ves_collector(self):
419 url = self.vpp_ves_url.format(self.hosts['mux']) + '/config'
420 r = requests.delete(url, headers=self.vpp_api_headers, auth=self.vpp_api_userpass)
421 self.logger.debug('%s', r)
422
423 def set_vgmux_ves_collector(self ):
424 url = self.vpp_ves_url.format(self.hosts['mux'])
425 data = {'config':
Kang Xi268b74d2018-05-23 15:53:42 -0400426 {'server-addr': self.hosts[self.dcae_ves_collector_name],
Kang Xi0e0a1d62018-07-23 16:53:54 -0400427 'server-port': '30235' if self.oom_mode else '8081',
Kang Xi11d278c2018-04-06 16:56:04 -0400428 'read-interval': '10',
429 'is-add':'1'
430 }
431 }
432 r = requests.post(url, headers=self.vpp_api_headers, auth=self.vpp_api_userpass, json=data)
433 self.logger.debug('%s', r)
434
435 def set_vgmux_packet_loss_rate(self, lossrate, vg_vnf_instance_name):
436 url = self.vpp_ves_url.format(self.hosts['mux'])
437 data = {"mode":
438 {"working-mode": "demo",
439 "base-packet-loss": str(lossrate),
440 "source-name": vg_vnf_instance_name
441 }
442 }
443 r = requests.post(url, headers=self.vpp_api_headers, auth=self.vpp_api_userpass, json=data)
444 self.logger.debug('%s', r)
445
446 # return all the VxLAN interface names of BRG or vGMUX based on the IP address
447 def get_vxlan_interfaces(self, ip, print_info=False):
448 url = self.vpp_inf_url.format(ip)
449 self.logger.debug('url is this: %s', url)
450 r = requests.get(url, headers=self.vpp_api_headers, auth=self.vpp_api_userpass)
451 data = r.json()['interfaces']['interface']
452 if print_info:
453 for inf in data:
454 if 'name' in inf and 'type' in inf and inf['type'] == 'v3po:vxlan-tunnel':
455 print(json.dumps(inf, indent=4, sort_keys=True))
456
457 return [inf['name'] for inf in data if 'name' in inf and 'type' in inf and inf['type'] == 'v3po:vxlan-tunnel']
458
459 # delete all VxLAN interfaces of each hosts
460 def delete_vxlan_interfaces(self, host_dic):
461 for host, ip in host_dic.items():
462 deleted = False
463 self.logger.info('{0}: Getting VxLAN interfaces'.format(host))
464 inf_list = self.get_vxlan_interfaces(ip)
465 for inf in inf_list:
466 deleted = True
467 time.sleep(2)
468 self.logger.info("{0}: Deleting VxLAN crossconnect {1}".format(host, inf))
469 url = self.vpp_inf_url.format(ip) + '/interface/' + inf + '/v3po:l2'
470 requests.delete(url, headers=self.vpp_api_headers, auth=self.vpp_api_userpass)
471
472 for inf in inf_list:
473 deleted = True
474 time.sleep(2)
475 self.logger.info("{0}: Deleting VxLAN interface {1}".format(host, inf))
476 url = self.vpp_inf_url.format(ip) + '/interface/' + inf
477 requests.delete(url, headers=self.vpp_api_headers, auth=self.vpp_api_userpass)
478
479 if len(self.get_vxlan_interfaces(ip)) > 0:
480 self.logger.error("Error deleting VxLAN from {0}, try to restart the VM, IP is {1}.".format(host, ip))
481 return False
482
483 if not deleted:
484 self.logger.info("{0}: no VxLAN interface found, nothing to delete".format(host))
485 return True
486
487 @staticmethod
488 def save_object(obj, filepathname):
489 with open(filepathname, 'wb') as fout:
490 pickle.dump(obj, fout)
491
492 @staticmethod
493 def load_object(filepathname):
494 with open(filepathname, 'rb') as fin:
495 return pickle.load(fin)
496
Kang Xi6c762392018-05-30 09:27:34 -0400497 @staticmethod
498 def increase_ip_address_or_vni_in_template(vnf_template_file, vnf_parameter_name_list):
499 with open(vnf_template_file) as json_input:
500 json_data = json.load(json_input)
501 param_list = json_data['VNF-API:input']['VNF-API:vnf-topology-information']['VNF-API:vnf-parameters']
502 for param in param_list:
503 if param['vnf-parameter-name'] in vnf_parameter_name_list:
504 ipaddr_or_vni = param['vnf-parameter-value'].split('.')
505 number = int(ipaddr_or_vni[-1])
506 if 254 == number:
507 number = 10
508 else:
509 number = number + 1
510 ipaddr_or_vni[-1] = str(number)
511 param['vnf-parameter-value'] = '.'.join(ipaddr_or_vni)
512
513 assert json_data is not None
514 with open(vnf_template_file, 'w') as json_output:
515 json.dump(json_data, json_output, indent=4, sort_keys=True)
516
Kang Xi11d278c2018-04-06 16:56:04 -0400517 def save_preload_data(self, preload_data):
518 self.save_object(preload_data, self.preload_dict_file)
519
520 def load_preload_data(self):
521 return self.load_object(self.preload_dict_file)
522
523 def save_vgmux_vnf_name(self, vgmux_vnf_name):
524 self.save_object(vgmux_vnf_name, self.vgmux_vnf_name_file)
525
526 def load_vgmux_vnf_name(self):
527 return self.load_object(self.vgmux_vnf_name_file)
528