blob: 12ac9bd8d0772667ff2ff48902faef52c3856bad [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 Xu86c0e4a2018-12-02 13:10:41 -050029 '--os-tenant-id': '41d6d38489bd40b09ea8a6b6b852dcbd' 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 Xu86c0e4a2018-12-02 13:10:41 -050032 '--os-project-domain-name': 'Integration-SB-00' 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 = {
Yang Xu86c0e4a2018-12-02 13:10:41 -050037 'oam_onap_net': 'oam_network_uB1y' if oom_mode else 'oam_onap_lAky',
38 'oam_onap_subnet': 'oam_network_uB1y' 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'
Yang Xu86c0e4a2018-12-02 13:10:41 -050064 owning_entity_name = 'OE-Demonstration1'
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
Yang Xu9f935b22018-11-22 10:56:52 -050070 # vgw_VfModuleModelInvariantUuid is in rescust service csar, look in service-VcpesvcRescust1118-template.yml for groups vgw module metadata. TODO: read this value automcatically
Yang Xu86c0e4a2018-12-02 13:10:41 -050071 self.vgw_VfModuleModelInvariantUuid = 'feb4cfc6-e018-4e42-808d-dbf242e7f63b'
Brian Freeman8076a872018-11-13 11:34:48 -050072 # 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 Xu86c0e4a2018-12-02 13:10:41 -050073 self.sdnc_oam_ip = '10.0.0.10'
Brian Freeman8076a872018-11-13 11:34:48 -050074 # OOM: this is a k8 host external IP
Yang Xu86c0e4a2018-12-02 13:10:41 -050075 self.oom_so_sdnc_aai_ip = '10.12.6.20'
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
Yang Xu86c0e4a2018-12-02 13:10:41 -050077 self.oom_dcae_ves_collector = '10.12.6.20'
Brian Freeman8076a872018-11-13 11:34:48 -050078 # OOM: this is a k8 host external IP can be same as oom_so_sdnc_aai_ip
Yang Xu86c0e4a2018-12-02 13:10:41 -050079 self.mr_ip_addr = '10.12.6.20'
Brian Freeman8076a872018-11-13 11:34:48 -050080 self.mr_ip_port = '30227'
Brian Freemana605bc72018-11-12 10:50:30 -050081 self.so_nbi_port = '30277' if self.oom_mode else '8080'
Kang Xi0e0a1d62018-07-23 16:53:54 -040082 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
Kang Xi268b74d2018-05-23 15:53:42 -040086 self.host_names = ['so', 'sdnc', 'robot', 'aai-inst1', self.dcae_ves_collector_name]
Kang Xi11d278c2018-04-06 16:56:04 -040087 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'
Brian Freeman81f6e9e2018-11-11 22:36:20 -050093 # 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'
Kang Xi11d278c2018-04-06 16:56:04 -040095 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
Kang Xi0e0a1d62018-07-23 16:53:54 -0400111 self.sniro_url = 'http://' + self.hosts['robot'] + ':' + self.sniro_port + '/__admin/mappings'
Kang Xi11d278c2018-04-06 16:56:04 -0400112 self.sniro_headers = {'Content-Type': 'application/json', 'Accept': 'application/json'}
Kang Xi268b74d2018-05-23 15:53:42 -0400113 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 }
Kang Xi11d278c2018-04-06 16:56:04 -0400120
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'
Kang Xi268b74d2018-05-23 15:53:42 -0400127 self.sdnc_db_port = '32774'
Kang Xi11d278c2018-04-06 16:56:04 -0400128 self.sdnc_headers = {'Content-Type': 'application/json', 'Accept': 'application/json'}
129 self.sdnc_preload_network_url = 'http://' + self.hosts['sdnc'] + \
Kang Xi0e0a1d62018-07-23 16:53:54 -0400130 ':' + self.sdnc_preloading_port + '/restconf/operations/VNF-API:preload-network-topology-operation'
Kang Xi11d278c2018-04-06 16:56:04 -0400131 self.sdnc_preload_vnf_url = 'http://' + self.hosts['sdnc'] + \
Kang Xi0e0a1d62018-07-23 16:53:54 -0400132 ':' + self.sdnc_preloading_port + '/restconf/operations/VNF-API:preload-vnf-topology-operation'
Brian Freeman81f6e9e2018-11-11 22:36:20 -0500133 self.sdnc_preload_gra_url = 'http://' + self.hosts['sdnc'] + \
134 ':' + self.sdnc_preloading_port + '/restconf/operations/GENERIC-RESOURCE-API:preload-vf-module-topology-operation'
Kang Xi0e0a1d62018-07-23 16:53:54 -0400135 self.sdnc_ar_cleanup_url = 'http://' + self.hosts['sdnc'] + ':' + self.sdnc_preloading_port + \
136 '/restconf/config/GENERIC-RESOURCE-API:'
Kang Xi11d278c2018-04-06 16:56:04 -0400137
138 #############################################################################################
139 # SO urls, note: do NOT add a '/' at the end of the url
Brian Freemana605bc72018-11-12 10:50:30 -0500140 self.so_req_api_url = {'v4': 'http://' + self.hosts['so'] + ':' + self.so_nbi_port + '/onap/so/infra/serviceInstantiation/v7/serviceInstances',
Yang Xu63a0afd2018-11-20 16:01:01 -0500141 'v5': 'http://' + self.hosts['so'] + ':' + self.so_nbi_port + '/onap/so/infra/serviceInstantiation/v7/serviceInstances'}
Brian Freemana605bc72018-11-12 10:50:30 -0500142 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 -0400143 self.so_userpass = 'InfraPortalClient', 'password1$'
144 self.so_headers = {'Content-Type': 'application/json', 'Accept': 'application/json'}
Brian Freemana605bc72018-11-12 10:50:30 -0500145 self.so_db_name = 'catalogdb'
Kang Xi11d278c2018-04-06 16:56:04 -0400146 self.so_db_user = 'root'
147 self.so_db_pass = 'password'
Kang Xi0e0a1d62018-07-23 16:53:54 -0400148 self.so_db_port = '30252' if self.oom_mode else '32769'
Kang Xi11d278c2018-04-06 16:56:04 -0400149
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))
Kang Xi0e0a1d62018-07-23 16:53:54 -0400160 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))
Kang Xi11d278c2018-04-06 16:56:04 -0400170
171 def get_brg_mac_from_sdnc(self):
172 """
Kang Xi6c762392018-05-30 09:27:34 -0400173 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.
Kang Xi11d278c2018-04-06 16:56:04 -0400175 """
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')
Kang Xi6c762392018-05-30 09:27:34 -0400183 mac_recent = None
184 host = -1
Kang Xi11d278c2018-04-06 16:56:04 -0400185 for mac, ip in cursor:
Kang Xi11d278c2018-04-06 16:56:04 -0400186 self.logger.debug(mac + ':' + ip)
Kang Xi6c762392018-05-30 09:27:34 -0400187 this_host = int(ip.split('.')[-1])
188 if host < this_host:
189 host = this_host
190 mac_recent = mac
Kang Xi11d278c2018-04-06 16:56:04 -0400191
192 cnx.close()
193
Kang Xi6c762392018-05-30 09:27:34 -0400194 assert mac_recent
195 return mac_recent
Kang Xi11d278c2018-04-06 16:56:04 -0400196
Kang Xi6c762392018-05-30 09:27:34 -0400197 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)
Kang Xi11d278c2018-04-06 16:56:04 -0400200
Kang Xi6c762392018-05-30 09:27:34 -0400201 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)
Kang Xi11d278c2018-04-06 16:56:04 -0400207 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
Kang Xi0e0a1d62018-07-23 16:53:54 -0400295 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)
Kang Xi11d278c2018-04-06 16:56:04 -0400297
Kang Xi268b74d2018-05-23 15:53:42 -0400298 headers = {'Content-Type': 'application/json', 'Accept': 'application/json', 'X-FromAppID': 'vCPE-Robot', 'X-TransactionId': 'get_aai_subscr'}
Kang Xi11d278c2018-04-06 16:56:04 -0400299 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
Yang Xu75b0f5e2018-11-14 14:04:20 -0500322 def get_pod_node_oam_ip(self, pod):
323 """
324 :Assuming kubectl is available
325 :param pod: pod name as a string, e.g. 'dev-sdnc-sdnc-0'
326 :return pod's node oam ip (10.0.0.0/16)
327 """
328 cmd = "kubectl -n onap describe pod {0} |grep Node:|cut -d'/' -f2".format(pod)
329 ret = commands.getstatusoutput(cmd)
330 self.logger.debug("cmd = %s, ret = %s", cmd, ret)
331 return ret
332
Kang Xi11d278c2018-04-06 16:56:04 -0400333 def get_vm_ip(self, keywords, net_addr=None, net_addr_len=None):
334 """
335 :param keywords: list of keywords to search for vm, e.g. ['bng', 'gmux', 'brg']
336 :param net_addr: e.g. 10.12.5.0
337 :param net_addr_len: e.g. 24
338 :return: dictionary {keyword: ip}
339 """
340 if not net_addr:
341 net_addr = self.external_net_addr
342
343 if not net_addr_len:
344 net_addr_len = self.external_net_prefix_len
345
346 param = ' '.join([k + ' ' + v for k, v in self.cloud.items() if 'identity' not in k])
347 openstackcmd = 'nova ' + param + ' list'
348 self.logger.debug(openstackcmd)
349
Kang Xi11d278c2018-04-06 16:56:04 -0400350 results = os.popen(openstackcmd).read()
Kang Xi6c762392018-05-30 09:27:34 -0400351 all_vm_ip_dict = self.extract_vm_ip_as_dict(results, net_addr, net_addr_len)
352 latest_vm_list = self.remove_old_vms(all_vm_ip_dict.keys(), self.cpe_vm_prefix)
353 latest_vm_ip_dict = {vm: all_vm_ip_dict[vm] for vm in latest_vm_list}
354 ip_dict = self.select_subset_vm_ip(latest_vm_ip_dict, keywords)
Kang Xi0e0a1d62018-07-23 16:53:54 -0400355 if self.oom_mode:
356 ip_dict.update(self.get_oom_onap_vm_ip(keywords))
Kang Xi6c762392018-05-30 09:27:34 -0400357
Kang Xi11d278c2018-04-06 16:56:04 -0400358 if len(ip_dict) != len(keywords):
359 self.logger.error('Cannot find all desired IP addresses for %s.', keywords)
360 self.logger.error(json.dumps(ip_dict, indent=4, sort_keys=True))
Kang Xi268b74d2018-05-23 15:53:42 -0400361 self.logger.error('Temporarily continue.. remember to check back vcpecommon.py line: 316')
362# sys.exit()
Kang Xi11d278c2018-04-06 16:56:04 -0400363 return ip_dict
364
Kang Xi0e0a1d62018-07-23 16:53:54 -0400365 def get_oom_onap_vm_ip(self, keywords):
366 vm_ip = {}
367 onap_vm_list = set(['so', 'sdnc', 'aai-inst1', 'robot', self.dcae_ves_collector_name])
368 for vm in keywords:
369 if vm in onap_vm_list:
370 vm_ip[vm] = self.oom_so_sdnc_aai_ip
371 return vm_ip
372
Kang Xi6c762392018-05-30 09:27:34 -0400373 def extract_vm_ip_as_dict(self, novalist_results, net_addr, net_addr_len):
374 vm_ip_dict = {}
375 for line in novalist_results.split('\n'):
376 fields = line.split('|')
377 if len(fields) == 8:
378 vm_name = fields[2]
379 ip_info = fields[-2]
380 ip = self.extract_ip_from_str(net_addr, net_addr_len, ip_info)
381 vm_ip_dict[vm_name] = ip
382
383 return vm_ip_dict
384
385 def remove_old_vms(self, vm_list, prefix):
386 """
387 For vms with format name_timestamp, only keep the one with the latest timestamp.
388 E.g.,
389 zdcpe1cpe01brgemu01_201805222148 (drop this)
390 zdcpe1cpe01brgemu01_201805222229 (keep this)
391 zdcpe1cpe01gw01_201805162201
392 """
393 new_vm_list = []
394 same_type_vm_dict = {}
395 for vm in vm_list:
396 fields = vm.split('_')
397 if vm.startswith(prefix) and len(fields) == 2 and len(fields[-1]) == len('201805222148') and fields[-1].isdigit():
398 if vm > same_type_vm_dict.get(fields[0], '0'):
399 same_type_vm_dict[fields[0]] = vm
400 else:
401 new_vm_list.append(vm)
402
403 new_vm_list.extend(same_type_vm_dict.values())
404 return new_vm_list
405
406 def select_subset_vm_ip(self, all_vm_ip_dict, vm_name_keyword_list):
407 vm_ip_dict = {}
408 for keyword in vm_name_keyword_list:
409 for vm, ip in all_vm_ip_dict.items():
410 if keyword in vm:
411 vm_ip_dict[keyword] = ip
412 break
413 return vm_ip_dict
414
Kang Xi11d278c2018-04-06 16:56:04 -0400415 def del_vgmux_ves_mode(self):
416 url = self.vpp_ves_url.format(self.hosts['mux']) + '/mode'
417 r = requests.delete(url, headers=self.vpp_api_headers, auth=self.vpp_api_userpass)
418 self.logger.debug('%s', r)
419
420 def del_vgmux_ves_collector(self):
421 url = self.vpp_ves_url.format(self.hosts['mux']) + '/config'
422 r = requests.delete(url, headers=self.vpp_api_headers, auth=self.vpp_api_userpass)
423 self.logger.debug('%s', r)
424
425 def set_vgmux_ves_collector(self ):
426 url = self.vpp_ves_url.format(self.hosts['mux'])
427 data = {'config':
Kang Xi268b74d2018-05-23 15:53:42 -0400428 {'server-addr': self.hosts[self.dcae_ves_collector_name],
Kang Xi0e0a1d62018-07-23 16:53:54 -0400429 'server-port': '30235' if self.oom_mode else '8081',
Kang Xi11d278c2018-04-06 16:56:04 -0400430 'read-interval': '10',
431 'is-add':'1'
432 }
433 }
434 r = requests.post(url, headers=self.vpp_api_headers, auth=self.vpp_api_userpass, json=data)
435 self.logger.debug('%s', r)
436
437 def set_vgmux_packet_loss_rate(self, lossrate, vg_vnf_instance_name):
438 url = self.vpp_ves_url.format(self.hosts['mux'])
439 data = {"mode":
440 {"working-mode": "demo",
441 "base-packet-loss": str(lossrate),
442 "source-name": vg_vnf_instance_name
443 }
444 }
445 r = requests.post(url, headers=self.vpp_api_headers, auth=self.vpp_api_userpass, json=data)
446 self.logger.debug('%s', r)
447
448 # return all the VxLAN interface names of BRG or vGMUX based on the IP address
449 def get_vxlan_interfaces(self, ip, print_info=False):
450 url = self.vpp_inf_url.format(ip)
451 self.logger.debug('url is this: %s', url)
452 r = requests.get(url, headers=self.vpp_api_headers, auth=self.vpp_api_userpass)
453 data = r.json()['interfaces']['interface']
454 if print_info:
455 for inf in data:
456 if 'name' in inf and 'type' in inf and inf['type'] == 'v3po:vxlan-tunnel':
457 print(json.dumps(inf, indent=4, sort_keys=True))
458
459 return [inf['name'] for inf in data if 'name' in inf and 'type' in inf and inf['type'] == 'v3po:vxlan-tunnel']
460
461 # delete all VxLAN interfaces of each hosts
462 def delete_vxlan_interfaces(self, host_dic):
463 for host, ip in host_dic.items():
464 deleted = False
465 self.logger.info('{0}: Getting VxLAN interfaces'.format(host))
466 inf_list = self.get_vxlan_interfaces(ip)
467 for inf in inf_list:
468 deleted = True
469 time.sleep(2)
470 self.logger.info("{0}: Deleting VxLAN crossconnect {1}".format(host, inf))
471 url = self.vpp_inf_url.format(ip) + '/interface/' + inf + '/v3po:l2'
472 requests.delete(url, headers=self.vpp_api_headers, auth=self.vpp_api_userpass)
473
474 for inf in inf_list:
475 deleted = True
476 time.sleep(2)
477 self.logger.info("{0}: Deleting VxLAN interface {1}".format(host, inf))
478 url = self.vpp_inf_url.format(ip) + '/interface/' + inf
479 requests.delete(url, headers=self.vpp_api_headers, auth=self.vpp_api_userpass)
480
481 if len(self.get_vxlan_interfaces(ip)) > 0:
482 self.logger.error("Error deleting VxLAN from {0}, try to restart the VM, IP is {1}.".format(host, ip))
483 return False
484
485 if not deleted:
486 self.logger.info("{0}: no VxLAN interface found, nothing to delete".format(host))
487 return True
488
489 @staticmethod
490 def save_object(obj, filepathname):
491 with open(filepathname, 'wb') as fout:
492 pickle.dump(obj, fout)
493
494 @staticmethod
495 def load_object(filepathname):
496 with open(filepathname, 'rb') as fin:
497 return pickle.load(fin)
498
Kang Xi6c762392018-05-30 09:27:34 -0400499 @staticmethod
500 def increase_ip_address_or_vni_in_template(vnf_template_file, vnf_parameter_name_list):
501 with open(vnf_template_file) as json_input:
502 json_data = json.load(json_input)
503 param_list = json_data['VNF-API:input']['VNF-API:vnf-topology-information']['VNF-API:vnf-parameters']
504 for param in param_list:
505 if param['vnf-parameter-name'] in vnf_parameter_name_list:
506 ipaddr_or_vni = param['vnf-parameter-value'].split('.')
507 number = int(ipaddr_or_vni[-1])
508 if 254 == number:
509 number = 10
510 else:
511 number = number + 1
512 ipaddr_or_vni[-1] = str(number)
513 param['vnf-parameter-value'] = '.'.join(ipaddr_or_vni)
514
515 assert json_data is not None
516 with open(vnf_template_file, 'w') as json_output:
517 json.dump(json_data, json_output, indent=4, sort_keys=True)
518
Kang Xi11d278c2018-04-06 16:56:04 -0400519 def save_preload_data(self, preload_data):
520 self.save_object(preload_data, self.preload_dict_file)
521
522 def load_preload_data(self):
523 return self.load_object(self.preload_dict_file)
524
525 def save_vgmux_vnf_name(self, vgmux_vnf_name):
526 self.save_object(vgmux_vnf_name, self.vgmux_vnf_name_file)
527
528 def load_vgmux_vnf_name(self):
529 return self.load_object(self.vgmux_vnf_name_file)
530