Extended Context class with get_physical_nodes functionality 01/59101/5
authorChornyi, TarasX <tarasx.chornyi@intel.com>
Mon, 11 Jun 2018 12:18:54 +0000 (15:18 +0300)
committerEmma Foley <emma.l.foley@intel.com>
Thu, 28 Jun 2018 10:32:33 +0000 (10:32 +0000)
JIRA: YARDSTICK-1255

Change-Id: I446d715dc6cf716a4fcbc1b809c1b1d6303071e0
Signed-off-by: Chornyi, TarasX <tarasx.chornyi@intel.com>
(cherry picked from commit 595212edf5ccd71af1bf7ef57a8d260fb1ec0c9e)

20 files changed:
yardstick/benchmark/contexts/base.py
yardstick/benchmark/contexts/dummy.py
yardstick/benchmark/contexts/heat.py
yardstick/benchmark/contexts/kubernetes.py
yardstick/benchmark/contexts/node.py
yardstick/benchmark/contexts/standalone/model.py
yardstick/benchmark/contexts/standalone/ovs_dpdk.py
yardstick/benchmark/contexts/standalone/sriov.py
yardstick/common/exceptions.py
yardstick/common/openstack_utils.py
yardstick/common/utils.py
yardstick/tests/unit/benchmark/contexts/standalone/test_model.py
yardstick/tests/unit/benchmark/contexts/standalone/test_ovs_dpdk.py
yardstick/tests/unit/benchmark/contexts/standalone/test_sriov.py
yardstick/tests/unit/benchmark/contexts/test_base.py
yardstick/tests/unit/benchmark/contexts/test_dummy.py
yardstick/tests/unit/benchmark/contexts/test_heat.py
yardstick/tests/unit/benchmark/contexts/test_kubernetes.py
yardstick/tests/unit/benchmark/contexts/test_node.py
yardstick/tests/unit/common/test_openstack_utils.py

index 64cee83..022e365 100644 (file)
@@ -8,10 +8,13 @@
 ##############################################################################
 
 import abc
+import errno
 import six
+import os
 
 from yardstick.common import constants
 from yardstick.common import utils
+from yardstick.common.constants import YARDSTICK_ROOT_PATH
 
 
 class Flags(object):
@@ -50,6 +53,7 @@ class Context(object):
         self._flags = Flags()
         self._name = None
         self._task_id = None
+        self.file_path = None
         self._host_name_separator = host_name_separator
 
     def init(self, attrs):
@@ -66,6 +70,26 @@ class Context(object):
             return tuple(name.split(self._host_name_separator, 1))
         return None, None
 
+    def read_pod_file(self, attrs):
+        self.file_path = file_path = attrs.get("file", "pod.yaml")
+        try:
+            cfg = utils.read_yaml_file(self.file_path)
+        except IOError as io_error:
+            if io_error.errno != errno.ENOENT:
+                raise
+
+            self.file_path = os.path.join(YARDSTICK_ROOT_PATH, file_path)
+            cfg = utils.read_yaml_file(self.file_path)
+
+        self.nodes.extend(cfg["nodes"])
+        self.controllers.extend([node for node in cfg["nodes"]
+                                 if node.get("role") == "Controller"])
+        self.computes.extend([node for node in cfg["nodes"]
+                              if node.get("role") == "Compute"])
+        self.baremetals.extend([node for node in cfg["nodes"]
+                                if node.get("role") == "Baremetal"])
+        return cfg
+
     @property
     def name(self):
         if self._flags.no_setup or self._flags.no_teardown:
@@ -130,6 +154,25 @@ class Context(object):
             raise ValueError("context not found for server %r" %
                              attr_name)
 
