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