Make hpa discovery as plugin 81/98281/4
authorHaibin Huang <haibin.huang@intel.com>
Tue, 12 Nov 2019 09:20:03 +0000 (17:20 +0800)
committerHaibin Huang <haibin.huang@intel.com>
Mon, 20 Jan 2020 08:31:46 +0000 (16:31 +0800)
Issue-ID: MULTICLOUD-695
Change-Id: I04547cfe664dfed457a228c04dfdf71c96b0ded0
Signed-off-by: Haibin Huang <haibin.huang@intel.com>
15 files changed:
hpa/.testr.conf [new file with mode: 0644]
hpa/LICENSE [new file with mode: 0644]
hpa/README.md [new file with mode: 0644]
hpa/assembly.xml [new file with mode: 0644]
hpa/hpa/__init__.py [new file with mode: 0644]
hpa/hpa/base.py [new file with mode: 0644]
hpa/hpa/hpa_discovery.py [new file with mode: 0644]
hpa/mvn-phase-script.sh [new file with mode: 0755]
hpa/pom.xml [new file with mode: 0644]
hpa/setup.py [new file with mode: 0644]
hpa/tests/__init__.py [new file with mode: 0644]
hpa/tests/test.py [new file with mode: 0644]
hpa/tests/test_hpa_discovery.py [new file with mode: 0644]
hpa/tox.ini [new file with mode: 0644]
pom.xml