+    @staticmethod
+    def get_physical_nodes():
+        """return physical node names for all contexts"""
+        physical_nodes = {}
+        for context in Context.list:
+            nodes = context._get_physical_nodes()
+            physical_nodes.update({context._name: nodes})
+
+        return physical_nodes
+
+    @staticmethod
+    def get_physical_node_from_server(server_name):
+        """return physical nodes for all contexts"""
+        context = Context.get_context_from_server(server_name)
+        if context == None:
+            return  None
+
+        return context._get_physical_node_for_server(server_name)
+
     @staticmethod
     def get_context_from_server(attr_name):
         """lookup context info by name from node config
@@ -159,3 +202,15 @@ class Context(object):
         except StopIteration:
             raise ValueError("context not found for server %r" %
                              attr_name)
+
+    @abc.abstractmethod
+    def _get_physical_nodes(self):
+        """return the list of physical nodes in context"""
+
+    @abc.abstractmethod
+    def _get_physical_node_for_server(self, server_name):
+        """ Find physical node for given server
+
+        :param server_name: (string) Server name in scenario
+        :return string:  <node_name>.<context_name>
+        """
index a9e4564..36e8854 100644 (file)
@@ -32,3 +32,9 @@ class DummyContext(Context):
 
     def _get_network(self, attr_name):
         return None
+
+    def _get_physical_nodes(self):
+        return None
+
+    def _get_physical_node_for_server(self, server_name):
+        return None
index cc87176..ac85b6f 100644 (file)
@@ -29,6 +29,7 @@ from yardstick.common import constants as consts
 from yardstick.common import utils
 from yardstick.common.utils import source_env
 from yardstick.ssh import SSH
+from yardstick.common import openstack_utils
 
 LOG = logging.getLogger(__name__)
 
@@ -68,6 +69,12 @@ class HeatContext(Context):
         self.shade_client = None
         self.heat_timeout = None
         self.key_filename = None
+        self.shade_client = None
+        self.operator_client = None
+        self.nodes = []
+        self.controllers = []
+        self.computes = []
+        self.baremetals = []
         super(HeatContext, self).__init__()
 
     @staticmethod
@@ -96,6 +103,14 @@ class HeatContext(Context):
 
         self.template_file = attrs.get("heat_template")
 
+        self.shade_client = openstack_utils.get_shade_client()
+        self.operator_client = openstack_utils.get_shade_operator_client()
+
+        try:
+            self.read_pod_file(attrs)
+        except IOError:
+            LOG.warning("No pod file specified. NVFi metrics will be disabled")
+
         self.heat_timeout = attrs.get("timeout", DEFAULT_HEAT_TIMEOUT)
         if self.template_file:
             self.heat_parameters = attrs.get("heat_parameters")
@@ -528,3 +543,30 @@ class HeatContext(Context):
             "physical_network": network.physical_network,
         }
         return result
+
+    def _get_physical_nodes(self):
+        return self.nodes
+
+    def _get_physical_node_for_server(self, server_name):
+        node_name, ctx_name = self.split_host_name(server_name)
+        if ctx_name is None or self.name != ctx_name:
+            return None
+
+        matching_nodes = [s for s in self.servers if s.name == node_name]
+        if len(matching_nodes) == 0:
+            return None
+
+        server = openstack_utils.get_server(self.shade_client,
+                                            name_or_id=server_name)
+
+        if server:
+            server = server.toDict()
+            list_hypervisors = self.operator_client.list_hypervisors()
+
+            for hypervisor in list_hypervisors:
+                if hypervisor.hypervisor_hostname == server['OS-EXT-SRV-ATTR:hypervisor_hostname']:
+                    for node in self.nodes:
+                        if node['ip'] == hypervisor.host_ip:
+                            return "{}.{}".format(node['name'], self._name)
+
+        return None
index 82435d4..1920331 100644 (file)
@@ -153,3 +153,9 @@ class KubernetesContext(Context):
 
     def _get_network(self, attr_name):
         return None
+
+    def _get_physical_nodes(self):
+        return None
+
+    def _get_physical_node_for_server(self, server_name):
+        return None
index 93888ef..d3af989 100644 (file)
@@ -8,7 +8,6 @@
 ##############################################################################
 
 from __future__ import absolute_import
-import errno
 import subprocess
 import os
 import collections
@@ -22,7 +21,7 @@ from yardstick import ssh
 from yardstick.benchmark.contexts.base import Context
 from yardstick.common.constants import ANSIBLE_DIR, YARDSTICK_ROOT_PATH
 from yardstick.common.ansible_common import AnsibleCommon
-from yardstick.common.yaml_loader import yaml_load
+from yardstick.common.exceptions import ContextUpdateCollectdForNodeError
 
 LOG = logging.getLogger(__name__)
 
@@ -49,40 +48,11 @@ class NodeContext(Context):
         }
         super(NodeContext, self).__init__()
 
-    def read_config_file(self):
-        """Read from config file"""
-
-        with open(self.file_path) as stream:
-            LOG.info("Parsing pod file: %s", self.file_path)
-            cfg = yaml_load(stream)
-        return cfg
-
     def init(self, attrs):
         """initializes itself from the supplied arguments"""
         super(NodeContext, self).init(attrs)
 
-        self.file_path = file_path = attrs.get("file", "pod.yaml")
-
-        try:
-            cfg = self.read_config_file()
-        except IOError as io_error:
-            if io_error.errno != errno.ENOENT:
-                raise
-
-            self.file_path = os.path.join(YARDSTICK_ROOT_PATH, file_path)
-            cfg = self.read_config_file()
-
-        self.nodes.extend(cfg["nodes"])
-        self.controllers.extend([node for node in cfg["nodes"]
-                                 if node.get("role") == "Controller"])
-        self.computes.extend([node for node in cfg["nodes"]
-                              if node.get("role") == "Compute"])
-        self.baremetals.extend([node for node in cfg["nodes"]
-                                if node.get("role") == "Baremetal"])
-        LOG.debug("Nodes: %r", self.nodes)
-        LOG.debug("Controllers: %r", self.controllers)
-        LOG.debug("Computes: %r", self.computes)
-        LOG.debug("BareMetals: %r", self.baremetals)
+        cfg = self.read_pod_file(attrs)
 
         self.env = attrs.get('env', {})
         self.attrs = attrs
@@ -135,6 +105,32 @@ class NodeContext(Context):
             playbook = os.path.join(ANSIBLE_DIR, playbook)
         return playbook
 
+    def _get_physical_nodes(self):
+        return self.nodes
+
+    def _get_physical_node_for_server(self, server_name):
+
+        node_name, context_name = self.split_host_name(server_name)
+
+        if context_name is None or self.name != context_name:
+            return None
+
+        for n in (n for n in self.nodes if n["name"] == node_name):
+            return "{}.{}".format(n["name"], self._name)
+
+        return None
+
+    def update_collectd_options_for_node(self, options, attr_name):
+        node_name, _ = self.split_host_name(attr_name)
+
+        matching_nodes = (n for n in self.nodes if n["name"] == node_name)
+        try:
+            node = next(matching_nodes)
+        except StopIteration:
+            raise ContextUpdateCollectdForNodeError(attr_name=attr_name)
+
+        node["collectd"] = options
+
     def _get_server(self, attr_name):
         """lookup server info by name from context
         attr_name: a name for a server listed in nodes config file
