From 845592d74de62986a392fb41f06dbfa67257ff64 Mon Sep 17 00:00:00 2001 From: Ruoyu Ying Date: Tue, 18 Sep 2018 01:21:27 +0800 Subject: Support new policy model in HAS Make changes to support the newly defined policy model Change-Id: Iea882b0c254c4bfca32da2458ea65f3daf56a779 Issue-ID: OPTFRA-322 Signed-off-by: Ruoyu Ying --- conductor/conductor/controller/translator.py | 20 +- .../data/plugins/inventory_provider/aai.py | 4 +- .../data/plugins/inventory_provider/hpa_utils.py | 36 +- conductor/conductor/data/service.py | 94 ++-- .../conductor/solver/optimizer/constraints/hpa.py | 10 +- conductor/conductor/solver/service.py | 23 +- .../solver/utils/constraint_engine_interface.py | 6 +- .../tests/unit/controller/hpa_constraints.json | 46 +- .../tests/unit/controller/test_translator.py | 74 ++- .../conductor/tests/unit/data/hpa_constraints.json | 46 +- .../plugins/inventory_provider/hpa_flavors.json | 99 ++++ .../inventory_provider/hpa_req_features.json | 519 +++++++++++++-------- .../data/plugins/inventory_provider/test_aai.py | 77 +-- .../conductor/tests/unit/data/test_service.py | 33 +- .../tests/unit/solver/hpa_constraints.json | 40 +- 15 files changed, 799 insertions(+), 328 deletions(-) diff --git a/conductor/conductor/controller/translator.py b/conductor/conductor/controller/translator.py index fb591e0..4f0ed20 100644 --- a/conductor/conductor/controller/translator.py +++ b/conductor/conductor/controller/translator.py @@ -105,7 +105,7 @@ CONSTRAINTS = { }, } HPA_FEATURES = ['architecture', 'hpa-feature', 'hpa-feature-attributes', - 'hpa-version', 'mandatory'] + 'hpa-version', 'mandatory', 'directives'] HPA_OPTIONAL = ['score'] HPA_ATTRIBUTES = ['hpa-attribute-key', 'hpa-attribute-value', 'operator'] HPA_ATTRIBUTES_OPTIONAL = ['unit'] @@ -553,14 +553,18 @@ class Translator(object): def validate_hpa_constraints(self, req_prop, value): for para in value.get(req_prop): # Make sure there is at least one - # set of flavorLabel and flavorProperties - if not para.get('flavorLabel') \ + # set of id, type, directives and flavorProperties + if not para.get('id') \ + or not para.get('type') \ + or not para.get('directives') \ or not para.get('flavorProperties') \ - or para.get('flavorLabel') == '' \ + or para.get('id') == '' \ + or para.get('type') == '' \ + or not isinstance(para.get('directives'), list) \ or para.get('flavorProperties') == '': raise TranslatorException( "HPA requirements need at least " - "one set of flavorLabel and flavorProperties" + "one set of id, type, directives and flavorProperties" ) for feature in para.get('flavorProperties'): if type(feature) is not dict: @@ -574,7 +578,7 @@ class Translator(object): hpa_optional = set(feature.keys()).difference(HPA_FEATURES) if hpa_optional and not hpa_optional.issubset(HPA_OPTIONAL): raise TranslatorException( - "Lack of compulsory elements inside HPA feature") + "Got unrecognized elements inside HPA feature") if feature.get('mandatory') == 'False' and not feature.get( 'score'): raise TranslatorException( @@ -591,7 +595,7 @@ class Translator(object): if bool(hpa_attr_mandatory): raise TranslatorException( "Lack of compulsory elements inside HPA " - "feature atrributes") + "feature attributes") # process optional hpa attribute parameter hpa_attr_optional = set(attr.keys()).difference( HPA_ATTRIBUTES) @@ -649,7 +653,7 @@ class Translator(object): "No value specified for property '{}' in " "constraint named '{}'".format( req_prop, name)) - # For HPA constraints + # For HPA constraints if constraint_type == 'hpa': self.validate_hpa_constraints(req_prop, value) diff --git a/conductor/conductor/data/plugins/inventory_provider/aai.py b/conductor/conductor/data/plugins/inventory_provider/aai.py index d23a483..8634b3f 100644 --- a/conductor/conductor/data/plugins/inventory_provider/aai.py +++ b/conductor/conductor/data/plugins/inventory_provider/aai.py @@ -1340,6 +1340,6 @@ class AAI(base.InventoryProviderBase): def match_hpa(self, candidate, features): """Match HPA features requirement with the candidate flavors """ hpa_provider = hpa_utils.HpaMatchProvider(candidate, features) - flavor_map = hpa_provider.match_flavor() - return flavor_map + directives = hpa_provider.match_flavor() + return directives diff --git a/conductor/conductor/data/plugins/inventory_provider/hpa_utils.py b/conductor/conductor/data/plugins/inventory_provider/hpa_utils.py index 648775a..2414e61 100644 --- a/conductor/conductor/data/plugins/inventory_provider/hpa_utils.py +++ b/conductor/conductor/data/plugins/inventory_provider/hpa_utils.py @@ -69,7 +69,7 @@ class HpaMatchProvider(object): if hpa_list not in req_filter_list: req_filter_list.append(hpa_list) max_score = -1 - flavor_map = None + directives = None for flavor in self.flavors_list: flavor_filter_list = [] try: @@ -84,7 +84,7 @@ class HpaMatchProvider(object): flavor_filter_list.append(hpa_list) # if flavor has the matching capability compare attributes if self._is_cap_supported(flavor_filter_list, req_filter_list): - match_found, score = self._compare_feature_attributes(flavor_cap_list) + match_found, score, req_directives = self._compare_feature_attributes(flavor_cap_list) if match_found: LOG.info(_LI("Matching Flavor found '{}' for request - {}"). format(flavor['flavor-name'], self.req_cap_list)) @@ -93,7 +93,9 @@ class HpaMatchProvider(object): flavor_map = {"flavor-id": flavor['flavor-id'], "flavor-name": flavor['flavor-name'], "score": max_score} - return flavor_map + directives = {"flavor_map": flavor_map, + "directives": req_directives} + return directives def _is_cap_supported(self, flavor, cap): @@ -212,7 +214,7 @@ class HpaMatchProvider(object): for capability in CapabilityDataParser.get_item(flavor_cap_list, 'hpa-capability'): flavor_feature, feature_attributes = capability.get_fields() - # One feature will match this condition as we have pre-filtered + # Multiple features will match this condition as we have pre-filtered if feature == flavor_feature: return feature_attributes @@ -221,24 +223,31 @@ class HpaMatchProvider(object): # and compare each attribute def _compare_feature_attributes(self, flavor_cap_list): score = 0 + directives = [] for capability in CapabilityDataParser.get_item(self.req_cap_list, None): hpa_feature, req_cfa_list = capability.get_fields() + feature_directive = capability.get_directives() + if feature_directive: + feature_directive[:] = [d for d in feature_directive + if d.get("type") != ""] + for item in feature_directive: + directives.append(item) flavor_cfa_list = self._get_flavor_cfa_list(hpa_feature, flavor_cap_list) if flavor_cfa_list is not None: for req_feature_attr in req_cfa_list: req_attr_key = req_feature_attr['hpa-attribute-key'] - # filter to get the attribute being compared + # filter to get the attribute being compared flavor_feature_attr = \ filter(lambda ele: ele['hpa-attribute-key'] == \ - req_attr_key, flavor_cfa_list) - if not flavor_feature_attr: - return False, 0 - if not self._compare_attribute(flavor_feature_attr[0], - req_feature_attr): - return False, 0 + req_attr_key, flavor_cfa_list) + if not flavor_feature_attr and capability.item['mandatory'] == 'True': + return False, 0, None + if not self._compare_attribute(flavor_feature_attr[0], req_feature_attr) \ + and capability.item['mandatory'] == 'True': + return False, 0, None if flavor_cfa_list is not None and capability.item['mandatory'] == 'False': score = score + int(capability.item['score']) - return True, score + return True, score, directives class CapabilityDataParser(object): @@ -269,3 +278,6 @@ class CapabilityDataParser(object): def get_feature(self): return self.item.get('hpa-feature') + + def get_directives(self): + return self.item.get('directives') diff --git a/conductor/conductor/data/service.py b/conductor/conductor/data/service.py index 0af7bb7..d6ea20f 100644 --- a/conductor/conductor/data/service.py +++ b/conductor/conductor/data/service.py @@ -52,13 +52,13 @@ DATA_OPTS = [ 'mode. When set to False, data will flush any abandoned ' 'messages at startup.'), cfg.FloatOpt('existing_placement_cost', - default=-8000.0, - help='Default value is -8000, which is the diameter of the earth. ' - 'The distance cannot larger than this value'), + default=-8000.0, + help='Default value is -8000, which is the diameter of the earth. ' + 'The distance cannot larger than this value'), cfg.FloatOpt('cloud_candidate_cost', - default=2.0), + default=2.0), cfg.FloatOpt('service_candidate_cost', - default=1.0), + default=1.0), ] CONF.register_opts(DATA_OPTS, group='data') @@ -223,7 +223,7 @@ class DataEndpoint(object): discard_set.add(candidate.get("candidate_id")) return discard_set - #(TODO:Larry) merge this function with the "get_candidate_discard_set" + # (TODO:Larry) merge this function with the "get_candidate_discard_set" def get_candidate_discard_set_by_cloud_region(self, value, candidate_list, value_attrib): discard_set = set() @@ -239,10 +239,8 @@ class DataEndpoint(object): (candidate.get(value_attrib) not in service_requests): discard_set.add(candidate.get("candidate_id")) - return discard_set - def get_inventory_group_candidates(self, ctx, arg): candidate_list = arg["candidate_list"] resolved_candidate = arg["resolved_candidate"] @@ -442,18 +440,22 @@ class DataEndpoint(object): ''' error = False candidate_list = arg["candidate_list"] - label_name = arg["label_name"] + id = arg["id"] + type = arg["type"] + directives = arg["directives"] + attr = directives[0].get("attributes") + label_name = attr[0].get("attribute_name") flavorProperties = arg["flavorProperties"] discard_set = set() - for candidate in candidate_list: + for i in range(len(candidate_list)): # perform this check only for cloud candidates - if candidate["inventory_type"] != "cloud": + if candidate_list[i]["inventory_type"] != "cloud": continue # Check if flavor mapping for current label_name already # exists. This is an invalid condition. - if candidate.get("flavor_map") and candidate["flavor_map"].get( - label_name): + if candidate_list[i].get("directives") and attr[0].get( + "attribute_value") != "": LOG.error(_LE("Flavor mapping for label name {} already" "exists").format(label_name)) continue @@ -461,36 +463,44 @@ class DataEndpoint(object): # RPC call to inventory provider for matching hpa capabilities results = self.ip_ext_manager.map_method( 'match_hpa', - candidate=candidate, + candidate=candidate_list[i], features=flavorProperties ) - if results and len(results) > 0: - flavor_info = results[0] + flavor_name = None + if results and len(results) > 0 and results[0] is not None: + LOG.debug("Find results {} and results length {}".format(results, len(results))) + flavor_info = results[0].get("flavor_map") + req_directives = results[0].get("directives") + LOG.debug("Get directives {}".format(req_directives)) + else: flavor_info = None LOG.info( _LW("No flavor mapping returned by " "inventory provider: {} for candidate: {}").format( self.ip_ext_manager.names()[0], - candidate.get("candidate_id"))) + candidate_list[i].get("candidate_id"))) if not flavor_info: - discard_set.add(candidate.get("candidate_id")) + discard_set.add(candidate_list[i].get("candidate_id")) else: if not flavor_info.get("flavor-name"): - discard_set.add(candidate.get("candidate_id")) + discard_set.add(candidate_list[i].get("candidate_id")) else: - # Create flavor_map if not exist already - if not candidate.get("flavor_map"): - candidate["flavor_map"] = {} + if not candidate_list[i].get("flavor_map"): + candidate_list[i]["flavor_map"] = {} # Create flavor mapping for label_name to flavor flavor_name = flavor_info.get("flavor-name") - candidate["flavor_map"][label_name] = flavor_name - # If hpa_score is not defined then initialize value 0 - # hpa_score = sum of scores of each vnfc hpa requirement score - if not candidate.get("hpa_score"): - candidate["hpa_score"] = 0 - candidate["hpa_score"] += flavor_info.get("score") + candidate_list[i]["flavor_map"][label_name] = flavor_name + # Create directives if not exist already + if not candidate_list[i].get("all_directives"): + candidate_list[i]["all_directives"] = {} + candidate_list[i]["all_directives"]["directives"] = [] + # Create flavor mapping and merge directives + self.merge_directives(candidate_list, i, id, type, directives, req_directives) + if not candidate_list[i].get("hpa_score"): + candidate_list[i]["hpa_score"] = 0 + candidate_list[i]["hpa_score"] += flavor_info.get("score") # return candidates not in discard set candidate_list[:] = [c for c in candidate_list @@ -501,6 +511,34 @@ class DataEndpoint(object): self.ip_ext_manager.names()[0])) return {'response': candidate_list, 'error': error} + def merge_directives(self, candidate_list, index, id, type, directives, feature_directives): + ''' + Merge the flavor_directives with other diectives listed under hpa capabilities in the policy + :param candidate_list: all candidates + :param index: index number + :param id: vfc name + :param type: vfc type + :param directives: directives for each vfc + :param feature_directives: directives for hpa-features + :return: + ''' + directive= {"id": id, + "type": type, + "directives": ""} + for ele in directives: + if "flavor_directives" in ele.get("type"): + flag = True + break + else: + flag = False + if not flag: + LOG.error("No flavor directives found in {}".format(id)) + for item in feature_directives: + if item and item not in directives: + directives.append(item) + directive["directives"] = directives + candidate_list[index]["all_directives"]["directives"].append(directive) + def get_candidates_with_vim_capacity(self, ctx, arg): ''' RPC for getting candidates with vim capacity diff --git a/conductor/conductor/solver/optimizer/constraints/hpa.py b/conductor/conductor/solver/optimizer/constraints/hpa.py index 98d95d9..106953b 100644 --- a/conductor/conductor/solver/optimizer/constraints/hpa.py +++ b/conductor/conductor/solver/optimizer/constraints/hpa.py @@ -54,15 +54,19 @@ class HPA(constraint.Constraint): self.constraint_type, demand_name)) vm_label_list = self.properties.get('evaluate') for vm_demand in vm_label_list: - label_name = vm_demand['flavorLabel'] + id = vm_demand['id'] + type = vm_demand['type'] + directives = vm_demand['directives'] flavorProperties = vm_demand['flavorProperties'] - response = (cei.get_candidates_with_hpa(label_name, + response = (cei.get_candidates_with_hpa(id, + type, + directives, _candidate_list, flavorProperties)) _candidate_list = response if not response: LOG.error(_LE("No matching candidates for HPA exists").format( - label_name)) + id)) break # No need to continue. diff --git a/conductor/conductor/solver/service.py b/conductor/conductor/solver/service.py index e539acd..56ec683 100644 --- a/conductor/conductor/solver/service.py +++ b/conductor/conductor/solver/service.py @@ -347,10 +347,10 @@ class SolverService(cotyledon.Service): rec["candidate"]["host_id"] = resource.get("host_id") if rec["candidate"]["inventory_type"] == "cloud": - if resource.get("flavor_map"): - rec["attributes"]["flavors"] = resource.get( - "flavor_map") - + if resource.get("all_directives") and resource.get("flavor_map"): + rec["attributes"]["directives"] = \ + self.set_flavor_in_flavor_directives( + resource.get("flavor_map"), resource.get("all_directives")) # TODO(snarayanan): Add total value to recommendations? # msg = "--- total value of decision = {}" # LOG.debug(msg.format(_best_path.total_value)) @@ -387,3 +387,18 @@ class SolverService(cotyledon.Service): """Reload""" LOG.debug("%s" % self.__class__.__name__) self._restart() + + def set_flavor_in_flavor_directives(self, flavor_map, directives): + ''' + Insert the flavor name inside the flavor_map into flavor_directives + :param flavor_map: flavor map get + :param directives: All the directives get from request + ''' + flavor_label = flavor_map.keys() + for ele in directives.get("directives"): + for item in ele.get("directives"): + if "flavor_directives" in item.get("type"): + for attr in item.get("attributes"): + attr["attribute_value"] = flavor_map.get(attr["attribute_name"]) \ + if attr.get("attribute_name") in flavor_label else "" + return directives diff --git a/conductor/conductor/solver/utils/constraint_engine_interface.py b/conductor/conductor/solver/utils/constraint_engine_interface.py index 43331aa..bbb782d 100644 --- a/conductor/conductor/solver/utils/constraint_engine_interface.py +++ b/conductor/conductor/solver/utils/constraint_engine_interface.py @@ -117,7 +117,7 @@ class ConstraintEngineInterface(object): # response is a list of (candidate, cost) tuples return response - def get_candidates_with_hpa(self, label_name, candidate_list, + def get_candidates_with_hpa(self, id, type, directives, candidate_list, flavorProperties): ''' Returns the candidate_list with an addition of flavor_mapping for @@ -130,7 +130,9 @@ class ConstraintEngineInterface(object): ctxt = {} args = {"candidate_list": candidate_list, "flavorProperties": flavorProperties, - "label_name": label_name} + "id": id, + "type": type, + "directives": directives} response = self.client.call(ctxt=ctxt, method="get_candidates_with_hpa", args=args) diff --git a/conductor/conductor/tests/unit/controller/hpa_constraints.json b/conductor/conductor/tests/unit/controller/hpa_constraints.json index 5a86ede..a2543bc 100644 --- a/conductor/conductor/tests/unit/controller/hpa_constraints.json +++ b/conductor/conductor/tests/unit/controller/hpa_constraints.json @@ -27,7 +27,8 @@ "unit": "GB" } ], - "hpa-version": "v1" + "hpa-version": "v1", + "directives": [] }, { "architecture": "generic", @@ -61,7 +62,8 @@ "unit": "GB" } ], - "hpa-version": "v1" + "hpa-version": "v1", + "directives": [] }, { "architecture": "generic", @@ -78,10 +80,23 @@ "operator": "=" } ], - "hpa-version": "v1" + "hpa-version": "v1", + "directives": [] } ], - "flavorLabel": "flavor_label_1" + "id": "vg_1", + "type": "vnfc", + "directives": [ + { + "type": "flavor_directives", + "attributes": [ + { + "attribute_name": "flavor_label_1", + "attribute_value": "" + } + ] + } + ] }, { "flavorProperties": [ @@ -101,7 +116,8 @@ "unit": "GB" } ], - "hpa-version": "v1" + "hpa-version": "v1", + "directives": [] }, { "architecture": "generic", @@ -135,7 +151,8 @@ "unit": "GB" } ], - "hpa-version": "v1" + "hpa-version": "v1", + "directives": [] }, { "architecture": "generic", @@ -148,10 +165,23 @@ "unit": "GB" } ], - "hpa-version": "v1" + "hpa-version": "v1", + "directives": [] } ], - "flavorLabel": "flavor_label_2" + "id": "vg_2", + "type": "vnfc", + "directives": [ + { + "type": "flavor_directives", + "attributes": [ + { + "attribute_name": "flavor_label_2", + "attribute_value": "" + } + ] + } + ] } ] } diff --git a/conductor/conductor/tests/unit/controller/test_translator.py b/conductor/conductor/tests/unit/controller/test_translator.py index e6575a9..c61e57e 100644 --- a/conductor/conductor/tests/unit/controller/test_translator.py +++ b/conductor/conductor/tests/unit/controller/test_translator.py @@ -232,12 +232,25 @@ class TestNoExceptionTranslator(unittest.TestCase): ], "properties": { "evaluate": [ - {'flavorLabel': 'xx', + {'id': 'vg_0', + 'type': 'vnfc', + 'directives': [ + { + "type": "flavor_directives", + "attributes": [ + { + "attribute_name": "label_0", + "attribute_value": "" + } + ] + } + ], 'flavorProperties': [{ 'hpa-feature': 'BasicCapabilities', 'hpa-version': 'v1', 'architecture': 'generic', 'mandatory': 'False', + 'directives': [], 'score': '5', 'hpa-feature-attributes': [ { @@ -264,6 +277,7 @@ class TestNoExceptionTranslator(unittest.TestCase): {'architecture': 'generic', 'mandatory': 'False', 'score': '5', + 'directives': [], 'hpa-feature': 'BasicCapabilities', 'hpa-feature-attributes': [ { @@ -279,7 +293,20 @@ class TestNoExceptionTranslator(unittest.TestCase): } ], 'hpa-version': 'v1'}], - 'flavorLabel': 'xx'}]}, + 'id': 'vg_0', + 'type': 'vnfc', + 'directives': [ + { + 'type': 'flavor_directives', + 'attributes': [ + { + 'attribute_name': 'label_0', + 'attribute_value': '' + } + ] + } + ] + }]}, 'type': 'hpa' } } @@ -295,12 +322,25 @@ class TestNoExceptionTranslator(unittest.TestCase): ], "properties": { "evaluate": [ - {'flavorLabel': 'xx', + {'id': 'vg_0', + 'type': 'vnfc', + 'directives': [ + { + 'type': 'flavor_directives', + 'attributes': [ + { + 'attribute_name': 'label_0', + 'attribute_value': '' + } + ] + } + ], 'flavorProperties': [{ 'hpa-feature': 'BasicCapabilities', 'hpa-version': 'v1', 'architecture': 'generic', 'mandatory': 'True', + 'directives': [], 'hpa-feature-attributes': [ { 'hpa-attribute-key': 'numVirtualCpu', @@ -325,6 +365,7 @@ class TestNoExceptionTranslator(unittest.TestCase): 'flavorProperties': [ {'architecture': 'generic', 'mandatory': 'True', + 'directives': [], 'hpa-feature': 'BasicCapabilities', 'hpa-feature-attributes': [ { @@ -340,7 +381,19 @@ class TestNoExceptionTranslator(unittest.TestCase): } ], 'hpa-version': 'v1'}], - 'flavorLabel': 'xx'}]}, + 'id': 'vg_0', + 'type': 'vnfc', + 'directives': [ + { + 'type': 'flavor_directives', + 'attributes': [ + { + 'attribute_name': 'label_0', + 'attribute_value': '' + } + ] + } + ]}]}, 'type': 'hpa' } } @@ -356,7 +409,7 @@ class TestNoExceptionTranslator(unittest.TestCase): "vG" ], "properties": { - "evaluate": [{'flavor': 'xx', + "evaluate": [{'id': 'xx', 'flavorProperties': []}] } } @@ -369,7 +422,8 @@ class TestNoExceptionTranslator(unittest.TestCase): ], "properties": { "evaluate": [ - {'flavorLabel': 'xx', + {'id': 'xx', + 'type': 'xx', 'flavorProperties': [ { 'hpa-feature': '', @@ -393,7 +447,9 @@ class TestNoExceptionTranslator(unittest.TestCase): "properties": { "evaluate": [ { - "flavorLabel": "xx", + "id": "xx", + "type": 'xx', + "directives": [], "flavorProperties": [ { "hpa-feature": "BasicCapabilities", @@ -422,7 +478,9 @@ class TestNoExceptionTranslator(unittest.TestCase): "vG" ], "properties": { - "evaluate": [{'flavorLabel': 'xx', + "evaluate": [{'id': 'xx', + "type": 'xx', + "directives": [], 'flavorProperties': [{ 'hpa-feature': '', 'architecture': '', diff --git a/conductor/conductor/tests/unit/data/hpa_constraints.json b/conductor/conductor/tests/unit/data/hpa_constraints.json index 829eaf3..0f42cc9 100644 --- a/conductor/conductor/tests/unit/data/hpa_constraints.json +++ b/conductor/conductor/tests/unit/data/hpa_constraints.json @@ -26,7 +26,8 @@ "unit": "GB" } ], - "hpa-version": "v1" + "hpa-version": "v1", + "directives": [] }, { "architecture": "generic", @@ -60,7 +61,8 @@ "unit": "GB" } ], - "hpa-version": "v1" + "hpa-version": "v1", + "directives": [] }, { "architecture": "generic", @@ -77,10 +79,23 @@ "operator": "=" } ], - "hpa-version": "v1" + "hpa-version": "v1", + "directives": [] } ], - "flavorLabel": "flavor_label_1" + "id": "vg_1", + "type": "vnfc", + "directives": [ + { + "type": "flavor_directives", + "attributes": [ + { + "attribute_name": "flavor_label_1", + "attribute_value": "" + } + ] + } + ] }, { "flavorProperties": [ @@ -100,7 +115,8 @@ "unit": "GB" } ], - "hpa-version": "v1" + "hpa-version": "v1", + "directives": [] }, { "architecture": "generic", @@ -134,7 +150,8 @@ "unit": "GB" } ], - "hpa-version": "v1" + "hpa-version": "v1", + "directives": [] }, { "architecture": "generic", @@ -147,10 +164,23 @@ "unit": "GB" } ], - "hpa-version": "v1" + "hpa-version": "v1", + "directives": [] } ], - "flavorLabel": "flavor_label_2" + "id": "vg_2", + "type": "vnfc", + "directives": [ + { + "type": "flavor_directives", + "attributes": [ + { + "attribute_name": "flavor_label_2", + "attribute_value": "" + } + ] + } + ] } ] } diff --git a/conductor/conductor/tests/unit/data/plugins/inventory_provider/hpa_flavors.json b/conductor/conductor/tests/unit/data/plugins/inventory_provider/hpa_flavors.json index db5ea54..19cf8b9 100644 --- a/conductor/conductor/tests/unit/data/plugins/inventory_provider/hpa_flavors.json +++ b/conductor/conductor/tests/unit/data/plugins/inventory_provider/hpa_flavors.json @@ -197,6 +197,105 @@ }, "resource-version": "1520943846264" }, + { + "flavor-id": "f5aa2b2e-3206-41b6-80d5-cf6t2b098c43", + "flavor-name": "flavor-ovsdpdk-cpu-pinning-sriov-NIC-Network-set", + "flavor-vcpus": 32, + "flavor-ram": 131072, + "flavor-disk": 2097152, + "flavor-ephemeral": 128, + "flavor-swap": "0", + "flavor-is-public": false, + "flavor-selflink": "pXtX", + "flavor-disabled": false, + "hpa-capabilities": { + "hpa-capability": [ + { + "hpa-capability-id": "8d36a8fe-bfee-446a-bbcb-881ee66c8f78", + "hpa-feature": "ovsDpdk", + "hpa-version": "v1", + "architecture": "generic", + "resource-version": "1520943846328", + "hpa-feature-attributes": [ + { + "hpa-attribute-key": "dataProcessingAccelerationLibrary", + "hpa-attribute-value": "{\"value\":\"v18.02\"}", + "resource-version": "1520943846346" + } + ] + }, + { + "hpa-capability-id": "c140c945-1532-4908-86c9-d7f71416f1dd", + "hpa-feature": "cpuPinning", + "hpa-version": "v1", + "architecture": "generic", + "resource-version": "1520943846297", + "hpa-feature-attributes": [ + { + "hpa-attribute-key": "logicalCpuPinningPolicy", + "hpa-attribute-value": "{\"value\":\"dedicated\"}", + "resource-version": "1520943846312" + }, + { + "hpa-attribute-key": "logicalCpuThreadPinningPolicy", + "hpa-attribute-value": "{\"value\":\"prefer\"}", + "resource-version": "1520943846301" + } + ] + }, + { + "hpa-capability-id": "4565615b-1077-4bb5-a340-c5be48db2aaa", + "hpa-feature": "basicCapabilities", + "hpa-version": "v1", + "architecture": "generic", + "resource-version": "1520943846269", + "hpa-feature-attributes": [ + { + "hpa-attribute-key": "virtualMemSize", + "hpa-attribute-value": "{\"value\":\"16\", \"unit\":\"GB\" }", + "resource-version": "1520943846282" + }, + { + "hpa-attribute-key": "numVirtualCpu", + "hpa-attribute-value": "{\"value\":\"8\"}", + "resource-version": "1520943846272" + } + ] + }, + { + "hpa-capability-id": "8fa22e64-41b4-471f-96ad-6c470868eo4c", + "hpa-feature": "sriovNICNetwork", + "hpa-version": "v1", + "architecture": "generic", + "resource-version": "1520943845443", + "hpa-feature-attributes": [ + { + "hpa-attribute-key": "pciCount", + "hpa-attribute-value": "{\"value\":\"1\"}", + "resource-version": "1520943845870" + }, + { + "hpa-attribute-key": "pciVendorId", + "hpa-attribute-value": "{\"value\": \"8086\"}", + "resource-version": "1520943845764" + }, + { + "hpa-attribute-key": "pciDeviceId", + "hpa-attribute-value": "{\"value\": \"1234\"}", + "resource-version": "1520943847729" + }, + { + "hpa-attribute-key": "physicalNetwork", + "hpa-attribute-value": "{\"value\": \"physnet1\"}", + "resource-version": "1520943871129" + } + ] + } + + ] + }, + "resource-version": "1520943439264" + }, { "flavor-id": "f5aa2b2e-3206-41b6-80d5-cf041b098c43", "flavor-name": "flavor-cpu-pinning-ovsdpdk-instruction-set", diff --git a/conductor/conductor/tests/unit/data/plugins/inventory_provider/hpa_req_features.json b/conductor/conductor/tests/unit/data/plugins/inventory_provider/hpa_req_features.json index 4a5d37a..bfda6a7 100644 --- a/conductor/conductor/tests/unit/data/plugins/inventory_provider/hpa_req_features.json +++ b/conductor/conductor/tests/unit/data/plugins/inventory_provider/hpa_req_features.json @@ -1,200 +1,327 @@ [ - [ - { - "hpa-feature":"basicCapabilities", - "hpa-version":"v1", - "architecture":"generic", - "mandatory":"True", - "hpa-feature-attributes":[ + [ + { + "hpa-feature": "basicCapabilities", + "hpa-version": "v1", + "architecture": "generic", + "mandatory": "True", + "directives": [], + "hpa-feature-attributes": [ + { + "hpa-attribute-key": "numVirtualCpu", + "hpa-attribute-value": "8", + "operator": "=" + }, + { + "hpa-attribute-key": "virtualMemSize", + "hpa-attribute-value": "16384", + "operator": "=", + "unit": "MB" + } + ] + }, + { + "hpa-feature": "cpuPinning", + "hpa-version": "v1", + "architecture": "generic", + "mandatory": "True", + "directives": [], + "hpa-feature-attributes": [ + { + "hpa-attribute-key": "logicalCpuThreadPinningPolicy", + "hpa-attribute-value": "prefer", + "operator": "=" + }, + { + "hpa-attribute-key": "logicalCpuPinningPolicy", + "hpa-attribute-value": "dedicated", + "operator": "=" + } + ] + }, + { + "hpa-feature": "cpuTopology", + "hpa-version": "v1", + "mandatory": "True", + "architecture": "generic", + "directives": [], + "hpa-feature-attributes": [ + { + "hpa-attribute-key": "numCpuSockets", + "hpa-attribute-value": "2", + "operator": ">=", + "unit": "" + }, + { + "hpa-attribute-key": "numCpuSockets", + "hpa-attribute-value": "4", + "operator": "<=", + "unit": "" + }, + { + "hpa-attribute-key": "numCpuCores", + "hpa-attribute-value": "2", + "operator": ">=", + "unit": "" + }, + { + "hpa-attribute-key": "numCpuCores", + "hpa-attribute-value": "4", + "operator": "<=", + "unit": "" + }, + { + "hpa-attribute-key": "numCpuThreads", + "hpa-attribute-value": "4", + "operator": ">=", + "unit": "" + }, + { + "hpa-attribute-key": "numCpuThreads", + "hpa-attribute-value": "8", + "operator": "<=", + "unit": "" + } + ] + } + ], + [ + { + "hpa-feature": "basicCapabilities", + "hpa-version": "v1", + "architecture": "generic", + "mandatory": "True", + "directives": [], + "hpa-feature-attributes": [ + { + "hpa-attribute-key": "numVirtualCpu", + "hpa-attribute-value": "8", + "operator": "=" + }, + { + "hpa-attribute-key": "virtualMemSize", + "hpa-attribute-value": "16384", + "operator": "=", + "unit": "MB" + } + ] + }, + { + "hpa-feature": "ovsDpdk", + "hpa-version": "v1", + "architecture": "generic", + "mandatory": "False", + "score": "5", + "directives": [], + "hpa-feature-attributes": [ + { + "hpa-attribute-key": "dataProcessingAccelerationLibrary", + "hpa-attribute-value": "v18.02", + "operator": "=" + } + ] + }, + { + "hpa-feature": "cpuPinning", + "hpa-version": "v1", + "architecture": "generic", + "mandatory": "False", + "score": "1", + "directives": [], + "hpa-feature-attributes": [ + { + "hpa-attribute-key": "logicalCpuThreadPinningPolicy", + "hpa-attribute-value": "prefer", + "operator": "=" + }, + { + "hpa-attribute-key": "logicalCpuPinningPolicy", + "hpa-attribute-value": "dedicated", + "operator": "=" + } + ] + }, + { + "hpa-feature": "instructionSetExtensions", + "hpa-version": "v1", + "architecture": "Intel64", + "mandatory": "False", + "score": "5", + "directives": [], + "hpa-feature-attributes": [ + { + "hpa-attribute-key": "instructionSetExtensions", + "hpa-attribute-value": [ + "A11", + "B22" + ], + "operator": "ALL" + } + ] + }, + { + "hpa-feature": "cpuTopology", + "hpa-version": "v1", + "mandatory": "True", + "architecture": "generic", + "directives": [], + "hpa-feature-attributes": [ + { + "hpa-attribute-key": "numCpuSockets", + "hpa-attribute-value": "2", + "operator": ">=", + "unit": "" + }, + { + "hpa-attribute-key": "numCpuSockets", + "hpa-attribute-value": "4", + "operator": "<=", + "unit": "" + }, + { + "hpa-attribute-key": "numCpuCores", + "hpa-attribute-value": "2", + "operator": ">=", + "unit": "" + }, + { + "hpa-attribute-key": "numCpuCores", + "hpa-attribute-value": "4", + "operator": "<=", + "unit": "" + }, + { + "hpa-attribute-key": "numCpuThreads", + "hpa-attribute-value": "4", + "operator": ">=", + "unit": "" + }, + { + "hpa-attribute-key": "numCpuThreads", + "hpa-attribute-value": "8", + "operator": "<=", + "unit": "" + } + ] + } + ], + [ + { + "hpa-feature": "basicCapabilities", + "hpa-version": "v1", + "architecture": "generic", + "mandatory": "True", + "directives": [], + "hpa-feature-attributes": [ + { + "hpa-attribute-key": "numVirtualCpu", + "hpa-attribute-value": "8", + "operator": "=" + }, + { + "hpa-attribute-key": "virtualMemSize", + "hpa-attribute-value": "16", + "operator": "=", + "unit": "GB" + } + ] + }, + { + "hpa-feature": "ovsDpdk", + "hpa-version": "v1", + "architecture": "generic", + "mandatory": "False", + "score": "5", + "directives": [], + "hpa-feature-attributes": [ + { + "hpa-attribute-key": "dataProcessingAccelerationLibrary", + "hpa-attribute-value": "v18.02", + "operator": "=" + } + ] + }, + { + "hpa-feature": "cpuPinning", + "hpa-version": "v1", + "architecture": "generic", + "mandatory": "False", + "score": "1", + "directives": [], + "hpa-feature-attributes": [ + { + "hpa-attribute-key": "logicalCpuThreadPinningPolicy", + "hpa-attribute-value": "prefer", + "operator": "=" + }, + { + "hpa-attribute-key": "logicalCpuPinningPolicy", + "hpa-attribute-value": "dedicated", + "operator": "=" + } + ] + }, + { + "hpa-feature": "instructionSetExtensions", + "hpa-version": "v1", + "architecture": "Intel64", + "mandatory": "False", + "score": "5", + "directives": [], + "hpa-feature-attributes": [ + { + "hpa-attribute-key": "instructionSetExtensions", + "hpa-attribute-value": [ + "A11", + "B22" + ], + "operator": "ALL" + } + ] + }, + { + "hpa-feature": "sriovNICNetwork", + "hpa-version": "v1", + "mandatory": "False", + "architecture": "generic", + "directives": [ + { + "type": "sriovNICNetwork_directives", + "attributes": [ { - "hpa-attribute-key":"numVirtualCpu", - "hpa-attribute-value":"8", - "operator":"=" - }, - { - "hpa-attribute-key":"virtualMemSize", - "hpa-attribute-value":"16384", - "operator":"=", - "unit":"MB" - } - ] - }, - { - "hpa-feature":"cpuPinning", - "hpa-version":"v1", - "architecture":"generic", - "mandatory":"True", - "hpa-feature-attributes":[ - { - "hpa-attribute-key":"logicalCpuThreadPinningPolicy", - "hpa-attribute-value":"prefer", - "operator":"=" - }, - { - "hpa-attribute-key":"logicalCpuPinningPolicy", - "hpa-attribute-value":"dedicated", - "operator":"=" - } - ] - }, - { - "hpa-feature":"cpuTopology", - "hpa-version":"v1", - "mandatory":"True", - "architecture":"generic", - "hpa-feature-attributes":[ - { - "hpa-attribute-key":"numCpuSockets", - "hpa-attribute-value":"2", - "operator":">=", - "unit":"" - }, - { - "hpa-attribute-key":"numCpuSockets", - "hpa-attribute-value":"4", - "operator":"<=", - "unit":"" - }, - { - "hpa-attribute-key":"numCpuCores", - "hpa-attribute-value":"2", - "operator":">=", - "unit":"" - }, - { - "hpa-attribute-key":"numCpuCores", - "hpa-attribute-value":"4", - "operator":"<=", - "unit":"" - }, - { - "hpa-attribute-key":"numCpuThreads", - "hpa-attribute-value":"4", - "operator":">=", - "unit":"" - }, - { - "hpa-attribute-key":"numCpuThreads", - "hpa-attribute-value":"8", - "operator":"<=", - "unit":"" - } - ] - } - ], - [ - { - "hpa-feature":"basicCapabilities", - "hpa-version":"v1", - "architecture":"generic", - "mandatory":"True", - "hpa-feature-attributes":[ - { - "hpa-attribute-key":"numVirtualCpu", - "hpa-attribute-value":"8", - "operator":"=" - }, - { - "hpa-attribute-key":"virtualMemSize", - "hpa-attribute-value":"16384", - "operator":"=", - "unit":"MB" - } - ] - }, - { - "hpa-feature":"ovsDpdk", - "hpa-version":"v1", - "architecture":"generic", - "mandatory":"False", - "score":"5", - "hpa-feature-attributes":[ - { - "hpa-attribute-key":"dataProcessingAccelerationLibrary", - "hpa-attribute-value":"v18.02", - "operator":"=" - } - ] - }, - { - "hpa-feature":"cpuPinning", - "hpa-version":"v1", - "architecture":"generic", - "mandatory":"False", - "score":"1", - "hpa-feature-attributes":[ - { - "hpa-attribute-key":"logicalCpuThreadPinningPolicy", - "hpa-attribute-value":"prefer", - "operator":"=" - }, - { - "hpa-attribute-key":"logicalCpuPinningPolicy", - "hpa-attribute-value":"dedicated", - "operator":"=" - } - ] - }, - { - "hpa-feature":"instructionSetExtensions", - "hpa-version":"v1", - "architecture":"Intel64", - "mandatory":"False", - "score":"5", - "hpa-feature-attributes":[ - { - "hpa-attribute-key":"instructionSetExtensions", - "hpa-attribute-value":[ - "A11", - "B22" - ], - "operator":"ALL" - } - ] - }, - { - "hpa-feature":"cpuTopology", - "hpa-version":"v1", - "mandatory":"True", - "architecture":"generic", - "hpa-feature-attributes":[ - { - "hpa-attribute-key":"numCpuSockets", - "hpa-attribute-value":"2", - "operator":">=", - "unit":"" - }, - { - "hpa-attribute-key":"numCpuSockets", - "hpa-attribute-value":"4", - "operator":"<=", - "unit":"" - }, - { - "hpa-attribute-key":"numCpuCores", - "hpa-attribute-value":"2", - "operator":">=", - "unit":"" - }, - { - "hpa-attribute-key":"numCpuCores", - "hpa-attribute-value":"4", - "operator":"<=", - "unit":"" - }, - { - "hpa-attribute-key":"numCpuThreads", - "hpa-attribute-value":"4", - "operator":">=", - "unit":"" - }, - { - "hpa-attribute-key":"numCpuThreads", - "hpa-attribute-value":"8", - "operator":"<=", - "unit":"" + "attribute_name": "A", + "attribute_value": "a" } - ] - } - ] + ] + } + ], + "score": "7", + "hpa-feature-attributes": [ + { + "hpa-attribute-key": "pciCount", + "hpa-attribute-value": "1", + "operator": "=", + "unit": "" + }, + { + "hpa-attribute-key": "pciVendorId", + "hpa-attribute-value": "8086", + "operator": "=", + "unit": "" + }, + { + "hpa-attribute-key": "pciDeviceId", + "hpa-attribute-value": "1234", + "operator": "=", + "unit": "" + }, + { + "hpa-attribute-key": "physicalNetwork", + "hpa-attribute-value": "physnet1", + "operator": "=", + "unit": "" + } + ] + } + ] ] \ 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 5713d04..435e0a9 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 @@ -28,7 +28,6 @@ from oslo_config import cfg class TestAAI(unittest.TestCase): def setUp(self): - CONF = cfg.CONF CONF.register_opts(aai.AAI_OPTS, group='aai') self.conf = CONF @@ -38,20 +37,16 @@ class TestAAI(unittest.TestCase): mock.patch.stopall() def test_get_version_from_string(self): - self.assertEqual("2.5", self.aai_ep._get_version_from_string("AAI2.5")) self.assertEqual("3.0", self.aai_ep._get_version_from_string("AAI3.0")) def test_aai_versioned_path(self): - self.assertEqual('/{}/cloud-infrastructure/cloud-regions/?depth=0'.format(self.conf.aai.server_url_version), self.aai_ep._aai_versioned_path("/cloud-infrastructure/cloud-regions/?depth=0")) 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' req_json = json.loads(open(req_json_file).read()) @@ -62,11 +57,10 @@ class TestAAI(unittest.TestCase): self.mock_get_request = mock.patch.object(AAI, '_request', return_value=response) self.mock_get_request.start() - self.assertEqual({'country': u'USA', 'latitude': u'40.39596', 'longitude': u'-74.135342'} , - self.aai_ep.resolve_clli_location("clli_code")) + self.assertEqual({'country': u'USA', 'latitude': u'40.39596', 'longitude': u'-74.135342'}, + self.aai_ep.resolve_clli_location("clli_code")) def test_get_inventory_group_pair(self): - req_json_file = './conductor/tests/unit/data/plugins/inventory_provider/_request_inventory_group_pair.json' req_json = json.loads(open(req_json_file).read()) @@ -77,11 +71,10 @@ class TestAAI(unittest.TestCase): self.mock_get_request = mock.patch.object(AAI, '_request', return_value=response) self.mock_get_request.start() - self.assertEqual([[u'instance-1', u'instance-2']] , - self.aai_ep.get_inventory_group_pairs("service_description")) + self.assertEqual([[u'instance-1', u'instance-2']], + self.aai_ep.get_inventory_group_pairs("service_description")) def test_resolve_host_location(self): - req_json_file = './conductor/tests/unit/data/plugins/inventory_provider/_request_host_name.json' req_json = json.loads(open(req_json_file).read()) @@ -99,11 +92,10 @@ class TestAAI(unittest.TestCase): self.mock_get_complex = mock.patch.object(AAI, '_get_complex', return_value=complex_json) self.mock_get_complex.start() - self.assertEqual({'country': u'USA', 'latitude': u'28.543251', 'longitude': u'-81.377112'} , + self.assertEqual({'country': u'USA', 'latitude': u'28.543251', 'longitude': u'-81.377112'}, self.aai_ep.resolve_host_location("host_name")) def test_resolve_demands(self): - self.assertEqual({}, self.aai_ep.resolve_demands(dict())) demands_list_file = './conductor/tests/unit/data/plugins/inventory_provider/demand_list.json' @@ -126,7 +118,8 @@ class TestAAI(unittest.TestCase): req_response.ok = True req_response.json.return_value = demand_service_response - self.mock_first_level_service_call = mock.patch.object(AAI, 'first_level_service_call', return_value=generic_vnf_list) + self.mock_first_level_service_call = mock.patch.object(AAI, 'first_level_service_call', + return_value=generic_vnf_list) self.mock_first_level_service_call.start() self.mock_get_regions = mock.patch.object(AAI, '_get_regions', return_value=regions_response) @@ -167,7 +160,6 @@ class TestAAI(unittest.TestCase): self.aai_ep.resolve_demands(demands_list)) def test_get_complex(self): - complex_json_file = './conductor/tests/unit/data/plugins/inventory_provider/_request_get_complex.json' complex_json = json.loads(open(complex_json_file).read()) @@ -179,12 +171,12 @@ 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.aai_ep._get_complex("/v10/complex/complex_id", "complex_id")) - + 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' network_role_json = json.loads(open(network_role_json_file).read()) @@ -195,12 +187,10 @@ class TestAAI(unittest.TestCase): self.mock_get_request = mock.patch.object(AAI, '_request', return_value=response) self.mock_get_request.start() - self.assertEqual(set(['test-cloud-value']) , - self.aai_ep.check_network_roles("network_role_id")) - + 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' candidate_role_json = json.loads(open(candidate_role_json_file).read()) @@ -223,7 +213,8 @@ class TestAAI(unittest.TestCase): inventory_attributes['attr-1'] = 'attr-1-value1' self.assertEqual(True, - self.aai_ep.match_inventory_attributes(template_attributes, inventory_attributes, "candidate-id")) + self.aai_ep.match_inventory_attributes(template_attributes, inventory_attributes, + "candidate-id")) template_attributes['attr-1'] = { 'not': ['attr-1-value2'] @@ -268,7 +259,6 @@ class TestAAI(unittest.TestCase): self.aai_ep._refresh_cache()) def test_get_aai_rel_link(self): - relatonship_response_file = './conductor/tests/unit/data/plugins/inventory_provider/relationship_list.json' relatonship_response = json.loads(open(relatonship_response_file).read()) related_to = "service-instance" @@ -301,7 +291,7 @@ class TestAAI(unittest.TestCase): def test_match_hpa(self): flavor_json_file = \ - './conductor/tests/unit/data/plugins/inventory_provider/hpa_flavors.json' + './conductor/tests/unit/data/plugins/inventory_provider/hpa_flavors.json' flavor_json = json.loads(open(flavor_json_file).read()) feature_json_file = \ './conductor/tests/unit/data/plugins/inventory_provider/hpa_req_features.json' @@ -310,17 +300,34 @@ class TestAAI(unittest.TestCase): candidate_json = json.loads(open(candidate_json_file).read()) candidate_json['candidate_list'][1]['flavors'] = flavor_json - flavor_map = {"flavor-id": "f5aa2b2e-3206-41b6-80d5-cf041b098c43", - "flavor-name": "flavor-cpu-pinning-ovsdpdk-instruction-set", - "score": 0} + flavor_map = { + "directives": [], + "flavor_map": {"flavor-id": "f5aa2b2e-3206-41b6-80d5-cf041b098c43", + "flavor-name": "flavor-cpu-pinning-ovsdpdk-instruction-set", + "score": 0}} self.assertEqual(flavor_map, self.aai_ep.match_hpa(candidate_json['candidate_list'][1], feature_json[0])) - flavor_map = {"flavor-id": "f5aa2b2e-3206-41b6-80d5-cf041b098c43", - "flavor-name": "flavor-cpu-ovsdpdk-instruction-set", - "score": 10} + flavor_map = {"flavor_map": {"flavor-id": "f5aa2b2e-3206-41b6-80d5-cf041b098c43", + "flavor-name": "flavor-cpu-ovsdpdk-instruction-set", + "score": 10}, + "directives": []} self.assertEqual(flavor_map, - self.aai_ep.match_hpa(candidate_json['candidate_list'][1], - feature_json[1])) - + self.aai_ep.match_hpa(candidate_json['candidate_list'][1], + feature_json[1])) + flavor_map = {"flavor_map": {"flavor-id": "f5aa2b2e-3206-41b6-80d5-cf6t2b098c43", + "flavor-name": "flavor-ovsdpdk-cpu-pinning-sriov-NIC-Network-set", + "score": 13}, + "directives": [{ + "type": "sriovNICNetwork_directives", + "attributes": [ + { + "attribute_name": "A", + "attribute_value": "a" + } + ] + }]} + self.assertEqual(flavor_map, + self.aai_ep.match_hpa(candidate_json['candidate_list'][1], + feature_json[2])) diff --git a/conductor/conductor/tests/unit/data/test_service.py b/conductor/conductor/tests/unit/data/test_service.py index 8c74097..7953f3f 100644 --- a/conductor/conductor/tests/unit/data/test_service.py +++ b/conductor/conductor/tests/unit/data/test_service.py @@ -238,25 +238,38 @@ class TestDataEndpoint(unittest.TestCase): hpa_json["conductor_solver"]["constraints"][0].items()[0] hpa_constraint = constraint_info['properties'] flavorProperties = hpa_constraint['evaluate'][0]['flavorProperties'] - label_name = hpa_constraint['evaluate'][0]['flavorLabel'] + id = hpa_constraint['evaluate'][0]['id'] + type = hpa_constraint['evaluate'][0]['type'] + directives = hpa_constraint['evaluate'][0]['directives'] + attr = directives[0].get("attributes") + label_name = attr[0].get("attribute_name") ext_mock1.return_value = ['aai'] flavor_info = {"flavor-id": "vim-flavor-id1", - "flavor-name": "vim-flavor-name1", - "score": 0} + "flavor-name": "vim-flavor-name1"} + directive = [ + { + "id": id, + "type": type, + "directives": directives + } + ] hpa_mock.return_value = [flavor_info] self.maxDiff = None - args = generate_args(candidate_list, flavorProperties, label_name) + args = generate_args(candidate_list, flavorProperties, id, type, directives) hpa_candidate_list = copy.deepcopy(candidate_list) hpa_candidate_list[1]['flavor_map'] = {} hpa_candidate_list[1]['flavor_map'][label_name] = "vim-flavor-name1" - hpa_candidate_list[1]['hpa_score'] = 0 - expected_response = {'response': hpa_candidate_list, 'error': False} + hpa_candidate_list[1]['all_directives'] = {} + hpa_candidate_list[1]['all_directives']['directives'] = directive + hpa_candidate_list1 = [] + hpa_candidate_list1.append(hpa_candidate_list[0]) + expected_response = {'response': hpa_candidate_list1, 'error': False} self.assertEqual(expected_response, self.data_ep.get_candidates_with_hpa(None, args)) hpa_candidate_list2 = list() hpa_candidate_list2.append(copy.deepcopy(candidate_list[0])) - args = generate_args(candidate_list, flavorProperties, label_name) + args = generate_args(candidate_list, flavorProperties, id, type, directives) hpa_mock.return_value = [] expected_response = {'response': hpa_candidate_list2, 'error': False} self.assertEqual(expected_response, @@ -322,11 +335,13 @@ class TestDataEndpoint(unittest.TestCase): args)) -def generate_args(candidate_list, flavorProperties, label_name): +def generate_args(candidate_list, flavorProperties, vf_id, model_type, directives): arg_candidate_list = copy.deepcopy(candidate_list) args = {"candidate_list": arg_candidate_list, "flavorProperties": flavorProperties, - "label_name": label_name} + "id": vf_id, + "type": model_type, + "directives": directives} return args def ip_ext_sideeffect(*args, **kwargs): diff --git a/conductor/conductor/tests/unit/solver/hpa_constraints.json b/conductor/conductor/tests/unit/solver/hpa_constraints.json index 829eaf3..5f9c4c5 100644 --- a/conductor/conductor/tests/unit/solver/hpa_constraints.json +++ b/conductor/conductor/tests/unit/solver/hpa_constraints.json @@ -13,6 +13,7 @@ { "architecture": "generic", "hpa-feature": "basicCapabilities", + "directives": [], "hpa-feature-attributes": [ { "hpa-attribute-key": "numVirtualCpu", @@ -31,6 +32,7 @@ { "architecture": "generic", "hpa-feature": "numa", + "directives": [], "hpa-feature-attributes": [ { "hpa-attribute-key": "numaNodes", @@ -65,6 +67,7 @@ { "architecture": "generic", "hpa-feature": "cpuPinning", + "directives": [], "hpa-feature-attributes": [ { "hpa-attribute-key": "logicalCpuThreadPinningPolicy", @@ -80,7 +83,19 @@ "hpa-version": "v1" } ], - "flavorLabel": "flavor_label_1" + "id": "vg_1", + "type": "vnfc", + "directives": [ + { + "type": "flavor_directives", + "attributes": [ + { + "attribute_name": "flavor_label_1", + "attribute_value": "" + } + ] + } + ] }, { "flavorProperties": [ @@ -100,7 +115,8 @@ "unit": "GB" } ], - "hpa-version": "v1" + "hpa-version": "v1", + "directives": [] }, { "architecture": "generic", @@ -134,7 +150,8 @@ "unit": "GB" } ], - "hpa-version": "v1" + "hpa-version": "v1", + "directives": [] }, { "architecture": "generic", @@ -147,10 +164,23 @@ "unit": "GB" } ], - "hpa-version": "v1" + "hpa-version": "v1", + "directives": [] } ], - "flavorLabel": "flavor_label_2" + "id": "vg_2", + "type": "vnfc", + "directives": [ + { + "type": "flavor_directives", + "attributes": [ + { + "attribute_name": "flavor_label_2", + "attribute_value": "" + } + ] + } + ] } ] } -- cgit 1.2.3-korg