def get_vim_by_id(vim_id): cloud_owner,cloud_region_id = decode_vim_id(vim_id) if cloud_owner and cloud_region_id: # get cloud region without depth retcode, content, status_code = \ restcall.req_to_aai("/cloud-infrastructure/cloud-regions/cloud-region/%s/%s" % (cloud_owner,cloud_region_id),"GET") if retcode != 0: logger.error("Status code is %s, detail is %s.", status_code, content) raise VimDriverNewtonException( "Failed to query VIM with id (%s:%s,%s)." % (vim_id,cloud_owner,cloud_region_id), status_code, content) tmp_viminfo = json.JSONDecoder().decode(content) # get esr-system-info under this cloud region retcode2, content2, status_code2 = \ restcall.req_to_aai("/cloud-infrastructure/cloud-regions/cloud-region/%s/%s/esr-system-info-list" % (cloud_owner,cloud_region_id),"GET") if retcode2 != 0: logger.error("Status code is %s, detail is %s.", status_code2, content2) raise VimDriverNewtonException( "Failed to query esr info for VIM with id (%s:%s,%s)." % (vim_id,cloud_owner,cloud_region_id), status_code2, content2) tmp_authinfo = json.JSONDecoder().decode(content2) #convert vim information if tmp_viminfo and tmp_authinfo and tmp_authinfo.get('esr-system-info'): viminfo = {} # get the first auth info by default tmp_authinfo = tmp_authinfo['esr-system-info'][0] viminfo['vimId'] = vim_id viminfo['resource-version'] = tmp_viminfo.get('resource-version') viminfo['cloud_owner'] = cloud_owner viminfo['cloud_region_id'] = cloud_region_id viminfo['type'] = tmp_viminfo.get('cloud-type') viminfo['name'] = tmp_viminfo.get('complex-name') viminfo['version'] = tmp_viminfo.get('cloud-region-version') viminfo['cloud_extra_info'] = tmp_viminfo.get('cloud-extra-info') viminfo['userName'] = tmp_authinfo.get('user-name', "") viminfo['password'] = tmp_authinfo.get('password', "") viminfo['domain'] = tmp_authinfo.get('cloud-domain', "") viminfo['url'] = tmp_authinfo.get('service-url', "") viminfo['tenant'] = tmp_authinfo.get('default-tenant', "") viminfo['cacert'] = tmp_authinfo.get('ssl-cacert', "") viminfo['insecure'] = tmp_authinfo.get('ssl-insecure', True) viminfo["complex-name"] = tmp_viminfo.get("complex-name") # move the openstack region id store location, but keep backward compatibility viminfo['openstack_region_id'] = tmp_authinfo.get("openstack-region-id") \ or tmp_viminfo.get("cloud-epa-caps", cloud_region_id) try: viminfo['cloud_extra_info_json'] = json.loads( viminfo.get('cloud_extra_info', {})) except Exception: pass return viminfo return None
def _update_resoure(self, cloud_owner, cloud_region_id, resoure_id, resource_info, resource_type): if cloud_owner and cloud_region_id: self._logger.debug( ("_update_resoure,vimid:%(cloud_owner)s" "_%(cloud_region_id)s req_to_aai: %(resoure_id)s, " "%(resource_type)s, %(resource_info)s") % { "cloud_owner": cloud_owner, "cloud_region_id": cloud_region_id, "resoure_id": resoure_id, "resource_type": resource_type, "resource_info": resource_info, }) # get the resource first resource_url = ("/cloud-infrastructure/cloud-regions/" "cloud-region/%(cloud_owner)s/%(cloud_region_id)s/" "%(resource_type)ss/%(resource_type)s/%(resoure_id)s" % { "cloud_owner": cloud_owner, "cloud_region_id": cloud_region_id, "resoure_id": resoure_id, "resource_type": resource_type, }) # get cloud-region retcode, content, status_code = \ restcall.req_to_aai(resource_url, "GET") # add resource-version if retcode == 0 and content: content = json.JSONDecoder().decode(content) #resource_info["resource-version"] = content["resource-version"] content.update(resource_info) resource_info = content #then update the resource retcode, content, status_code = \ restcall.req_to_aai(resource_url, "PUT", content=resource_info) # self._logger.debug( # ("_update_resoure,vimid:%(cloud_owner)s" # "_%(cloud_region_id)s req_to_aai: %(resoure_id)s, " # "return %(retcode)s, %(content)s, %(status_code)s") # % { # "cloud_owner": cloud_owner, # "cloud_region_id": cloud_region_id, # "resoure_id": resoure_id, # "retcode": retcode, # "content": content, # "status_code": status_code, # }) return retcode, content # unknown cloud owner,region_id return ( 11, "Unknown Cloud Region ID: %s ,%s" %(cloud_owner, cloud_region_id) )
def get_vim_by_id(vim_id): cloud_owner, cloud_region_id = decode_vim_id(vim_id) if cloud_owner and cloud_region_id: retcode, content, status_code = \ restcall.req_to_aai("/cloud-infrastructure/cloud-regions/cloud-region/%s/%s" % (cloud_owner, cloud_region_id), "GET") if retcode != 0: logger.error("Status code is %s, detail is %s.", status_code, content) raise VimDriverNewtonException( "Failed to query VIM with id (%s:%s,%s)." % (vim_id, cloud_owner, cloud_region_id), status_code, content) tmp_viminfo = json.JSONDecoder().decode(content) # assume esr-system-info-id is composed by {cloud-owner} _ {cloud-region-id} vimid = cloud_owner + "_" + cloud_region_id base_url = "/cloud-infrastructure/cloud-regions/cloud-region" esr_url = "/%s/%s/esr-system-info-list/esr-system-info/%s" % ( cloud_owner, cloud_region_id, vimid) retcode2, content2, status_code2 = restcall.req_to_aai( base_url + esr_url, "GET") if retcode2 != 0: logger.error("Status code is %s, detail is %s.", status_code, content) raise VimDriverNewtonException( "Failed to query ESR system with id (%s:%s,%s)." % (vim_id, cloud_owner, cloud_region_id), status_code, content) tmp_authinfo = json.JSONDecoder().decode(content2) # convert vim information if tmp_viminfo: viminfo = {} viminfo['vimId'] = vim_id viminfo['cloud_owner'] = cloud_owner viminfo['cloud_region_id'] = cloud_region_id viminfo['type'] = tmp_viminfo['cloud-type'] viminfo['name'] = tmp_viminfo['complex-name'] viminfo['version'] = tmp_viminfo['cloud-region-version'] viminfo['cloud_extra_info'] = tmp_viminfo['cloud-extra-info'] if tmp_authinfo: viminfo['userName'] = tmp_authinfo['user-name'] viminfo['password'] = tmp_authinfo['password'] viminfo['domain'] = tmp_authinfo['cloud-domain'] viminfo['url'] = tmp_authinfo['service-url'] viminfo['tenant'] = tmp_authinfo['default-tenant'] viminfo['cacert'] = tmp_authinfo['ssl-cacert'] viminfo['insecure'] = tmp_authinfo['ssl-insecure'] else: return None return viminfo else: return None else: return None
def delete_vim_by_id(vim_id): cloud_owner, cloud_region_id = decode_vim_id(vim_id) if cloud_owner and cloud_region_id: del_url = "/cloud-infrastructure/cloud-regions/cloud-region/%s/%s" retcode, content, status_code = restcall.req_to_aai(del_url % (cloud_owner, cloud_region_id), "DELETE") if retcode != 0: logger.error("Status code is %s, detail is %s.", status_code, content) raise VimDriverNewtonException( "Failed to delete VIM in AAI with id (%s:%s,%s)." % (vim_id, cloud_owner, cloud_region_id), status_code, content) return 0 # return non zero if failed to decode cloud owner and region id return 1
def _update_pserver_relation_cloudregion(self, cloud_owner, cloud_region_id, pserverinfo): related_link = \ "/aai/%s/cloud-infrastructure/cloud-regions/"\ "cloud-region/%s/%s" % ( settings.AAI_SCHEMA_VERSION, cloud_owner, cloud_region_id) relationship_data = \ { 'related-to': 'cloud-region', 'related-link': related_link, 'relationship-data': [ { 'relationship-key': 'cloud-region.cloud-owner', 'relationship-value': cloud_owner }, { 'relationship-key': 'cloud-region.cloud-region-id', 'relationship-value': cloud_region_id } ], "related-to-property": [ { "property-key": "cloud-region.cloud-owner" }, { "property-key": "cloud-region.cloud-region-id" } ] } retcode, content, status_code = \ restcall.req_to_aai("/cloud-infrastructure/pservers/pserver" "/%s/relationship-list/relationship" % (pserverinfo['hostname']), "PUT", content=relationship_data) self._logger.debug( "update_pserver_cloudregion_relation,vimid:%s_%s" " req_to_aai: %s, return %s, %s, %s" % (cloud_owner, cloud_region_id, pserverinfo['hostname'], retcode, content, status_code)) return (0, "succeed")
def delete_vim_by_id(vim_id): cloud_owner, cloud_region_id = decode_vim_id(vim_id) if cloud_owner and cloud_region_id: #get the vim info viminfo = get_vim_by_id(vim_id) if not viminfo or not viminfo['resource-version']: return 0 retcode, content, status_code = \ restcall.req_to_aai("/cloud-infrastructure/cloud-regions/cloud-region/%s/%s?resource-version=%s" % ( cloud_owner, cloud_region_id, viminfo['resource-version']), "DELETE") if retcode != 0: logger.error("Status code is %s, detail is %s.", status_code, content) raise VimDriverNewtonException( "Failed to delete VIM in AAI with id (%s:%s,%s)." % (vim_id,cloud_owner,cloud_region_id), status_code, content) return 0 # return non zero if failed to decode cloud owner and region id return 1
def _update_pserver_relation_az(self, cloud_owner, cloud_region_id, pserverinfo, azName): related_link = \ "/aai/%s/cloud-infrastructure/cloud-regions/"\ "cloud-region/%s/%s/"\ "availability-zones/availability-zone/%s" % ( settings.AAI_SCHEMA_VERSION, cloud_owner, cloud_region_id, azName) relationship_data = \ { 'related-to': 'availability-zone', 'related-link': related_link, 'relationship-data': [ { 'relationship-key': 'availability-zone.availability-zone-name', 'relationship-value': azName } ], "related-to-property": [ { "property-key": "availability-zone.availability-zone-name" } ] } retcode, content, status_code = \ restcall.req_to_aai("/cloud-infrastructure/pservers/pserver/%s" "/relationship-list/relationship" % (pserverinfo['hostname']), "PUT", content=relationship_data) self._logger.debug( "update_pserver_az_relation,vimid:%s_%s, " "az:%s req_to_aai: %s, return %s, %s, %s" % (cloud_owner, cloud_region_id, azName, pserverinfo['hostname'], retcode, content, status_code)) return (0, "succeed")
def _update_cloud_region(self, cloud_owner, cloud_region_id, openstack_region_id, viminfo, session=None): if cloud_owner and cloud_region_id: self._logger.debug(("_update_cloud_region, %(cloud_owner)s" "_%(cloud_region_id)s ") % { "cloud_owner": cloud_owner, "cloud_region_id": cloud_region_id }) # update cloud_extra_info oldregionid = viminfo.get('openstack_region_id') # update openstack region id so the call will go the specified reigon viminfo['openstack_region_id'] = openstack_region_id cloud_extra_info = viminfo.get("cloud_extra_info_json", {}) system_info = self._get_system_info(cloud_owner, cloud_region_id, viminfo, session) if system_info: cloud_extra_info["isystem"] = system_info # recover the openstack region id of viminfo viminfo['openstack_region_id'] = oldregionid # Note1: populate the openstack region id into property # : cloud-region.esr-system-info.openstack-region-id resource_info = { "cloud-owner": cloud_owner, "cloud-region-id": cloud_region_id, "cloud-type": viminfo["type"], "cloud-region-version": viminfo["version"], "identity-url": self.proxy_prefix + "/%s_%s/identity/v2.0" % (cloud_owner, cloud_region_id) if self.proxy_prefix[-3:] == "/v0" else self.proxy_prefix + "/%s/%s/identity/v2.0" % (cloud_owner, cloud_region_id), "complex-name": viminfo["complex-name"], "cloud-extra-info": json.dumps(cloud_extra_info), "cloud-epa-caps": openstack_region_id, "esr-system-info-list": { "esr-system-info": [{ "esr-system-info-id": str(uuid.uuid4()), "service-url": viminfo["url"], "user-name": viminfo["userName"], "password": viminfo["password"], "system-type": "VIM", "ssl-cacert": viminfo["cacert"], "ssl-insecure": viminfo["insecure"], "cloud-domain": viminfo["domain"], "default-tenant": viminfo["tenant"], "openstack-region-id": openstack_region_id }] } } # get the resource first resource_url = ( "/cloud-infrastructure/cloud-regions/" "cloud-region/%(cloud_owner)s/%(cloud_region_id)s?depth=1" % { "cloud_owner": cloud_owner, "cloud_region_id": cloud_region_id }) # get cloud-region retcode, content, status_code = \ restcall.req_to_aai(resource_url, "GET", nocache=True) # add resource-version if retcode == 0 and content: content = json.JSONDecoder().decode(content) # now take care of esr-system-info esrinfo = content.get("esr-system-info-list", {}).get("esr-system-info", [{}])[0] if esrinfo: # keep esr-system-info-id intact resource_info[esr-system-info-list]["esr-system-info"]["esr-system-info-id"] \ = esrinfo.get("esr-system-info-id", str(uuid.uuid4())) content.update(resource_info) resource_info = content # then update the resource retcode, content, status_code = \ restcall.req_to_aai(resource_url, "PUT", content=resource_info) self._logger.debug( ("_update_cloud_region,%(cloud_owner)s" "_%(cloud_region_id)s , " "return %(retcode)s, %(content)s, %(status_code)s") % { "cloud_owner": cloud_owner, "cloud_region_id": cloud_region_id, "retcode": retcode, "content": content, "status_code": status_code, }) # wait and confirm the update has been available for next AAI calls while True: # get cloud-region retcode2, content2, status_code2 = \ restcall.req_to_aai(resource_url, "GET", nocache=True) if retcode2 == 0 and content2: content2 = json.JSONDecoder().decode(content2) if content2.get("identity-url", None)\ == resource_info.get("identity-url", None): break return retcode return 1 # unknown cloud owner,region_id
def heatbridge_delete(self, request, vimid, stack_id): ''' remove heat resource from AAI for the specified cloud region and tenant The resources includes: vserver, vserver/l-interface, :param request: :param vimid: :param stack_id: :param tenant_id: :return: ''' # enumerate the resources cloud_owner, regionid = extsys.decode_vim_id(vimid) # should go via multicloud proxy so that the selflink is updated by multicloud retcode, v2_token_resp_json, os_status = \ helper.MultiCloudIdentityHelper(settings.MULTICLOUD_API_V1_PREFIX, cloud_owner, regionid, "/v2.0/tokens") if retcode > 0: logger.error("authenticate fails:%s, %s, %s" % (cloud_owner, regionid, v2_token_resp_json)) return None tenant_id = v2_token_resp_json["access"]["token"]["tenant"]["id"] # tenant_name = v2_token_resp_json["access"]["token"]["tenant"]["name"] # common prefix aai_cloud_region = \ "/cloud-infrastructure/cloud-regions/cloud-region/%s/%s/tenants/tenant/%s" \ % (cloud_owner, regionid, tenant_id) # get stack resource service_type = "orchestration" resource_uri = "/stacks/%s/resources" % (stack_id) self._logger.info("retrieve stack resources, URI:%s" % resource_uri) retcode, content, os_status = \ helper.MultiCloudServiceHelper(cloud_owner, regionid, v2_token_resp_json, service_type, resource_uri, None, "GET") resources = content.get('resources', []) \ if retcode == 0 and content else [] vserver_list = [resource['physical_resource_id'] for resource in resources if resource.get('resource_type', None) == 'OS::Nova::Server'] try: # get list of vservers vserver_list_url = aai_cloud_region + "/vservers?depth=all" retcode, content, status_code = \ restcall.req_to_aai(vserver_list_url, "GET") if retcode > 0 or not content: self._logger.debug("AAI get %s response: %s" % (vserver_list_url, content)) return None content = json.JSONDecoder().decode(content) vservers = content['vserver'] for vserver in vservers: if vserver['vserver-id'] not in vserver_list: continue try: # iterate vport, except will be raised if no l-interface exist for vport in vserver['l-interfaces']['l-interface']: # delete vport vport_delete_url = \ aai_cloud_region + \ "/vservers/vserver/%s/l-interfaces/l-interface/%s?resource-version=%s" \ % (vserver['vserver-id'], vport['interface-name'], vport['resource-version']) restcall.req_to_aai(vport_delete_url, "DELETE") except Exception: pass try: # delete vserver vserver_delete_url = \ aai_cloud_region + \ "/vservers/vserver/%s?resource-version=%s" \ % (vserver['vserver-id'], vserver['resource-version']) restcall.req_to_aai(vserver_delete_url, "DELETE") except Exception: continue except Exception: self._logger.error(traceback.format_exc()) return None pass
def heatbridge_update(self, request, vimid, stack_id): ''' update heat resource to AAI for the specified cloud region and tenant The resources includes: vserver, vserver/l-interface, :param request: :param vimid: :param stack_id: :return: ''' cloud_owner, regionid = extsys.decode_vim_id(vimid) # should go via multicloud proxy so that the selflink is updated by multicloud retcode, v2_token_resp_json, os_status = \ helper.MultiCloudIdentityHelper(settings.MULTICLOUD_API_V1_PREFIX, cloud_owner, regionid, "/v2.0/tokens") if retcode > 0: logger.error("authenticate fails:%s, %s, %s" % (cloud_owner, regionid, v2_token_resp_json)) return None tenant_id = v2_token_resp_json["access"]["token"]["tenant"]["id"] # tenant_name = v2_token_resp_json["access"]["token"]["tenant"]["name"] # common prefix aai_cloud_region = \ "/cloud-infrastructure/cloud-regions/cloud-region/%s/%s/tenants/tenant/%s" \ % (cloud_owner, regionid, tenant_id) # get stack resource service_type = "orchestration" resource_uri = "/stacks/%s/resources" % (stack_id) self._logger.info("retrieve stack resources, URI:%s" % resource_uri) retcode, content, os_status = \ helper.MultiCloudServiceHelper(cloud_owner, regionid, v2_token_resp_json, service_type, resource_uri, None, "GET") resources = content.get('resources', []) if retcode == 0 and content else [] # find and update resources transactions = [] for resource in resources: if resource.get('resource_status', None) != "CREATE_COMPLETE": continue if resource.get('resource_type', None) == 'OS::Nova::Server': # retrieve vserver details service_type = "compute" resource_uri = "/servers/%s" % (resource['physical_resource_id']) self._logger.info("retrieve vserver detail, URI:%s" % resource_uri) retcode, content, os_status = \ helper.MultiCloudServiceHelper(cloud_owner, regionid, v2_token_resp_json, service_type, resource_uri, None, "GET") self._logger.debug(" resp data:%s" % content) vserver_detail = content.get('server', None) if retcode == 0 and content else None if vserver_detail: # compose inventory entry for vserver vserver_link = "" for link in vserver_detail['links']: if link['rel'] == 'self': vserver_link = link['href'] break pass # note: relationship-list to flavor/image is not be update yet # note: volumes is not updated yet # note: relationship-list to vnf will be handled somewhere else aai_resource = { 'body': { 'vserver-name': vserver_detail['name'], 'vserver-name2': vserver_detail['name'], "vserver-id": vserver_detail['id'], "vserver-selflink": vserver_link, "prov-status": vserver_detail['status'] }, "uri": aai_cloud_region + "/vservers/vserver/%s" % (vserver_detail['id']) } try: # then update the resource retcode, content, status_code = \ restcall.req_to_aai(aai_resource['uri'], "PUT", content=aai_resource['body']) if retcode == 0 and content: content = json.JSONDecoder().decode(content) self._logger.debug("AAI update %s response: %s" % (aai_resource['uri'], content)) except Exception: self._logger.error(traceback.format_exc()) pass aai_resource_transactions = {"put": [aai_resource]} transactions.append(aai_resource_transactions) # self._logger.debug("aai_resource :%s" % aai_resource_transactions) pass for resource in resources: if resource.get('resource_status', None) != "CREATE_COMPLETE": continue if resource.get('resource_type', None) == 'OS::Neutron::Port': # retrieve vport details service_type = "network" resource_uri = "/v2.0/ports/%s" % (resource['physical_resource_id']) self._logger.info("retrieve vport detail, URI:%s" % resource_uri) retcode, content, os_status = \ helper.MultiCloudServiceHelper(cloud_owner, regionid, v2_token_resp_json, service_type, resource_uri, None, "GET") self._logger.debug(" resp data:%s" % content) vport_detail = content.get('port', None) if retcode == 0 and content else None if vport_detail: # compose inventory entry for vport # note: l3-interface-ipv4-address-list, # l3-interface-ipv6-address-list are not updated yet # note: network-name is not update yet since the detail # coming with network-id aai_resource = { "body": { "interface-name": vport_detail['name'], "interface-id": vport_detail['id'], "macaddr": vport_detail['mac_address'] }, 'uri': aai_cloud_region + "/vservers/vserver/%s/l-interfaces/l-interface/%s" % (vport_detail['device_id'], vport_detail['name']) } try: # then update the resource retcode, content, status_code = \ restcall.req_to_aai(aai_resource['uri'], "PUT", content=aai_resource['body']) if retcode == 0 and content: content = json.JSONDecoder().decode(content) self._logger.debug("AAI update %s response: %s" % (aai_resource['uri'], content)) except Exception: self._logger.error(traceback.format_exc()) pass aai_resource_transactions = {"put": [aai_resource]} transactions.append(aai_resource_transactions) # self._logger.debug("aai_resource :%s" % aai_resource_transactions) pass aai_transactions = {"transactions": transactions} self._logger.debug("aai_transactions :%s" % aai_transactions) return aai_transactions
def _update_cloud_region(self, cloud_owner, cloud_region_id, openstack_region_id, viminfo, session=None): if cloud_owner and cloud_region_id: self._logger.debug( ("_update_cloud_region, %(cloud_owner)s" "_%(cloud_region_id)s ") % { "cloud_owner": cloud_owner, "cloud_region_id": cloud_region_id }) # Note1: The intent is to populate the openstack region id into property: cloud-region.esr-system-info.openstackRegionId # Note2: As temp solution: the openstack region id was put into AAI cloud-region["cloud-epa-caps"] resource_info = { "cloud-owner": cloud_owner, "cloud-region-id": cloud_region_id, "cloud-type": viminfo["type"], "cloud-region-version": viminfo["version"], "identity-url": self.proxy_prefix + "/%s_%s/identity/v2.0" % (cloud_owner, cloud_region_id) if self.proxy_prefix[-3:] == "/v0" else self.proxy_prefix + "/%s/%s/identity/v2.0" % (cloud_owner, cloud_region_id), "complex-name": viminfo["complex-name"], "cloud-extra-info": viminfo["cloud_extra_info"], "cloud-epa-caps": openstack_region_id, "esr-system-info-list": { "esr-system-info": [ { "esr-system-info-id": str(uuid.uuid4()), "service-url": viminfo["url"], "user-name": viminfo["userName"], "password": viminfo["password"], "system-type": "VIM", "ssl-cacert": viminfo["cacert"], "ssl-insecure": viminfo["insecure"], "cloud-domain": viminfo["domain"], "default-tenant": viminfo["tenant"] } ] } } # get the resource first resource_url = ("/cloud-infrastructure/cloud-regions/" "cloud-region/%(cloud_owner)s/%(cloud_region_id)s" % { "cloud_owner": cloud_owner, "cloud_region_id": cloud_region_id }) # get cloud-region retcode, content, status_code = \ restcall.req_to_aai(resource_url, "GET") # add resource-version if retcode == 0 and content: content = json.JSONDecoder().decode(content) # resource_info["resource-version"] = content["resource-version"] content.update(resource_info) resource_info = content # then update the resource retcode, content, status_code = \ restcall.req_to_aai(resource_url, "PUT", content=resource_info) self._logger.debug( ("_update_cloud_region,%(cloud_owner)s" "_%(cloud_region_id)s , " "return %(retcode)s, %(content)s, %(status_code)s") % { "cloud_owner": cloud_owner, "cloud_region_id": cloud_region_id, "retcode": retcode, "content": content, "status_code": status_code, }) # wait and confirm the update has been available for next AAI calls while True: # get cloud-region retcode2, content2, status_code2 = \ restcall.req_to_aai(resource_url, "GET") if retcode2 == 0 and content2: content2 = json.JSONDecoder().decode(content2) if content2.get("identity-url", None)\ == resource_info.get("identity-url", None): break return retcode return 1 # unknown cloud owner,region_id
def _update_pserver(self, cloud_owner, cloud_region_id, pserverinfo): ''' populate pserver into AAI :param cloud_owner: :param cloud_region_id: :param pserverinfo: hostname: string in-maint: boolean pserver-name2: string pserver-id: string ptnii-equip-name: string number-of-cpus: integer disk-in-gigabytes: integer ram-in-megabytes: integer equip-type: string equip-vendor: string equip-model: string fqdn: string pserver-selflink: string ipv4-oam-address: string serial-number: string ipaddress-v4-loopback-0: string ipaddress-v6-loopback-0: string ipaddress-v4-aim: string ipaddress-v6-aim: string ipaddress-v6-oam: string inv-status: string internet-topology: string purpose: string prov-status: string management-option: string host-profile: string :return: ''' if cloud_owner and cloud_region_id: resource_url = "/cloud-infrastructure/pservers/pserver/%s" \ % (pserverinfo['hostname']) # get cloud-region retcode, content, status_code = \ restcall.req_to_aai(resource_url, "GET", nocache=True) # add resource-version to url if retcode == 0 and content: content = json.JSONDecoder().decode(content) #pserverinfo["resource-version"] = content["resource-version"] content.update(pserverinfo) pserverinfo = content retcode, content, status_code = \ restcall.req_to_aai(resource_url, "PUT", content=pserverinfo) self._logger.debug( "update_snapshot,vimid:%s_%s req_to_aai: %s," " return %s, %s, %s" % (cloud_owner, cloud_region_id, pserverinfo['hostname'], retcode, content, status_code)) return retcode, content else: # unknown cloud owner,region_id return (10, "Cloud Region not found: %s,%s" % (cloud_owner, cloud_region_id))
def unregistryV0(self, vimid): # prepare request resource to vim instance # get token: viminfo = VimDriverUtils.get_vim_info(vimid) if not viminfo: return (10, "Cloud Region not found:" % vimid) cloud_owner, cloud_region_id = extsys.decode_vim_id(vimid) # get the resource first resource_url = ( "/cloud-infrastructure/cloud-regions/" "cloud-region/%(cloud_owner)s/%(cloud_region_id)s?depth=all" % { "cloud_owner": cloud_owner, "cloud_region_id": cloud_region_id, }) # get cloud-region retcode, content, status_code = \ restcall.req_to_aai(resource_url, "GET", nocache=True) # add resource-version cloudregiondata = {} if retcode == 0 and content: cloudregiondata = json.JSONDecoder().decode(content) else: return (10, "Cloud Region not found: %s, %s" % (cloud_owner, cloud_region_id)) # step 1. remove all tenants tenants = cloudregiondata.get("tenants", None) for tenant in tenants.get("tenant", []) if tenants else []: # common prefix aai_cloud_region = \ "/cloud-infrastructure/cloud-regions/cloud-region/%s/%s/tenants/tenant/%s" \ % (cloud_owner, cloud_region_id, tenant['tenant-id']) # remove all vservers try: # get list of vservers vservers = tenant.get('vservers', {}).get('vserver', []) for vserver in vservers: try: # iterate vport, except will be raised if no l-interface exist for vport in vserver['l-interfaces']['l-interface']: # delete vport vport_delete_url =\ aai_cloud_region + \ "/vservers/vserver/%s/l-interfaces/l-interface/%s?resource-version=%s" \ % (vserver['vserver-id'], vport['interface-name'], vport['resource-version']) restcall.req_to_aai(vport_delete_url, "DELETE") except Exception as e: pass try: # delete vserver vserver_delete_url =\ aai_cloud_region +\ "/vservers/vserver/%s?resource-version=%s" \ % (vserver['vserver-id'], vserver['resource-version']) restcall.req_to_aai(vserver_delete_url, "DELETE") except Exception as e: continue except Exception: self._logger.error(traceback.format_exc()) pass resource_url = ( "/cloud-infrastructure/cloud-regions/" "cloud-region/%(cloud_owner)s/%(cloud_region_id)s/" "%(resource_type)ss/%(resource_type)s/%(resource_id)s/" "?resource-version=%(resource-version)s" % { "cloud_owner": cloud_owner, "cloud_region_id": cloud_region_id, "resource_type": "tenant", "resource_id": tenant["tenant-id"], "resource-version": tenant["resource-version"] }) # remove tenant retcode, content, status_code = \ restcall.req_to_aai(resource_url, "DELETE") # remove all flavors flavors = cloudregiondata.get("flavors", None) for flavor in flavors.get("flavor", []) if flavors else []: # iterate hpa-capabilities hpa_capabilities = flavor.get("hpa-capabilities", None) for hpa_capability in hpa_capabilities.get("hpa-capability", [])\ if hpa_capabilities else []: resource_url = ( "/cloud-infrastructure/cloud-regions/" "cloud-region/%(cloud_owner)s/%(cloud_region_id)s/" "%(resource_type)ss/%(resource_type)s/%(resource_id)s/" "hpa-capabilities/hpa-capability/%(hpa-capability-id)s/" "?resource-version=%(resource-version)s" % { "cloud_owner": cloud_owner, "cloud_region_id": cloud_region_id, "resource_type": "flavor", "resource_id": flavor["flavor-id"], "hpa-capability-id": hpa_capability["hpa-capability-id"], "resource-version": hpa_capability["resource-version"] }) # remove hpa-capability retcode, content, status_code = \ restcall.req_to_aai(resource_url, "DELETE") # remove flavor resource_url = ( "/cloud-infrastructure/cloud-regions/" "cloud-region/%(cloud_owner)s/%(cloud_region_id)s/" "%(resource_type)ss/%(resource_type)s/%(resource_id)s/" "?resource-version=%(resource-version)s" % { "cloud_owner": cloud_owner, "cloud_region_id": cloud_region_id, "resource_type": "flavor", "resource_id": flavor["flavor-id"], "resource-version": flavor["resource-version"] }) retcode, content, status_code = \ restcall.req_to_aai(resource_url, "DELETE") # remove all images images = cloudregiondata.get("images", None) for image in images.get("image", []) if images else []: resource_url = ( "/cloud-infrastructure/cloud-regions/" "cloud-region/%(cloud_owner)s/%(cloud_region_id)s/" "%(resource_type)ss/%(resource_type)s/%(resource_id)s/" "?resource-version=%(resource-version)s" % { "cloud_owner": cloud_owner, "cloud_region_id": cloud_region_id, "resource_type": "image", "resource_id": image["image-id"], "resource-version": image["resource-version"] }) # remove image retcode, content, status_code = \ restcall.req_to_aai(resource_url, "DELETE") # remove all az azs = cloudregiondata.get("availability-zones", None) for az in azs.get("availability-zone", []) if azs else []: # delete az relationship first resource_url = ( "/cloud-infrastructure/cloud-regions/" "cloud-region/%(cloud_owner)s/%(cloud_region_id)s/" "%(resource_type)ss/%(resource_type)s/%(resource_id)s" % { "cloud_owner": cloud_owner, "cloud_region_id": cloud_region_id, "resource_type": "availability-zone", "resource_id": az["availability-zone-name"] }) rs = az.get("relationship-list", []).get("relationship", []) for r in rs: retcode, content, status_code = \ restcall.req_to_aai( resource_url+"/relationship-list/relationship", "DELETE", content=r) # delete az resource_url2 = (resource_url + "?resource-version=%(resource-version)s" % { "resource-version": az["resource-version"] }) retcode, content, status_code = \ restcall.req_to_aai(resource_url2, "DELETE") # remove all vg # remove all snapshots snapshots = cloudregiondata.get("snapshots", None) for snapshot in snapshots.get("snapshot", []) if snapshots else []: resource_url = ( "/cloud-infrastructure/cloud-regions/" "cloud-region/%(cloud_owner)s/%(cloud_region_id)s/" "%(resource_type)ss/%(resource_type)s/%(resource_id)s/" "?resource-version=%(resource-version)s" % { "cloud_owner": cloud_owner, "cloud_region_id": cloud_region_id, "resource_type": "snapshot", "resource_id": snapshot["snapshot-id"], "resource-version": snapshot["resource-version"] }) # remove snapshot retcode, content, status_code = \ restcall.req_to_aai(resource_url, "DELETE") # remove all server groups # remove all pservers # remove cloud region itself resource_url = ( "/cloud-infrastructure/cloud-regions/" "cloud-region/%(cloud_owner)s/%(cloud_region_id)s" "?resource-version=%(resource-version)s" % { "cloud_owner": cloud_owner, "cloud_region_id": cloud_region_id, "resource-version": cloudregiondata["resource-version"] }) # remove cloud region retcode, content, status_code = \ restcall.req_to_aai(resource_url, "DELETE") return retcode, content
def _update_proxy_identity_endpoint(self, vimid): ''' update cloud_region's identity url :param cloud_owner: :param cloud_region_id: :param url: :return: ''' try: cloud_owner, cloud_region_id = extsys.decode_vim_id(vimid) if cloud_owner and cloud_region_id: resource_url = \ "/cloud-infrastructure/cloud-regions" \ "/cloud-region/%s/%s" \ % (cloud_owner, cloud_region_id) # get cloud-region retcode, content, status_code = \ restcall.req_to_aai(resource_url, "GET", nocache=True) # add resource-version to url if retcode == 0 and content: viminfo = json.JSONDecoder().decode(content) viminfo['identity-url'] =\ self.proxy_prefix + "/%s/identity/v2.0" % vimid \ if self.proxy_prefix[-3:] == "/v0" \ else self.proxy_prefix +\ "/%s/%s/identity/v2.0"\ % extsys.decode_vim_id(vimid) retcode, content, status_code = \ restcall.req_to_aai( "/cloud-infrastructure/cloud-regions" "/cloud-region/%s/%s" % (cloud_owner, cloud_region_id), "PUT", content=viminfo) self._logger.debug("update_proxy_identity_endpoint,vimid:" "%s req_to_aai: %s, return %s, %s, %s" % (vimid, viminfo['identity-url'], retcode, content, status_code)) return 0, "succeed" else: self._logger.debug( "failure: update_proxy_identity_endpoint,vimid:" "%s req_to_aai: return %s, %s, %s" % (vimid, retcode, content, status_code)) return retcode, content else: return (10, "Cloud Region not found: %s" % vimid) except VimDriverNewtonException as e: self._logger.error( "VimDriverNewtonException: status:%s, response:%s" % (e.http_status, e.content)) return (e.http_status, e.content) except HttpError as e: self._logger.error("HttpError: status:%s, response:%s" % (e.http_status, e.response.json())) return (e.http_status, e.response.json()) except Exception as e: self._logger.error(traceback.format_exc()) return (11, str(e))
def workload_delete(self, vimid, stack_id, otherinfo=None, project_idorname=None): ''' remove heat resource from AAI for the specified cloud region and tenant The resources includes: vserver, vserver/l-interface, :param vimid: :param stack_id: id of the created stack in OpenStack instance :param otherinfo: :return: result code, status enum, status reason result code: 0-ok, otherwise error status enum: "DELETE_IN_PROGRESS", "DELETE_FAILED" status reason: message to explain the status enum ''' # enumerate the resources cloud_owner, regionid = extsys.decode_vim_id(vimid) # should go via multicloud proxy so that the selflink is updated by multicloud retcode, v2_token_resp_json, os_status = \ helper.MultiCloudIdentityHelper( settings.MULTICLOUD_API_V1_PREFIX, cloud_owner, regionid, "/v2.0/tokens", {"Project": project_idorname}) if retcode > 0: errmsg = "authenticate fails:%s, %s, %s" %\ (cloud_owner, regionid, v2_token_resp_json) logger.error(errmsg) return os_status, "DELETE_FAILED", errmsg tenant_id = v2_token_resp_json["access"]["token"]["tenant"]["id"] # tenant_name = v2_token_resp_json["access"]["token"]["tenant"]["name"] # common prefix aai_cloud_region = \ "/cloud-infrastructure/cloud-regions/cloud-region/%s/%s/tenants/tenant/%s" \ % (cloud_owner, regionid, tenant_id) # get stack resource service_type = "orchestration" resource_uri = "/stacks/%s/resources" % (stack_id) self._logger.info("retrieve stack resources, URI:%s" % resource_uri) retcode, content, os_status = \ helper.MultiCloudServiceHelper(cloud_owner, regionid, v2_token_resp_json, service_type, resource_uri, None, "GET") resources = content.get('resources', []) \ if retcode == 0 and content else [] vserver_list = [ resource['physical_resource_id'] for resource in resources if resource.get('resource_type', None) == 'OS::Nova::Server' ] try: # get list of vservers vserver_list_url = aai_cloud_region + "/vservers?depth=all" retcode, content, status_code = \ restcall.req_to_aai(vserver_list_url, "GET") if retcode > 0 or not content: self._logger.debug("AAI get %s response: %s" % (vserver_list_url, content)) return (status_code, "DELETE_FAILED", "authenticate fails:%s, %s, %s" % (cloud_owner, regionid, v2_token_resp_json)) content = json.JSONDecoder().decode(content) vservers = content['vserver'] for vserver in vservers: if vserver['vserver-id'] not in vserver_list: continue try: # iterate vport, except will be raised if no l-interface exist for vport in vserver['l-interfaces']['l-interface']: # delete vport vport_delete_url = \ aai_cloud_region + \ "/vservers/vserver/%s/l-interfaces/l-interface/%s?resource-version=%s" \ % (vserver['vserver-id'], vport['interface-name'], vport['resource-version']) restcall.req_to_aai(vport_delete_url, "DELETE") except Exception as e: # return 12, "DELETE_FAILED", e.message pass try: # delete vserver vserver_delete_url = \ aai_cloud_region + \ "/vservers/vserver/%s?resource-version=%s" \ % (vserver['vserver-id'], vserver['resource-version']) restcall.req_to_aai(vserver_delete_url, "DELETE") except Exception: continue return 0, "DELETE_COMPLETE", "succeed" except Exception as e: self._logger.error(e.message) return status.HTTP_500_INTERNAL_SERVER_ERROR, "DELETE_FAILED", e.message pass
def workload_update(self, vimid, stack_id, otherinfo=None, project_idorname=None): ''' update heat resource to AAI for the specified cloud region and tenant The resources includes: vserver, vserver/l-interface, :param vimid: :param stack_id: id of the created stack in OpenStack instance :param stack_name: name of stack :param otherinfo: :return: result code, status enum, status reason result code: 0-ok, otherwise error status enum: "UPDATE_IN_PROGRESS", "UPDATE_FAILED" status reason: message to explain the status enum ''' cloud_owner, regionid = extsys.decode_vim_id(vimid) # should go via multicloud proxy so that the selflink is updated by multicloud retcode, v2_token_resp_json, os_status = \ helper.MultiCloudIdentityHelper( settings.MULTICLOUD_API_V1_PREFIX, cloud_owner, regionid, "/v2.0/tokens", {"Project": project_idorname}) if retcode > 0: errmsg = "authenticate fails:%s, %s, %s" %\ (cloud_owner, regionid, v2_token_resp_json) logger.error(errmsg) return os_status, "UPDATE_FAILED", errmsg tenant_id = v2_token_resp_json["access"]["token"]["tenant"]["id"] # tenant_name = v2_token_resp_json["access"]["token"]["tenant"]["name"] # common prefix aai_cloud_region = \ "/cloud-infrastructure/cloud-regions/cloud-region/%s/%s/tenants/tenant/%s" \ % (cloud_owner, regionid, tenant_id) # get stack resource service_type = "orchestration" resource_uri = "/stacks/%s/resources" % (stack_id) self._logger.info("retrieve stack resources, URI:%s" % resource_uri) retcode, content, os_status = \ helper.MultiCloudServiceHelper(cloud_owner, regionid, v2_token_resp_json, service_type, resource_uri, None, "GET") resources = content.get('resources', []) if retcode == 0 and content else [] if retcode > 0: errmsg = "stack:%s, query fails: %s" %\ (resource_uri, content) logger.error(errmsg) return os_status, "UPDATE_FAILED", content # find and update resources # transactions = [] for resource in resources: if resource.get('resource_status', None) != "CREATE_COMPLETE": # this resource is not ready yet, just return errmsg = "stack: %s, resource not ready :%s" % \ (resource_uri, resource) logger.info(errmsg) return status.HTTP_206_PARTIAL_CONTENT, "UPDATE_FAILED", errmsg # continue if resource.get('resource_type', None) == 'OS::Nova::Server': # retrieve vserver details service_type = "compute" resource_uri = "/servers/%s" % ( resource['physical_resource_id']) self._logger.info("retrieve vserver detail, URI:%s" % resource_uri) retcode, content, os_status = \ helper.MultiCloudServiceHelper(cloud_owner, regionid, v2_token_resp_json, service_type, resource_uri, None, "GET") self._logger.debug(" resp data:%s" % content) if retcode > 0: errmsg = "stack resource:%s, query fails: %s" % \ (resource_uri, content) logger.error(errmsg) return os_status, "UPDATE_FAILED", content vserver_detail = content.get( 'server', None) if retcode == 0 and content else None if vserver_detail: # compose inventory entry for vserver vserver_link = "" for link in vserver_detail['links']: if link['rel'] == 'self': vserver_link = link['href'] break pass # note: relationship-list to flavor/image is not be update yet # note: volumes is not updated yet # note: relationship-list to vnf will be handled somewhere else aai_resource = { 'body': { 'vserver-name': vserver_detail['name'], 'vserver-name2': vserver_detail['name'], "vserver-id": vserver_detail['id'], "vserver-selflink": vserver_link, "prov-status": vserver_detail['status'] }, "uri": aai_cloud_region + "/vservers/vserver/%s" % (vserver_detail['id']) } try: # then update the resource retcode, content, status_code = \ restcall.req_to_aai(aai_resource['uri'], "PUT", content=aai_resource['body']) if retcode == 0 and content: content = json.JSONDecoder().decode(content) self._logger.debug("AAI update %s response: %s" % (aai_resource['uri'], content)) except Exception as e: self._logger.error(e.message) return status.HTTP_500_INTERNAL_SERVER_ERROR, "UPDATE_FAILED", e.message # aai_resource_transactions = {"put": [aai_resource]} # transactions.append(aai_resource_transactions) # self._logger.debug("aai_resource :%s" % aai_resource_transactions) for resource in resources: if resource.get('resource_status', None) != "CREATE_COMPLETE": continue if resource.get('resource_type', None) == 'OS::Neutron::Port': # retrieve vport details service_type = "network" resource_uri = "/v2.0/ports/%s" % ( resource['physical_resource_id']) self._logger.info("retrieve vport detail, URI:%s" % resource_uri) retcode, content, os_status = \ helper.MultiCloudServiceHelper(cloud_owner, regionid, v2_token_resp_json, service_type, resource_uri, None, "GET") self._logger.debug(" resp data:%s" % content) if retcode > 0: errmsg = "stack resource:%s, query fails: %s" % \ (resource_uri, content) logger.error(errmsg) return os_status, "UPDATE_FAILED", content vport_detail = content.get( 'port', None) if retcode == 0 and content else None if vport_detail: # compose inventory entry for vport # note: l3-interface-ipv4-address-list, # l3-interface-ipv6-address-list are not updated yet # note: network-name is not update yet since the detail # coming with network-id aai_resource = { "body": { "interface-name": vport_detail['name'], "interface-id": vport_detail['id'], "macaddr": vport_detail['mac_address'] }, 'uri': aai_cloud_region + "/vservers/vserver/%s/l-interfaces/l-interface/%s" % (vport_detail['device_id'], vport_detail['name']) } try: # then update the resource retcode, content, status_code = \ restcall.req_to_aai(aai_resource['uri'], "PUT", content=aai_resource['body']) if retcode == 0 and content: content = json.JSONDecoder().decode(content) self._logger.debug("AAI update %s response: %s" % (aai_resource['uri'], content)) except Exception as e: self._logger.error(e.message) return status.HTTP_500_INTERNAL_SERVER_ERROR, "UPDATE_FAILED", e.message # aai_resource_transactions = {"put": [aai_resource]} # transactions.append(aai_resource_transactions) # self._logger.debug("aai_resource :%s" % aai_resource_transactions) # aai_transactions = {"transactions": transactions} # self._logger.debug("aai_transactions :%s" % aai_transactions) return 0, "UPDATE_COMPLETE", "succeed"