index 5134217..e555235 100644 (file)
@@ -26,7 +26,7 @@ import xml.etree.ElementTree as ET
 from yardstick import ssh
 from yardstick.common import constants
 from yardstick.common import exceptions
-from yardstick.common.yaml_loader import yaml_load
+from yardstick.common.utils import read_yaml_file
 from yardstick.network_services.utils import PciAddress
 from yardstick.network_services.helpers.cpu import CpuSysCores
 
@@ -368,26 +368,18 @@ class StandaloneContextHelper(object):
 
         return pf_vfs
 
-    def read_config_file(self):
-        """Read from config file"""
-
-        with open(self.file_path) as stream:
-            LOG.info("Parsing pod file: %s", self.file_path)
-            cfg = yaml_load(stream)
-        return cfg
-
     def parse_pod_file(self, file_path, nfvi_role='Sriov'):
         self.file_path = file_path
         nodes = []
         nfvi_host = []
         try:
-            cfg = self.read_config_file()
+            cfg = read_yaml_file(self.file_path)
         except IOError as io_error:
             if io_error.errno != errno.ENOENT:
                 raise
             self.file_path = os.path.join(constants.YARDSTICK_ROOT_PATH,
                                           file_path)
-            cfg = self.read_config_file()
+            cfg = read_yaml_file(self.file_path)
 
         nodes.extend([node for node in cfg["nodes"] if str(node["role"]) != nfvi_role])
         nfvi_host.extend([node for node in cfg["nodes"] if str(node["role"]) == nfvi_role])
index ccb0f8f..c240048 100644 (file)
@@ -299,6 +299,21 @@ class OvsDpdkContext(Context):
         for vm in self.vm_names:
             model.Libvirt.check_if_vm_exists_and_delete(vm, self.connection)
 
+    def _get_physical_nodes(self):
+        return self.nfvi_host
+
+    def _get_physical_node_for_server(self, server_name):
+        node_name, ctx_name = self.split_host_name(server_name)
+        if ctx_name is None or self.name != ctx_name:
+            return None
+
+        matching_nodes = [s for s in self.servers if s == node_name]
+        if len(matching_nodes) == 0:
+            return None
+
+        # self.nfvi_host always contain only one host
+        return "{}.{}".format(self.nfvi_host[0]["name"], self._name)
+
     def _get_server(self, attr_name):
         """lookup server info by name from context
 
index c5438b3..5822feb 100644 (file)
@@ -109,6 +109,22 @@ class SriovContext(Context):
             build_vfs = "echo 0 > /sys/bus/pci/devices/{0}/sriov_numvfs"
             self.connection.execute(build_vfs.format(ports.get('phy_port')))
 
+    def _get_physical_nodes(self):
+        return self.nfvi_host
+
+    def _get_physical_node_for_server(self, server_name):
+
+        # self.nfvi_host always contain only one host.
+        node_name, ctx_name = self.split_host_name(server_name)
+        if ctx_name is None or self.name != ctx_name:
+            return None
+
+        matching_nodes = [s for s in self.servers if s == node_name]
+        if len(matching_nodes) == 0:
+            return None
+
+        return "{}.{}".format(self.nfvi_host[0]["name"], self._name)
+
     def _get_server(self, attr_name):
         """lookup server info by name from context
 
