import time import os import json from vcpeutils.csar_parser import CsarParser from robot.api import logger from datetime import datetime import sys from ONAPLibrary.PreloadSDNCKeywords import PreloadSDNCKeywords from ONAPLibrary.RequestSOKeywords import RequestSOKeywords from ONAPLibrary.BaseAAIKeywords import BaseAAIKeywords from ONAPLibrary.UUIDKeywords import UUIDKeywords class SoUtils: def __init__(self): # SO urls, note: do NOT add a '/' at the end of the url self.so_nbi_port = '8080' self.so_host = 'so.onap' self.so_si_path = '/onap/so/infra/serviceInstantiation/v7/serviceInstances' self.so_orch_path = '/onap/so/infra/orchestrationRequests/v6' self.service_req_api_url = 'http://' + self.so_host + ':' + self.so_nbi_port self.so_check_progress_api_url = 'http://' + self.so_host + ':' + self.so_nbi_port + self.so_orch_path + '/' self.so_userpass = 'InfraPortalClient', 'password1$' self.so_headers = {'Content-Type': 'application/json', 'Accept': 'application/json'} # mr utls self.mr_ip_addr = 'mr.onap' self.mr_ip_port = '3904' # sdnc urls self.sdnc_ip_addr = 'sdnc.onap' self.sdnc_preloading_port = '8282' self.sdnc_endpoint = 'http://' + self.sdnc_ip_addr + ':' + self.sdnc_preloading_port self.sdnc_preload_vnf_url = '/restconf/operations/VNF-API:preload-vnf-topology-operation' # properties self.homing_solution = 'sniro' # value is either 'sniro' or 'oof' self.customer_location_used_by_oof = { "customerLatitude": "32.897480", "customerLongitude": "-97.040443", "customerName": "some_company" } self.product_family_id = 'f9457e8c-4afd-45da-9389-46acd9bf5116' self.custom_product_family_id = 'a9a77d5a-123e-4ca2-9eb9-0b015d2ee0fb' self.instance_name_prefix = { 'service': 'svc', 'network': 'net', 'vnf': 'vnf', 'vfmodule': 'vf' } # set the openstack cloud access credentials here self.cloud = { '--os-auth-url': 'http://10.12.25.2:5000', '--os-username': 'kxi', '--os-user-domain-id': 'default', '--os-project-domain-id': 'default', '--os-tenant-id': '09d8566ea45e43aa974cf447ed591d77', '--os-region-name': 'RegionOne', '--os-password': 'n3JhGMGuDzD8', '--os-project-domain-name': 'Integration-SB-03', '--os-identity-api-version': '3' } self.template_path = 'robot/assets/templates' self.owning_entity_name = 'OE-Demonstration1' self.project_name = 'Project-Demonstration' self.owning_entity_id = '520cc603-a3c4-4ec2-9ef4-ca70facd79c0' self.global_subscriber_id = 'Demonstration' self.vgw_VfModuleModelInvariantUuid = '26d6a718-17b2-4ba8-8691-c44343b2ecd2' self.so = RequestSOKeywords() self.aai = BaseAAIKeywords() self.uuid = UUIDKeywords() @staticmethod def add_req_info(req_details, instance_name, product_family_id=None): req_details['requestInfo'] = { 'instanceName': instance_name, 'source': 'VID', 'suppressRollback': 'true', 'requestorId': 'vCPE-Robot' } if product_family_id: req_details['requestInfo']['productFamilyId'] = product_family_id @staticmethod def add_related_instance(req_details, instance_id, instance_model): instance = {"instanceId": instance_id, "modelInfo": instance_model} if 'relatedInstanceList' not in req_details: req_details['relatedInstanceList'] = [{"relatedInstance": instance}] else: req_details['relatedInstanceList'].append({"relatedInstance": instance}) def generate_vnf_or_network_request(self, instance_name, vnf_or_network_model, service_instance_id, service_model, tenant_id, region_name): req_details = { 'modelInfo': vnf_or_network_model, 'cloudConfiguration': {"lcpCloudRegionId": region_name, "tenantId": tenant_id}, 'requestParameters': {"userParams": []}, 'platform': {"platformName": "Platform-Demonstration"} } self.add_req_info(req_details, instance_name, self.product_family_id) self.add_related_instance(req_details, service_instance_id, service_model) return {'requestDetails': req_details} def generate_vfmodule_request(self, instance_name, vfmodule_model, service_instance_id, service_model, vnf_instance_id, vnf_model, tenant_id, region_name): req_details = { 'modelInfo': vfmodule_model, 'cloudConfiguration': {"lcpCloudRegionId": region_name, "tenantId": tenant_id}, 'requestParameters': {"usePreload": 'true'} } self.add_req_info(req_details, instance_name, self.product_family_id) self.add_related_instance(req_details, service_instance_id, service_model) self.add_related_instance(req_details, vnf_instance_id, vnf_model) return {'requestDetails': req_details} def generate_service_request(self, instance_name, model): req_details = { 'modelInfo': model, 'subscriberInfo': {'globalSubscriberId': self.global_subscriber_id}, 'requestParameters': { "userParams": [], "subscriptionServiceType": "vCPE", "aLaCarte": 'true' } } self.add_req_info(req_details, instance_name) self.add_project_info(req_details) self.add_owning_entity(req_details) return {'requestDetails': req_details} def add_project_info(self, req_details): req_details['project'] = {'projectName': self.project_name} def add_owning_entity(self, req_details): req_details['owningEntity'] = {'owningEntityId': self.owning_entity_id, 'owningEntityName': self.owning_entity_name} def generate_custom_service_request(self, instance_name, model, brg_mac, tenant_id, region_name): brg_mac_enc = brg_mac.replace(':', '-') req_details = { 'modelInfo': model, 'subscriberInfo': {'subscriberName': 'Kaneohe', 'globalSubscriberId': self.global_subscriber_id}, 'cloudConfiguration': {"lcpCloudRegionId": region_name, "tenantId": tenant_id}, 'requestParameters': { "userParams": [ { 'name': 'BRG_WAN_MAC_Address', 'value': brg_mac }, { 'name': 'VfModuleNames', 'value': [ { 'VfModuleModelInvariantUuid': self.vgw_VfModuleModelInvariantUuid, 'VfModuleName': 'VGW2BRG-{0}'.format(brg_mac_enc) } ] }, { "name": "Customer_Location", "value": self.customer_location_used_by_oof }, { "name": "Homing_Solution", "value": self.homing_solution } ], "subscriptionServiceType": "vCPE", 'aLaCarte': 'false' } } self.add_req_info(req_details, instance_name, self.custom_product_family_id) self.add_project_info(req_details) self.add_owning_entity(req_details) return {'requestDetails': req_details} def create_custom_service(self, csar_file, brg_mac, tenant_id, region_name, name_suffix=None): parser = CsarParser() if not parser.parse_csar(csar_file): return False # yyyymmdd_hhmm if not name_suffix: name_suffix = '_' + datetime.now().strftime('%Y%m%d%H%M') # create service instance_name = '_'.join([self.instance_name_prefix['service'], parser.svc_model['modelName'][0:10], name_suffix]) instance_name = instance_name.lower() req = self.generate_custom_service_request(instance_name, parser.svc_model, brg_mac, tenant_id, region_name) logger.info(json.dumps(req, indent=2, sort_keys=True)) logger.info('Creating custom service {0}.'.format(instance_name)) req_id, svc_instance_id = self.so.run_create_request(self.service_req_api_url, self.so_si_path, json.dumps(req), auth=self.so_userpass) done, resp = self.so.run_polling_get_request(self.so_check_progress_api_url, req_id, tries=50, interval=5, auth=self.so_userpass) return done def create_entire_service(self, csar_file, vnf_template_file, preload_dict, region_name, tenant_id, ssh_key): """ :param csar_file: :param vnf_template_file: :param preload_dict: :param region_name: :param tenant_id :param ssh_key :return: service instance UUID """ name_suffix = str(self.uuid.generate_timestamp()) logger.info('\n----------------------------------------------------------------------------------') logger.info('Start to create entire service defined in csar: {0}'.format(csar_file)) parser = CsarParser() logger.info('Parsing csar ...') if not parser.parse_csar(csar_file): logger.error('Cannot parse csar: {0}'.format(csar_file)) return None # Set Global timestamp for instancenames global_timestamp = datetime.now().strftime("%Y%m%d%H%M%S") # create service instance_name = '_'.join([self.instance_name_prefix['service'], parser.svc_model['modelName'], global_timestamp, name_suffix]) instance_name = instance_name.lower() instance_name = instance_name.replace(' ', '') instance_name = instance_name.replace(':', '') logger.info('Creating service instance: {0}.'.format(instance_name)) req = self.generate_service_request(instance_name, parser.svc_model) logger.debug(json.dumps(req, indent=2, sort_keys=True)) req_id, svc_instance_id = self.so.run_create_request(self.service_req_api_url, self.so_si_path, json.dumps(req), auth=self.so_userpass) done, resp = self.so.run_polling_get_request(self.so_check_progress_api_url, req_id, tries=50, interval=5, auth=self.so_userpass) if not done: return None # wait for AAI to complete traversal self.aai.wait_for_node_to_exist('service-instance', 'service-instance-id', svc_instance_id) # create networks for model in parser.net_models: base_name = model['modelCustomizationName'].lower().replace('mux_vg', 'mux_gw') network_name = '_'.join([self.instance_name_prefix['network'], base_name, name_suffix]) network_name = network_name.lower() logger.info('Creating network: ' + network_name) req = self.generate_vnf_or_network_request(network_name, model, svc_instance_id, parser.svc_model, tenant_id, region_name) logger.debug(json.dumps(req, indent=2, sort_keys=True)) url = '/'.join([self.so_si_path, svc_instance_id, 'networks']) req_id, net_instance_id = self.so.run_create_request(self.service_req_api_url, url, json.dumps(req), auth=self.so_userpass) done, resp = self.so.run_polling_get_request(self.so_check_progress_api_url, req_id, tries=50, interval=5, auth=self.so_userpass) if not done: return None logger.info('Changing subnet name to ' + self.network_name_to_subnet_name(network_name)) self.set_network_name(network_name) subnet_name_changed = False for i in range(20): time.sleep(3) if self.set_subnet_name(network_name): subnet_name_changed = True break if not subnet_name_changed: logger.error('Failed to change subnet name for ' + network_name) return None vnf_model = None vnf_instance_id = None # create VNF if len(parser.vnf_models) == 1: vnf_model = parser.vnf_models[0] vnf_instance_name = '_'.join([self.instance_name_prefix['vnf'], vnf_model['modelCustomizationName'].split(' ')[0], name_suffix]) vnf_instance_name = vnf_instance_name.lower() vnf_instance_name = vnf_instance_name.replace(' ', '') vnf_instance_name = vnf_instance_name.replace(':', '') logger.info('Creating VNF: ' + vnf_instance_name) req = self.generate_vnf_or_network_request(vnf_instance_name, vnf_model, svc_instance_id, parser.svc_model, tenant_id, region_name) logger.debug(json.dumps(req, indent=2, sort_keys=True)) url = '/'.join([self.so_si_path, svc_instance_id, 'vnfs']) req_id, vnf_instance_id = self.so.run_create_request(self.service_req_api_url, url, json.dumps(req), auth=self.so_userpass) done, resp = self.so.run_polling_get_request(self.so_check_progress_api_url, req_id, tries=50, interval=5, auth=self.so_userpass) if not done: logger.error('Failed to create VNF {0}.'.format(vnf_instance_name)) return False # wait for AAI to complete traversal if not vnf_instance_id: logger.error('No VNF instance ID returned!') sys.exit() self.aai.wait_for_node_to_exist('generic-vnf', 'vnf-id', vnf_instance_id) # SDNC Preload preloader = PreloadSDNCKeywords() vfmodule_name = '_'.join(['vf', parser.vfmodule_models[0]['modelCustomizationName'].split('..')[0].lower(), name_suffix]) extra_preload = { 'pub_key': ssh_key, 'vnf_type': parser.vfmodule_models[0]['modelCustomizationName'], 'generic_vnf_type': parser.vfmodule_models[0]['modelCustomizationName'], 'service_type': svc_instance_id, 'generic_vnf_name': vnf_model['modelCustomizationName'], 'vnf_name': vfmodule_name, 'mr_ip_addr': self.mr_ip_addr, 'mr_ip_port': self.mr_ip_port, 'sdnc_oam_ip': self.sdnc_ip_addr, 'suffix': name_suffix, 'oam_onap_net': 'oam_network_2No2', 'oam_onap_subnet': 'oam_network_2No2', 'public_net': 'external', 'public_net_id': '971040b2-7059-49dc-b220-4fab50cb2ad4' } preload_dict.update(extra_preload) preloader.preload_vfmodule(self.sdnc_endpoint, self.sdnc_preload_vnf_url, self.template_path, vnf_template_file, preload_dict) # create VF Module if len(parser.vfmodule_models) == 1: if not vnf_instance_id or not vnf_model: logger.error('Invalid VNF instance ID or VNF model!') sys.exit() model = parser.vfmodule_models[0] vfmodule_instance_name = '_'.join([self.instance_name_prefix['vfmodule'], model['modelCustomizationName'].split('..')[0], name_suffix]) vfmodule_instance_name = vfmodule_instance_name.lower() vfmodule_instance_name = vfmodule_instance_name.replace(' ', '') vfmodule_instance_name = vfmodule_instance_name.replace(':', '') logger.info('Creating VF Module: ' + vfmodule_instance_name) req = self.generate_vfmodule_request(vfmodule_instance_name, model, svc_instance_id, parser.svc_model, vnf_instance_id, vnf_model, tenant_id, region_name) logger.debug(json.dumps(req, indent=2, sort_keys=True)) url = '/'.join([self.so_si_path, svc_instance_id, 'vnfs', vnf_instance_id, 'vfModules']) req_id, vfmodule_instance_id = self.so.run_create_request(self.service_req_api_url, url, json.dumps(req), auth=self.so_userpass) done, resp = self.so.run_polling_get_request(self.so_check_progress_api_url, req_id, tries=50, interval=50, auth=self.so_userpass) if not done: logger.error('Failed to create VF Module {0}.'.format(vfmodule_instance_name)) return None return svc_instance_id @staticmethod def network_name_to_subnet_name(network_name): """ :param network_name: example: vcpe_net_cpe_signal_201711281221 :return: vcpe_net_cpe_signal_subnet_201711281221 """ fields = network_name.split('_') fields.insert(-1, 'subnet') return '_'.join(fields) def set_network_name(self, network_name): param = ' '.join([k + ' ' + v for k, v in list(self.cloud.items())]) openstackcmd = 'openstack ' + param cmd = ' '.join([openstackcmd, 'network set --name', network_name, 'ONAP-NW1']) os.popen(cmd) def set_subnet_name(self, network_name): """ Example: network_name = vcpe_net_cpe_signal_201711281221 set subnet name to vcpe_net_cpe_signal_subnet_201711281221 :return: """ param = ' '.join([k + ' ' + v for k, v in list(self.cloud.items())]) openstackcmd = 'openstack ' + param # expected results: | subnets | subnet_id | subnet_info = os.popen(openstackcmd + ' network show ' + network_name + ' |grep subnets').read().split('|') if len(subnet_info) > 2 and subnet_info[1].strip() == 'subnets': subnet_id = subnet_info[2].strip() subnet_name = self.network_name_to_subnet_name(network_name) cmd = ' '.join([openstackcmd, 'subnet set --name', subnet_name, subnet_id]) os.popen(cmd) logger.info("Subnet name set to: " + subnet_name) return True else: logger.error("Can't get subnet info from network name: " + network_name) return False