diff --git a/hpa/.testr.conf b/hpa/.testr.conf
new file mode 100644 (file)
index 0000000..6e39851
--- /dev/null
@@ -0,0 +1,8 @@
+[DEFAULT]
+test_command=OS_STDOUT_CAPTURE=${OS_STDOUT_CAPTURE:-1} \
+             OS_STDERR_CAPTURE=${OS_STDERR_CAPTURE:-1} \
+             OS_LOG_CAPTURE=${OS_LOG_CAPTURE:-1} \
+             OS_TEST_TIMEOUT=${OS_TEST_TIMEOUT:-160} \
+             ${PYTHON:-python} -m subunit.run discover -t ./ ${OS_TEST_PATH:-./hpa/tests/unit} $LISTOPT $IDOPTION
+test_id_option=--load-list $IDFILE
+test_list_option=--list
diff --git a/hpa/LICENSE b/hpa/LICENSE
new file mode 100644 (file)
index 0000000..fffadb0
--- /dev/null
@@ -0,0 +1,26 @@
+
+The following licence applies to all files in this and subdirectories. Licences
+are included in individual source files where appropriate, and if it differs
+from this text, it supersedes this.  Any file that does not have licence text
+defaults to being covered by this text; not all files support the addition of
+licenses. 
+
+#
+# -------------------------------------------------------------------------
+#   Copyright (c) 2015-2017 AT&T Intellectual Property
+#
+#   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.
+#
+# -------------------------------------------------------------------------
+#
+
diff --git a/hpa/README.md b/hpa/README.md
new file mode 100644 (file)
index 0000000..fe568ad
--- /dev/null
@@ -0,0 +1,16 @@
+# 1. compile hpa plugin
+cd hpa
+python setup.py compile
+
+# 2. install hpa plugin
+cd hpa
+python setup.py install
+
+# 3. test hpa plugin
+cd hpa/test
+# 3.1 test cloud extra info with dpdk
+python test.py -f "dpdk"
+# 3.2 test without cloud extra info
+python test.py -t "windriver"
+python test.py -t "starlingx"
+python test.py -t "pike"
diff --git a/hpa/assembly.xml b/hpa/assembly.xml
new file mode 100644 (file)
index 0000000..18126dc
--- /dev/null
@@ -0,0 +1,37 @@
+<!--
+ Copyright (c) 2019 Intel Corporation. All rights reserved.
+
+ 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.
+-->
+<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0"
+          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+          xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd">
+    <id>hpa</id>
+    <formats>
+        <format>zip</format>
+    </formats>
+    <fileSets>
+        <fileSet>
+            <includes>
+               <include>*/**</include>
+            </includes>
+            <excludes>
+                <exclude>**/*.pyc</exclude>
+               <exclude>target/**</exclude>
+               <exclude>docker/**</exclude>
+               <exclude>cover/**</exclude>
+               <exclude>pom.xml</exclude>
+               <exclude>assembly.xml</exclude>
+               <exclude>xunit-results.xml</exclude>
+           </excludes>
+        </fileSet>
+    </fileSets>
+    <baseDirectory>hpa</baseDirectory>
+</assembly>
diff --git a/hpa/hpa/__init__.py b/hpa/hpa/__init__.py
new file mode 100644 (file)
index 0000000..81362a2
--- /dev/null
@@ -0,0 +1,13 @@
+# Copyright (c) 2019 Intel Corporation.
+#
+# 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.
diff --git a/hpa/hpa/base.py b/hpa/hpa/base.py
new file mode 100644 (file)
index 0000000..90eb643
--- /dev/null
@@ -0,0 +1,22 @@
+import abc
+
+import six
+
+
+@six.add_metaclass(abc.ABCMeta)
+class HPA_DiscoveryBase(object):
+    """Base class for example plugin used in the tutorial.
+    """
+
+    def __init__(self):
+        """do nothing""" 
+
+    @abc.abstractmethod
+    def get_hpa_capabilities(self, data):
+        """Get cpupinning capabilities.
+
+        :param data: A dictionary with string keys and simple types as
+                     values.
+        :type data: dict(str:?)
+        :returns: Iterable producing the formatted text.
+        """
diff --git a/hpa/hpa/hpa_discovery.py b/hpa/hpa/hpa_discovery.py
new file mode 100644 (file)
index 0000000..69b9f22
--- /dev/null
@@ -0,0 +1,450 @@
+import traceback
+import uuid
+import json
+import logging
+from hpa import base
+
+
+def ignore_case_get(args, key, def_val=""):
+    if not key:
+        return def_val
+    if key in args:
+        return args[key]
+    for old_key in args:
+        if old_key.upper() == key.upper():
+            return args[old_key]
+    return def_val
+
+class HPA_Discovery(base.HPA_DiscoveryBase):
+    """HPA Discovery implementation.
+    """
+    def __init__(self):
+        if not hasattr(self, "_logger"):
+            self._logger = logging.getLogger("hpa_discovery")
+            self.fh = logging.FileHandler('discovery.log')
+            self.fh.setLevel(logging.INFO)
+            self._logger.addHandler(self.fh)
+
+    def get_hpa_capabilities(self, data):
+        hpa_caps = []
+
+        # Basic capabilties
+        caps_dict = self._get_hpa_basic_capabilities(data)
+        if len(caps_dict) > 0:
+            self._logger.debug("basic_capabilities_info: %s" % caps_dict)
+            hpa_caps.append(caps_dict)
+
+        # cpupining capabilities
+        caps_dict = self._get_cpupining_capabilities(data)
+        if len(caps_dict) > 0:
+            self._logger.debug("cpupining_capabilities_info: %s" % caps_dict)
+            hpa_caps.append(caps_dict)
+
+        # cputopology capabilities
+        caps_dict = self._get_cputopology_capabilities(data)
+        if len(caps_dict) > 0:
+            self._logger.debug("cputopology_capabilities_info: %s" % caps_dict)
+            hpa_caps.append(caps_dict)
+
+        # hugepages capabilities
+        caps_dict = self._get_hugepages_capabilities(data)
+        if len(caps_dict) > 0:
+            self._logger.debug("hugepages_capabilities_info: %s" % caps_dict)
+            hpa_caps.append(caps_dict)
+
+        # numa capabilities
+        caps_dict = self._get_numa_capabilities(data)
+        if len(caps_dict) > 0:
+            self._logger.debug("numa_capabilities_info: %s" % caps_dict)
+            hpa_caps.append(caps_dict)
+
+        # storage capabilities
+        caps_dict = self._get_storage_capabilities(data)
+        if len(caps_dict) > 0:
+            self._logger.debug("storage_capabilities_info: %s" % caps_dict)
+            hpa_caps.append(caps_dict)
+
+        # CPU instruction set extension capabilities
+        caps_dict = self._get_instruction_set_capabilities(data)
+        if len(caps_dict) > 0:
+            self._logger.debug("instruction_set_capabilities_info: %s" % caps_dict)
+            hpa_caps.append(caps_dict)
+
+        # PCI passthrough capabilities
+        caps_dict = self._get_pci_passthrough_capabilities(data)
+        if len(caps_dict) > 0:
+            self._logger.debug("pci_passthrough_capabilities_info: %s" % caps_dict)
+            hpa_caps.append(caps_dict)
+
+        # SRIOV-NIC capabilities
+        caps_dict = self._get_sriov_nic_capabilities(data)
+        if len(caps_dict) > 0:
+            self._logger.debug("sriov_nic_capabilities_info: %s" % caps_dict)
+            hpa_caps.append(caps_dict)
+
+        # ovsdpdk capabilities
+        caps_dict = self._get_ovsdpdk_capabilities(data)
+        if len(caps_dict) > 0:
+            self._logger.debug("ovsdpdk_capabilities_info: %s" % caps_dict)
+            hpa_caps.append(caps_dict)
+
+        # self._logger.error("hpa_caps: %s" % (hpa_caps))
+        return hpa_caps
+
+    def _get_hpa_basic_capabilities(self, data):
+        basic_capability = {}
+        feature_uuid = uuid.uuid4()
+        flavor = data["flavor"]
+
+        try:
+            basic_capability['hpa-capability-id'] = str(feature_uuid)
+            basic_capability['hpa-feature'] = 'basicCapabilities'
+            basic_capability['architecture'] = 'generic'
+            basic_capability['hpa-version'] = 'v1'
+
+            basic_capability['hpa-feature-attributes'] = []
+            basic_capability['hpa-feature-attributes'].append(
+                {'hpa-attribute-key': 'numVirtualCpu',
+                 'hpa-attribute-value':
+                     '{{\"value\":\"{0}\"}}'.format(flavor['vcpus'])
+                 })
+            basic_capability['hpa-feature-attributes'].append(
+                {'hpa-attribute-key':'virtualMemSize',
+                 'hpa-attribute-value':
+                     '{{\"value\":\"{0}\",\"unit\":\"{1}\"}}'.format(flavor['ram'],"MB")
+                 })
+        except Exception as e:
+            self._logger.error(traceback.format_exc())
+            return (
+                11, e.message
+            )
+
+        return basic_capability
+
+    def _get_cpupining_capabilities(self, data):
+        cpupining_capability = {}
+        feature_uuid = uuid.uuid4()
+        extra_specs = data["extra_specs"]
+
+        try:
+            if 'hw:cpu_policy' in extra_specs\
+                    or 'hw:cpu_thread_policy' in extra_specs:
+                cpupining_capability['hpa-capability-id'] = str(feature_uuid)
+                cpupining_capability['hpa-feature'] = 'cpuPinning'
+                cpupining_capability['architecture'] = 'generic'
+                cpupining_capability['hpa-version'] = 'v1'
+
+                cpupining_capability['hpa-feature-attributes'] = []
+                if 'hw:cpu_thread_policy' in extra_specs:
+                    cpupining_capability['hpa-feature-attributes'].append(
+                        {'hpa-attribute-key': 'logicalCpuThreadPinningPolicy',
+                         'hpa-attribute-value':
+                             '{{\"value\":\"{0}\"}}'.format(
+                                 extra_specs['hw:cpu_thread_policy'])
+                         })
+                if 'hw:cpu_policy' in extra_specs:
+                    cpupining_capability['hpa-feature-attributes'].append(
+                        {'hpa-attribute-key':'logicalCpuPinningPolicy',
+                         'hpa-attribute-value':
+                             '{{\"value\":\"{0}\"}}'.format(
+                                 extra_specs['hw:cpu_policy'])
+                         })
+        except Exception:
+            self._logger.error(traceback.format_exc())
+
+        return cpupining_capability
+
+    def _get_cputopology_capabilities(self, data):
+        cputopology_capability = {}
+        feature_uuid = uuid.uuid4()
+        extra_specs = data["extra_specs"]
+
+        try:
+            if 'hw:cpu_sockets' in extra_specs\
+                    or 'hw:cpu_cores' in extra_specs\
+                    or 'hw:cpu_threads' in extra_specs:
+                cputopology_capability['hpa-capability-id'] = str(feature_uuid)
+                cputopology_capability['hpa-feature'] = 'cpuTopology'
+                cputopology_capability['architecture'] = 'generic'
+                cputopology_capability['hpa-version'] = 'v1'
+
+                cputopology_capability['hpa-feature-attributes'] = []
+                if 'hw:cpu_sockets' in extra_specs:
+                    cputopology_capability['hpa-feature-attributes'].append(
+                        {'hpa-attribute-key': 'numCpuSockets',
+                         'hpa-attribute-value':
+                             '{{\"value\":\"{0}\"}}'.format(extra_specs['hw:cpu_sockets'])
+                         })
+                if 'hw:cpu_cores' in extra_specs:
+                    cputopology_capability['hpa-feature-attributes'].append(
+                        {'hpa-attribute-key': 'numCpuCores',
+                         'hpa-attribute-value':
+                             '{{\"value\":\"{0}\"}}'.format(extra_specs['hw:cpu_cores'])
+                         })
+                if 'hw:cpu_threads' in extra_specs:
+                    cputopology_capability['hpa-feature-attributes'].append(
+                        {'hpa-attribute-key': 'numCpuThreads',
+                         'hpa-attribute-value':
+                             '{{\"value\":\"{0}\"}}'.format(extra_specs['hw:cpu_threads'])
+                         })
+        except Exception:
+            self._logger.error(traceback.format_exc())
+
+        return cputopology_capability
+
+    def _get_hugepages_capabilities(self, data):
+        hugepages_capability = {}
+        feature_uuid = uuid.uuid4()
+        extra_specs = data["extra_specs"]
+
+        try:
+            if 'hw:mem_page_size' in extra_specs:
+                hugepages_capability['hpa-capability-id'] = str(feature_uuid)
+                hugepages_capability['hpa-feature'] = 'hugePages'
+                hugepages_capability['architecture'] = 'generic'
+                hugepages_capability['hpa-version'] = 'v1'
+
+                hugepages_capability['hpa-feature-attributes'] = []
+                if extra_specs['hw:mem_page_size'] == 'large':
+                    hugepages_capability['hpa-feature-attributes'].append(
+                        {'hpa-attribute-key': 'memoryPageSize',
+                         'hpa-attribute-value':
+                             '{{\"value\":\"{0}\",\"unit\":\"{1}\"}}'.format(2,"MB")
+                         })
+                elif extra_specs['hw:mem_page_size'] == 'small':
+                    hugepages_capability['hpa-feature-attributes'].append(
+                        {'hpa-attribute-key': 'memoryPageSize',
+                         'hpa-attribute-value':
+                             '{{\"value\":\"{0}\",\"unit\":\"{1}\"}}'.format(4,"KB")
+                         })
+                elif extra_specs['hw:mem_page_size'] == 'any':
+                    self._logger.info("Currently HPA feature memoryPageSize did not support 'any' page!!")
+                else :
+                    hugepages_capability['hpa-feature-attributes'].append(
+                        {'hpa-attribute-key': 'memoryPageSize',
+                         'hpa-attribute-value':
+                             '{{\"value\":\"{0}\",\"unit\":\"{1}\"}}'.format(extra_specs['hw:mem_page_size'],"KB")
+                         })
+        except Exception:
+            self._logger.error(traceback.format_exc())
+
+        return hugepages_capability
+
+    def _get_numa_capabilities(self, data):
+        numa_capability = {}
+        feature_uuid = uuid.uuid4()
+        extra_specs = data["extra_specs"]
+
+        try:
+            if 'hw:numa_nodes' in extra_specs:
+                numa_capability['hpa-capability-id'] = str(feature_uuid)
+                numa_capability['hpa-feature'] = 'numa'
+                numa_capability['architecture'] = 'generic'
+                numa_capability['hpa-version'] = 'v1'
+
+                numa_capability['hpa-feature-attributes'] = []
+                numa_capability['hpa-feature-attributes'].append(
+                    {'hpa-attribute-key': 'numaNodes',
+                     'hpa-attribute-value':
+                         '{{\"value\":\"{0}\"}}'.format(extra_specs['hw:numa_nodes'] or 0)
+                     })
+
+                for num in range(0, int(extra_specs['hw:numa_nodes'])):
+                    numa_cpu_node = "hw:numa_cpus.%s" % num
+                    numa_mem_node = "hw:numa_mem.%s" % num
+                    numacpu_key = "numaCpu-%s" % num
+                    numamem_key = "numaMem-%s" % num
+
+                    if numa_cpu_node in extra_specs and numa_mem_node in extra_specs:
+                        numa_capability['hpa-feature-attributes'].append(
+                            {'hpa-attribute-key': numacpu_key,
+                             'hpa-attribute-value':
+                                 '{{\"value\":\"{0}\"}}'.format(extra_specs[numa_cpu_node])
+                             })
+                        numa_capability['hpa-feature-attributes'].append(
+                            {'hpa-attribute-key': numamem_key,
+                             'hpa-attribute-value':
+                                 '{{\"value\":\"{0}\",\"unit\":\"{1}\"}}'.format(extra_specs[numa_mem_node],"MB")
+                             })
+        except Exception:
+            self._logger.error(traceback.format_exc())
+
+        return numa_capability
+
+    def _get_storage_capabilities(self, data):
+        storage_capability = {}
+        feature_uuid = uuid.uuid4()
+        flavor = data["flavor"]
+
+        try:
+            storage_capability['hpa-capability-id'] = str(feature_uuid)
+            storage_capability['hpa-feature'] = 'localStorage'
+            storage_capability['architecture'] = 'generic'
+            storage_capability['hpa-version'] = 'v1'
+
+            storage_capability['hpa-feature-attributes'] = []
+            storage_capability['hpa-feature-attributes'].append(
+                {'hpa-attribute-key': 'diskSize',
+                 'hpa-attribute-value':
+                     '{{\"value\":\"{0}\",\"unit\":\"{1}\"}}'.format(
+                         flavor['disk'] or 0, "GB")
+                 })
+            storage_capability['hpa-feature-attributes'].append(
+                {'hpa-attribute-key': 'swapMemSize',
+                 'hpa-attribute-value':
+                     '{{\"value\":\"{0}\",\"unit\":\"{1}\"}}'.format(
+                         flavor['swap'] or 0, "MB")
+                 })
+            storage_capability['hpa-feature-attributes'].append(
+                {'hpa-attribute-key': 'ephemeralDiskSize',
+                 'hpa-attribute-value':
+                     '{{\"value\":\"{0}\",\"unit\":\"{1}\"}}'.format(
+                         flavor['OS-FLV-EXT-DATA:ephemeral'] or 0, "GB")
+                 })
+        except Exception:
+            self._logger.error(traceback.format_exc())
+
+        return storage_capability
+
+    def _get_instruction_set_capabilities(self, data):
+        instruction_capability = {}
+        feature_uuid = uuid.uuid4()
+        extra_specs = data["extra_specs"]
+
+        try:
+            if 'hw:capabilities:cpu_info:features' in extra_specs:
+                instruction_capability['hpa-capability-id'] = str(feature_uuid)
+                instruction_capability['hpa-feature'] = 'instructionSetExtensions'
+                instruction_capability['architecture'] = 'Intel64'
+                instruction_capability['hpa-version'] = 'v1'
+
+                instruction_capability['hpa-feature-attributes'] = []
+                instruction_capability['hpa-feature-attributes'].append(
+                    {'hpa-attribute-key': 'instructionSetExtensions',
+                     'hpa-attribute-value':
+                         '{{\"value\":\"{0}\"}}'.format(
+                             extra_specs['hw:capabilities:cpu_info:features'])
+                     })
+        except Exception:
+            self._logger.error(traceback.format_exc())
+
+        return instruction_capability
+
+    def _get_pci_passthrough_capabilities(self, data):
+        pci_passthrough_capability = {}
+        feature_uuid = uuid.uuid4()
+        extra_specs = data["extra_specs"]
+
+        try:
+
+            if 'pci_passthrough:alias' in extra_specs:
+                value1 = extra_specs['pci_passthrough:alias'].split(':')
+                value2 = value1[0].split('-')
+
+                pci_passthrough_capability['hpa-capability-id'] = str(feature_uuid)
+                pci_passthrough_capability['hpa-feature'] = 'pciePassthrough'
+                pci_passthrough_capability['architecture'] = str(value2[2])
+                pci_passthrough_capability['hpa-version'] = 'v1'
+
+
+                pci_passthrough_capability['hpa-feature-attributes'] = []
+                pci_passthrough_capability['hpa-feature-attributes'].append(
+                    {'hpa-attribute-key': 'pciCount',
+                     'hpa-attribute-value':
+                         '{{\"value\":\"{0}\"}}'.format(value1[1])
+                     })
+                pci_passthrough_capability['hpa-feature-attributes'].append(
+                    {'hpa-attribute-key': 'pciVendorId',
+                     'hpa-attribute-value':
+                         '{{\"value\":\"{0}\"}}'.format(value2[3])
+                     })
+                pci_passthrough_capability['hpa-feature-attributes'].append(
+                    {'hpa-attribute-key': 'pciDeviceId',
+                     'hpa-attribute-value':
+                         '{{\"value\":\"{0}\"}}'.format(value2[4])
+                                                                         })
+        except Exception:
+            self._logger.error(traceback.format_exc())
+
+        return pci_passthrough_capability
+
+    def _get_sriov_nic_capabilities(self, data):
+        sriov_capability = {}
+        feature_uuid = uuid.uuid4()
+        extra_specs = data["extra_specs"]
+
+        try:
+            if 'aggregate_instance_extra_specs:sriov_nic' in extra_specs:
+                value1 = extra_specs['aggregate_instance_extra_specs:sriov_nic'].split(':')
+                value2 = value1[0].split('-', 5)
+
+                sriov_capability['hpa-capability-id'] = str(feature_uuid)
+                sriov_capability['hpa-feature'] = 'sriovNICNetwork'
+                sriov_capability['architecture'] = str(value2[2])
+                sriov_capability['hpa-version'] = 'v1'
+
+                sriov_capability['hpa-feature-attributes'] = []
+                sriov_capability['hpa-feature-attributes'].append(
+                    {'hpa-attribute-key': 'pciCount',
+                     'hpa-attribute-value':
+                         '{{\"value\":\"{0}\"}}'.format(value1[1])})
+                sriov_capability['hpa-feature-attributes'].append(
+                    {'hpa-attribute-key': 'pciVendorId',
+                     'hpa-attribute-value':
+                         '{{\"value\":\"{0}\"}}'.format(value2[3])})
+                sriov_capability['hpa-feature-attributes'].append(
+                    {'hpa-attribute-key': 'pciDeviceId',
+                     'hpa-attribute-value':
+                         '{{\"value\":\"{0}\"}}'.format(value2[4])})
+                sriov_capability['hpa-feature-attributes'].append(
+                    {'hpa-attribute-key': 'physicalNetwork',
+                     'hpa-attribute-value':
+                         '{{\"value\":\"{0}\"}}'.format(value2[5])})
+        except Exception:
+            self._logger.error(traceback.format_exc())
+
+        return sriov_capability
+
+    def _get_ovsdpdk_capabilities(self, data):
+        ovsdpdk_capability = {}
+        feature_uuid = uuid.uuid4()
+        extra_specs = data["extra_specs"]
+        viminfo = data["viminfo"]
+        vimtype = data["vimtype"]
+        libname = "dataProcessingAccelerationLibrary"
+        libversion = "12.1"
+
+        try:
+            ovsdpdk_capability['hpa-capability-id'] = str(feature_uuid)
+            ovsdpdk_capability['hpa-feature'] = 'ovsDpdk'
+            ovsdpdk_capability['architecture'] = 'Intel64'
+            ovsdpdk_capability['hpa-version'] = 'v1'
+
+            cloud_extra_info_str = viminfo.get('cloud_extra_info')
+            if cloud_extra_info_str in [None, '']:
+                if vimtype in ["windriver", "starlingx"]:
+                    libname = "dataProcessingAccelerationLibrary"
+                    libversion = "17.2"
+            else:
+                if not isinstance(cloud_extra_info_str, dict):
+                    try:
+                        cloud_extra_info_str = json.loads(cloud_extra_info_str)
+                    except Exception as ex:
+                        logger.error("Can not convert cloud extra info %s %s" % (
+                                     str(ex), cloud_extra_info_str))
+                        return {}
+                if cloud_extra_info_str :
+                    cloud_dpdk_info = cloud_extra_info_str.get("ovsDpdk")
+                    if cloud_dpdk_info :
+                        libname = cloud_dpdk_info.get("libname")
+                        libversion = cloud_dpdk_info.get("libversion")
+            
+            ovsdpdk_capability['hpa-feature-attributes'] = [
+                {
+                    'hpa-attribute-key': str(libname),
+                    'hpa-attribute-value': '{{\"value\":\"{0}\"}}'.format(libversion)
+                },]
+        except Exception:
+            self._logger.error(traceback.format_exc())
+
+        return ovsdpdk_capability
diff --git a/hpa/mvn-phase-script.sh b/hpa/mvn-phase-script.sh
new file mode 100755 (executable)
index 0000000..6cc1b2b
--- /dev/null
@@ -0,0 +1,83 @@
+#!/bin/bash
+# Copyright (c) 2017-2018 Wind River Systems, Inc.
+#
+# 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.
+
+
+set -e
+
+echo "running script: [$0] for module [$1] at stage [$2]"
+
+export SETTINGS_FILE=${SETTINGS_FILE:-$HOME/.m2/settings.xml}
+MVN_PROJECT_MODULEID="$1"
+MVN_PHASE="$2"
+
+
+FQDN="${MVN_PROJECT_GROUPID}.${MVN_PROJECT_ARTIFACTID}"
+if [ "$MVN_PROJECT_MODULEID" == "__" ]; then
+  MVN_PROJECT_MODULEID=""
+fi
+
+if [ -z "$WORKSPACE" ]; then
+    WORKSPACE=$(pwd)
+fi
+
+# mvn phase in life cycle
+MVN_PHASE="$2"
+
+
+echo "MVN_PROJECT_MODULEID is            [$MVN_PROJECT_MODULEID]"
+echo "MVN_PHASE is                       [$MVN_PHASE]"
+echo "MVN_PROJECT_GROUPID is             [$MVN_PROJECT_GROUPID]"
+echo "MVN_PROJECT_ARTIFACTID is          [$MVN_PROJECT_ARTIFACTID]"
+echo "MVN_PROJECT_VERSION is             [$MVN_PROJECT_VERSION]"
+
+run_tox_test()
+{
+  set -x
+  echo $PWD
+  CURDIR=$(pwd)
+  TOXINIS=$(find . -name "tox.ini")
+  cd ..
+  for TOXINI in "${TOXINIS[@]}"; do
+    DIR=$(echo "$TOXINI" | rev | cut -f2- -d'/' | rev)
+    cd "${CURDIR}/${DIR}"
+    rm -rf ./venv-tox ./.tox
+    virtualenv ./venv-tox --python=python3
+    source ./venv-tox/bin/activate
+    pip install --upgrade pip
+    pip install --upgrade tox argparse
+    pip freeze
+    cd ${CURDIR}
+    tox
+    deactivate
+    cd ..
+    rm -rf ./venv-tox ./.tox
+  done
+}
+
+
+case $MVN_PHASE in
+clean)
+  echo "==> clean phase script"
+  rm -rf ./venv-*
+  ;;
+test)
+  echo "==> test phase script"
+  run_tox_test
+  ;;
+*)
+  echo "==> unprocessed phase"
+  ;;
+esac
+
diff --git a/hpa/pom.xml b/hpa/pom.xml
new file mode 100644 (file)
index 0000000..7d65834
--- /dev/null
@@ -0,0 +1,199 @@
+<?xml version="1.0"?>
+<!--
+ Copyright (c) Intel 2020, Inc.
+
+ 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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <groupId>org.onap.multicloud.openstack</groupId>
+        <artifactId>multicloud-openstack-root</artifactId>
+        <version>1.5.3-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+    <groupId>org.onap.multicloud.openstack</groupId>
+    <artifactId>multicloud-openstack-hpa</artifactId>
+    <version>1.5.3-SNAPSHOT</version>
+    <packaging>pom</packaging>
+    <name>multicloud-openstack-hpar</name>
+    <description>multicloud for hpa plugin</description>
+    <properties>
+        <encoding>UTF-8</encoding>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
+        <nexusproxy>https://nexus.onap.org</nexusproxy>
+        <sonar.sources>.</sonar.sources>
+        <sonar.junit.reportsPath>xunit-results.xml</sonar.junit.reportsPath>
+        <sonar.python.coverage.reportPath>coverage.xml</sonar.python.coverage.reportPath>
+        <sonar.language>py</sonar.language>
+        <sonar.pluginName>Python</sonar.pluginName>
+        <sonar.inclusions>**/*.py</sonar.inclusions>
+        <sonar.exclusions>**/venv-tox/**,**/.tox/**, **/tests/**,setup.py</sonar.exclusions>
+    </properties>
+    <build>
+      <pluginManagement>
+        <plugins>
+            <plugin>
+              <groupId>org.codehaus.mojo</groupId>
+              <artifactId>exec-maven-plugin</artifactId>
+              <version>1.2.1</version>
+              <configuration>
+                <executable>${project.basedir}/mvn-phase-script.sh</executable>
+                <environmentVariables>
+                  <!-- make mvn properties as env for our script -->
+                  <MVN_PROJECT_GROUPID>${project.groupId}</MVN_PROJECT_GROUPID>
+                  <MVN_PROJECT_ARTIFACTID>${project.artifactId}</MVN_PROJECT_ARTIFACTID>
+                  <MVN_PROJECT_VERSION>${project.version}</MVN_PROJECT_VERSION>
+                </environmentVariables>
+              </configuration>
+            </plugin>
+        </plugins>
+      </pluginManagement>
+        <plugins>
+        <plugin>
+            <groupId>org.codehaus.mojo</groupId>
+            <artifactId>exec-maven-plugin</artifactId>
+            <version>1.2.1</version>
+            <executions>
+              <execution>
+                <id>clean phase script</id>
+                <phase>clean</phase>
+                <goals>
+                  <goal>exec</goal>
+                </goals>
+                <configuration>
+                  <arguments>
+                    <argument>__</argument>
+                    <argument>clean</argument>
+                  </arguments>
+                </configuration>
+              </execution>
+              <execution>
+                <id>test script</id>
+                <phase>test</phase>
+                <goals>
+                  <goal>exec</goal>
+                </goals>
+                <configuration>
+                  <arguments>
+                    <argument>__</argument>
+                    <argument>test</argument>
+                  </arguments>
+                </configuration>
+              </execution>
+            </executions>
+        </plugin>
+        <plugin>
+            <artifactId>maven-assembly-plugin</artifactId>
+            <configuration>
+                <appendAssemblyId>false</appendAssemblyId>
+                <descriptors>
+                    <descriptor>assembly.xml</descriptor>
+                </descriptors>
+            </configuration>
+            <executions>
+                <execution>
+                    <id>make-assembly</id>
+                    <phase>package</phase>
+                    <goals>
+                        <goal>single</goal>
+                    </goals>
+                </execution>
+            </executions>
+        </plugin>
+      </plugins>
+    </build>
+    <profiles>
+        <profile>
+            <id>docker</id>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-resources-plugin</artifactId>
+                        <version>3.1.0</version>
+                        <executions>
+                            <execution>
+                                <id>copy-resources</id>
+                                <phase>install</phase>
+                                <goals>
+                                    <goal>copy-resources</goal>
+                                </goals>
+                                <configuration>
+                                    <overwrite>true</overwrite>
+                                    <nonFilteredFileExtensions>
+                                        <nonFilteredFileExtension>zip</nonFilteredFileExtension>
+                                    </nonFilteredFileExtensions>
+                                    <outputDirectory>${project.basedir}/docker_target</outputDirectory>
+                                    <resources>
+                                        <resource>
+                                            <directory>${project.basedir}/docker</directory>
+                                            <filtering>true</filtering>
+                                        </resource>
+                                        <resource>
+                                            <directory>${project.basedir}/target</directory>
+                                            <filtering>true</filtering>
+                                            <includes>
+                                                <include>*.zip</include>
+                                            </includes>
+                                        </resource>
+                                    </resources>
+                                </configuration>
+                            </execution>
+                        </executions>
+                    </plugin>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-antrun-plugin</artifactId>
+                        <version>1.6</version>
+                        <executions>
+                            <execution>
+                                <phase>install</phase>
+                                <inherited>false</inherited>
+                                <configuration>
+                                    <target>
+                                        <exec executable="docker">
+                                           <arg value="build"/>
+                                           <arg value="-t"/>
+                                           <arg value="${CONTAINER_PUSH_REGISTRY}/onap/multicloud/openstack-hpa:${project.version}"/>
+                                           <arg value="docker_target"/>
+                                        </exec>
+                                        <exec executable="docker">
+                                            <arg value="tag"/>
+                                            <arg value="${CONTAINER_PUSH_REGISTRY}/onap/multicloud/openstack-hpa:${project.version}"/>
+                                            <arg value="${CONTAINER_PUSH_REGISTRY}/onap/multicloud/openstack-hpa:latest"/>
+                                        </exec>
+                                        <exec executable="docker">
+                                            <arg value="push"/>
+                                            <arg value="${CONTAINER_PUSH_REGISTRY}/onap/multicloud/openstack-hpa:${project.version}"/>
+                                        </exec>
+                                        <exec executable="docker">
+                                            <arg value="push"/>
+                                            <arg value="${CONTAINER_PUSH_REGISTRY}/onap/multicloud/openstack-hpa:latest"/>
+                                        </exec>
+                                    </target>
+                                </configuration>
+                                <goals>
+                                    <goal>run</goal>
+                                </goals>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+            <activation>
+                <activeByDefault>false</activeByDefault>
+            </activation>
+        </profile>
+    </profiles>
+</project>
diff --git a/hpa/setup.py b/hpa/setup.py
new file mode 100644 (file)
index 0000000..93babd2
--- /dev/null
@@ -0,0 +1,43 @@
+from setuptools import setup, find_packages
+
+setup(
+    name='hpa',
+    version='1.0',
+
+    description='HPA discovery package for stevedore',
+
+    author='Haibin Huang',
+    author_email='haibin.huang@intel.com',
+
+    url='https://opendev.org/openstack/stevedore',
+
+    classifiers=['Development Status :: 3 - Alpha',
+                 'License :: OSI Approved :: Apache Software License',
+                 'Programming Language :: Python',
+                 'Programming Language :: Python :: 2',
+                 'Programming Language :: Python :: 2.7',
+                 'Programming Language :: Python :: 3',
+                 'Programming Language :: Python :: 3.5',
+                 'Intended Audience :: Developers',
+                 'Environment :: Console',
+                 ],
+
+    platforms=['Any'],
+
+    scripts=[],
+
+    provides=['hpa',
+              ],
+
+    packages=find_packages(),
+    install_requires=['stevedore'],
+    include_package_data=True,
+
+    entry_points={
+        'hpa.discovery': [
+            'discovery = hpa.hpa_discovery:HPA_Discovery',
+        ],
+    },
+
+    zip_safe=False,
+)
diff --git a/hpa/tests/__init__.py b/hpa/tests/__init__.py
new file mode 100644 (file)
index 0000000..792d600
--- /dev/null
@@ -0,0 +1 @@
+#
diff --git a/hpa/tests/test.py b/hpa/tests/test.py
new file mode 100644 (file)
index 0000000..a9fdcd7
--- /dev/null
@@ -0,0 +1,148 @@
+from __future__ import print_function
+
+import argparse
+
+from stevedore import extension
+
+
+if __name__ == '__main__':
+
+    parser = argparse.ArgumentParser()
+    parser.add_argument('-f', action='store', dest='dpdk', help='dpdk use?')
+    parser.add_argument('-t', action='store', dest='vimtype', help='vim type')
+    parser.add_argument('--version', action='version', version='%(prog)s 1.0')
+    results = parser.parse_args()
+    dpdk = results.dpdk
+    vimtype = results.vimtype
+
+    flavor = {
+        "vcpus": 2,
+        "ram": "2048",
+        "disk": "2G",
+        "swap": False,
+        "OS-FLV-EXT-DATA:ephemeral": False
+    }
+
+    # viminfo
+    viminfo = {
+        "createTime": "2017-04-01 02:22:27",
+        "domain": "Default",
+        "name": "TiS_R4",
+        "password": "admin",
+        "tenant": "admin",
+        "type": "openstack",
+        "url": "http://128.224.180.14:5000/v3",
+        "userName": "admin",
+        "vendor": "WindRiver",
+        "version": "newton",
+        "vimId": "windriver-hudson-dc_RegionOne",
+        'cloud_owner': 'windriver-hudson-dc',
+        'cloud_region_id': 'RegionOne',
+        'insecure': 'True'
+    }
+
+    # Add cloud_extra_info in convert_vim_info
+    viminfo_with_dpdk = {
+        "createTime": "2017-04-01 02:22:27",
+        "domain": "Default",
+        "name": "TiS_R4",
+        "password": "admin",
+        "tenant": "admin",
+        "type": "openstack",
+        "url": "http://128.224.180.14:5000/v3",
+        "userName": "admin",
+        "vendor": "WindRiver",
+        "version": "newton",
+        "vimId": "windriver-hudson-dc_RegionOne",
+        'cloud_owner': 'windriver-hudson-dc',
+        'cloud_region_id': 'RegionOne',
+        'insecure': 'True',
+        'cloud_extra_info': '{ \
+            "ovsDpdk": { \
+                "version": "v1", \
+                "arch": "Intel64", \
+                "libname": "dataProcessingAccelerationLibrary", \
+                "libversion": "v12.1" \
+            } \
+        }'
+    }
+
+    # flavor extra specs
+    extra_specs = [
+        # HPA UT1: CPU-Pinning
+        {
+            "aggregate_instance_extra_specs:storage": "local_image",
+            "capabilities:cpu_info:model": "Haswell",
+            "hw:cpu_policy": "dedicated",
+            "hw:cpu_thread_policy": "prefer"
+        },
+        # HPA UT2: CPU-Topology
+        {
+            "aggregate_instance_extra_specs:storage": "local_image",
+            "capabilities:cpu_info:model": "Haswell",
+            "hw:cpu_sockets": "2",
+            "hw:cpu_cores": "4",
+            "hw:cpu_threads": "16"
+        },
+        # HPA UT3: mem_page_size
+        {
+            "aggregate_instance_extra_specs:storage": "local_image",
+            "capabilities:cpu_info:model": "Haswell",
+            "hw:mem_page_size": "large"
+        },
+        # HPA UT4: numa_nodes
+        {
+            "aggregate_instance_extra_specs:storage": "local_image",
+            "capabilities:cpu_info:model": "Haswell",
+            "hw:numa_nodes": "2",
+            "hw:numa_cpus.0": "0,1",
+            "hw:numa_cpus.1": "2,3,4,5",
+            "hw:numa_mem.0": "2048",
+            "hw:numa_mem.1": "2048"
+        },
+        # HPA UT5: instruction set
+        {
+            "aggregate_instance_extra_specs:storage": "local_image",
+            "capabilities:cpu_info:model": "Haswell",
+            "hw:capabilities:cpu_info:features": "avx,acpi"
+        },
+        # HPA UT6: pci passthrough
+        {
+            "aggregate_instance_extra_specs:storage": "local_image",
+            "capabilities:cpu_info:model": "Haswell",
+            "pci_passthrough:alias": "sriov-vf-intel-8086-15b3:4"
+        },
+        # HPA UT7: sriov-nic
+        {
+            "aggregate_instance_extra_specs:sriov_nic": "sriov-nic-intel-8086-15b3-physnet-1:1",
+            "capabilities:cpu_info:model": "Haswell"
+        }
+    ]
+
+
+    def get_hpa_capabilities(ext, data):
+        return (ext.obj.get_hpa_capabilities(data))
+
+    extra_specs = [
+        # HPA UT1: CPU-Pinning
+        {
+            "aggregate_instance_extra_specs:storage": "local_image",
+            "capabilities:cpu_info:model": "Haswell",
+            "hw:cpu_policy": "dedicated",
+            "hw:cpu_thread_policy": "prefer"
+        },
+    ]
+    if dpdk != "dpdk":
+        viminfo = viminfo
+    else:
+        viminfo = viminfo_with_dpdk
+
+    for extra_spec in extra_specs:
+        data = {"flavor": flavor, "extra_specs": extra_spec, "viminfo": viminfo, "vimtype": vimtype}
+        mgr = extension.ExtensionManager(
+            namespace='hpa.discovery',
+            invoke_on_load=True,
+        )
+        
+        results = mgr.map(get_hpa_capabilities, data)
+        print(results)
diff --git a/hpa/tests/test_hpa_discovery.py b/hpa/tests/test_hpa_discovery.py
new file mode 100644 (file)
index 0000000..c63f377
--- /dev/null
@@ -0,0 +1,105 @@
+import unittest
+
+from hpa import hpa_discovery
+
+class TestDiscovery(unittest.TestCase):
+    def test_hpa_discovery(self):
+        """
+        Test that it can discovery hpa capability
+        """
+
+        flavor = {
+            "vcpus": 2,
+            "ram": "2048",
+            "disk": "2G",
+            "swap": False,
+            "OS-FLV-EXT-DATA:ephemeral": False
+        }
+
+        # Add cloud_extra_info in convert_vim_info
+        viminfo = {
+            "createTime": "2017-04-01 02:22:27",
+            "domain": "Default",
+            "name": "TiS_R4",
+            "password": "admin",
+            "tenant": "admin",
+            "type": "openstack",
+            "url": "http://128.224.180.14:5000/v3",
+            "userName": "admin",
+            "vendor": "WindRiver",
+            "version": "newton",
+            "vimId": "windriver-hudson-dc_RegionOne",
+            'cloud_owner': 'windriver-hudson-dc',
+            'cloud_region_id': 'RegionOne',
+            'insecure': 'True',
+            'cloud_extra_info': '{ \
+                "ovsDpdk": { \
+                    "version": "v1", \
+                    "arch": "Intel64", \
+                    "libname": "dataProcessingAccelerationLibrary", \
+                    "libversion": "v12.1" \
+                } \
+            }'
+        }
+
+        # flavor extra specs
+        extra_specs = [
+            # HPA UT1: CPU-Pinning
+            {
+                "aggregate_instance_extra_specs:storage": "local_image",
+                "capabilities:cpu_info:model": "Haswell",
+                "hw:cpu_policy": "dedicated",
+                "hw:cpu_thread_policy": "prefer"
+            },
+            # HPA UT2: CPU-Topology
+            {
+                "aggregate_instance_extra_specs:storage": "local_image",
+                "capabilities:cpu_info:model": "Haswell",
+                "hw:cpu_sockets": "2",
+                "hw:cpu_cores": "4",
+                "hw:cpu_threads": "16"
+            },
+            # HPA UT3: mem_page_size
+            {
+                "aggregate_instance_extra_specs:storage": "local_image",
+                "capabilities:cpu_info:model": "Haswell",
+                "hw:mem_page_size": "large"
+            },
+            # HPA UT4: numa_nodes
+            {
+                "aggregate_instance_extra_specs:storage": "local_image",
+                "capabilities:cpu_info:model": "Haswell",
+                "hw:numa_nodes": "2",
+                "hw:numa_cpus.0": "0,1",
+                "hw:numa_cpus.1": "2,3,4,5",
+                "hw:numa_mem.0": "2048",
+                "hw:numa_mem.1": "2048"
+            },
+            # HPA UT5: instruction set
+            {
+                "aggregate_instance_extra_specs:storage": "local_image",
+                "capabilities:cpu_info:model": "Haswell",
+                "hw:capabilities:cpu_info:features": "avx,acpi"
+            },
+            # HPA UT6: pci passthrough
+            {
+                "aggregate_instance_extra_specs:storage": "local_image",
+                "capabilities:cpu_info:model": "Haswell",
+                "pci_passthrough:alias": "sriov-vf-intel-8086-15b3:4"
+            },
+            # HPA UT7: sriov-nic
+            {
+                "aggregate_instance_extra_specs:sriov_nic": "sriov-nic-intel-8086-15b3-physnet-1:1",
+                "capabilities:cpu_info:model": "Haswell"
+            }
+        ]
+
+        vimtype = "windriver"
+        hpa = hpa_discovery.HPA_Discovery()
+        for extra_spec in extra_specs:
+            data = {"flavor": flavor, "extra_specs": extra_spec, "viminfo": viminfo, "vimtype": vimtype}
+            results = hpa.get_hpa_capabilities(data)
+
+if __name__ == '__main__':
+    unittest.main()
+
diff --git a/hpa/tox.ini b/hpa/tox.ini
new file mode 100644 (file)
index 0000000..8727707
--- /dev/null
@@ -0,0 +1,8 @@
+[tox]
+envlist = py35
+
+[testenv]
+deps =
+
+commands =
+    python3 -m unittest discover
diff --git a/pom.xml b/pom.xml
index 478df46..e1d32a6 100644 (file)
--- a/pom.xml
+++ b/pom.xml
@@ -45,6 +45,7 @@
         <module>pike</module>
         <module>starlingx</module>
         <!--module>lenovo</module-->
+        <module>hpa</module>
     </modules>
 
     <build>