index 1aeee20..fa002c0 100644 (file)
@@ -68,6 +68,10 @@ class ResourceCommandError(YardstickException):
     message = 'Command: "%(command)s" Failed, stderr: "%(stderr)s"'
 
 
+class ContextUpdateCollectdForNodeError(YardstickException):
+    message = 'Cannot find node %(attr_name)s'
+
+
 class FunctionNotImplemented(YardstickException):
     message = ('The function "%(function_name)s" is not implemented in '
                '"%(class_name)" class.')
index 6ff6617..5410613 100644 (file)
@@ -172,6 +172,15 @@ def get_shade_client(**os_cloud_config):
     params.update(os_cloud_config)
     return shade.openstack_cloud(**params)
 
+def get_shade_operator_client(**os_cloud_config):
+    """Get Shade Operator cloud client
+
+    :return: ``shade.OperatorCloud`` object.
+    """
+    params = copy.deepcopy(constants.OS_CLOUD_DEFAULT_CONFIG)
+    params.update(os_cloud_config)
+    return shade.operator_cloud(**params)
+
 
 # *********************************************
 #   NOVA
index f9fe0e3..251e5cc 100644 (file)
@@ -37,6 +37,7 @@ from oslo_utils import encodeutils
 
 import yardstick
 from yardstick.common import exceptions
+from yardstick.common.yaml_loader import yaml_load
 
 
 logger = logging.getLogger(__name__)
@@ -527,3 +528,11 @@ def wait_until_true(predicate, timeout=60, sleep=1, exception=None):
         if exception and issubclass(exception, Exception):
             raise exception  # pylint: disable=raising-bad-type
         raise exceptions.WaitTimeout
+
+
+def read_yaml_file(path):
+    """Read yaml file"""
+
+    with open(path) as stream:
+        data = yaml_load(stream)
+    return data
index 5ed199a..3137821 100644 (file)
@@ -315,11 +315,6 @@ class StandaloneContextHelperTestCase(unittest.TestCase):
         file_path = os.path.join(curr_path, filename)
         return file_path
 
