summaryrefslogtreecommitdiffstats
path: root/conductor
diff options
context:
space:
mode:
Diffstat (limited to 'conductor')
-rw-r--r--conductor/conductor/data/plugins/inventory_provider/aai.py8
-rw-r--r--conductor/conductor/data/plugins/inventory_provider/hpa_utils.py223
-rw-r--r--conductor/conductor/tests/unit/data/plugins/inventory_provider/hpa_flavors.json297
-rw-r--r--conductor/conductor/tests/unit/data/plugins/inventory_provider/hpa_req_features.json200
-rw-r--r--conductor/conductor/tests/unit/data/plugins/inventory_provider/test_aai.py26
5 files changed, 752 insertions, 2 deletions
diff --git a/conductor/conductor/data/plugins/inventory_provider/aai.py b/conductor/conductor/data/plugins/inventory_provider/aai.py
index c40e15c..41f55c5 100644
--- a/conductor/conductor/data/plugins/inventory_provider/aai.py
+++ b/conductor/conductor/data/plugins/inventory_provider/aai.py
@@ -24,6 +24,7 @@ import uuid
from conductor.common import rest
from conductor.data.plugins import constants
from conductor.data.plugins.inventory_provider import base
+from conductor.data.plugins.inventory_provider import hpa_utils
from conductor.i18n import _LE, _LI
from oslo_config import cfg
from oslo_log import log
@@ -1300,3 +1301,10 @@ class AAI(base.InventoryProviderBase):
" {}".format(inventory_type))
return resolved_demands
+
+ 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
+
diff --git a/conductor/conductor/data/plugins/inventory_provider/hpa_utils.py b/conductor/conductor/data/plugins/inventory_provider/hpa_utils.py
index 6ed622c..41e217c 100644
--- a/conductor/conductor/data/plugins/inventory_provider/hpa_utils.py
+++ b/conductor/conductor/data/plugins/inventory_provider/hpa_utils.py
@@ -22,8 +22,10 @@
Hardware Platform Awareness (HPA) constraint plugin'''
# python imports
+import yaml
+import operator
-# Conductor imports
+from conductor.i18n import _LE, _LI
# Third-party library imports
from oslo_log import log
@@ -46,3 +48,222 @@ def match_all_operator(big_list, small_list):
small_set = set(small_list)
return small_set.issubset(big_set)
+
+
+class HpaMatchProvider(object):
+
+ def __init__(self, candidate, req_cap_list):
+ self.flavors_list = candidate['flavors']['flavor']
+ self.req_cap_list = req_cap_list
+
+ # Find the flavor which has all the required capabilities
+ def match_flavor(self):
+ # Keys to find capability match
+ hpa_keys = ['hpa-feature', 'architecture', 'hpa-version']
+ req_filter_list = []
+ for capability in CapabilityDataParser.get_item(self.req_cap_list,
+ None):
+ if capability.item['mandatory'] == 'True':
+ hpa_list = {k: capability.item[k] \
+ for k in hpa_keys if k in capability.item}
+ req_filter_list.append(hpa_list)
+ max_score = -1
+ flavor_map = None
+ for flavor in self.flavors_list:
+ flavor_filter_list = []
+ try:
+ flavor_cap_list = flavor['hpa-capabilities']
+ except KeyError:
+ LOG.info(_LI("invalid JSON "))
+ return None
+ for capability in CapabilityDataParser.get_item(flavor_cap_list,
+ 'hpa-capability'):
+ hpa_list = {k: capability.item[k] \
+ for k in hpa_keys if k in capability.item}
+ 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)
+ if match_found:
+ LOG.info(_LI("Matching Flavor found '{}' for request - {}").
+ format(flavor['flavor-name'], self.req_cap_list))
+ if score > max_score:
+ max_score = score
+ flavor_map = {"flavor-id": flavor['flavor-id'],
+ "flavor-name": flavor['flavor-name']}
+ return flavor_map
+
+
+ def _is_cap_supported(self, flavor, cap):
+ try:
+ for elem in cap:
+ flavor.remove(elem)
+ except ValueError:
+ return False
+ # Found all capabilities in Flavor
+ return True
+
+ # Convert to bytes value using unit
+ def _get_normalized_value(self, unit, value):
+
+ if not value.isdigit():
+ return value
+ value = int(value)
+ if unit == 'KB':
+ value = value * 1024
+ elif unit == 'MB':
+ value = value * 1024 * 1024
+ elif unit == 'GB':
+ value = value * 1024 * 1024 * 1024
+ return str(value)
+
+ def _get_req_attribute(self, req_attr):
+ try:
+ c_op = req_attr['operator']
+ c_value = req_attr['hpa-attribute-value']
+ c_unit = None
+ if 'unit' in req_attr:
+ c_unit = req_attr['unit']
+ except KeyError:
+ LOG.info(_LI("invalid JSON "))
+ return None
+
+ if c_unit:
+ c_value = self._get_normalized_value(c_unit, c_value)
+ return c_value, c_op
+
+ def _get_flavor_attribute(self, flavor_attr):
+ try:
+ attrib_value = yaml.load(flavor_attr['hpa-attribute-value'])
+ except:
+ return None
+
+ f_unit = None
+ f_value = None
+ for key, value in attrib_value.iteritems():
+ if key == 'value':
+ f_value = value
+ elif key == 'unit':
+ f_unit = value
+ if f_unit:
+ f_value = self._get_normalized_value(f_unit, f_value)
+ return f_value
+
+ def _get_operator(self, req_op):
+
+ operator_list = ['=', '<', '>', '<=', '>=', 'ALL']
+
+ if req_op not in operator_list:
+ return None
+
+ if req_op == ">":
+ op = operator.gt
+ elif req_op == ">=":
+ op = operator.ge
+ elif req_op == "<":
+ op = operator.lt
+ elif req_op == "<=":
+ op = operator.le
+ elif req_op == "=":
+ op = operator.eq
+ elif req_op == 'ALL':
+ op = match_all_operator
+
+ return op
+
+
+ def _compare_attribute(self, flavor_attr, req_attr):
+
+ req_value, req_op = self._get_req_attribute(req_attr)
+ flavor_value = self._get_flavor_attribute(flavor_attr)
+
+ if req_value is None or flavor_value is None:
+ return False
+
+ # Compare operators only valid for Integers
+ if req_op in ['<', '>', '<=', '>=']:
+ if not req_value.isdigit() or not flavor_value.isdigit():
+ return False
+
+ op = self._get_operator(req_op)
+ if not op:
+ return False
+
+ if req_op == 'ALL':
+ # All is valid only for lists
+ if isinstance(req_value, list) and isinstance(flavor_value, list):
+ return op(flavor_value, req_value)
+
+ # if values are string compare them as strings
+ if req_op == '=':
+ if not req_value.isdigit() or not flavor_value.isdigit():
+ return op(req_value, flavor_value)
+
+ # Only integers left to compare
+ if req_op in ['<', '>', '<=', '>=', '=']:
+ return op(int(flavor_value), int(req_value))
+
+ return False
+
+ # for the feature get the capabilty feature attribute list
+ def _get_flavor_cfa_list(self, feature, flavor_cap_list):
+ 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
+ if feature == flavor_feature:
+ return feature_attributes
+
+ # flavor has all the required capabilties
+ # For each required capability find capability in flavor
+ # and compare each attribute
+ def _compare_feature_attributes(self, flavor_cap_list):
+ score = 0
+ for capability in CapabilityDataParser.get_item(self.req_cap_list, None):
+ hpa_feature, req_cfa_list = capability.get_fields()
+ 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
+ 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
+ if flavor_cfa_list is not None and capability.item['mandatory'] == 'False':
+ score = score + int(capability.item['score'])
+ return True, score
+
+
+class CapabilityDataParser(object):
+ """Helper class to parse data"""
+
+ def __init__(self, item):
+ self.item = item
+
+ @classmethod
+ def get_item(cls, payload, key):
+ try:
+ if key is None:
+ features = payload
+ else:
+ features = (payload[key])
+
+ for f in features:
+ yield cls(f)
+ except KeyError:
+ LOG.info(_LI("invalid JSON "))
+
+ def get_fields(self):
+ return (self.get_feature(),
+ self.get_feature_attributes())
+
+ def get_feature_attributes(self):
+ return self.item.get('hpa-feature-attributes')
+
+ def get_feature(self):
+ return self.item.get('hpa-feature')
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
new file mode 100644
index 0000000..db5ea54
--- /dev/null
+++ b/conductor/conductor/tests/unit/data/plugins/inventory_provider/hpa_flavors.json
@@ -0,0 +1,297 @@
+{
+ "flavor": [
+ {
+ "flavor-id": "9cf8220b-4d96-4c30-a426-2e9382f3fff2",
+ "flavor-name": "flavor-numa-cpu-topology-instruction-set",
+ "flavor-vcpus": 64,
+ "flavor-ram": 65536,
+ "flavor-disk": 1048576,
+ "flavor-ephemeral": 128,
+ "flavor-swap": "0",
+ "flavor-is-public": false,
+ "flavor-selflink": "pXtX",
+ "flavor-disabled": false,
+ "hpa-capabilities": {
+ "hpa-capability": [
+ {
+ "hpa-capability-id": "13ec6d4d-7fee-48d8-9e4a-c598feb101ed",
+ "hpa-feature": "basicCapabilities",
+ "hpa-version": "v1",
+ "architecture": "generic",
+ "resource-version": "1520943845409",
+ "hpa-feature-attributes": [
+ {
+ "hpa-attribute-key": "numVirtualCpu",
+ "hpa-attribute-value": "{value:4}",
+ "resource-version": "1520943845416"
+ },
+ {
+ "hpa-attribute-key": "virtualMemSize",
+ "hpa-attribute-value": "{value:4, unit:\"GB\" }",
+ "resource-version": "1520943845427"
+ }
+ ]
+ },
+ {
+ "hpa-capability-id": "01a4bfe1-1993-4fda-bd1c-ef333b4f76a9",
+ "hpa-feature": "instructionSetExtensions",
+ "hpa-version": "v1",
+ "architecture": "Intel64",
+ "resource-version": "1520943846236",
+ "hpa-feature-attributes": [
+ {
+ "hpa-attribute-key": "instructionSetExtensions",
+ "hpa-attribute-value": "{value:{['AAA', 'BBB', 'CCC', 'DDD']}}",
+ "resource-version": "1520943846241"
+ }
+ ]
+ },
+ {
+ "hpa-capability-id": "167ad6a2-7d9c-4bf2-9a1b-30e5311b8c66",
+ "hpa-feature": "numa",
+ "hpa-version": "v1",
+ "architecture": "generic",
+ "resource-version": "1520943846158",
+ "hpa-feature-attributes": [
+ {
+ "hpa-attribute-key": "numaCpu-0",
+ "hpa-attribute-value": "{value:2}",
+ "resource-version": "1520943846178"
+ },
+ {
+ "hpa-attribute-key": "numaMem-0",
+ "hpa-attribute-value": "{value:2, unit:\"GB\" }",
+ "resource-version": "1520943846204"
+ },
+ {
+ "hpa-attribute-key": "numaCpu-1",
+ "hpa-attribute-value": "{value:4}",
+ "resource-version": "1520943846191"
+ },
+ {
+ "hpa-attribute-key": "numaMem-1",
+ "hpa-attribute-value": "{value:4, unit:\"GB\" }",
+ "resource-version": "1520943846217"
+ },
+ {
+ "hpa-attribute-key": "numaNodes",
+ "hpa-attribute-value": "{value:2}",
+ "resource-version": "1520943846163"
+ }
+ ]
+ },
+ {
+ "hpa-capability-id": "8fa22e64-41b4-471f-96ad-6c4708635e4c",
+ "hpa-feature": "cpuTopology",
+ "hpa-version": "v1",
+ "architecture": "generic",
+ "resource-version": "1520943845443",
+ "hpa-feature-attributes": [
+ {
+ "hpa-attribute-key": "numCpuCores",
+ "hpa-attribute-value": "{value:8}",
+ "resource-version": "1520943845456"
+ },
+ {
+ "hpa-attribute-key": "numCpuSockets",
+ "hpa-attribute-value": "{value:6}",
+ "resource-version": "1520943845447"
+ },
+ {
+ "hpa-attribute-key": "numCpuThreads",
+ "hpa-attribute-value": "{value:8}",
+ "resource-version": "1520943846129"
+ }
+ ]
+ }
+ ]
+ },
+ "resource-version": "1520943845399"
+ },
+ {
+ "flavor-id": "f5aa2b2e-3206-41b6-80d5-cf041b098c43",
+ "flavor-name": "flavor-cpu-ovsdpdk-instruction-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": "4d04f4d8-e257-4442-8417-19a525e56096",
+ "hpa-feature": "instructionSetExtensions",
+ "hpa-version": "v1",
+ "architecture": "Intel64",
+ "resource-version": "1520943846362",
+ "hpa-feature-attributes": [
+ {
+ "hpa-attribute-key": "instructionSetExtensions",
+ "hpa-attribute-value": "{\"value\" : [\"A11\", \"B22\"] }",
+ "resource-version": "1520943846365"
+ }
+ ]
+ },
+ {
+ "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-6c4708635e4c",
+ "hpa-feature": "cpuTopology",
+ "hpa-version": "v1",
+ "architecture": "generic",
+ "resource-version": "1520943845443",
+ "hpa-feature-attributes": [
+ {
+ "hpa-attribute-key": "numCpuCores",
+ "hpa-attribute-value": "{\"value\":\"4\"}",
+ "resource-version": "1520943845456"
+ },
+ {
+ "hpa-attribute-key": "numCpuSockets",
+ "hpa-attribute-value": "{\"value\": \"4\"}",
+ "resource-version": "1520943845447"
+ },
+ {
+ "hpa-attribute-key": "numCpuThreads",
+ "hpa-attribute-value": "{\"value\": \"8\"}",
+ "resource-version": "1520943846129"
+ }
+ ]
+ }
+
+ ]
+ },
+ "resource-version": "1520943846264"
+ },
+ {
+ "flavor-id": "f5aa2b2e-3206-41b6-80d5-cf041b098c43",
+ "flavor-name": "flavor-cpu-pinning-ovsdpdk-instruction-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-6c4708635e4c",
+ "hpa-feature": "cpuTopology",
+ "hpa-version": "v1",
+ "architecture": "generic",
+ "resource-version": "1520943845443",
+ "hpa-feature-attributes": [
+ {
+ "hpa-attribute-key": "numCpuCores",
+ "hpa-attribute-value": "{\"value\":\"4\"}",
+ "resource-version": "1520943845456"
+ },
+ {
+ "hpa-attribute-key": "numCpuSockets",
+ "hpa-attribute-value": "{\"value\": \"4\"}",
+ "resource-version": "1520943845447"
+ },
+ {
+ "hpa-attribute-key": "numCpuThreads",
+ "hpa-attribute-value": "{\"value\": \"8\"}",
+ "resource-version": "1520943846129"
+ }
+ ]
+ }
+
+ ]
+ },
+ "resource-version": "1520943846264"
+ }
+
+ ]
+}
+
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
new file mode 100644
index 0000000..4a5d37a
--- /dev/null
+++ b/conductor/conductor/tests/unit/data/plugins/inventory_provider/hpa_req_features.json
@@ -0,0 +1,200 @@
+[
+ [
+ {
+ "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":"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":""
+ }
+ ]
+ }
+ ]
+] \ 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 b148579..e12a114 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
@@ -297,4 +297,28 @@ class TestAAI(unittest.TestCase):
flavors_info = self.aai_ep._get_flavors("mock-cloud-owner",
"mock-cloud-region-id")
- self.assertEqual(2, len(flavors_info['flavor'])) \ No newline at end of file
+ self.assertEqual(2, len(flavors_info['flavor']))
+
+ def test_match_hpa(self):
+ flavor_json_file = \
+ './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'
+ feature_json = json.loads(open(feature_json_file).read())
+ candidate_json_file = './conductor/tests/unit/data/candidate_list.json'
+ 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"}
+ 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" }
+ self.assertEqual(flavor_map,
+ self.aai_ep.match_hpa(candidate_json['candidate_list'][1],
+ feature_json[1]))
+