blob: ffc63347ff45d8f5c16a401a8284f8faba83a849 [file] [log] [blame]
Bartek Grzybowskifbbdbec2019-09-25 16:37:05 +02001#!/usr/bin/env python
2
Kang Xi11d278c2018-04-06 16:56:04 -04003import json
4import logging
5import os
6import pickle
7import re
8import sys
9
10import ipaddress
11import mysql.connector
12import requests
13import commands
14import time
Yang Xu65b84a42018-12-31 17:48:02 +000015from novaclient import client as openstackclient
Yang Xu64339a82018-12-30 05:32:21 +000016from kubernetes import client, config
Yang Xu65b84a42018-12-31 17:48:02 +000017from netaddr import IPAddress, IPNetwork
Kang Xi11d278c2018-04-06 16:56:04 -040018
Michal Ptacek0b06f782019-09-12 12:27:47 +000019######################################################################
20# Parts which must be updated / cross-checked during each deployment #
21# are marked as CHANGEME #
22######################################################################
23
Kang Xi11d278c2018-04-06 16:56:04 -040024class VcpeCommon:
25 #############################################################################################
Michal Ptacek0b06f782019-09-12 12:27:47 +000026 # Set network prefix of k8s host external address; it's used for pod public IP autodetection
27 # but can be overriden from user in case of autodetection failure
Kang Xi11d278c2018-04-06 16:56:04 -040028 external_net_addr = '10.12.0.0'
29 external_net_prefix_len = 16
Bartek Grzybowski73b02ed2019-09-12 14:04:59 +020030
Kang Xi11d278c2018-04-06 16:56:04 -040031 #############################################################################################
32 # set the openstack cloud access credentials here
Brian Freeman9b3d6ca2019-11-06 13:22:53 -050033 oom_mode = True
34
35 #############################################################################################
36 # set the gra_api flag
Bartek Grzybowski6eea34b2019-11-18 14:58:00 +010037 # Mustn't be set to True until Frankfurt DGs are updated for GRA-API infrastructure
38 gra_api_flag= False
Kang Xi0e0a1d62018-07-23 16:53:54 -040039
Michal Ptacek0b06f782019-09-12 12:27:47 +000040 ###########################
41 # set Openstack credentials
42 # CHANGEME part
Kang Xi11d278c2018-04-06 16:56:04 -040043 cloud = {
44 '--os-auth-url': 'http://10.12.25.2:5000',
Kang Xi268b74d2018-05-23 15:53:42 -040045 '--os-username': 'kxi',
Kang Xi11d278c2018-04-06 16:56:04 -040046 '--os-user-domain-id': 'default',
47 '--os-project-domain-id': 'default',
Brian Freeman9b3d6ca2019-11-06 13:22:53 -050048 '--os-tenant-id': '712b6016580e410b9abfec9ca34953ce' if oom_mode else '1e097c6713e74fd7ac8e4295e605ee1e',
Kang Xi11d278c2018-04-06 16:56:04 -040049 '--os-region-name': 'RegionOne',
Kang Xi268b74d2018-05-23 15:53:42 -040050 '--os-password': 'n3JhGMGuDzD8',
Brian Freeman9b3d6ca2019-11-06 13:22:53 -050051 '--os-project-domain-name': 'Integration-Release-Daily' if oom_mode else 'Integration-SB-07',
Kang Xi11d278c2018-04-06 16:56:04 -040052 '--os-identity-api-version': '3'
53 }
54
Michal Ptacek0b06f782019-09-12 12:27:47 +000055 ############################################################################
56 # set oam and public network which must exist in openstack before deployment
57 # CHANGEME part
Kang Xi11d278c2018-04-06 16:56:04 -040058 common_preload_config = {
Brian Freeman9b3d6ca2019-11-06 13:22:53 -050059 'oam_onap_net': 'oam_network_exxC' if oom_mode else 'oam_onap_lAky',
60 'oam_onap_subnet': 'oam_network_exxC' if oom_mode else 'oam_onap_lAky',
Kang Xi11d278c2018-04-06 16:56:04 -040061 'public_net': 'external',
62 'public_net_id': '971040b2-7059-49dc-b220-4fab50cb2ad4'
63 }
Yang Xu75b0f5e2018-11-14 14:04:20 -050064
Michal Ptacek0b06f782019-09-12 12:27:47 +000065 #############################################################################
Bartek Grzybowskidbb3ba12019-09-25 11:21:42 +020066 # Set name of Onap's k8s namespace and sdnc controller pod
Michal Ptacek0b06f782019-09-12 12:27:47 +000067 # CHANGEME part
Bartek Grzybowski1ee85df2019-10-10 14:57:13 +020068 onap_namespace = 'onap'
69 onap_environment = 'dev'
70 sdnc_controller_pod = '-'.join([onap_environment, 'sdnc-sdnc-0'])
Kang Xi11d278c2018-04-06 16:56:04 -040071
72 template_variable_symbol = '${'
Kang Xi6c762392018-05-30 09:27:34 -040073 cpe_vm_prefix = 'zdcpe'
Michal Ptacek0b06f782019-09-12 12:27:47 +000074
Kang Xi11d278c2018-04-06 16:56:04 -040075 #############################################################################################
76 # preloading network config
77 # key=network role
78 # value = [subnet_start_ip, subnet_gateway_ip]
79 preload_network_config = {
80 'cpe_public': ['10.2.0.2', '10.2.0.1'],
81 'cpe_signal': ['10.4.0.2', '10.4.0.1'],
82 'brg_bng': ['10.3.0.2', '10.3.0.1'],
83 'bng_mux': ['10.1.0.10', '10.1.0.1'],
84 'mux_gw': ['10.5.0.10', '10.5.0.1']
85 }
86
Kang Xi268b74d2018-05-23 15:53:42 -040087 dcae_ves_collector_name = 'dcae-bootstrap'
Kang Xi11d278c2018-04-06 16:56:04 -040088 global_subscriber_id = 'SDN-ETHERNET-INTERNET'
Kang Xi268b74d2018-05-23 15:53:42 -040089 project_name = 'Project-Demonstration'
90 owning_entity_id = '520cc603-a3c4-4ec2-9ef4-ca70facd79c0'
Yang Xu86c0e4a2018-12-02 13:10:41 -050091 owning_entity_name = 'OE-Demonstration1'
Kang Xi11d278c2018-04-06 16:56:04 -040092
93 def __init__(self, extra_host_names=None):
94 self.logger = logging.getLogger(__name__)
Yang Xu65b84a42018-12-31 17:48:02 +000095 self.logger.setLevel(logging.DEBUG)
Kang Xi11d278c2018-04-06 16:56:04 -040096 self.logger.info('Initializing configuration')
97
Michal Ptacek0b06f782019-09-12 12:27:47 +000098 ##################################################################################################################################
99 # following param must be updated e.g. from csar file (grep for VfModuleModelInvariantUuid string) before vcpe.py customer call !!
100 # vgw_VfModuleModelInvariantUuid is in rescust service csar,
101 # look in service-VcpesvcRescust1118-template.yml for groups vgw module metadata. TODO: read this value automatically
102 # CHANGEME part
Yang Xu27e16242018-12-28 01:00:50 -0500103 self.vgw_VfModuleModelInvariantUuid = '26d6a718-17b2-4ba8-8691-c44343b2ecd2'
Michal Ptacek0b06f782019-09-12 12:27:47 +0000104
105 # 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
Bartek Grzybowski863af9a2019-09-13 08:54:14 +0200106 self.sdnc_oam_ip = self.get_pod_node_oam_ip(self.sdnc_controller_pod)
107 # OOM: this is a k8s host external IP, e.g. oom-k8s-01 IP
108 self.oom_so_sdnc_aai_ip = self.get_pod_node_public_ip(self.sdnc_controller_pod)
Michal Ptacek0b06f782019-09-12 12:27:47 +0000109 # OOM: this is a k8s host external IP, e.g. oom-k8s-01 IP
Yang Xu65b84a42018-12-31 17:48:02 +0000110 self.oom_dcae_ves_collector = self.oom_so_sdnc_aai_ip
Michal Ptacek0b06f782019-09-12 12:27:47 +0000111 # OOM: this is a k8s host external IP, e.g. oom-k8s-01 IP
Yang Xu65b84a42018-12-31 17:48:02 +0000112 self.mr_ip_addr = self.oom_so_sdnc_aai_ip
Brian Freeman8076a872018-11-13 11:34:48 -0500113 self.mr_ip_port = '30227'
Brian Freemana605bc72018-11-12 10:50:30 -0500114 self.so_nbi_port = '30277' if self.oom_mode else '8080'
Brian Freemane8aa3f02019-09-20 08:29:22 -0500115 self.sdnc_preloading_port = '30267' if self.oom_mode else '8282'
Kang Xi0e0a1d62018-07-23 16:53:54 -0400116 self.aai_query_port = '30233' if self.oom_mode else '8443'
117 self.sniro_port = '30288' if self.oom_mode else '8080'
118
Bartek Grzybowski19199da2019-11-07 12:44:46 +0100119 self.host_names = ['sdc', 'so', 'sdnc', 'robot', 'aai-inst1', self.dcae_ves_collector_name, 'mariadb-galera']
Kang Xi11d278c2018-04-06 16:56:04 -0400120 if extra_host_names:
121 self.host_names.extend(extra_host_names)
122 # get IP addresses
123 self.hosts = self.get_vm_ip(self.host_names, self.external_net_addr, self.external_net_prefix_len)
124 # this is the keyword used to name vgw stack, must not be used in other stacks
125 self.vgw_name_keyword = 'base_vcpe_vgw'
Brian Freeman81f6e9e2018-11-11 22:36:20 -0500126 # this is the file that will keep the index of last assigned SO name
127 self.vgw_vfmod_name_index_file= '__var/vgw_vfmod_name_index'
Kang Xi11d278c2018-04-06 16:56:04 -0400128 self.svc_instance_uuid_file = '__var/svc_instance_uuid'
129 self.preload_dict_file = '__var/preload_dict'
130 self.vgmux_vnf_name_file = '__var/vgmux_vnf_name'
131 self.product_family_id = 'f9457e8c-4afd-45da-9389-46acd9bf5116'
132 self.custom_product_family_id = 'a9a77d5a-123e-4ca2-9eb9-0b015d2ee0fb'
133 self.instance_name_prefix = {
134 'service': 'vcpe_svc',
135 'network': 'vcpe_net',
136 'vnf': 'vcpe_vnf',
137 'vfmodule': 'vcpe_vfmodule'
138 }
139 self.aai_userpass = 'AAI', 'AAI'
Michal Ptacek0b06f782019-09-12 12:27:47 +0000140
141 ############################################################################################################
142 # following key is overriding public key from vCPE heat templates, it's important to use correct one in here
143 # CHANGEME part
Kang Xi11d278c2018-04-06 16:56:04 -0400144 self.pub_key = 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDKXDgoo3+WOqcUG8/5uUbk81+yczgwC4Y8ywTmuQqbNxlY1oQ0YxdMUqUnhitSXs5S/yRuAVOYHwGg2mCs20oAINrP+mxBI544AMIb9itPjCtgqtE2EWo6MmnFGbHB4Sx3XioE7F4VPsh7japsIwzOjbrQe+Mua1TGQ5d4nfEOQaaglXLLPFfuc7WbhbJbK6Q7rHqZfRcOwAMXgDoBqlyqKeiKwnumddo2RyNT8ljYmvB6buz7KnMinzo7qB0uktVT05FH9Rg0CTWH5norlG5qXgP2aukL0gk1ph8iAt7uYLf1ktp+LJI2gaF6L0/qli9EmVCSLr1uJ38Q8CBflhkh'
Michal Ptacek0b06f782019-09-12 12:27:47 +0000145
Kang Xi11d278c2018-04-06 16:56:04 -0400146 self.os_tenant_id = self.cloud['--os-tenant-id']
147 self.os_region_name = self.cloud['--os-region-name']
148 self.common_preload_config['pub_key'] = self.pub_key
Kang Xi0e0a1d62018-07-23 16:53:54 -0400149 self.sniro_url = 'http://' + self.hosts['robot'] + ':' + self.sniro_port + '/__admin/mappings'
Kang Xi11d278c2018-04-06 16:56:04 -0400150 self.sniro_headers = {'Content-Type': 'application/json', 'Accept': 'application/json'}
Kang Xi268b74d2018-05-23 15:53:42 -0400151 self.homing_solution = 'sniro' # value is either 'sniro' or 'oof'
152# self.homing_solution = 'oof'
153 self.customer_location_used_by_oof = {
154 "customerLatitude": "32.897480",
155 "customerLongitude": "-97.040443",
156 "customerName": "some_company"
157 }
Kang Xi11d278c2018-04-06 16:56:04 -0400158
159 #############################################################################################
Yang Xuc52ed6e2019-04-29 00:20:52 -0400160 # SDC urls
Brian Freeman0c724152019-09-18 09:30:05 -0500161 self.sdc_be_port = '30204'
Yang Xu0e319ef2019-04-30 14:28:07 -0400162 self.sdc_be_request_userpass = 'vid', 'Kp8bJ4SXszM0WXlhak3eHlcse2gAw84vaoGGmJvUy2U'
163 self.sdc_be_request_headers = {'X-ECOMP-InstanceID': 'VID'}
Brian Freeman0c724152019-09-18 09:30:05 -0500164 self.sdc_be_url_prefix = 'https://' + self.hosts['sdc'] + ':' + self.sdc_be_port
Yang Xu0e319ef2019-04-30 14:28:07 -0400165 self.sdc_service_list_url = self.sdc_be_url_prefix + '/sdc/v1/catalog/services'
166
Brian Freeman0c724152019-09-18 09:30:05 -0500167 self.sdc_fe_port = '30207'
Yang Xu0e319ef2019-04-30 14:28:07 -0400168 self.sdc_fe_request_userpass = 'beep', 'boop'
169 self.sdc_fe_request_headers = {'USER_ID': 'demo', 'Content-Type': 'application/json'}
Brian Freeman0c724152019-09-18 09:30:05 -0500170 self.sdc_fe_url_prefix = 'https://' + self.hosts['sdc'] + ':' + self.sdc_fe_port
Yang Xu0e319ef2019-04-30 14:28:07 -0400171 self.sdc_get_category_list_url = self.sdc_fe_url_prefix + '/sdc1/feProxy/rest/v1/categories'
172 self.sdc_create_allotted_resource_subcategory_url = self.sdc_fe_url_prefix + '/sdc1/feProxy/rest/v1/category/resources/resourceNewCategory.allotted%20resource/subCategory'
Yang Xuc52ed6e2019-04-29 00:20:52 -0400173
174 #############################################################################################
Kang Xi11d278c2018-04-06 16:56:04 -0400175 # SDNC urls
176 self.sdnc_userpass = 'admin', 'Kp8bJ4SXszM0WXlhak3eHlcse2gAw84vaoGGmJvUy2U'
177 self.sdnc_db_name = 'sdnctl'
178 self.sdnc_db_user = 'sdnctl'
179 self.sdnc_db_pass = 'gamma'
Bartek Grzybowski19199da2019-11-07 12:44:46 +0100180 self.sdnc_db_port = self.get_k8s_service_endpoint_info('mariadb-galera','port') if self.oom_mode else '3306'
Kang Xi11d278c2018-04-06 16:56:04 -0400181 self.sdnc_headers = {'Content-Type': 'application/json', 'Accept': 'application/json'}
Brian Freemane8aa3f02019-09-20 08:29:22 -0500182 self.sdnc_preload_network_url = 'https://' + self.hosts['sdnc'] + \
Kang Xi0e0a1d62018-07-23 16:53:54 -0400183 ':' + self.sdnc_preloading_port + '/restconf/operations/VNF-API:preload-network-topology-operation'
Brian Freeman9b3d6ca2019-11-06 13:22:53 -0500184 self.sdnc_preload_network_gra_url = 'https://' + self.hosts['sdnc'] + \
185 ':' + self.sdnc_preloading_port + '/restconf/operations/GENERIC-RESOURCE-API:preload-network-topology-operation'
Brian Freemane8aa3f02019-09-20 08:29:22 -0500186 self.sdnc_preload_vnf_url = 'https://' + self.hosts['sdnc'] + \
Kang Xi0e0a1d62018-07-23 16:53:54 -0400187 ':' + self.sdnc_preloading_port + '/restconf/operations/VNF-API:preload-vnf-topology-operation'
Brian Freemane8aa3f02019-09-20 08:29:22 -0500188 self.sdnc_preload_gra_url = 'https://' + self.hosts['sdnc'] + \
Brian Freeman81f6e9e2018-11-11 22:36:20 -0500189 ':' + self.sdnc_preloading_port + '/restconf/operations/GENERIC-RESOURCE-API:preload-vf-module-topology-operation'
Brian Freemane8aa3f02019-09-20 08:29:22 -0500190 self.sdnc_ar_cleanup_url = 'https://' + self.hosts['sdnc'] + ':' + self.sdnc_preloading_port + \
Kang Xi0e0a1d62018-07-23 16:53:54 -0400191 '/restconf/config/GENERIC-RESOURCE-API:'
Kang Xi11d278c2018-04-06 16:56:04 -0400192
193 #############################################################################################
Bartek Grzybowskiba8a72f2019-11-22 15:02:21 +0100194 # MARIADB-GALERA settings
195 self.mariadb_galera_endpoint_ip = self.get_k8s_service_endpoint_info('mariadb-galera','ip')
196 self.mariadb_galera_endpoint_port = self.get_k8s_service_endpoint_info('mariadb-galera','port')
197
198 #############################################################################################
Kang Xi11d278c2018-04-06 16:56:04 -0400199 # SO urls, note: do NOT add a '/' at the end of the url
Brian Freemana605bc72018-11-12 10:50:30 -0500200 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 -0500201 'v5': 'http://' + self.hosts['so'] + ':' + self.so_nbi_port + '/onap/so/infra/serviceInstantiation/v7/serviceInstances'}
Brian Freemana605bc72018-11-12 10:50:30 -0500202 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 -0400203 self.so_userpass = 'InfraPortalClient', 'password1$'
204 self.so_headers = {'Content-Type': 'application/json', 'Accept': 'application/json'}
Brian Freemana605bc72018-11-12 10:50:30 -0500205 self.so_db_name = 'catalogdb'
Kang Xi11d278c2018-04-06 16:56:04 -0400206 self.so_db_user = 'root'
Yang Xu21b09c92019-06-13 13:19:20 -0400207 self.so_db_pass = 'secretpassword'
Bartek Grzybowskiba8a72f2019-11-22 15:02:21 +0100208 self.so_db_host = self.mariadb_galera_endpoint_ip if self.oom_mode else self.hosts['so']
209 self.so_db_port = self.mariadb_galera_endpoint_port if self.oom_mode else '3306'
Kang Xi11d278c2018-04-06 16:56:04 -0400210
211 self.vpp_inf_url = 'http://{0}:8183/restconf/config/ietf-interfaces:interfaces'
212 self.vpp_api_headers = {'Content-Type': 'application/json', 'Accept': 'application/json'}
213 self.vpp_api_userpass = ('admin', 'admin')
214 self.vpp_ves_url= 'http://{0}:8183/restconf/config/vesagent:vesagent'
215
Bartek Grzybowskidbb3ba12019-09-25 11:21:42 +0200216 #############################################################################################
217 # POLICY urls
218 self.policy_userpass = ('healthcheck', 'zb!XztG34')
219 self.policy_headers = {'Accept': 'application/json', 'Content-Type': 'application/json'}
220 self.policy_api_url = 'https://{0}:6969/policy/api/v1/policytypes/onap.policies.controlloop.Operational/versions/1.0.0/policies'
221 self.policy_pap_get_url = 'https://{0}:6969/policy/pap/v1/pdps'
222 self.policy_pap_json = {'policies': [{'policy-id': 'operational.vcpe'}]}
223 self.policy_pap_post_url = self.policy_pap_get_url + '/policies'
224 self.policy_api_service_name = 'policy-api'
225 self.policy_pap_service_name = 'policy-pap'
226
Bartek Grzybowski9018a842019-10-16 15:28:23 +0200227 #############################################################################################
Bartek Grzybowski6358aa32019-10-30 13:46:43 +0100228 # AAI urls
229 self.aai_region_query_url = 'https://' + self.oom_so_sdnc_aai_ip + ':' +\
230 self.aai_query_port +\
231 '/aai/v14/cloud-infrastructure/cloud-regions/cloud-region/CloudOwner/' +\
232 self.cloud['--os-region-name']
233 self.aai_headers = {'Accept': 'application/json',
234 'Content-Type': 'application/json',
235 'X-FromAppId': 'postman', 'X-TransactionId': '9999'}
236
Bartek Grzybowskibfeeb242019-09-13 08:35:48 +0200237 def heatbridge(self, openstack_stack_name, svc_instance_uuid):
Kang Xi11d278c2018-04-06 16:56:04 -0400238 """
239 Add vserver information to AAI
240 """
241 self.logger.info('Adding vServer information to AAI for {0}'.format(openstack_stack_name))
Kang Xi0e0a1d62018-07-23 16:53:54 -0400242 if not self.oom_mode:
243 cmd = '/opt/demo.sh heatbridge {0} {1} vCPE'.format(openstack_stack_name, svc_instance_uuid)
244 ret = commands.getstatusoutput("ssh -i onap_dev root@{0} '{1}'".format(self.hosts['robot'], cmd))
245 self.logger.debug('%s', ret)
246 else:
247 print('To add vGMUX vserver info to AAI, do the following:')
248 print('- ssh to rancher')
249 print('- sudo su -')
250 print('- cd /root/oom/kubernetes/robot')
251 print('- ./demo-k8s.sh onap heatbridge {0} {1} vCPE'.format(openstack_stack_name, svc_instance_uuid))
Kang Xi11d278c2018-04-06 16:56:04 -0400252
253 def get_brg_mac_from_sdnc(self):
254 """
Kang Xi6c762392018-05-30 09:27:34 -0400255 Check table DHCP_MAP in the SDNC DB. Find the newly instantiated BRG MAC address.
256 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 -0400257 """
Bartek Grzybowski19199da2019-11-07 12:44:46 +0100258 if self.oom_mode:
259 db_host=self.mariadb_galera_endpoint_ip
260 else:
261 db_host=self.hosts['mariadb-galera']
262
263 cnx = mysql.connector.connect(user=self.sdnc_db_user,
264 password=self.sdnc_db_pass,
265 database=self.sdnc_db_name,
266 host=db_host,
267 port=self.sdnc_db_port)
Kang Xi11d278c2018-04-06 16:56:04 -0400268 cursor = cnx.cursor()
269 query = "SELECT * from DHCP_MAP"
270 cursor.execute(query)
271
272 self.logger.debug('DHCP_MAP table in SDNC')
Kang Xi6c762392018-05-30 09:27:34 -0400273 mac_recent = None
274 host = -1
Kang Xi11d278c2018-04-06 16:56:04 -0400275 for mac, ip in cursor:
Bartek Grzybowski19199da2019-11-07 12:44:46 +0100276 self.logger.debug(mac + ' - ' + ip)
Kang Xi6c762392018-05-30 09:27:34 -0400277 this_host = int(ip.split('.')[-1])
278 if host < this_host:
279 host = this_host
280 mac_recent = mac
Kang Xi11d278c2018-04-06 16:56:04 -0400281
282 cnx.close()
283
Bartek Grzybowski19199da2019-11-07 12:44:46 +0100284 try:
285 assert mac_recent
286 except AssertionError:
287 self.logger.error('Failed to obtain BRG MAC address from database')
288 sys.exit(1)
289
Kang Xi6c762392018-05-30 09:27:34 -0400290 return mac_recent
Kang Xi11d278c2018-04-06 16:56:04 -0400291
Bartek Grzybowski9018a842019-10-16 15:28:23 +0200292 def execute_cmds_mariadb(self, cmds):
293 self.execute_cmds_db(cmds, self.sdnc_db_user, self.sdnc_db_pass,
294 self.sdnc_db_name, self.mariadb_galera_endpoint_ip,
295 self.mariadb_galera_endpoint_port)
296
Kang Xi6c762392018-05-30 09:27:34 -0400297 def execute_cmds_sdnc_db(self, cmds):
298 self.execute_cmds_db(cmds, self.sdnc_db_user, self.sdnc_db_pass, self.sdnc_db_name,
299 self.hosts['sdnc'], self.sdnc_db_port)
Kang Xi11d278c2018-04-06 16:56:04 -0400300
Kang Xi6c762392018-05-30 09:27:34 -0400301 def execute_cmds_so_db(self, cmds):
302 self.execute_cmds_db(cmds, self.so_db_user, self.so_db_pass, self.so_db_name,
Bartek Grzybowskiba8a72f2019-11-22 15:02:21 +0100303 self.so_db_host, self.so_db_port)
Kang Xi6c762392018-05-30 09:27:34 -0400304
305 def execute_cmds_db(self, cmds, dbuser, dbpass, dbname, host, port):
306 cnx = mysql.connector.connect(user=dbuser, password=dbpass, database=dbname, host=host, port=port)
Kang Xi11d278c2018-04-06 16:56:04 -0400307 cursor = cnx.cursor()
308 for cmd in cmds:
309 self.logger.debug(cmd)
310 cursor.execute(cmd)
311 self.logger.debug('%s', cursor)
312 cnx.commit()
313 cursor.close()
314 cnx.close()
315
316 def find_file(self, file_name_keyword, file_ext, search_dir):
317 """
318 :param file_name_keyword: keyword used to look for the csar file, case insensitive matching, e.g, infra
319 :param file_ext: e.g., csar, json
320 :param search_dir path to search
321 :return: path name of the file
322 """
323 file_name_keyword = file_name_keyword.lower()
324 file_ext = file_ext.lower()
325 if not file_ext.startswith('.'):
326 file_ext = '.' + file_ext
327
328 filenamepath = None
329 for file_name in os.listdir(search_dir):
330 file_name_lower = file_name.lower()
331 if file_name_keyword in file_name_lower and file_name_lower.endswith(file_ext):
332 if filenamepath:
333 self.logger.error('Multiple files found for *{0}*.{1} in '
334 'directory {2}'.format(file_name_keyword, file_ext, search_dir))
Bartek Grzybowski68d93c22019-10-30 10:55:55 +0100335 sys.exit(1)
Kang Xi11d278c2018-04-06 16:56:04 -0400336 filenamepath = os.path.abspath(os.path.join(search_dir, file_name))
337
338 if filenamepath:
339 return filenamepath
340 else:
341 self.logger.error("Cannot find *{0}*{1} in directory {2}".format(file_name_keyword, file_ext, search_dir))
Bartek Grzybowski68d93c22019-10-30 10:55:55 +0100342 sys.exit(1)
Kang Xi11d278c2018-04-06 16:56:04 -0400343
344 @staticmethod
345 def network_name_to_subnet_name(network_name):
346 """
347 :param network_name: example: vcpe_net_cpe_signal_201711281221
348 :return: vcpe_net_cpe_signal_subnet_201711281221
349 """
350 fields = network_name.split('_')
351 fields.insert(-1, 'subnet')
352 return '_'.join(fields)
353
354 def set_network_name(self, network_name):
355 param = ' '.join([k + ' ' + v for k, v in self.cloud.items()])
356 openstackcmd = 'openstack ' + param
357 cmd = ' '.join([openstackcmd, 'network set --name', network_name, 'ONAP-NW1'])
358 os.popen(cmd)
359
360 def set_subnet_name(self, network_name):
361 """
362 Example: network_name = vcpe_net_cpe_signal_201711281221
363 set subnet name to vcpe_net_cpe_signal_subnet_201711281221
364 :return:
365 """
366 param = ' '.join([k + ' ' + v for k, v in self.cloud.items()])
367 openstackcmd = 'openstack ' + param
368
369 # expected results: | subnets | subnet_id |
370 subnet_info = os.popen(openstackcmd + ' network show ' + network_name + ' |grep subnets').read().split('|')
371 if len(subnet_info) > 2 and subnet_info[1].strip() == 'subnets':
372 subnet_id = subnet_info[2].strip()
373 subnet_name = self.network_name_to_subnet_name(network_name)
374 cmd = ' '.join([openstackcmd, 'subnet set --name', subnet_name, subnet_id])
375 os.popen(cmd)
376 self.logger.info("Subnet name set to: " + subnet_name)
377 return True
378 else:
379 self.logger.error("Can't get subnet info from network name: " + network_name)
380 return False
381
Bartek Grzybowskidbb3ba12019-09-25 11:21:42 +0200382 def set_closed_loop_policy(self, policy_template_file):
383 # Gather policy services cluster ips
384 p_api_cluster_ip = self.get_k8s_service_cluster_ip(self.policy_api_service_name)
385 p_pap_cluster_ip = self.get_k8s_service_cluster_ip(self.policy_pap_service_name)
386
387 # Read policy json from file
388 with open(policy_template_file) as f:
389 try:
390 policy_json = json.load(f)
391 except ValueError:
392 self.logger.error(policy_template_file + " doesn't seem to contain valid JSON data")
Bartek Grzybowski68d93c22019-10-30 10:55:55 +0100393 sys.exit(1)
Bartek Grzybowskidbb3ba12019-09-25 11:21:42 +0200394
395 # Check policy already applied
Bartek Grzybowskidbb3ba12019-09-25 11:21:42 +0200396 policy_exists_req = requests.get(self.policy_pap_get_url.format(
397 p_pap_cluster_ip), auth=self.policy_userpass,
398 verify=False, headers=self.policy_headers)
399 if policy_exists_req.status_code != 200:
400 self.logger.error('Failure in checking CL policy existence. '
401 'Policy-pap responded with HTTP code {0}'.format(
402 policy_exists_req.status_code))
Bartek Grzybowski68d93c22019-10-30 10:55:55 +0100403 sys.exit(1)
Bartek Grzybowskidbb3ba12019-09-25 11:21:42 +0200404
405 try:
406 policy_exists_json = policy_exists_req.json()
407 except ValueError as e:
408 self.logger.error('Policy-pap request failed: ' + e.message)
Bartek Grzybowski68d93c22019-10-30 10:55:55 +0100409 sys.exit(1)
Bartek Grzybowskidbb3ba12019-09-25 11:21:42 +0200410
411 try:
412 assert policy_exists_json['groups'][0]['pdpSubgroups'] \
413 [1]['policies'][0]['name'] != 'operational.vcpe'
414 except AssertionError:
415 self.logger.info('vCPE closed loop policy already exists, not applying')
416 return
417 except IndexError:
418 pass # policy doesn't exist
419
420 # Create policy
421 policy_create_req = requests.post(self.policy_api_url.format(
422 p_api_cluster_ip), auth=self.policy_userpass,
423 json=policy_json, verify=False,
424 headers=self.policy_headers)
425 # Get the policy id from policy-api response
426 if policy_create_req.status_code != 200:
427 self.logger.error('Failed creating policy. Policy-api responded'
428 ' with HTTP code {0}'.format(policy_create_req.status_code))
Bartek Grzybowski68d93c22019-10-30 10:55:55 +0100429 sys.exit(1)
Bartek Grzybowskidbb3ba12019-09-25 11:21:42 +0200430
431 try:
432 policy_version = json.loads(policy_create_req.text)['policy-version']
433 except (KeyError, ValueError):
434 self.logger.error('Policy API response not understood:')
435 self.logger.debug('\n' + str(policy_create_req.text))
436
437 # Inject the policy into Policy PAP
438 self.policy_pap_json['policies'].append({'policy-version': policy_version})
439 policy_insert_req = requests.post(self.policy_pap_post_url.format(
440 p_pap_cluster_ip), auth=self.policy_userpass,
441 json=self.policy_pap_json, verify=False,
442 headers=self.policy_headers)
443 if policy_insert_req.status_code != 200:
444 self.logger.error('Policy PAP request failed with HTTP code'
445 '{0}'.format(policy_insert_req.status_code))
Bartek Grzybowski68d93c22019-10-30 10:55:55 +0100446 sys.exit(1)
Bartek Grzybowskidbb3ba12019-09-25 11:21:42 +0200447 self.logger.info('Successully pushed closed loop Policy')
448
Kang Xi11d278c2018-04-06 16:56:04 -0400449 def is_node_in_aai(self, node_type, node_uuid):
450 key = None
451 search_node_type = None
452 if node_type == 'service':
453 search_node_type = 'service-instance'
454 key = 'service-instance-id'
455 elif node_type == 'vnf':
456 search_node_type = 'generic-vnf'
457 key = 'vnf-id'
458 else:
459 logging.error('Invalid node_type: ' + node_type)
Bartek Grzybowski68d93c22019-10-30 10:55:55 +0100460 sys.exit(1)
Kang Xi11d278c2018-04-06 16:56:04 -0400461
Kang Xi0e0a1d62018-07-23 16:53:54 -0400462 url = 'https://{0}:{1}/aai/v11/search/nodes-query?search-node-type={2}&filter={3}:EQUALS:{4}'.format(
463 self.hosts['aai-inst1'], self.aai_query_port, search_node_type, key, node_uuid)
Kang Xi11d278c2018-04-06 16:56:04 -0400464
Kang Xi268b74d2018-05-23 15:53:42 -0400465 headers = {'Content-Type': 'application/json', 'Accept': 'application/json', 'X-FromAppID': 'vCPE-Robot', 'X-TransactionId': 'get_aai_subscr'}
Kang Xi11d278c2018-04-06 16:56:04 -0400466 r = requests.get(url, headers=headers, auth=self.aai_userpass, verify=False)
467 response = r.json()
468 self.logger.debug('aai query: ' + url)
469 self.logger.debug('aai response:\n' + json.dumps(response, indent=4, sort_keys=True))
470 return 'result-data' in response
471
472 @staticmethod
473 def extract_ip_from_str(net_addr, net_addr_len, sz):
474 """
475 :param net_addr: e.g. 10.5.12.0
476 :param net_addr_len: e.g. 24
477 :param sz: a string
478 :return: the first IP address matching the network, e.g. 10.5.12.3
479 """
480 network = ipaddress.ip_network(unicode('{0}/{1}'.format(net_addr, net_addr_len)), strict=False)
481 ip_list = re.findall(r'[0-9]+(?:\.[0-9]+){3}', sz)
482 for ip in ip_list:
483 this_net = ipaddress.ip_network(unicode('{0}/{1}'.format(ip, net_addr_len)), strict=False)
484 if this_net == network:
485 return str(ip)
486 return None
487
Yang Xu75b0f5e2018-11-14 14:04:20 -0500488 def get_pod_node_oam_ip(self, pod):
489 """
Yang Xu64339a82018-12-30 05:32:21 +0000490 :Assuming kubectl is available and configured by default config (~/.kube/config)
491 :param pod: pod name substring, e.g. 'sdnc-sdnc-0'
492 :return pod's cluster node oam ip (10.0.0.0/16)
Yang Xu75b0f5e2018-11-14 14:04:20 -0500493 """
Yang Xu64339a82018-12-30 05:32:21 +0000494 ret = None
495 config.load_kube_config()
496 api = client.CoreV1Api()
497 kslogger = logging.getLogger('kubernetes')
498 kslogger.setLevel(logging.INFO)
499 res = api.list_pod_for_all_namespaces()
500 for i in res.items:
501 if pod in i.metadata.name:
Yang Xu65b84a42018-12-31 17:48:02 +0000502 self.logger.debug("found {0}\t{1}\t{2}".format(i.metadata.name, i.status.host_ip, i.spec.node_name))
Yang Xu64339a82018-12-30 05:32:21 +0000503 ret = i.status.host_ip
504 break
505
506 if ret is None:
Bartek Grzybowski863af9a2019-09-13 08:54:14 +0200507 ret = raw_input("Enter " + self.sdnc_controller_pod + " pod cluster node OAM IP address(10.0.0.0/16): ")
Yang Xu64339a82018-12-30 05:32:21 +0000508 return ret
509
510 def get_pod_node_public_ip(self, pod):
511 """
512 :Assuming kubectl is available and configured by default config (~/.kube/config)
513 :param pod: pod name substring, e.g. 'sdnc-sdnc-0'
514 :return pod's cluster node public ip (i.e. 10.12.0.0/16)
515 """
516 ret = None
517 config.load_kube_config()
518 api = client.CoreV1Api()
519 kslogger = logging.getLogger('kubernetes')
520 kslogger.setLevel(logging.INFO)
521 res = api.list_pod_for_all_namespaces()
522 for i in res.items:
523 if pod in i.metadata.name:
Yang Xu65b84a42018-12-31 17:48:02 +0000524 ret = self.get_vm_public_ip_by_nova(i.spec.node_name)
525 self.logger.debug("found node {0} public ip: {1}".format(i.spec.node_name, ret))
Yang Xu64339a82018-12-30 05:32:21 +0000526 break
527
528 if ret is None:
Bartek Grzybowski863af9a2019-09-13 08:54:14 +0200529 ret = raw_input("Enter " + self.sdnc_controller_pod + " pod cluster node public IP address(i.e. " + self.external_net_addr + "): ")
Yang Xu75b0f5e2018-11-14 14:04:20 -0500530 return ret
531
Yang Xu65b84a42018-12-31 17:48:02 +0000532 def get_vm_public_ip_by_nova(self, vm):
533 """
534 This method uses openstack nova api to retrieve vm public ip
535 :param vm: vm name
536 :return vm public ip
537 """
538 subnet = IPNetwork('{0}/{1}'.format(self.external_net_addr, self.external_net_prefix_len))
539 nova = openstackclient.Client(2, self.cloud['--os-username'], self.cloud['--os-password'], self.cloud['--os-tenant-id'], self.cloud['--os-auth-url'])
540 for i in nova.servers.list():
541 if i.name == vm:
542 for k, v in i.networks.items():
543 for ip in v:
544 if IPAddress(ip) in subnet:
545 return ip
546 return None
547
Kang Xi11d278c2018-04-06 16:56:04 -0400548 def get_vm_ip(self, keywords, net_addr=None, net_addr_len=None):
549 """
550 :param keywords: list of keywords to search for vm, e.g. ['bng', 'gmux', 'brg']
551 :param net_addr: e.g. 10.12.5.0
552 :param net_addr_len: e.g. 24
553 :return: dictionary {keyword: ip}
554 """
555 if not net_addr:
556 net_addr = self.external_net_addr
557
558 if not net_addr_len:
559 net_addr_len = self.external_net_prefix_len
560
561 param = ' '.join([k + ' ' + v for k, v in self.cloud.items() if 'identity' not in k])
562 openstackcmd = 'nova ' + param + ' list'
563 self.logger.debug(openstackcmd)
564
Kang Xi11d278c2018-04-06 16:56:04 -0400565 results = os.popen(openstackcmd).read()
Kang Xi6c762392018-05-30 09:27:34 -0400566 all_vm_ip_dict = self.extract_vm_ip_as_dict(results, net_addr, net_addr_len)
567 latest_vm_list = self.remove_old_vms(all_vm_ip_dict.keys(), self.cpe_vm_prefix)
568 latest_vm_ip_dict = {vm: all_vm_ip_dict[vm] for vm in latest_vm_list}
569 ip_dict = self.select_subset_vm_ip(latest_vm_ip_dict, keywords)
Kang Xi0e0a1d62018-07-23 16:53:54 -0400570 if self.oom_mode:
571 ip_dict.update(self.get_oom_onap_vm_ip(keywords))
Kang Xi6c762392018-05-30 09:27:34 -0400572
Kang Xi11d278c2018-04-06 16:56:04 -0400573 if len(ip_dict) != len(keywords):
574 self.logger.error('Cannot find all desired IP addresses for %s.', keywords)
575 self.logger.error(json.dumps(ip_dict, indent=4, sort_keys=True))
Yang Xu64339a82018-12-30 05:32:21 +0000576 self.logger.error('Temporarily continue.. remember to check back vcpecommon.py line: 396')
Bartek Grzybowski68d93c22019-10-30 10:55:55 +0100577# sys.exit(1)
Kang Xi11d278c2018-04-06 16:56:04 -0400578 return ip_dict
579
Kang Xi0e0a1d62018-07-23 16:53:54 -0400580 def get_oom_onap_vm_ip(self, keywords):
581 vm_ip = {}
Kang Xi0e0a1d62018-07-23 16:53:54 -0400582 for vm in keywords:
Bartek Grzybowski8b409a12019-10-24 13:26:21 +0200583 if vm in self.host_names:
Kang Xi0e0a1d62018-07-23 16:53:54 -0400584 vm_ip[vm] = self.oom_so_sdnc_aai_ip
585 return vm_ip
586
Bartek Grzybowskidbb3ba12019-09-25 11:21:42 +0200587 def get_k8s_service_cluster_ip(self, service):
588 """
589 Returns cluster IP for a given service
590 :param service: name of the service
591 :return: cluster ip
592 """
593 config.load_kube_config()
594 api = client.CoreV1Api()
595 kslogger = logging.getLogger('kubernetes')
596 kslogger.setLevel(logging.INFO)
597 try:
598 resp = api.read_namespaced_service(service, self.onap_namespace)
599 except client.rest.ApiException as e:
600 self.logger.error('Error while making k8s API request: ' + e.body)
Bartek Grzybowski68d93c22019-10-30 10:55:55 +0100601 sys.exit(1)
Bartek Grzybowskidbb3ba12019-09-25 11:21:42 +0200602
603 return resp.spec.cluster_ip
604
Bartek Grzybowski9018a842019-10-16 15:28:23 +0200605 def get_k8s_service_endpoint_info(self, service, subset):
606 """
607 Returns endpoint data for a given service and subset. If there
608 is more than one endpoint returns data for the first one from
609 the list that API returned.
610 :param service: name of the service
611 :param subset: subset name, one of "ip","port"
612 :return: endpoint ip
613 """
614 config.load_kube_config()
615 api = client.CoreV1Api()
616 kslogger = logging.getLogger('kubernetes')
617 kslogger.setLevel(logging.INFO)
618 try:
619 resp = api.read_namespaced_endpoints(service, self.onap_namespace)
620 except client.rest.ApiException as e:
621 self.logger.error('Error while making k8s API request: ' + e.body)
Bartek Grzybowski68d93c22019-10-30 10:55:55 +0100622 sys.exit(1)
Bartek Grzybowski9018a842019-10-16 15:28:23 +0200623
624 if subset == "ip":
625 return resp.subsets[0].addresses[0].ip
626 elif subset == "port":
627 return resp.subsets[0].ports[0].port
628 else:
629 self.logger.error("Unsupported subset type")
630
Kang Xi6c762392018-05-30 09:27:34 -0400631 def extract_vm_ip_as_dict(self, novalist_results, net_addr, net_addr_len):
632 vm_ip_dict = {}
633 for line in novalist_results.split('\n'):
634 fields = line.split('|')
635 if len(fields) == 8:
636 vm_name = fields[2]
637 ip_info = fields[-2]
638 ip = self.extract_ip_from_str(net_addr, net_addr_len, ip_info)
639 vm_ip_dict[vm_name] = ip
640
641 return vm_ip_dict
642
643 def remove_old_vms(self, vm_list, prefix):
644 """
645 For vms with format name_timestamp, only keep the one with the latest timestamp.
646 E.g.,
647 zdcpe1cpe01brgemu01_201805222148 (drop this)
648 zdcpe1cpe01brgemu01_201805222229 (keep this)
649 zdcpe1cpe01gw01_201805162201
650 """
651 new_vm_list = []
652 same_type_vm_dict = {}
653 for vm in vm_list:
654 fields = vm.split('_')
655 if vm.startswith(prefix) and len(fields) == 2 and len(fields[-1]) == len('201805222148') and fields[-1].isdigit():
656 if vm > same_type_vm_dict.get(fields[0], '0'):
657 same_type_vm_dict[fields[0]] = vm
658 else:
659 new_vm_list.append(vm)
660
661 new_vm_list.extend(same_type_vm_dict.values())
662 return new_vm_list
663
664 def select_subset_vm_ip(self, all_vm_ip_dict, vm_name_keyword_list):
665 vm_ip_dict = {}
666 for keyword in vm_name_keyword_list:
667 for vm, ip in all_vm_ip_dict.items():
668 if keyword in vm:
669 vm_ip_dict[keyword] = ip
670 break
671 return vm_ip_dict
672
Kang Xi11d278c2018-04-06 16:56:04 -0400673 def del_vgmux_ves_mode(self):
674 url = self.vpp_ves_url.format(self.hosts['mux']) + '/mode'
675 r = requests.delete(url, headers=self.vpp_api_headers, auth=self.vpp_api_userpass)
676 self.logger.debug('%s', r)
677
678 def del_vgmux_ves_collector(self):
679 url = self.vpp_ves_url.format(self.hosts['mux']) + '/config'
680 r = requests.delete(url, headers=self.vpp_api_headers, auth=self.vpp_api_userpass)
681 self.logger.debug('%s', r)
682
683 def set_vgmux_ves_collector(self ):
684 url = self.vpp_ves_url.format(self.hosts['mux'])
685 data = {'config':
Kang Xi268b74d2018-05-23 15:53:42 -0400686 {'server-addr': self.hosts[self.dcae_ves_collector_name],
Kang Xi0e0a1d62018-07-23 16:53:54 -0400687 'server-port': '30235' if self.oom_mode else '8081',
Kang Xi11d278c2018-04-06 16:56:04 -0400688 'read-interval': '10',
689 'is-add':'1'
690 }
691 }
692 r = requests.post(url, headers=self.vpp_api_headers, auth=self.vpp_api_userpass, json=data)
693 self.logger.debug('%s', r)
694
695 def set_vgmux_packet_loss_rate(self, lossrate, vg_vnf_instance_name):
696 url = self.vpp_ves_url.format(self.hosts['mux'])
697 data = {"mode":
698 {"working-mode": "demo",
699 "base-packet-loss": str(lossrate),
700 "source-name": vg_vnf_instance_name
701 }
702 }
703 r = requests.post(url, headers=self.vpp_api_headers, auth=self.vpp_api_userpass, json=data)
704 self.logger.debug('%s', r)
705
706 # return all the VxLAN interface names of BRG or vGMUX based on the IP address
707 def get_vxlan_interfaces(self, ip, print_info=False):
708 url = self.vpp_inf_url.format(ip)
709 self.logger.debug('url is this: %s', url)
710 r = requests.get(url, headers=self.vpp_api_headers, auth=self.vpp_api_userpass)
711 data = r.json()['interfaces']['interface']
712 if print_info:
713 for inf in data:
714 if 'name' in inf and 'type' in inf and inf['type'] == 'v3po:vxlan-tunnel':
715 print(json.dumps(inf, indent=4, sort_keys=True))
716
717 return [inf['name'] for inf in data if 'name' in inf and 'type' in inf and inf['type'] == 'v3po:vxlan-tunnel']
718
719 # delete all VxLAN interfaces of each hosts
720 def delete_vxlan_interfaces(self, host_dic):
721 for host, ip in host_dic.items():
722 deleted = False
723 self.logger.info('{0}: Getting VxLAN interfaces'.format(host))
724 inf_list = self.get_vxlan_interfaces(ip)
725 for inf in inf_list:
726 deleted = True
727 time.sleep(2)
728 self.logger.info("{0}: Deleting VxLAN crossconnect {1}".format(host, inf))
729 url = self.vpp_inf_url.format(ip) + '/interface/' + inf + '/v3po:l2'
730 requests.delete(url, headers=self.vpp_api_headers, auth=self.vpp_api_userpass)
731
732 for inf in inf_list:
733 deleted = True
734 time.sleep(2)
735 self.logger.info("{0}: Deleting VxLAN interface {1}".format(host, inf))
736 url = self.vpp_inf_url.format(ip) + '/interface/' + inf
737 requests.delete(url, headers=self.vpp_api_headers, auth=self.vpp_api_userpass)
738
739 if len(self.get_vxlan_interfaces(ip)) > 0:
740 self.logger.error("Error deleting VxLAN from {0}, try to restart the VM, IP is {1}.".format(host, ip))
741 return False
742
743 if not deleted:
744 self.logger.info("{0}: no VxLAN interface found, nothing to delete".format(host))
745 return True
746
747 @staticmethod
748 def save_object(obj, filepathname):
749 with open(filepathname, 'wb') as fout:
750 pickle.dump(obj, fout)
751
752 @staticmethod
753 def load_object(filepathname):
754 with open(filepathname, 'rb') as fin:
755 return pickle.load(fin)
756
Kang Xi6c762392018-05-30 09:27:34 -0400757 @staticmethod
758 def increase_ip_address_or_vni_in_template(vnf_template_file, vnf_parameter_name_list):
759 with open(vnf_template_file) as json_input:
760 json_data = json.load(json_input)
761 param_list = json_data['VNF-API:input']['VNF-API:vnf-topology-information']['VNF-API:vnf-parameters']
762 for param in param_list:
763 if param['vnf-parameter-name'] in vnf_parameter_name_list:
764 ipaddr_or_vni = param['vnf-parameter-value'].split('.')
765 number = int(ipaddr_or_vni[-1])
766 if 254 == number:
767 number = 10
768 else:
769 number = number + 1
770 ipaddr_or_vni[-1] = str(number)
771 param['vnf-parameter-value'] = '.'.join(ipaddr_or_vni)
772
773 assert json_data is not None
774 with open(vnf_template_file, 'w') as json_output:
775 json.dump(json_data, json_output, indent=4, sort_keys=True)
776
Kang Xi11d278c2018-04-06 16:56:04 -0400777 def save_preload_data(self, preload_data):
778 self.save_object(preload_data, self.preload_dict_file)
779
780 def load_preload_data(self):
781 return self.load_object(self.preload_dict_file)
782
783 def save_vgmux_vnf_name(self, vgmux_vnf_name):
784 self.save_object(vgmux_vnf_name, self.vgmux_vnf_name_file)
785
786 def load_vgmux_vnf_name(self):
787 return self.load_object(self.vgmux_vnf_name_file)
788