-    def test_read_config_file(self):
-        self.helper.file_path = self._get_file_abspath(self.NODE_SAMPLE)
-        status = self.helper.read_config_file()
-        self.assertIsNotNone(status)
-
     def test_parse_pod_file(self):
         self.helper.file_path = self._get_file_abspath("dummy")
         self.assertRaises(IOError, self.helper.parse_pod_file,
index 6eb438c..5be22a0 100644 (file)
@@ -290,6 +290,22 @@ class OvsDpdkContextTestCase(unittest.TestCase):
         self.assertEqual(result['user'], 'root')
         self.assertEqual(result['key_filename'], '/root/.yardstick_key')
 
+    def test__get_physical_node_for_server(self):
+        attrs = self.attrs
+        attrs.update({'servers': {'server1': {}}})
+        self.ovs_dpdk.init(attrs)
+
+        # When server is not from this context
+        result = self.ovs_dpdk._get_physical_node_for_server('server1.another-context')
+        self.assertIsNone(result)
+
+        # When node_name is not from this context
+        result = self.ovs_dpdk._get_physical_node_for_server('fake.foo-12345678')
+        self.assertIsNone(result)
+
+        result = self.ovs_dpdk._get_physical_node_for_server('server1.foo-12345678')
+        self.assertEqual(result, 'node5.foo')
+
     # TODO(elfoley): Split this test for networks that exist and networks that
     #                don't
     def test__get_network(self):
index de748e2..1690846 100644 (file)
@@ -62,7 +62,7 @@ class SriovContextTestCase(unittest.TestCase):
         self.attrs = {
             'name': 'foo',
             'task_id': '1234567890',
-            'file': self._get_file_abspath(self.NODES_SRIOV_SAMPLE)
+            'file': self._get_file_abspath(self.NODES_SRIOV_SAMPLE),
         }
         self.sriov = sriov.SriovContext()
         self.addCleanup(self._remove_contexts)
@@ -171,6 +171,22 @@ class SriovContextTestCase(unittest.TestCase):
         self.assertEqual(result['user'], 'root')
         self.assertEqual(result['key_filename'], '/root/.yardstick_key')
 
+    def test__get_physical_node_for_server(self):
+        attrs = self.attrs
+        attrs.update({'servers': {'server1': {}}})
+        self.sriov.init(attrs)
+
+        # When server is not from this context
+        result = self.sriov._get_physical_node_for_server('server1.another-context')
+        self.assertIsNone(result)
+
+        # When node_name is not from this context
+        result = self.sriov._get_physical_node_for_server('fake.foo-12345678')
+        self.assertIsNone(result)
+
+        result = self.sriov._get_physical_node_for_server('server1.foo-12345678')
+        self.assertEqual(result, 'node5.foo')
+
     def test__get_server_no_task_id(self):
         self.attrs['flags'] = {'no_setup': True}
         self.sriov.init(self.attrs)
index 81267cf..8f1cbcc 100644 (file)
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+import os
+import errno
+
+import mock
+
 from yardstick.benchmark.contexts import base
+from yardstick.benchmark.contexts.base import Context
 from yardstick.tests.unit import base as ut_base
+from yardstick.common.constants import YARDSTICK_ROOT_PATH
+
 
+class DummyContextClass(Context):
 
-class DummyContextClass(base.Context):
+    def __init__(self, host_name_separator='.'):
+        super(DummyContextClass, self).__init__\
+            (host_name_separator=host_name_separator)
+        self.nodes = []
+        self.controllers = []
+        self.computes = []
+        self.baremetals = []
 
     def _get_network(self, *args):
         pass
@@ -30,6 +45,12 @@ class DummyContextClass(base.Context):
     def undeploy(self):
         pass
 
+    def _get_physical_nodes(self):
+        pass
+
+    def _get_physical_node_for_server(self, server_name):
+        pass
+
 
 class FlagsTestCase(ut_base.BaseUnitTestCase):
 
@@ -87,3 +108,64 @@ class ContextTestCase(ut_base.BaseUnitTestCase):
         config_name = 'host_name-ctx_name'
         self.assertEqual(('host_name', 'ctx_name'),
                          ctx_obj.split_host_name(config_name))
+
+    def test_get_physical_nodes(self):
+        ctx_obj = DummyContextClass()
+        self.addCleanup(self._remove_ctx, ctx_obj)
+
+        result = Context.get_physical_nodes()
+
+        self.assertEqual(result, {None: None})
+
+    @mock.patch.object(Context, 'get_context_from_server')
+    def test_get_physical_node_from_server(self, mock_get_ctx):
+        ctx_obj = DummyContextClass()
+        self.addCleanup(self._remove_ctx, ctx_obj)
+
+        mock_get_ctx.return_value = ctx_obj
+
+        result = Context.get_physical_node_from_server("mock_server")
+
+        mock_get_ctx.assert_called_once()
+        self.assertIsNone(result)
+
+    @mock.patch('yardstick.common.utils.read_yaml_file')
+    def test_read_pod_file(self, mock_read_yaml_file):
+        attrs = {'name': 'foo',
+                 'task_id': '12345678',
+                 'file': 'pod.yaml'
+                 }
+
+        ctx_obj = DummyContextClass()
+        cfg = {"nodes": [
+                    {
+                        "name": "node1",
+                        "role": "Controller",
+                        "ip": "10.229.47.137",
+                        "user": "root",
+                        "key_filename": "/root/.yardstick_key"
+                    },
+                    {
+                        "name": "node2",
+                        "role": "Compute",
+                        "ip": "10.229.47.139",
+                        "user": "root",
+                        "key_filename": "/root/.yardstick_key"
+                    }
+                ]
+            }
+
+        mock_read_yaml_file.return_value = cfg
+        result = ctx_obj.read_pod_file(attrs)
+        self.assertEqual(result, cfg)
+
+        mock_read_yaml_file.side_effect = IOError(errno.EPERM, '')
+        with self.assertRaises(IOError):
+            ctx_obj.read_pod_file(attrs)
+
+        mock_read_yaml_file.side_effect = IOError(errno.ENOENT, '')
+        with self.assertRaises(IOError):
+            ctx_obj.read_pod_file(attrs)
+
+        file_path = os.path.join(YARDSTICK_ROOT_PATH, 'pod.yaml')
+        self.assertEqual(ctx_obj.file_path, file_path)
index c4113be..3383237 100644 (file)
@@ -76,3 +76,11 @@ class DummyContextTestCase(unittest.TestCase):
         self.assertEqual(result, None)
 
         self.test_context.undeploy()
+
+    def test__get_physical_nodes(self):
+        result = self.test_context._get_physical_nodes()
+        self.assertIsNone(result)
+
+    def test__get_physical_node_for_server(self):
+        result = self.test_context._get_physical_node_for_server("fake")
+        self.assertIsNone(result)
index bcc3590..df57ca4 100644 (file)
@@ -12,30 +12,53 @@ import logging
 import os
 
 import mock
+import unittest
 
-from yardstick import ssh
 from yardstick.benchmark.contexts import base
 from yardstick.benchmark.contexts import heat
 from yardstick.benchmark.contexts import model
 from yardstick.common import constants as consts
 from yardstick.common import exceptions as y_exc
-from yardstick.tests.unit import base as ut_base
+from yardstick.common import openstack_utils
+from yardstick import ssh
 
 
 LOG = logging.getLogger(__name__)
 
 
-class HeatContextTestCase(ut_base.BaseUnitTestCase):
+class HeatContextTestCase(unittest.TestCase):
+
+    HEAT_POD_SAMPLE = {
+        "nodes": [
+            {
+                "name": "node1",
+                "role": "Controller",
+                "ip": "10.229.47.137",
+                "user": "root",
+                "key_filename": "/root/.yardstick_key"
+            },
+            {
+                "name": "node2",
+                "role": "Compute",
+                "ip": "10.229.47.139",
+                "user": "root",
+                "key_filename": "/root/.yardstick_key"
+            }
+        ]
+    }
+
+    def __init__(self, *args, **kwargs):
+
+        super(HeatContextTestCase, self).__init__(*args, **kwargs)
 
     def setUp(self):
         self.test_context = heat.HeatContext()
         self.addCleanup(self._remove_contexts)
+        self.mock_context = mock.Mock(spec=heat.HeatContext())
 
-    @staticmethod
-    def _remove_contexts():
-        for context in base.Context.list:
-            context._delete_context()
-        base.Context.list = []
+    def _remove_contexts(self):
+        if self.test_context in self.test_context.list:
+            self.test_context._delete_context()
 
     def test___init__(self):
         self.assertIsNone(self.test_context._name)
@@ -57,24 +80,29 @@ class HeatContextTestCase(ut_base.BaseUnitTestCase):
         self.assertIsNone(self.test_context.heat_parameters)
         self.assertIsNone(self.test_context.key_filename)
 
+    @mock.patch('yardstick.common.utils.read_yaml_file')
     @mock.patch('yardstick.benchmark.contexts.heat.PlacementGroup')
     @mock.patch('yardstick.benchmark.contexts.heat.ServerGroup')
     @mock.patch('yardstick.benchmark.contexts.heat.Network')
     @mock.patch('yardstick.benchmark.contexts.heat.Server')
-    def test_init(self, mock_server, mock_network, mock_sg, mock_pg):
+    def test_init(self, mock_server, mock_network, mock_sg, mock_pg, mock_read_yaml):
 
+        mock_read_yaml.return_value = self.HEAT_POD_SAMPLE
         pgs = {'pgrp1': {'policy': 'availability'}}
         sgs = {'servergroup1': {'policy': 'affinity'}}
         networks = {'bar': {'cidr': '10.0.1.0/24'}}
         servers = {'baz': {'floating_ip': True, 'placement': 'pgrp1'}}
         attrs = {'name': 'foo',
+                 'file': 'pod.yaml',
                  'task_id': '1234567890',
                  'placement_groups': pgs,
                  'server_groups': sgs,
                  'networks': networks,
                  'servers': servers}
 
-        self.test_context.init(attrs)
+        with mock.patch.object(openstack_utils, 'get_shade_client'), \
+             mock.patch.object(openstack_utils, 'get_shade_operator_client'):
+            self.test_context.init(attrs)
 
         self.assertFalse(self.test_context._flags.no_setup)
         self.assertFalse(self.test_context._flags.no_teardown)
@@ -128,13 +156,17 @@ class HeatContextTestCase(ut_base.BaseUnitTestCase):
                  'server_groups': {},
                  'networks': {},
                  'servers': {},
+                 'file': "pod.yaml",
                  'flags': {
                      'no_setup': True,
                      'no_teardown': True,
                      },
                 }
 
