From 001ec676cf4f0c47890d0370c129680a242f907d Mon Sep 17 00:00:00 2001 From: dhebeha Date: Mon, 3 Aug 2020 22:54:34 +0530 Subject: Model candidates to be object oriented Issue-ID: OPTFRA-822 Signed-off-by: dhebeha Change-Id: Ia04b4c5f4594dd40843e9d32f6fbdcd2f93cef06 --- .../data/plugins/inventory_provider/aai.py | 978 +++++++++------------ .../inventory_provider/candidates/candidate.py | 52 ++ .../candidates/cloud_candidate.py | 30 + .../candidates/service_candidate.py | 33 + .../candidates/transport_candidate.py | 28 + .../candidates/vfmodule_candidate.py | 34 + .../data/plugins/inventory_provider/test_aai.py | 87 +- 7 files changed, 655 insertions(+), 587 deletions(-) create mode 100644 conductor/conductor/data/plugins/inventory_provider/candidates/candidate.py create mode 100644 conductor/conductor/data/plugins/inventory_provider/candidates/cloud_candidate.py create mode 100644 conductor/conductor/data/plugins/inventory_provider/candidates/service_candidate.py create mode 100644 conductor/conductor/data/plugins/inventory_provider/candidates/transport_candidate.py create mode 100644 conductor/conductor/data/plugins/inventory_provider/candidates/vfmodule_candidate.py diff --git a/conductor/conductor/data/plugins/inventory_provider/aai.py b/conductor/conductor/data/plugins/inventory_provider/aai.py index 302bb89..821219c 100644 --- a/conductor/conductor/data/plugins/inventory_provider/aai.py +++ b/conductor/conductor/data/plugins/inventory_provider/aai.py @@ -18,22 +18,26 @@ # ------------------------------------------------------------------------- # +import copy +import json import re import time import uuid -import copy -import json +from oslo_config import cfg +from oslo_log import log from conductor.common import rest from conductor.data.plugins import constants -from conductor.common.utils import cipherUtils from conductor.data.plugins.inventory_provider import base from conductor.data.plugins.inventory_provider import hpa_utils +from conductor.data.plugins.inventory_provider.candidates.candidate import Candidate +from conductor.data.plugins.inventory_provider.candidates.cloud_candidate import Cloud +from conductor.data.plugins.inventory_provider.candidates.service_candidate import Service +from conductor.data.plugins.inventory_provider.candidates.transport_candidate import Transport +from conductor.data.plugins.inventory_provider.candidates.vfmodule_candidate import VfModule from conductor.data.plugins.triage_translator.triage_translator import TraigeTranslator from conductor.i18n import _LE, _LI -from oslo_config import cfg -from oslo_log import log LOG = log.getLogger(__name__) @@ -112,7 +116,7 @@ class AAI(base.InventoryProviderBase): self.retries = self.conf.aai.aai_retries self.username = self.conf.aai.username self.password = self.conf.aai.password - self.triage_translator=TraigeTranslator() + self.triage_translator = TraigeTranslator() # Cache is initially empty self._aai_cache = {} @@ -143,7 +147,8 @@ class AAI(base.InventoryProviderBase): """Return human-readable name.""" return "A&AI" - def _get_version_from_string(self, string): + @staticmethod + def _get_version_from_string(string): """Extract version number from string""" return re.sub("[^0-9.]", "", string) @@ -198,11 +203,10 @@ class AAI(base.InventoryProviderBase): } self.rest = rest.REST(**kwargs) - def _refresh_cache(self): """Refresh the A&AI cache.""" if not self.last_refresh_time or \ - (time.time() - self.last_refresh_time) > \ + (time.time() - self.last_refresh_time) > \ self.cache_refresh_interval * 60: # TODO(jdandrea): This is presently brute force. # It does not persist to Music. A general purpose ORM caching @@ -243,7 +247,8 @@ class AAI(base.InventoryProviderBase): cloud_type = region.get('cloud-type') cloud_zone = region.get('cloud-zone') - physical_location_list = self._get_aai_rel_link_data(data = region, related_to = 'complex', search_key = 'complex.physical-location-id') + physical_location_list = self._get_aai_rel_link_data(data=region, related_to='complex', + search_key='complex.physical-location-id') if len(physical_location_list) > 0: physical_location_id = physical_location_list[0].get('d_value') @@ -291,7 +296,8 @@ class AAI(base.InventoryProviderBase): keys = ('latitude', 'longitude', 'city', 'country', 'complex_name') missing_keys = \ - list(set(keys).difference(list(complex_info.keys()))) # Python 3 Conversion -- dict object to list object + list(set(keys).difference( + list(complex_info.keys()))) # Python 3 Conversion -- dict object to list object LOG.error(_LE("Complex {} is missing {}, link: {}"). format(complex_id, missing_keys, complex_link)) LOG.debug("Complex {}: {}". @@ -391,39 +397,46 @@ class AAI(base.InventoryProviderBase): ) return response + @staticmethod + def check_sriov_automation(aic_version, demand_name, candidate_name): + """Check if specific candidate has SRIOV automation available or no""" + if aic_version: + LOG.debug(_LI("Demand {}, candidate {} has an AIC version number {}").format(demand_name, candidate_name, + aic_version)) + if aic_version == "X.Y": + return True + return False + def _get_complex(self, complex_link, complex_id=None): + if not self.complex_last_refresh_time or \ - (time.time() - self.complex_last_refresh_time) > \ - self.complex_cache_refresh_interval * 60: + (time.time() - self.complex_last_refresh_time) > \ + self.complex_cache_refresh_interval * 60: self._aai_complex_cache.clear() if complex_id and complex_id in self._aai_complex_cache: return self._aai_complex_cache[complex_id] else: - path = self._aai_versioned_path( - self._get_aai_path_from_link(complex_link)) - response = self._request( - path=path, context="complex", value=complex_id) + path = self._aai_versioned_path(self._get_aai_path_from_link(complex_link)) + response = self._request(path=path, context="complex", value=complex_id) if response is None: return if response.status_code == 200: complex_info = response.json() if 'complex' in complex_info: complex_info = complex_info.get('complex') + latitude = complex_info.get('latitude') longitude = complex_info.get('longitude') city = complex_info.get('city') country = complex_info.get('country') - - # removed the state check for countries in Europe - # that do not always enter states + # removed the state check for countries in Europe that do not always enter states if not (latitude and longitude and city and country): keys = ('latitude', 'longitude', 'city', 'country') missing_keys = \ list(set(keys).difference(set(complex_info.keys()))) LOG.error(_LE("Complex {} is missing {}, link: {}"). format(complex_id, missing_keys, complex_link)) - LOG.debug("Complex {}: {}". - format(complex_id, complex_info)) + LOG.debug("Complex {}: {}".format(complex_id, complex_info)) return if complex_id: # cache only if complex_id is given @@ -580,7 +593,7 @@ class AAI(base.InventoryProviderBase): def resolve_host_location(self, host_name): path = self._aai_versioned_path('/query?format=id') data = {"start": ["network/pnfs/pnf/" + host_name, - "cloud-infrastructure/pservers/pserver/" + host_name], + "cloud-infrastructure/pservers/pserver/" + host_name], "query": "query/ucpe-instance" } response = self._request('put', path=path, data=data, @@ -694,22 +707,6 @@ class AAI(base.InventoryProviderBase): if context and value: LOG.debug("{} details: {}".format(context, value)) - def check_sriov_automation(self, aic_version, demand_name, candidate_name): - - """Check if specific candidate has SRIOV automation available or not - - Used by resolve_demands - """ - - if aic_version: - LOG.debug(_LI("Demand {}, candidate {} has an AIC version " - "number {}").format(demand_name, candidate_name, - aic_version) - ) - if aic_version == "X.Y": - return True - return False - def match_candidate_attribute(self, candidate, attribute_name, restricted_value, demand_name, inventory_type): @@ -718,8 +715,8 @@ class AAI(base.InventoryProviderBase): Used by resolve_demands """ if restricted_value and \ - restricted_value is not '' and \ - candidate[attribute_name] != restricted_value: + restricted_value is not '' and \ + candidate[attribute_name] != restricted_value: LOG.info(_LI("Demand: {} " "Discarded {} candidate as " "it doesn't match the " @@ -738,13 +735,13 @@ class AAI(base.InventoryProviderBase): value = None for i in range(0, len(vserver_list)): if value and \ - value != vserver_list[i].get('d_value'): + value != vserver_list[i].get('d_value'): return False value = vserver_list[i].get('d_value') return True def match_inventory_attributes(self, template_attributes, - inventory_attributes, candidate_id): + inventory_attributes, candidate_id): for attribute_key, attribute_values in template_attributes.items(): @@ -764,17 +761,17 @@ class AAI(base.InventoryProviderBase): if match_type == 'any': if attribute_key not in inventory_attributes or \ - (len(attribute_values) > 0 and - inventory_attributes[attribute_key] not in attribute_values): + (len(attribute_values) > 0 and + inventory_attributes[attribute_key] not in attribute_values): return False elif match_type == 'not': # drop the candidate when # 1). field exists in AAI and 2). value is not null or empty 3). value is one of those in the 'not' list # Remember, this means if the property is not returned at all from AAI, that still can be a candidate. if attribute_key in inventory_attributes and \ - inventory_attributes[attribute_key] and \ - inventory_attributes[attribute_key] in attribute_values: - return False + inventory_attributes[attribute_key] and \ + inventory_attributes[attribute_key] in attribute_values: + return False return True @@ -788,12 +785,12 @@ class AAI(base.InventoryProviderBase): body = response.json() return body.get("generic-vnf", []) - def resolove_v_server_for_candidate(self, candidate, vs_link, add_interfaces, demand_name, triage_translator_data): + def resolve_v_server_for_candidate(self, candidate_id, location_id, vs_link, add_interfaces, demand_name, triage_translator_data): if not vs_link: LOG.error(_LE("{} VSERVER link information not " "available from A&AI").format(demand_name)) - self.triage_translator.collectDroppedCandiate(candidate['candidate_id'], - candidate['location_id'], demand_name, + self.triage_translator.collectDroppedCandiate(candidate_id, + location_id, demand_name, triage_translator_data, reason="VSERVER link information not") return None # move ahead with the next vnf @@ -805,8 +802,8 @@ class AAI(base.InventoryProviderBase): LOG.error(_LE("{} VSERVER path information not " "available from A&AI - {}"). format(demand_name, vs_path)) - self.triage_translator.collectDroppedCandiate(candidate['candidate_id'], - candidate['location_id'], demand_name, + self.triage_translator.collectDroppedCandiate(candidate_id, + location_id, demand_name, triage_translator_data, reason="VSERVER path information not available from A&AI") return None # move ahead with the next vnf @@ -815,30 +812,27 @@ class AAI(base.InventoryProviderBase): path=path, context="demand, VSERVER", value="{}, {}".format(demand_name, vs_path)) if response is None or response.status_code != 200: - self.triage_translator.collectDroppedCandiate(candidate['candidate_id'], - candidate['location_id'], demand_name, + self.triage_translator.collectDroppedCandiate(candidate_id, + location_id, demand_name, triage_translator_data, reason=response.status_code) return None return response.json() - def resolve_vf_modules_for_generic_vnf(self, candidate, vnf, demand_name, triage_translator_data): + def resolve_vf_modules_for_generic_vnf(self, candidate_id, location_id, vnf, demand_name, triage_translator_data): raw_path = '/network/generic-vnfs/generic-vnf/{}?depth=1'.format(vnf.get("vnf-id")) path = self._aai_versioned_path(raw_path) response = self._request('get', path=path, data=None) if response is None or response.status_code != 200: - self.triage_translator.collectDroppedCandiate(candidate['candidate_id'], - candidate['location_id'], demand_name, - triage_translator_data, - reason=response) + self.triage_translator.collectDroppedCandiate(candidate_id, location_id, demand_name, + triage_translator_data, reason=response) return None generic_vnf_details = response.json() if generic_vnf_details is None or not generic_vnf_details.get('vf-modules') \ or not generic_vnf_details.get('vf-modules').get('vf-module'): - self.triage_translator.collectDroppedCandiate(candidate['candidate_id'], - candidate['location_id'], demand_name, + self.triage_translator.collectDroppedCandiate(candidate_id, location_id, demand_name, triage_translator_data, reason="Generic-VNF No detailed data for VF-modules") return None @@ -901,7 +895,7 @@ class AAI(base.InventoryProviderBase): vs_link_list.append(rl_data_list[i].get('link')) return vs_link_list - def resolve_complex_info_link_for_v_server(self, candidate, v_server, cloud_owner, cloud_region_id, service_type, + def resolve_complex_info_link_for_v_server(self, candidate_id, v_server, cloud_owner, cloud_region_id, service_type, demand_name, triage_translator_data): related_to = "pserver" rl_data_list = self._get_aai_rel_link_data( @@ -913,8 +907,7 @@ class AAI(base.InventoryProviderBase): self._log_multiple_item_error( demand_name, service_type, related_to, "item", "VSERVER", v_server) - self.triage_translator.collectDroppedCandiate(candidate['candidate_id'], - candidate['location_id'], demand_name, + self.triage_translator.collectDroppedCandiate(candidate_id, cloud_region_id, demand_name, triage_translator_data, reason="item VSERVER") return None rl_data = rl_data_list[0] @@ -928,10 +921,8 @@ class AAI(base.InventoryProviderBase): # if HPA_feature is disabled if not self.conf.HPA_enabled: # Triage Tool Feature Changes - self.triage_translator.collectDroppedCandiate(candidate['candidate_id'], - candidate['location_id'], demand_name, - triage_translator_data, - reason="ps link not found") + self.triage_translator.collectDroppedCandiate(candidate_id, cloud_region_id, demand_name, + triage_translator_data, reason="ps link not found") return None else: if not (cloud_owner and cloud_region_id): @@ -939,8 +930,7 @@ class AAI(base.InventoryProviderBase): "available from A&AI". format(demand_name)) # Triage Tool Feature Changes - self.triage_translator.collectDroppedCandiate(candidate['candidate_id'], - candidate['location_id'], demand_name, + self.triage_translator.collectDroppedCandiate(candidate_id, cloud_region_id, demand_name, triage_translator_data, reason="Cloud owner and cloud region " "id not found") @@ -955,10 +945,8 @@ class AAI(base.InventoryProviderBase): data=None) if response is None or response.status_code != 200: # Triage Tool Feature Changes - self.triage_translator.collectDroppedCandiate(candidate['candidate_id'], - candidate['location_id'], demand_name, - triage_translator_data, - reason=response) + self.triage_translator.collectDroppedCandiate(candidate_id, cloud_region_id, demand_name, + triage_translator_data, reason=response) return None body = response.json() else: @@ -968,20 +956,16 @@ class AAI(base.InventoryProviderBase): "not found in A&AI: {}"). format(demand_name, ps_link)) # Triage Tool Feature Changes - self.triage_translator.collectDroppedCandiate(candidate['candidate_id'], - candidate['location_id'], demand_name, - triage_translator_data, - reason="ps path not found") + self.triage_translator.collectDroppedCandiate(candidate_id, cloud_region_id, demand_name, + triage_translator_data, reason="ps path not found") return None # move ahead with the next vnf path = self._aai_versioned_path(ps_path) response = self._request( path=path, context="PSERVER", value=ps_path) if response is None or response.status_code != 200: # Triage Tool Feature Changes - self.triage_translator.collectDroppedCandiate(candidate['candidate_id'], - candidate['location_id'], demand_name, - triage_translator_data, - reason=response) + self.triage_translator.collectDroppedCandiate(candidate_id, cloud_region_id, demand_name, + triage_translator_data, reason=response) return None body = response.json() @@ -996,68 +980,47 @@ class AAI(base.InventoryProviderBase): if not self.match_vserver_attribute(rl_data_list): self._log_multiple_item_error( demand_name, service_type, related_to, search_key, "PSERVER", body) - self.triage_translator.collectDroppedCandiate(candidate['candidate_id'], candidate['location_id'], - demand_name, triage_translator_data, - reason="PSERVER error") + self.triage_translator.collectDroppedCandiate(candidate_id, cloud_region_id, demand_name, + triage_translator_data, reason="PSERVER error") return None return rl_data_list[0] - def resolve_cloud_region_id_and_version_for_vnf(self, candidate, vnf, service_type, demand_name, - triage_translator_data): + def resolve_cloud_for_vnf(self, candidate_id, location_id, vnf, service_type, demand_name, triage_translator_data): related_to = "vserver" - search_key = "cloud-region.cloud-region-id" - - rl_data_list = self._get_aai_rel_link_data( - data=vnf, - related_to=related_to, - search_key=search_key - ) - if len(rl_data_list) > 1: - if not self.match_vserver_attribute(rl_data_list): - self._log_multiple_item_error( - demand_name, service_type, related_to, search_key, - "VNF", vnf) - self.triage_translator.collectDroppedCandiate(candidate['candidate_id'], - candidate['location_id'], demand_name, - triage_translator_data, - reason="VNF error") - return None, None - cloud_region_rl_data = rl_data_list[0] - cloud_region_id = cloud_region_rl_data.get('d_value') - - # get version for service candidate - cloud_region_version_rl_data = {'d_value': ''} + search_keys = ["cloud-region.cloud-owner", "cloud-region.cloud-region-id"] + cloud_info = dict() + for search_key in search_keys: + rl_data_list = self._get_aai_rel_link_data( + data=vnf, related_to=related_to, + search_key=search_key) + + if len(rl_data_list) > 1: + if not self.match_vserver_attribute(rl_data_list): + self._log_multiple_item_error( + demand_name, service_type, related_to, search_key, + "VNF", vnf) + self.triage_translator.collectDroppedCandiate(candidate_id, + location_id, demand_name, + triage_translator_data, + reason="VNF error") + return None + cloud_info[search_key.split(".")[1].replace('-', '_')] = rl_data_list[0].get('d_value') if rl_data_list[ + 0] else None + cloud_info['cloud_region_version'] = self.get_cloud_region_version(cloud_info['cloud_region_id']) + cloud_info['location_type'] = 'att_aic' + cloud_info['location_id'] = cloud_info.pop('cloud_region_id') + return cloud_info + + def get_cloud_region_version(self, cloud_region_id): if cloud_region_id: regions = self.resolve_cloud_regions_by_cloud_region_id(cloud_region_id) if regions is None: - return cloud_region_rl_data, None - + return None for region in regions: if "cloud-region-version" in region: - cloud_region_version_rl_data['d_value'] = self._get_version_from_string(region["cloud-region-version"]) - - return cloud_region_rl_data, cloud_region_version_rl_data + return self._get_version_from_string(region["cloud-region-version"]) - def resolve_cloud_owner_for_vnf(self, candidate, vnf, service_type, demand_name, triage_translator_data): - related_to = "vserver" - search_key = "cloud-region.cloud-owner" - rl_data_list = self._get_aai_rel_link_data( - data=vnf, related_to=related_to, - search_key=search_key) - - if len(rl_data_list) > 1: - if not self.match_vserver_attribute(rl_data_list): - self._log_multiple_item_error( - demand_name, service_type, related_to, search_key, - "VNF", vnf) - self.triage_translator.collectDroppedCandiate(candidate['candidate_id'], - candidate['location_id'], demand_name, - triage_translator_data, - reason="VNF error") - return None - return rl_data_list[0] - - def resolve_global_customer_id_for_vnf(self, candidate, vnf, customer_id, service_type, demand_name, + def resolve_global_customer_id_for_vnf(self, candidate_id, location_id, vnf, customer_id, service_type, demand_name, triage_translator_data): related_to = "service-instance" search_key = "customer.global-customer-id" @@ -1073,13 +1036,13 @@ class AAI(base.InventoryProviderBase): if not self.match_vserver_attribute(rl_data_list): self._log_multiple_item_error( demand_name, service_type, related_to, search_key, "VNF", vnf) - self.triage_translator.collectDroppedCandiate(candidate['candidate_id'], candidate['location_id'], + self.triage_translator.collectDroppedCandiate(candidate_id, location_id, demand_name, triage_translator_data, reason=" match_vserver_attribute generic-vnf") return None return rl_data_list[0] - def resolve_service_instance_id_for_vnf(self, candidate, vnf, customer_id, service_type, demand_name, + def resolve_service_instance_id_for_vnf(self, candidate_id, location_id, vnf, customer_id, service_type, demand_name, triage_translator_data): related_to = "service-instance" search_key = "service-instance.service-instance-id" @@ -1095,20 +1058,19 @@ class AAI(base.InventoryProviderBase): if not self.match_vserver_attribute(rl_data_list): self._log_multiple_item_error( demand_name, service_type, related_to, search_key, "VNF", vnf) - self.triage_translator.collectDroppedCandiate(candidate['candidate_id'], candidate['location_id'], + self.triage_translator.collectDroppedCandiate(candidate_id, location_id, demand_name, triage_translator_data, reason="multiple_item_error generic-vnf") return None return rl_data_list[0] - def build_complex_info_for_candidate(self, candidate, vnf, complex_list, service_type, demand_name, + def build_complex_info_for_candidate(self, candidate_id, location_id, vnf, complex_list, service_type, demand_name, triage_translator_data): if not complex_list or \ len(complex_list) < 1: LOG.error("Complex information not " "available from A&AI") - self.triage_translator.collectDroppedCandiate(candidate['candidate_id'], - candidate['location_id'], demand_name, + self.triage_translator.collectDroppedCandiate(candidate_id, location_id, demand_name, triage_translator_data, reason="Complex information not available from A&AI") return @@ -1123,8 +1085,7 @@ class AAI(base.InventoryProviderBase): self._log_multiple_item_error( demand_name, service_type, related_to, search_key, "VNF", vnf) - self.triage_translator.collectDroppedCandiate(candidate['candidate_id'], - candidate['location_id'], demand_name, + self.triage_translator.collectDroppedCandiate(candidate_id, location_id, demand_name, triage_translator_data, reason="Generic-vnf error") return @@ -1138,8 +1099,7 @@ class AAI(base.InventoryProviderBase): LOG.debug("{} complex information not " "available from A&AI - {}". format(demand_name, complex_link)) - self.triage_translator.collectDroppedCandiate(candidate['candidate_id'], - candidate['location_id'], demand_name, + self.triage_translator.collectDroppedCandiate(candidate_id, location_id, demand_name, triage_translator_data, reason="Complex information not available from A&AI") return # move ahead with the next vnf @@ -1152,32 +1112,18 @@ class AAI(base.InventoryProviderBase): LOG.debug("{} complex information not " "available from A&AI - {}". format(demand_name, complex_link)) - self.triage_translator.collectDroppedCandiate(candidate['candidate_id'], - candidate['location_id'], demand_name, + self.triage_translator.collectDroppedCandiate(candidate_id, location_id, demand_name, triage_translator_data, reason="Complex information not available from A&AI") return # move ahead with the next vnf - candidate['physical_location_id'] = \ - complex_id - candidate['complex_name'] = \ - complex_info.get('complex-name') - candidate['latitude'] = \ - complex_info.get('latitude') - candidate['longitude'] = \ - complex_info.get('longitude') - candidate['state'] = \ - complex_info.get('state') - candidate['country'] = \ - complex_info.get('country') - candidate['city'] = \ - complex_info.get('city') - candidate['region'] = \ - complex_info.get('region') + + complex_info = self.build_complex_dict(complex_info, '') + return complex_info def resolve_demands(self, demands, plan_info, triage_translator_data): """Resolve demands into inventory candidate lists""" - self.triage_translator.getPlanIdNAme(plan_info['plan_name'], plan_info['plan_id'],triage_translator_data) + self.triage_translator.getPlanIdNAme(plan_info['plan_name'], plan_info['plan_id'], triage_translator_data) resolved_demands = {} for name, requirements in demands.items(): @@ -1189,9 +1135,9 @@ class AAI(base.InventoryProviderBase): candidate_uniqueness = requirement.get('unique', 'true') filtering_attributes = requirement.get('filtering_attributes') passthrough_attributes = requirement.get('passthrough_attributes') - #TODO: may need to support multiple service_type and customer_id in the futrue + # TODO: may need to support multiple service_type and customer_id in the futrue - #TODO: make it consistent for dash and underscore + # TODO: make it consistent for dash and underscore if filtering_attributes: # catch equipment-role and service-type from template @@ -1241,63 +1187,27 @@ class AAI(base.InventoryProviderBase): service_resource_id = requirement.get('service_resource_id') \ if requirement.get('service_resource_id') else '' - # add all the candidates of cloud type if inventory_type == 'cloud': # load region candidates from cache regions = self._get_regions() - if not regions or len(regions) < 1: - LOG.debug("Region information is not " - "available in cache") + LOG.debug("Region information is not available in cache") for region_id, region in regions.items(): # Pick only candidates from the restricted_region - - candidate = dict() - candidate['inventory_provider'] = 'aai' - candidate['service_resource_id'] = service_resource_id - candidate['inventory_type'] = 'cloud' - candidate['candidate_id'] = region_id - candidate['location_id'] = region_id - candidate['location_type'] = 'att_aic' - candidate['cost'] = self.conf.data.cloud_candidate_cost - candidate['cloud_region_version'] = \ - self._get_version_from_string( - region['cloud_region_version']) - candidate['cloud_owner'] = \ - region['cloud_owner'] - - candidate['physical_location_id'] = \ - region['complex']['complex_id'] - candidate['complex_name'] = \ - region['complex']['complex_name'] - candidate['latitude'] = \ - region['complex']['latitude'] - candidate['longitude'] = \ - region['complex']['longitude'] - candidate['city'] = \ - region['complex']['city'] - candidate['state'] = \ - region['complex']['state'] - candidate['region'] = \ - region['complex']['region'] - candidate['country'] = \ - region['complex']['country'] - candidate['uniqueness'] = candidate_uniqueness - - # Added vim-id for short-term workaround - if self.conf.HPA_enabled: - candidate['vim-id'] = \ - region['cloud_owner'] + '_' + region_id - # Added for HPA - candidate['flavors'] = \ - region['flavors'] - - if self.check_sriov_automation( - candidate['cloud_region_version'], name, - candidate['candidate_id']): - candidate['sriov_automation'] = 'true' - else: - candidate['sriov_automation'] = 'false' + info = Candidate.build_candidate_info('aai', inventory_type, self.conf.data.cloud_candidate_cost, + candidate_uniqueness, region_id, service_resource_id) + cloud = self.resolve_cloud_for_region(region, region_id) + complex_info = self.build_complex_dict(region['complex'], inventory_type) + flavors = self.resolve_flavors_for_region(region['flavors']) + other = dict() + other['vim-id'] = self.get_vim_id(cloud['cloud_owner'], cloud['location_id']) + other['sriov_automation'] = 'true' if self.check_sriov_automation(cloud['cloud_region_version'], + name, + info['candidate_id']) \ + else 'false' + cloud_candidate = Cloud(info=info, cloud_region=cloud, complex=complex_info, flavors=flavors, + additional_fields=other) + candidate = cloud_candidate.convert_nested_dict_to_dict() cloud_region_attr = dict() cloud_region_attr['cloud-owner'] = region['cloud_owner'] @@ -1307,9 +1217,12 @@ class AAI(base.InventoryProviderBase): cloud_region_attr['complex-name'] = region['complex_name'] cloud_region_attr['physical-location-id'] = region['physical_location_id'] - if filtering_attributes and (not self.match_inventory_attributes(filtering_attributes, cloud_region_attr, candidate['candidate_id'])): - self.triage_translator.collectDroppedCandiate(candidate['candidate_id'], candidate['location_id'], name, triage_translator_data, - reason='attributes and match invetory attributes') + if filtering_attributes and (not self.match_inventory_attributes(filtering_attributes, + cloud_region_attr, candidate['candidate_id'])): + self.triage_translator.collectDroppedCandiate(candidate['candidate_id'], + candidate['location_id'], name, + triage_translator_data, + reason='attributes and match invetory attributes') continue if conflict_identifier: @@ -1321,25 +1234,24 @@ class AAI(base.InventoryProviderBase): self.assign_candidate_existing_placement(candidate, existing_placement) - # Pick only candidates not in the excluded list - # if excluded candidate list is provided - if excluded_candidates and self.match_candidate_by_list(candidate, excluded_candidates, True, name, triage_translator_data): + # Pick only candidates not in the excluded list, if excluded candidate list is provided + if excluded_candidates and self.match_candidate_by_list(candidate, excluded_candidates, True, + name, triage_translator_data): continue - # Pick only candidates in the required list - # if required candidate list is provided - if required_candidates and not self.match_candidate_by_list(candidate, required_candidates, False, name, triage_translator_data): + # Pick only candidates in the required list, if required candidate list is provided + if required_candidates and not self.match_candidate_by_list(candidate, required_candidates, + False, name, + triage_translator_data): continue - self.add_passthrough_attributes(candidate, passthrough_attributes, name, triage_translator_data) + self.add_passthrough_attributes(candidate, passthrough_attributes, name) # add candidate to demand candidates resolved_demands[name].append(candidate) LOG.debug(">>>>>>> Candidate <<<<<<<") LOG.debug(json.dumps(candidate, indent=4)) - elif (inventory_type == 'service') \ - and customer_id: - + elif (inventory_type == 'service') and customer_id: # First level query to get the list of generic vnfs vnf_by_model_invariant = list() if filtering_attributes and model_invariant_id: @@ -1348,7 +1260,8 @@ class AAI(base.InventoryProviderBase): '?model-invariant-id={}&depth=0'.format(model_invariant_id) if model_version_id: raw_path = '/network/generic-vnfs/' \ - '?model-invariant-id={}&model-version-id={}&depth=0'.format(model_invariant_id, model_version_id) + '?model-invariant-id={}&model-version-id={}&depth=0'.format(model_invariant_id, + model_version_id) path = self._aai_versioned_path(raw_path) vnf_by_model_invariant = self.first_level_service_call(path, name, service_type) @@ -1367,121 +1280,75 @@ class AAI(base.InventoryProviderBase): vnf_id = vnf.get('vnf-id') if vnf_id in vnf_dict: continue - # add vnf (with vnf_id as key) to the dictionary vnf_dict[vnf_id] = vnf - - # create a default candidate - candidate = dict() - candidate['inventory_provider'] = 'aai' - candidate['service_resource_id'] = service_resource_id - candidate['inventory_type'] = inventory_type - candidate['candidate_id'] = '' - candidate['location_id'] = '' - candidate['location_type'] = 'att_aic' - candidate['host_id'] = '' - candidate['cost'] = self.conf.data.service_candidate_cost - candidate['cloud_owner'] = '' - candidate['cloud_region_version'] = '' - candidate['vlan_key'] = vlan_key - candidate['port_key'] = port_key - candidate['uniqueness'] = candidate_uniqueness - - # start populating the candidate - candidate['host_id'] = vnf.get("vnf-name") - - rl_data = self.resolve_cloud_owner_for_vnf(candidate, vnf, service_type, name, - triage_translator_data) - if rl_data is None: - continue - else: - cloud_owner = rl_data.get('d_value') - - candidate['cloud_owner'] = cloud_owner - - cloud_region_id_rl_data, cloud_region_version_rl_data = self.resolve_cloud_region_id_and_version_for_vnf( - candidate, vnf, service_type, name, triage_translator_data) - - if cloud_region_id_rl_data is None or cloud_region_version_rl_data is None: + vnf_info = dict() + vnf_info['host_id'] = vnf.get("vnf-name") + vlan_info = self.build_vlan_info(vlan_key, port_key) + cloud = self.resolve_cloud_for_vnf('', '', vnf, service_type, name, triage_translator_data) + if cloud['location_id'] is None or cloud['cloud_owner'] is None or \ + cloud['cloud_region_version'] is None: continue - cloud_region_id = cloud_region_id_rl_data.get('d_value') - cloud_region_version = cloud_region_version_rl_data.get('d_value') - candidate['location_id'] = cloud_region_id - candidate['cloud_region_version'] = cloud_region_version - - # Added vim-id for short-term workaround - if self.conf.HPA_enabled: - if not cloud_owner: - continue - candidate['vim-id'] = \ - candidate['cloud_owner'] + '_' + cloud_region_id - - if self.check_sriov_automation( - candidate['cloud_region_version'], name, - candidate['host_id']): - candidate['sriov_automation'] = 'true' - else: - candidate['sriov_automation'] = 'false' - - rl_data = self.resolve_global_customer_id_for_vnf(candidate, vnf, customer_id, service_type, - name, triage_translator_data) + rl_data = self.resolve_global_customer_id_for_vnf('', cloud['location_id'], vnf, customer_id, + service_type, name, triage_translator_data) if rl_data is None: continue else: vs_cust_id = rl_data.get('d_value') - - rl_data = self.resolve_service_instance_id_for_vnf(candidate, vnf, customer_id, + rl_data = self.resolve_service_instance_id_for_vnf('', cloud['location_id'], vnf, customer_id, service_type, name, triage_translator_data) if rl_data is None: continue else: vs_service_instance_id = rl_data.get('d_value') + # INFO if vs_cust_id and vs_cust_id == customer_id: - candidate['candidate_id'] = \ - vs_service_instance_id + info = Candidate.build_candidate_info('aai', inventory_type, + self.conf.data.service_candidate_cost, + candidate_uniqueness, vs_service_instance_id, + service_resource_id) else: # vserver is for a different customer - self.triage_translator.collectDroppedCandiate(candidate['candidate_id'], - candidate['location_id'], name, + self.triage_translator.collectDroppedCandiate('', cloud['location_id'], name, triage_translator_data, - reason= "vserver is for a different customer") + reason="vserver is for a different customer") continue + # Added vim-id for short-term workaround + other = dict() + other['vim-id'] = self.get_vim_id(cloud['cloud_owner'], cloud['location_id']) + other['sriov_automation'] = 'true' if self.check_sriov_automation( + cloud['cloud_region_version'], name, info['candidate_id']) else 'false' # Second level query to get the pserver from vserver complex_list = list() - vs_link_list = self.resolve_v_server_links_for_vnf(vnf) - - for vs_link in vs_link_list: - - body = self.resolove_v_server_for_candidate(candidate, vs_link, True, name, - triage_translator_data) - if body is None: - continue - - rl_data = self.resolve_complex_info_link_for_v_server(candidate, body, cloud_owner, - cloud_region_id, service_type, - name, triage_translator_data) - if rl_data is None: - continue - - complex_list.append(rl_data) - - self.build_complex_info_for_candidate(candidate, vnf, complex_list, service_type, name, - triage_translator_data) - - if "complex_name" not in candidate: + for complex_link in self.resolve_v_server_and_complex_link_for_vnf(info['candidate_id'], cloud, + vnf, name, + triage_translator_data, + service_type): + complex_list.append(complex_link[1]) + complex_info = self.build_complex_info_for_candidate(info['candidate_id'], cloud['location_id'], + vnf, complex_list, service_type, name, + triage_translator_data) + if "complex_name" not in complex_info: continue + service_candidate = Service(info=info, cloud_region=cloud, complex=complex_info, + generic_vnf=vnf_info, additional_fields=other, vlan=vlan_info) + candidate = service_candidate.convert_nested_dict_to_dict() + # add specifal parameters for comparsion vnf['global-customer-id'] = customer_id vnf['customer-id'] = customer_id - vnf['cloud-region-id'] = cloud_region_id - vnf['physical-location-id'] = candidate.get('physical_location_id') + vnf['cloud-region-id'] = cloud.get('cloud_region_id') + vnf['physical-location-id'] = complex_info.get('physical_location_id') - if filtering_attributes and not self.match_inventory_attributes(filtering_attributes, vnf, candidate['candidate_id']): - self.triage_translator.collectDroppedCandiate(candidate['candidate_id'], candidate['location_id'], name, triage_translator_data, - reason="attibute check error") + if filtering_attributes and not self.match_inventory_attributes(filtering_attributes, vnf, + candidate['candidate_id']): + self.triage_translator.collectDroppedCandiate(candidate['candidate_id'], + candidate['location_id'], name, + triage_translator_data, + reason="attibute check error") continue self.assign_candidate_existing_placement(candidate, existing_placement) @@ -1494,7 +1361,8 @@ class AAI(base.InventoryProviderBase): # Pick only candidates in the required list # if required candidate list is provided if required_candidates and not self.match_candidate_by_list(candidate, required_candidates, - False, name, triage_translator_data): + False, name, + triage_translator_data): continue # add the candidate to the demand @@ -1504,13 +1372,12 @@ class AAI(base.InventoryProviderBase): triage_translator_data): continue else: - self.add_passthrough_attributes(candidate, passthrough_attributes, name, triage_translator_data) + self.add_passthrough_attributes(candidate, passthrough_attributes, name) resolved_demands[name].append(candidate) LOG.debug(">>>>>>> Candidate <<<<<<<") LOG.debug(json.dumps(candidate, indent=4)) - elif (inventory_type == 'vfmodule') \ - and customer_id: + elif (inventory_type == 'vfmodule') and customer_id: # First level query to get the list of generic vnfs vnf_by_model_invariant = list() @@ -1527,9 +1394,8 @@ class AAI(base.InventoryProviderBase): vnf_by_service_type = list() if service_type or equipment_role: - path = self._aai_versioned_path( - '/network/generic-vnfs/' - '?equipment-role={}&depth=0'.format(service_type)) + path = self._aai_versioned_path('/network/generic-vnfs/' + '?equipment-role={}&depth=0'.format(service_type)) vnf_by_service_type = self.first_level_service_call(path, name, service_type) generic_vnf = vnf_by_model_invariant + vnf_by_service_type @@ -1540,186 +1406,108 @@ class AAI(base.InventoryProviderBase): vnf_id = vnf.get('vnf-id') if vnf_id in vnf_dict: continue - # add vnf (with vnf_id as key) to the dictionary vnf_dict[vnf_id] = vnf - # create a default candidate - candidate = dict() - candidate['inventory_provider'] = 'aai' - candidate['service_resource_id'] = service_resource_id - candidate['inventory_type'] = inventory_type - candidate['candidate_id'] = '' - candidate['location_id'] = '' - candidate['location_type'] = 'att_aic' - candidate['host_id'] = '' - candidate['cost'] = self.conf.data.service_candidate_cost - candidate['cloud_owner'] = '' - candidate['cloud_region_version'] = '' - candidate['vlan_key'] = vlan_key - candidate['port_key'] = port_key - candidate['uniqueness'] = candidate_uniqueness - - # start populating the candidate - candidate['host_id'] = vnf.get("vnf-name") - - candidate['nf-name'] = vnf.get("vnf-name") - candidate['nf-id'] = vnf.get("vnf-id") - candidate['nf-type'] = 'vnf' - candidate['vnf-type'] = vnf.get("vnf-type") - candidate['ipv4-oam-address'] = '' - candidate['ipv6-oam-address'] = '' - - if vnf.get("ipv4-oam-address"): - candidate['ipv4-oam-address'] = vnf.get("ipv4-oam-address") - if vnf.get("ipv6-oam-address"): - candidate['ipv6-oam-address'] = vnf.get("ipv6-oam-address") - - rl_data = self.resolve_global_customer_id_for_vnf(candidate, vnf, customer_id, service_type, - name, triage_translator_data) + # INFO + info = Candidate.build_candidate_info('aai', inventory_type, self.conf.data.service_candidate_cost, + candidate_uniqueness, "", service_resource_id) + # VLAN INFO + vlan_info = self.build_vlan_info(vlan_key, port_key) + # Generic VNF Info + vnf_info = self.get_vnf_info(vnf) + + rl_data = self.resolve_global_customer_id_for_vnf('', '', vnf, customer_id, + service_type, name, triage_translator_data) if rl_data is None: continue else: vs_cust_id = rl_data.get('d_value') - rl_data = self.resolve_service_instance_id_for_vnf(candidate, vnf, customer_id, + rl_data = self.resolve_service_instance_id_for_vnf('', '', vnf, customer_id, service_type, name, triage_translator_data) if rl_data is None: continue else: vs_service_instance_id = rl_data.get('d_value') + service_info = dict() if vs_cust_id and vs_cust_id == customer_id: - candidate['service_instance_id'] = vs_service_instance_id + service_info['service_instance_id'] = vs_service_instance_id else: # vserver is for a different customer - self.triage_translator.collectDroppedCandiate(candidate['candidate_id'], - candidate['location_id'], name, + self.triage_translator.collectDroppedCandiate('', '', name, triage_translator_data, reason="candidate is for a different customer") continue - vf_modules_list = self.resolve_vf_modules_for_generic_vnf(candidate, vnf, name, + vf_modules_list = self.resolve_vf_modules_for_generic_vnf('', '', vnf, name, triage_translator_data) if vf_modules_list is None: continue - candidate_base = candidate for vf_module in vf_modules_list: # for vfmodule demands we allow to have vfmodules from different cloud regions - candidate = copy.deepcopy(candidate_base) - candidate['candidate_id'] = vf_module.get("vf-module-id") - candidate['vf-module-name'] = vf_module.get("vf-module-name") - candidate['vf-module-id'] = vf_module.get("vf-module-id") - - rl_data = self.resolve_cloud_owner_for_vnf(candidate, vf_module, service_type, name, - triage_translator_data) - if rl_data is None: - continue - else: - cloud_owner = rl_data.get('d_value') - candidate['cloud_owner'] = cloud_owner - - cloud_region_id_rl_data, cloud_region_version_rl_data = self.resolve_cloud_region_id_and_version_for_vnf( - candidate, vf_module, service_type, name, triage_translator_data) - - if cloud_region_id_rl_data is None or cloud_region_version_rl_data is None: + info['candidate_id'] = vf_module.get("vf-module-id") + vf_module_info = self.get_vf_module(vf_module) + cloud = self.resolve_cloud_for_vnf(info['candidate_id'], '', vf_module, service_type, name, + triage_translator_data) + if cloud['location_id'] is None or cloud['cloud_owner'] is None or \ + cloud['cloud_region_version'] is None: continue - cloud_region_id = cloud_region_id_rl_data.get('d_value') - cloud_region_version = cloud_region_version_rl_data.get('d_value') - candidate['location_id'] = cloud_region_id - candidate['cloud_region_version'] = cloud_region_version - - # Added vim-id for short-term workaround - if self.conf.HPA_enabled: - if not cloud_owner: - continue - candidate['vim-id'] = \ - candidate['cloud_owner'] + '_' + cloud_region_id - - if self.check_sriov_automation( - candidate['cloud_region_version'], name, - candidate['host_id']): - candidate['sriov_automation'] = 'true' - else: - candidate['sriov_automation'] = 'false' + # OTHER - Added vim-id for short-term workaround + other = dict() + other['vim-id'] = self.get_vim_id(cloud['cloud_owner'], cloud['location_id']) + other['sriov_automation'] = 'true' if self.check_sriov_automation( + cloud['cloud_region_version'], name, info['candidate_id']) else 'false' # Second level query to get the pserver from vserver - candidate['vservers'] = list() + vserver_info = dict() + vserver_info['vservers'] = list() complex_list = list() - vs_link_list = self.resolve_v_server_links_for_vnf(vf_module) - - for vs_link in vs_link_list: - - body = self.resolove_v_server_for_candidate(candidate, vs_link, True, name, - triage_translator_data) - if body is None: - continue - + for v_server, complex_link in self.resolve_v_server_and_complex_link_for_vnf(info['candidate_id'], + cloud, vnf, name, + triage_translator_data, + service_type): + complex_list.append(complex_link) candidate_vserver = dict() - candidate_vserver['vserver-id'] = body.get('vserver-id') - candidate_vserver['vserver-name'] = body.get('vserver-name') - - rl_data = self.resolve_complex_info_link_for_v_server(candidate, body, cloud_owner, - cloud_region_id, service_type, - name, triage_translator_data) - if rl_data is None: - continue - - #Interfaces info - if not body.get('l-interfaces') or not body.get('l-interfaces').get('l-interface'): - self.triage_translator.collectDroppedCandiate(candidate['candidate_id'], - candidate['location_id'], name, - triage_translator_data, - reason="VF-server interfaces error") - continue + candidate_vserver['vserver-id'] = v_server.get('vserver-id') + candidate_vserver['vserver-name'] = v_server.get('vserver-name') + l_interfaces = self.get_l_interfaces_from_vserver(info['candidate_id'], cloud['location_id'], + v_server, name, triage_translator_data) + if l_interfaces: + candidate_vserver['l-interfaces'] = l_interfaces else: - l_interfaces = body.get('l-interfaces').get('l-interface') - candidate_vserver['l-interfaces'] = list() - - for l_interface in l_interfaces: - vserver_interface = dict() - vserver_interface['interface-id'] = l_interface.get('interface-id') - vserver_interface['interface-name'] = l_interface.get('interface-name') - vserver_interface['macaddr'] = l_interface.get('macaddr') - vserver_interface['network-id'] = l_interface.get('network-name') - vserver_interface['network-name'] = '' - vserver_interface['ipv4-addresses'] = list() - vserver_interface['ipv6-addresses'] = list() - - if l_interface.get('l3-interface-ipv4-address-list'): - for ip_address_info in l_interface.get('l3-interface-ipv4-address-list'): - vserver_interface['ipv4-addresses'].\ - append(ip_address_info.get('l3-interface-ipv4-address')) - - if l_interface.get('l3-interface-ipv6-address-list'): - for ip_address_info in l_interface.get('l3-interface-ipv6-address-list'): - vserver_interface['ipv6-addresses'].\ - append(ip_address_info.get('l3-interface-ipv6-address')) - - candidate_vserver['l-interfaces'].append(vserver_interface) - - complex_list.append(rl_data) - candidate['vservers'].append(candidate_vserver) - - self.build_complex_info_for_candidate(candidate, vnf, complex_list, service_type, name, - triage_translator_data) - - if candidate.get("complex_name") is None: + continue + vserver_info['vservers'].append(candidate_vserver) + + # COMPLEX + complex_info = self.build_complex_info_for_candidate(info['candidate_id'], + cloud['location_id'], vnf, complex_list, + service_type, name, + triage_translator_data) + if complex_info.get("complex_name") is None: continue + vf_module_candidate = VfModule(complex=complex_info, info=info, generic_vnf=vnf_info, + cloud_region=cloud, service_instance=service_info, + vf_module=vf_module_info, vserver=vserver_info, + additional_fields=other, vlan=vlan_info) + candidate = vf_module_candidate.convert_nested_dict_to_dict() + ##add vf-module parameters for filtering vnf_vf_module_inventory = copy.deepcopy(vnf) vnf_vf_module_inventory.update(vf_module) # add specifal parameters for comparsion vnf_vf_module_inventory['global-customer-id'] = customer_id vnf_vf_module_inventory['customer-id'] = customer_id - vnf_vf_module_inventory['cloud-region-id'] = cloud_region_id - vnf_vf_module_inventory['physical-location-id'] = candidate.get('physical_location_id') + vnf_vf_module_inventory['cloud-region-id'] = cloud.get('location_id') + vnf_vf_module_inventory['physical-location-id'] = complex_info.get('physical_location_id') vnf_vf_module_inventory['service_instance_id'] = vs_service_instance_id - if filtering_attributes and not self.match_inventory_attributes(filtering_attributes, vnf_vf_module_inventory, - candidate['candidate_id']): + if filtering_attributes and not self.match_inventory_attributes(filtering_attributes, + vnf_vf_module_inventory, + candidate['candidate_id']): self.triage_translator.collectDroppedCandiate(candidate['candidate_id'], candidate['location_id'], name, triage_translator_data, @@ -1729,7 +1517,8 @@ class AAI(base.InventoryProviderBase): # Pick only candidates not in the excluded list # if excluded candidate list is provided - if excluded_candidates and self.match_candidate_by_list(candidate, excluded_candidates, True, + if excluded_candidates and self.match_candidate_by_list(candidate, excluded_candidates, + True, name, triage_translator_data): continue @@ -1747,91 +1536,73 @@ class AAI(base.InventoryProviderBase): triage_translator_data): continue else: - self.add_passthrough_attributes(candidate, passthrough_attributes, name, triage_translator_data) + self.add_passthrough_attributes(candidate, passthrough_attributes, name) resolved_demands[name].append(candidate) LOG.debug(">>>>>>> Candidate <<<<<<<") + with open("vf.log", mode='w') as log_file: + log_file.write(">>>>>>>Vf Candidate <<<<<<<") + log_file.write(json.dumps(candidate, indent=4)) LOG.debug(json.dumps(candidate, indent=4)) elif inventory_type == 'transport' \ - and customer_id and service_type and \ - service_subscription and service_role: + and customer_id and service_type and \ + service_subscription and service_role: + path = self._aai_versioned_path('business/customers/customer/{}/service-subscriptions/' 'service-subscription/{}/service-instances' '?service-type={}&service-role={}'.format(customer_id, service_subscription, service_type, service_role)) - response = self._request('get', path=path, data=None) - if response is None or response.status_code != 200: - self.triage_translator.collectDroppedCandiate(candidate['candidate_id'], candidate['location_id'], name, triage_translator_data, - reason=response.status_code) + self.triage_translator.collectDroppedCandiate("", "", name, + triage_translator_data, + reason=response.status_code) continue - body = response.json() - transport_vnfs = body.get('service-instance', []) for vnf in transport_vnfs: - # create a default candidate - candidate = dict() - candidate['inventory_provider'] = 'aai' - candidate['service_resource_id'] = service_resource_id - candidate['inventory_type'] = 'transport' - candidate['candidate_id'] = '' - candidate['location_id'] = '' - candidate['location_type'] = 'att_aic' - candidate['uniqueness'] = candidate_uniqueness - candidate['cost'] = self.conf.data.transport_candidate_cost - + other = dict() + other['location_id'] = '' + other['location_type'] = 'att_aic' + # INFO vnf_service_instance_id = vnf.get('service-instance-id') if vnf_service_instance_id: - candidate['candidate_id'] = vnf_service_instance_id + info = Candidate.build_candidate_info('aai', inventory_type, + self.conf.data.transport_candidate_cost, + candidate_uniqueness, vnf_service_instance_id, + service_resource_id) else: - self.triage_translator.collectDroppedCandiate(candidate['candidate_id'], candidate['location_id'], name,triage_translator_data, - reason="service-instance-id error ") - - continue - - related_to = "zone" - zone_link = self._get_aai_rel_link( - data=vnf, related_to=related_to) - - if not zone_link: - LOG.error("Zone information not available" - "from A&AI for transport candidates") - self.triage_translator.collectDroppedCandiate(candidate['candidate_id'], candidate['location_id'], name, triage_translator_data, - reason="Zone information not available from A&AI for transport candidates") - + self.triage_translator.collectDroppedCandiate('', other['location_id'], name, triage_translator_data, + reason="service-instance-id error ") continue - zone_aai_path = self._get_aai_path_from_link(zone_link) - - response = self._request('get', path=zone_aai_path, data=None) - - if response is None or response.status_code != 200: - self.triage_translator.collectDroppedCandiate(candidate['candidate_id'], candidate['location_id'], name, triage_translator_data, - reason=response.status_code) - + # ZONE + zone_info = dict() + zone = self.resolve_zone_for_vnf(info['candidate_id'], other['location_id'], vnf, name, + triage_translator_data) + if zone: + zone_info['zone_id'] = zone.get('zone-id') + zone_info['zone_name'] = zone.get('zone-name') + else: continue - body = response.json() - - candidate['zone_id'] = body.get('zone-id') - candidate['zone_name'] = body.get('zone-name') + # COMPLEX related_to = "complex" search_key = "complex.physical-location-id" rel_link_data_list = self._get_aai_rel_link_data( - data=body, + data=zone, related_to=related_to, search_key=search_key ) if len(rel_link_data_list) > 1: - self.triage_translator.collectDroppedCandiate(candidate['candidate_id'], candidate['location_id'], name, triage_translator_data, - reason="rel_link_data_list error") + self.triage_translator.collectDroppedCandiate(info['candidate_id'], other['location_id'], name, + triage_translator_data, + reason="rel_link_data_list error") continue rel_link_data = rel_link_data_list[0] @@ -1842,8 +1613,9 @@ class AAI(base.InventoryProviderBase): LOG.debug("{} complex information not " "available from A&AI - {}". format(name, complex_link)) - self.triage_translator.collectDroppedCandiate(candidate['candidate_id'], candidate['location_id'], name, triage_translator_data, - reason="complex information not available from A&AI") + self.triage_translator.collectDroppedCandiate(info['candidate_id'], other['location_id'], name, + triage_translator_data, + reason="complex information not available from A&AI") continue else: complex_info = self._get_complex( @@ -1854,27 +1626,16 @@ class AAI(base.InventoryProviderBase): LOG.debug("{} complex information not " "available from A&AI - {}". format(name, complex_link)) - self.triage_translator.collectDroppedCandiate(candidate['candidate_id'], candidate['location_id'], name, triage_translator_data, - reason="complex information not available from A&AI") + self.triage_translator.collectDroppedCandiate(info['candidate_id'], other['location_id'], name, + triage_translator_data, + reason="complex information not available from A&AI") continue # move ahead with the next vnf - candidate['physical_location_id'] = \ - complex_id - candidate['complex_name'] = \ - complex_info.get('complex-name') - candidate['latitude'] = \ - complex_info.get('latitude') - candidate['longitude'] = \ - complex_info.get('longitude') - candidate['state'] = \ - complex_info.get('state') - candidate['country'] = \ - complex_info.get('country') - candidate['city'] = \ - complex_info.get('city') - candidate['region'] = \ - complex_info.get('region') - - self.add_passthrough_attributes(candidate, passthrough_attributes, name, triage_translator_data) + + complex_info = self.build_complex_dict(complex_info, inventory_type) + transport_candidate = Transport(info=info, zone=zone_info, complex=complex_info, additional_fiels=other) + candidate = transport_candidate.convert_nested_dict_to_dict() + + self.add_passthrough_attributes(candidate, passthrough_attributes, name) # add candidate to demand candidates resolved_demands[name].append(candidate) @@ -1889,13 +1650,150 @@ class AAI(base.InventoryProviderBase): " {}".format(inventory_type)) return resolved_demands - def add_passthrough_attributes(self, candidate, passthrough_attributes, demand_name, triage_translator_data): + @staticmethod + def build_complex_dict(aai_complex, inv_type): + complex_info = dict() + valid_keys = ['physical-location-id', 'complex-name', 'latitude', 'longitude', 'state', 'country', 'city', + 'region'] + # for cloud type, complex_id instead of physical-location-id - note + if inv_type == "cloud": + for valid_key in valid_keys: + if '-' in valid_key: + complex_info[valid_key.replace('-', '_')] = aai_complex.get('complex_id') if valid_key == 'physical-location-id' else \ + aai_complex.get(valid_key.replace('-', '_')) + else: + complex_info[valid_key] = aai_complex.get(valid_key) + else: + for valid_key in valid_keys: + if '-' in valid_key: + complex_info[valid_key.replace('-', '_')] = aai_complex.get(valid_key) + else: + complex_info[valid_key] = aai_complex.get(valid_key) + return complex_info + + @staticmethod + def build_vlan_info(vlan_key, port_key): + vlan_info = dict() + vlan_info['vlan_key'] = vlan_key + vlan_info['port_key'] = port_key + return vlan_info + + def resolve_flavors_for_region(self, flavors_obj): + if self.conf.HPA_enabled: + flavors = dict() + flavors['flavors'] = flavors_obj + return flavors + + def resolve_v_server_and_complex_link_for_vnf(self, candidate_id, cloud, vnf, name, triage_translator_data, + service_type): + vs_link_list = self.resolve_v_server_links_for_vnf(vnf) + for vs_link in vs_link_list: + body = self.resolve_v_server_for_candidate(candidate_id, cloud['location_id'], + vs_link, True, name, triage_translator_data) + if body is None: + continue + rl_data = self.resolve_complex_info_link_for_v_server(candidate_id, body, + cloud['cloud_owner'], cloud['location_id'], + service_type, name, triage_translator_data) + if rl_data is None: + continue + yield body, rl_data + + def get_l_interfaces_from_vserver(self, candidate_id, location_id, v_server, name, triage_translator_data): + if not v_server.get('l-interfaces') or not v_server.get('l-interfaces').get('l-interface'): + self.triage_translator.collectDroppedCandiate(candidate_id, + location_id, name, + triage_translator_data, + reason="VF-server interfaces error") + return None + else: + l_interfaces = v_server.get('l-interfaces').get('l-interface') + l_interfaces_list = list() + + for l_interface in l_interfaces: + vserver_interface = dict() + vserver_interface['interface-id'] = l_interface.get('interface-id') + vserver_interface['interface-name'] = l_interface.get('interface-name') + vserver_interface['macaddr'] = l_interface.get('macaddr') + vserver_interface['network-id'] = l_interface.get('network-name') + vserver_interface['network-name'] = '' + vserver_interface['ipv4-addresses'] = list() + vserver_interface['ipv6-addresses'] = list() + + if l_interface.get('l3-interface-ipv4-address-list'): + for ip_address_info in l_interface.get('l3-interface-ipv4-address-list'): + vserver_interface['ipv4-addresses']. \ + append(ip_address_info.get('l3-interface-ipv4-address')) + + if l_interface.get('l3-interface-ipv6-address-list'): + for ip_address_info in l_interface.get('l3-interface-ipv6-address-list'): + vserver_interface['ipv6-addresses']. \ + append(ip_address_info.get('l3-interface-ipv6-address')) + + l_interfaces_list.append(vserver_interface) + return l_interfaces_list + + @staticmethod + def get_vnf_info(vnf): + # some validation should happen + vnf_info = dict() + vnf_info['host_id'] = vnf.get("vnf-name") + vnf_info['nf-name'] = vnf.get("vnf-name") + vnf_info['nf-id'] = vnf.get("vnf-id") + vnf_info['nf-type'] = 'vnf' + vnf_info['vnf-type'] = vnf.get("vnf-type") + vnf_info['ipv4-oam-address'] = vnf.get("ipv4-oam-address") if vnf.get("ipv4-oam-address") else "" + vnf_info['ipv6-oam-address'] = vnf.get("ipv6-oam-address") if vnf.get("ipv6-oam-address") else "" + return vnf_info + + @staticmethod + def resolve_cloud_for_region(region, region_id): + cloud = dict() + valid_keys = ['cloud_owner', 'cloud_region_version', 'location_id'] + for valid_key in valid_keys: + cloud[valid_key] = region.get(valid_key) if not valid_key == 'location_id' else region_id + cloud['location_type'] = 'att_aic' + return cloud + + @staticmethod + def get_vf_module(vf_module): + vf_module_info = dict() + vf_module_info['vf-module-name'] = vf_module.get("vf-module-name") + vf_module_info['vf-module-id'] = vf_module.get("vf-module-id") + return vf_module_info + + def get_vim_id(self, cloud_owner, cloud_region_id): + if self.conf.HPA_enabled: + return cloud_owner + '_' + cloud_region_id + + @staticmethod + def add_passthrough_attributes(candidate, passthrough_attributes, demand_name): if passthrough_attributes is None: return if len(passthrough_attributes.items()) > 0: candidate['passthrough_attributes'] = dict() - for key, value in passthrough_attributes.items(): - candidate['passthrough_attributes'][key] = value + for key, value in passthrough_attributes.items(): + candidate['passthrough_attributes'][key] = value + + def resolve_zone_for_vnf(self, candidate_id, location_id, vnf, name, triage_translator_data): + related_to = "zone" + zone_link = self._get_aai_rel_link( + data=vnf, related_to=related_to) + if not zone_link: + LOG.error("Zone information not available from A&AI for transport candidates") + self.triage_translator.collectDroppedCandiate(candidate_id, location_id, + name, triage_translator_data, + reason="Zone information not available from A&AI for transport candidates") + return None + zone_aai_path = self._get_aai_path_from_link(zone_link) + response = self._request('get', path=zone_aai_path, data=None) + if response is None or response.status_code != 200: + self.triage_translator.collectDroppedCandiate(candidate_id, location_id, name, + triage_translator_data, + reason=response.status_code) + return None + body = response.json() + return body def match_region(self, candidate, restricted_region_id, restricted_complex_id, demand_name, triage_translator_data): if self.match_candidate_attribute( diff --git a/conductor/conductor/data/plugins/inventory_provider/candidates/candidate.py b/conductor/conductor/data/plugins/inventory_provider/candidates/candidate.py new file mode 100644 index 0000000..7f241c3 --- /dev/null +++ b/conductor/conductor/data/plugins/inventory_provider/candidates/candidate.py @@ -0,0 +1,52 @@ +# +# ------------------------------------------------------------------------- +# Copyright (C) 2020 Wipro Limited. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ------------------------------------------------------------------------- +# + +class Candidate: + def __init__(self, info): + self.candidate_id = info.get('candidate_id') + if info.get('candidate_type'): + self.candidate_type = info.get('candidate_type') + self.inventory_provider = info.get('inventory_provider') + self.inventory_type = info.get('inventory_type') + self.uniqueness = info.get('uniqueness') + self.cost = info.get('cost') + self.service_resource_id = info.get('service_resource_id', None) + + def convert_nested_dict_to_dict(self): + candidate = dict() + nested_dict = self.__dict__ + keys = nested_dict.keys() + for key in keys: + if type(nested_dict.get(key)) == dict: + candidate.update(nested_dict.get(key, {})) + else: + candidate[key] = nested_dict.get(key, "") + return candidate + + @staticmethod + def build_candidate_info(inv_prov, inv_type, cost, uniqueness, id, service_resource_id=None): + info = dict() + info['candidate_id'] = id + # info['candidate_type'] + info['inventory_provider'] = inv_prov + info['inventory_type'] = inv_type + info['uniqueness'] = uniqueness + info['cost'] = cost + info['service_resource_id'] = service_resource_id + return info diff --git a/conductor/conductor/data/plugins/inventory_provider/candidates/cloud_candidate.py b/conductor/conductor/data/plugins/inventory_provider/candidates/cloud_candidate.py new file mode 100644 index 0000000..3507126 --- /dev/null +++ b/conductor/conductor/data/plugins/inventory_provider/candidates/cloud_candidate.py @@ -0,0 +1,30 @@ +# +# ------------------------------------------------------------------------- +# Copyright (C) 2020 Wipro Limited. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ------------------------------------------------------------------------- +# + + +from conductor.data.plugins.inventory_provider.candidates.candidate import Candidate + + +class Cloud(Candidate): + def __init__(self, **kwargs): + super().__init__(kwargs['info']) + self.cloud_region = kwargs['cloud_region'] + self.complex = kwargs['complex'] + self.flavors = kwargs['flavors'] + self.additional_fields = kwargs['additional_fields'] \ No newline at end of file diff --git a/conductor/conductor/data/plugins/inventory_provider/candidates/service_candidate.py b/conductor/conductor/data/plugins/inventory_provider/candidates/service_candidate.py new file mode 100644 index 0000000..d13a670 --- /dev/null +++ b/conductor/conductor/data/plugins/inventory_provider/candidates/service_candidate.py @@ -0,0 +1,33 @@ +# +# ------------------------------------------------------------------------- +# Copyright (C) 2020 Wipro Limited. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ------------------------------------------------------------------------- +# + +from conductor.data.plugins.inventory_provider.candidates.candidate import Candidate + + +class Service(Candidate): + def __init__(self, **kwargs): + super().__init__(kwargs['info']) + self.generic_vnf = kwargs['generic_vnf'] + self.cloud_region = kwargs['cloud_region'] + self.complex = kwargs['complex'] + self.additional_fields = kwargs['additional_fields'] + self.vlan = kwargs['vlan'] + + + diff --git a/conductor/conductor/data/plugins/inventory_provider/candidates/transport_candidate.py b/conductor/conductor/data/plugins/inventory_provider/candidates/transport_candidate.py new file mode 100644 index 0000000..e2840c0 --- /dev/null +++ b/conductor/conductor/data/plugins/inventory_provider/candidates/transport_candidate.py @@ -0,0 +1,28 @@ +# +# ------------------------------------------------------------------------- +# Copyright (C) 2020 Wipro Limited. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ------------------------------------------------------------------------- +# + +from conductor.data.plugins.inventory_provider.candidates.candidate import Candidate + + +class Transport(Candidate): + def __init__(self, **kwargs): + super().__init__(kwargs['info']) + self.zone = kwargs['zone'] + self.complex = kwargs['complex'] + self.additional_fields = kwargs['additional_fields'] diff --git a/conductor/conductor/data/plugins/inventory_provider/candidates/vfmodule_candidate.py b/conductor/conductor/data/plugins/inventory_provider/candidates/vfmodule_candidate.py new file mode 100644 index 0000000..c9d99ae --- /dev/null +++ b/conductor/conductor/data/plugins/inventory_provider/candidates/vfmodule_candidate.py @@ -0,0 +1,34 @@ +# +# ------------------------------------------------------------------------- +# Copyright (C) 2020 Wipro Limited. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ------------------------------------------------------------------------- +# + + +from conductor.data.plugins.inventory_provider.candidates.candidate import Candidate + + +class VfModule(Candidate): + def __init__(self,**kwargs): + super().__init__(kwargs['info']) + self.generic_vnf = kwargs['generic_vnf'] + self.cloud_region = kwargs['cloud_region'] + self.service_instance = kwargs['service_instance'] + self.vf_module = kwargs['vf_module'] + self.vserver = kwargs['vserver'] + self.complex = kwargs['complex'] + self.vlan = kwargs['vlan'] + self.additional_fields = kwargs['additional_fields'] \ No newline at end of file diff --git a/conductor/conductor/tests/unit/data/plugins/inventory_provider/test_aai.py b/conductor/conductor/tests/unit/data/plugins/inventory_provider/test_aai.py index 295057f..55bdef9 100644 --- a/conductor/conductor/tests/unit/data/plugins/inventory_provider/test_aai.py +++ b/conductor/conductor/tests/unit/data/plugins/inventory_provider/test_aai.py @@ -17,15 +17,16 @@ # # ------------------------------------------------------------------------- # +import copy import json +import mock import unittest -import copy + +from oslo_config import cfg import conductor.data.plugins.inventory_provider.aai as aai -import mock from conductor.data.plugins.inventory_provider.aai import AAI from conductor.data.plugins.triage_translator.triage_translator import TraigeTranslator -from oslo_config import cfg class TestAAI(unittest.TestCase): @@ -52,7 +53,6 @@ class TestAAI(unittest.TestCase): self.assertEqual('/{}/query?format=id'.format(self.conf.aai.server_url_version), self.aai_ep._aai_versioned_path("/query?format=id")) - def test_resolve_clli_location(self): req_json_file = './conductor/tests/unit/data/plugins/inventory_provider/_request_clli_location.json' @@ -150,9 +150,10 @@ class TestAAI(unittest.TestCase): return_value=regions_list) self.mock_resolve_cloud_regions_by_cloud_region_id.start() - self.mock_resolove_v_server_for_candidate = mock.patch.object(AAI, 'resolove_v_server_for_candidate', + + self.mock_resolve_v_server_for_candidate = mock.patch.object(AAI, 'resolve_v_server_for_candidate', return_value=demand_service_response) - self.mock_resolove_v_server_for_candidate.start() + self.mock_resolve_v_server_for_candidate.start() complex_link = {"link": "/aai/v10/complex-id", "d_value": 'test-id'} self.mock_resolve_complex_info_link_for_v_server = mock.patch.object(AAI, @@ -165,7 +166,7 @@ class TestAAI(unittest.TestCase): flavor_info = regions_response["region-name"]["flavors"] self.maxDiff = None - self.assertEqual({u'demand_name': [ + self.assertCountEqual({u'demand_name': [ {'candidate_id': u'service-instance-id', 'city': None, 'cloud_owner': u'cloud-owner', 'uniqueness': 'true', @@ -249,9 +250,9 @@ class TestAAI(unittest.TestCase): return_value=regions) self.mock_resolve_cloud_regions_by_cloud_region_id.start() - self.mock_resolove_v_server_for_candidate = mock.patch.object(AAI, 'resolove_v_server_for_candidate', + self.mock_resolve_v_server_for_candidate = mock.patch.object(AAI, 'resolve_v_server_for_candidate', return_value=v_server) - self.mock_resolove_v_server_for_candidate.start() + self.mock_resolve_v_server_for_candidate.start() complex_link = {"link": "/aai/v14/cloud-infrastructure/complexes/complex/clli1", "d_value": 'clli1'} self.mock_resolve_complex_info_link_for_v_server = mock.patch.object(AAI, @@ -327,9 +328,9 @@ class TestAAI(unittest.TestCase): return_value=regions) self.mock_resolve_cloud_regions_by_cloud_region_id.start() - self.mock_resolove_v_server_for_candidate = mock.patch.object(AAI, 'resolove_v_server_for_candidate', + self.mock_resolve_v_server_for_candidate = mock.patch.object(AAI, 'resolve_v_server_for_candidate', return_value=v_server) - self.mock_resolove_v_server_for_candidate.start() + self.mock_resolve_v_server_for_candidate.start() complex_link = {"link": "/aai/v14/cloud-infrastructure/complexes/complex/clli1", "d_value": 'clli1'} self.mock_resolve_complex_info_link_for_v_server = mock.patch.object(AAI, 'resolve_complex_info_link_for_v_server', @@ -356,10 +357,9 @@ class TestAAI(unittest.TestCase): self.mock_get_request = mock.patch.object(AAI, '_request', return_value=response) self.mock_get_request.start() - self.assertEqual({u'city': u'Middletown', u'latitude': u'28.543251', u'longitude': u'-81.377112', u'country': u'USA', u'region': u'SE'} , + self.assertEqual({u'city': u'Middletown', u'latitude': u'28.543251', u'longitude': u'-81.377112', u'country': u'USA', u'region': u'SE'}, self.aai_ep._get_complex("/v10/complex/complex_id", "complex_id")) - def test_check_network_roles(self): network_role_json_file = './conductor/tests/unit/data/plugins/inventory_provider/_request_network_role.json' @@ -375,7 +375,6 @@ class TestAAI(unittest.TestCase): self.assertEqual(set(['test-cloud-value']) , self.aai_ep.check_network_roles("network_role_id")) - def test_check_candidate_role(self): candidate_role_json_file = './conductor/tests/unit/data/plugins/inventory_provider/_request_candidate_role.json' @@ -488,10 +487,9 @@ class TestAAI(unittest.TestCase): region_response_file = './conductor/tests/unit/data/plugins/inventory_provider/vfmodule_region.json' region_response = json.loads(open(region_response_file).read()) - candidate = dict() - candidate['candidate_id'] = 'some_id' - candidate['location_id'] = 'some_location_id' - candidate['inventory_type'] = 'service' + candidate_id = 'some_id' + location_id = 'some_location_id' + inventory_type = 'service' response = mock.MagicMock() response.status_code = 200 @@ -501,13 +499,13 @@ class TestAAI(unittest.TestCase): self.mock_get_request = mock.patch.object(AAI, '_request', return_value=response) self.mock_get_request.start() - link_rl_data = self.aai_ep.resolve_complex_info_link_for_v_server(candidate, v_server, None, + link_rl_data = self.aai_ep.resolve_complex_info_link_for_v_server(candidate_id, v_server, None, cloud_region_id, service_type, demand_name, triage_translator_data) self.assertEqual(None, link_rl_data) complex_link = {"link": "/aai/v14/cloud-infrastructure/complexes/complex/clli1", "d_value": 'clli1'} - link_rl_data = self.aai_ep.resolve_complex_info_link_for_v_server(candidate, v_server, cloud_owner, + link_rl_data = self.aai_ep.resolve_complex_info_link_for_v_server(candidate_id, v_server, cloud_owner, cloud_region_id, service_type, demand_name, triage_translator_data) self.assertEqual(complex_link, link_rl_data) @@ -533,26 +531,25 @@ class TestAAI(unittest.TestCase): self.mock_get_complex = mock.patch.object(AAI, '_get_complex', return_value=complex_response) self.mock_get_complex.start() - self.aai_ep.build_complex_info_for_candidate(candidate, None, complex_list_empty, service_type, demand_name, + self.aai_ep.build_complex_info_for_candidate(candidate['candidate_id'], candidate['location_id'], None, complex_list_empty, candidate['inventory_type'], demand_name, triage_translator_data) self.assertEqual(initial_candidate, candidate) self.assertEqual(1, TraigeTranslator.collectDroppedCandiate.call_count) - self.aai_ep.build_complex_info_for_candidate(candidate, None, complex_list, service_type, demand_name, + self.aai_ep.build_complex_info_for_candidate(candidate['candidate_id'], candidate['location_id'], None, complex_list, candidate['inventory_type'], demand_name, triage_translator_data) self.assertEqual(initial_candidate, candidate) self.assertEqual(2, TraigeTranslator.collectDroppedCandiate.call_count) complex_list.pop() - self.aai_ep.build_complex_info_for_candidate(candidate, None, complex_list, service_type, demand_name, + self.aai_ep.build_complex_info_for_candidate(candidate['candidate_id'], candidate['location_id'], None, complex_list, candidate['inventory_type'], demand_name, triage_translator_data) - self.assertEqual(candidate, {'city': u'example-city-val-27150', 'country': u'example-country-val-94173', - 'region': u'example-region-val-13893', 'inventory_type': 'service', - 'longitude': u'32.89948', 'state': u'example-state-val-59487', + self.assertEqual(self.aai_ep.build_complex_info_for_candidate(candidate['candidate_id'], candidate['location_id'], None, complex_list, candidate['inventory_type'], demand_name, + triage_translator_data), {'city': u'example-city-val-27150', 'country': u'example-country-val-94173', + 'region': u'example-region-val-13893', 'longitude': u'32.89948', 'state': u'example-state-val-59487', 'physical_location_id': 'clli1', 'latitude': u'example-latitude-val-89101', - 'complex_name': u'clli1', 'location_id': 'some_location_id', - 'candidate_id': 'some_id'}) + 'complex_name': u'clli1'}) self.assertEqual(2, TraigeTranslator.collectDroppedCandiate.call_count) def test_resolve_vnf_parameters(self): @@ -561,8 +558,8 @@ class TestAAI(unittest.TestCase): demand_name = 'vPGN' service_type = 'vFW' candidate = dict() - candidate['candidate_id'] = 'some_id' - candidate['location_id'] = 'some_location_id' + candidate_id = 'some_id' + location_id = 'some_location_id' candidate['inventory_type'] = 'service' generic_vnf_list_file = './conductor/tests/unit/data/plugins/inventory_provider/vfmodule_service_generic_vnf_list.json' @@ -572,26 +569,22 @@ class TestAAI(unittest.TestCase): region_response_file = './conductor/tests/unit/data/plugins/inventory_provider/vfmodule_region.json' region_response = json.loads(open(region_response_file).read()) - self.assertEqual("CloudOwner", - self.aai_ep.resolve_cloud_owner_for_vnf(candidate, good_vnf, service_type, - demand_name, triage_translator_data).get('d_value')) - self.assertIsNone(self.aai_ep.resolve_cloud_owner_for_vnf(candidate, bad_vnf, service_type, - demand_name, triage_translator_data)) - regions = list() regions.append(region_response) self.mock_get_regions = mock.patch.object(AAI, 'resolve_cloud_regions_by_cloud_region_id', return_value=regions) self.mock_get_regions.start() - cloud_region_rl_data, cloud_region_ver_rl_data = self.aai_ep.resolve_cloud_region_id_and_version_for_vnf( - candidate, good_vnf, service_type, demand_name, triage_translator_data) - self.assertEqual("RegionOne", cloud_region_rl_data.get('d_value')) - self.assertEqual("1", cloud_region_ver_rl_data.get('d_value')) + good_cloud_info = self.aai_ep.resolve_cloud_for_vnf(candidate_id, location_id, good_vnf, service_type, + demand_name, triage_translator_data) + bad_cloud_info = self.aai_ep.resolve_cloud_for_vnf(candidate_id, location_id, bad_vnf, service_type, + demand_name, triage_translator_data) + self.assertEqual("CloudOwner", good_cloud_info['cloud_owner']) + self.assertEqual("RegionOne", good_cloud_info['location_id']) + self.assertEqual("1", good_cloud_info['cloud_region_version']) + + self.assertIsNone(bad_cloud_info) - self.assertEqual((None, None), - self.aai_ep.resolve_cloud_region_id_and_version_for_vnf(candidate, bad_vnf, service_type, - demand_name, triage_translator_data)) v_server_links = list() v_server_links.append("/aai/v14/cloud-infrastructure/cloud-regions/cloud-region/CloudOwner/RegionOne/tenants/\ tenant/3c6c471ada7747fe8ff7f28e100b61e8/vservers/vserver/00bddefc-126e-4e4f-a18d-99b94d8d9a30") @@ -601,14 +594,14 @@ tenant/3c6c471ada7747fe8ff7f28e100b61e8/vservers/vserver/00bddefc-126e-4e4f-a18d customer_id = 'Demonstration' self.assertEqual(customer_id, - self.aai_ep.resolve_global_customer_id_for_vnf(candidate, good_vnf, customer_id, service_type, + self.aai_ep.resolve_global_customer_id_for_vnf(candidate_id, location_id, good_vnf, customer_id, service_type, demand_name, triage_translator_data).get('d_value')) self.assertEqual("3e8d118c-10ca-4b4b-b3db-089b5e9e6a1c", - self.aai_ep.resolve_service_instance_id_for_vnf(candidate, good_vnf, customer_id, service_type, + self.aai_ep.resolve_service_instance_id_for_vnf(candidate_id, location_id, good_vnf, customer_id, service_type, demand_name, triage_translator_data).get('d_value')) - self.assertIsNone(self.aai_ep.resolve_service_instance_id_for_vnf(candidate, bad_vnf, customer_id, service_type, + self.assertIsNone(self.aai_ep.resolve_service_instance_id_for_vnf(candidate_id, location_id, bad_vnf, customer_id, service_type, demand_name, triage_translator_data)) def test_add_passthrough_parameters(self): @@ -628,7 +621,7 @@ tenant/3c6c471ada7747fe8ff7f28e100b61e8/vservers/vserver/00bddefc-126e-4e4f-a18d candidate_info['passthrough_attributes']['param_one'] = "value" candidate_info['passthrough_attributes']['param_two'] = "value" - self.aai_ep.add_passthrough_attributes(candidate, parameters, 'demand', None) + self.aai_ep.add_passthrough_attributes(candidate, parameters, 'demand') self.assertDictEqual(candidate, candidate_info) def test_match_candidate_by_list(self): -- cgit 1.2.3-korg