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