-        self.test_context.init(attrs)
+        with mock.patch.object(openstack_utils, 'get_shade_client'), \
+             mock.patch.object(openstack_utils, 'get_shade_operator_client'):
+            self.test_context.init(attrs)
+
         self.assertTrue(self.test_context._flags.no_setup)
         self.assertTrue(self.test_context._flags.no_teardown)
 
@@ -654,7 +686,6 @@ class HeatContextTestCase(ut_base.BaseUnitTestCase):
         baz3_server.public_ip = None
         baz3_server.context.user = 'zab'
 
-        self.mock_context = mock.Mock(spec=heat.HeatContext())
         self.mock_context._name = 'bar1'
         self.test_context.stack = mock.Mock()
         self.mock_context.stack.outputs = {
@@ -722,3 +753,56 @@ class HeatContextTestCase(ut_base.BaseUnitTestCase):
         }
         result = self.test_context._get_network(attr_name)
         self.assertDictEqual(result, expected)
+
+    def _get_file_abspath(self, filename):
+        curr_path = os.path.dirname(os.path.abspath(__file__))
+        file_path = os.path.join(curr_path, filename)
+        return file_path
+
+    def test__get_physical_nodes(self):
+        self.test_context.nodes = {}
+        nodes = self.test_context._get_physical_nodes()
+        self.assertEquals(nodes, {})
+
+    @mock.patch('yardstick.common.utils.read_yaml_file')
+    def test__get_physical_node_for_server(self, mock_read_yaml):
+        attrs = {'name': 'foo',
+                 'task_id': '12345678',
+                 'file': "pod.yaml",
+                 'servers': {'vnf': {}},
+                 'networks': {'mgmt': {'cidr': '10.0.1.0/24'}}
+                 }
+
+        with mock.patch.object(openstack_utils, 'get_shade_client'), \
+             mock.patch.object(openstack_utils, 'get_shade_operator_client'):
+            mock_read_yaml.return_value = self.HEAT_POD_SAMPLE
+            self.test_context.init(attrs)
+
+        with mock.patch('yardstick.common.openstack_utils.get_server') as mock_get_server:
+            mock_get_server.return_value = {'vnf': {}}
+
+            # When server is not from this context
+            result = self.test_context._get_physical_node_for_server('node1.foo-context')
+            self.assertIsNone(result)
+
+            # When node_name is not from this context
+            result = self.test_context._get_physical_node_for_server('fake.foo-12345678')
+            self.assertIsNone(result)
+
+            mock_munch = mock.Mock()
+            mock_munch.toDict = mock.Mock(return_value={
+                'OS-EXT-SRV-ATTR:hypervisor_hostname': 'hypervisor_hostname'
+            })
+            mock_get_server.return_value = mock_munch
+
+            hypervisor = mock.Mock()
+            hypervisor.hypervisor_hostname = 'hypervisor_hostname'
+            hypervisor.host_ip = '10.229.47.137'
+
+            self.test_context.operator_client.list_hypervisors = mock.Mock(
+                return_value=[hypervisor])
+
+            mock_get_server.return_value = mock_munch
+
+            result = self.test_context._get_physical_node_for_server('vnf.foo-12345678')
+            self.assertEqual(result, 'node1.foo')
index 0e11a53..b33be03 100644 (file)
@@ -12,9 +12,10 @@ import unittest
 
 from yardstick.benchmark.contexts import base
 from yardstick.benchmark.contexts import kubernetes
+from yardstick.orchestrator import kubernetes as orchestrator_kubernetes
 
 
-context_cfg = {
+CONTEXT_CFG = {
     'type': 'Kubernetes',
     'name': 'k8s',
     'task_id': '1234567890',
@@ -22,14 +23,14 @@ context_cfg = {
         'host': {
             'image': 'openretriever/yardstick',
             'command': '/bin/bash',
-            'args': ['-c', 'chmod 700 ~/.ssh; chmod 600 ~/.ssh/*; \
-service ssh restart;while true ; do sleep 10000; done']
+            'args': ['-c', 'chmod 700 ~/.ssh; chmod 600 ~/.ssh/*; '
+                     'service ssh restart;while true ; do sleep 10000; done']
         },
         'target': {
             'image': 'openretriever/yardstick',
             'command': '/bin/bash',
-            'args': ['-c', 'chmod 700 ~/.ssh; chmod 600 ~/.ssh/*; \
-service ssh restart;while true ; do sleep 10000; done']
+            'args': ['-c', 'chmod 700 ~/.ssh; chmod 600 ~/.ssh/*; '
+                     'service ssh restart;while true ; do sleep 10000; done']
         }
     }
 }
@@ -42,7 +43,7 @@ class KubernetesTestCase(unittest.TestCase):
     def setUp(self):
         self.k8s_context = kubernetes.KubernetesContext()
         self.addCleanup(self._remove_contexts)
-        self.k8s_context.init(context_cfg)
+        self.k8s_context.init(CONTEXT_CFG)
 
     @staticmethod
     def _remove_contexts():
@@ -68,7 +69,8 @@ class KubernetesTestCase(unittest.TestCase):
 
     @mock.patch.object(kubernetes.KubernetesContext, '_create_services')
     @mock.patch.object(kubernetes.KubernetesContext, '_wait_until_running')
-    @mock.patch.object(kubernetes.KubernetesTemplate, 'get_rc_pods')
+    @mock.patch.object(orchestrator_kubernetes.KubernetesTemplate,
+                       'get_rc_pods')
     @mock.patch.object(kubernetes.KubernetesContext, '_create_rcs')
     @mock.patch.object(kubernetes.KubernetesContext, '_set_ssh_key')
     def test_deploy(self,
@@ -170,3 +172,11 @@ class KubernetesTestCase(unittest.TestCase):
     def test_delete_services(self, mock_delete):
         self.k8s_context._delete_services()
         mock_delete.assert_called()
+
+    def test__get_physical_nodes(self):
+        result = self.k8s_context._get_physical_nodes()
+        self.assertIsNone(result)
+
+    def test__get_physical_node_for_server(self):
+        result = self.k8s_context._get_physical_node_for_server("fake")
+        self.assertIsNone(result)
index b67be37..5d7b24c 100644 (file)
@@ -15,6 +15,7 @@ import mock
 from yardstick.common import constants as consts
 from yardstick.benchmark.contexts import base
 from yardstick.benchmark.contexts import node
+from yardstick.common import exceptions
 
 
 class NodeContextTestCase(unittest.TestCase):
@@ -55,8 +56,9 @@ class NodeContextTestCase(unittest.TestCase):
         self.assertEqual(self.test_context.env, {})
         self.assertEqual(self.test_context.attrs, {})
 
+    @mock.patch('yardstick.common.utils.read_yaml_file')
     @mock.patch('{}.os.path.join'.format(PREFIX))
-    def test_init_negative(self, mock_path_join):
+    def test_init_negative(self, mock_path_join, read_mock):
         special_path = '/foo/bar/error_file'
         error_path = self._get_file_abspath("error_file")
 
@@ -68,7 +70,6 @@ class NodeContextTestCase(unittest.TestCase):
         # we can't count mock_path_join calls because
         # it can catch join calls for .pyc files.
         mock_path_join.side_effect = path_join
-        self.test_context.read_config_file = read_mock = mock.Mock()
         read_calls = 0
 
         with self.assertRaises(KeyError):
@@ -86,7 +87,7 @@ class NodeContextTestCase(unittest.TestCase):
             self.test_context.init(attrs)
 
         read_calls += 1
-        self.assertEqual(read_mock.called, read_calls)
+        self.assertEqual(read_mock.call_count, read_calls)
         self.assertIn(attrs['file'], self.test_context.file_path)
         self.assertEqual(raised.exception.errno, errno.EBUSY)
         self.assertEqual(str(raised.exception), str(read_mock.side_effect))
@@ -101,11 +102,6 @@ class NodeContextTestCase(unittest.TestCase):
         self.assertEqual(raised.exception.errno, errno.ENOENT)
         self.assertEqual(str(raised.exception), str(read_mock.side_effect))
 
-    def test_read_config_file(self):
-        self.test_context.init(self.attrs)
-
-        self.assertIsNotNone(self.test_context.read_config_file())
-
     def test__dispatch_script(self):
         self.test_context.init(self.attrs)
 
@@ -171,6 +167,39 @@ class NodeContextTestCase(unittest.TestCase):
         self.assertEqual(result['user'], 'root')
         self.assertEqual(result['key_filename'], '/root/.yardstick_key')
 
+    def test__get_physical_nodes(self):
+        self.test_context.init(self.attrs)
+        nodes = self.test_context._get_physical_nodes()
+        self.assertEquals(nodes, self.test_context.nodes)
+
+    def test__get_physical_node_for_server(self):
+        self.test_context.init(self.attrs)
+
+        # When server is not from this context
+        result = self.test_context._get_physical_node_for_server('node1.another-context')
+        self.assertIsNone(result)
+
+        # When node_name is not from this context
+        result = self.test_context._get_physical_node_for_server('fake.foo-12345678')
+        self.assertIsNone(result)
+
+        result = self.test_context._get_physical_node_for_server('node1.foo-12345678')
+        self.assertEqual(result, 'node1.foo')
+
+    def test_update_collectd_options_for_node(self):
+        self.test_context.init(self.attrs)
+        options = {'collectd': {'interval': 5}}
+
+        with self.assertRaises(exceptions.ContextUpdateCollectdForNodeError):
+            self.test_context.update_collectd_options_for_node(options, 'fake.foo-12345678')
+
+        self.test_context.update_collectd_options_for_node(options, 'node1.foo-12345678')
+
+        node_collectd_options = [node for node in self.test_context.nodes
+                                 if node['name'] == 'node1'][0]['collectd']
+
+        self.assertEquals(node_collectd_options, options)
+
     @mock.patch('{}.NodeContext._dispatch_script'.format(PREFIX))
     def test_deploy(self, dispatch_script_mock):
         obj = node.NodeContext()
index 9361a97..d02a34d 100644 (file)
@@ -59,6 +59,12 @@ class GetShadeClientTestCase(unittest.TestCase):
         mock_openstack_cloud.assert_called_once_with(
             **constants.OS_CLOUD_DEFAULT_CONFIG)
 
+    @mock.patch.object(shade, 'operator_cloud', return_value='os_client')
+    def test_get_shade_operator_client(self, mock_operator_cloud):
+        self.assertEqual('os_client', openstack_utils.get_shade_operator_client())
+        mock_operator_cloud.assert_called_once_with(
+            **constants.OS_CLOUD_DEFAULT_CONFIG)
+
 
 class DeleteNeutronNetTestCase(unittest.TestCase):