From a2ee61016721386b40caa4e2d72f61be8adec94a Mon Sep 17 00:00:00 2001 From: Rodolfo Alonso Hernandez Date: Mon, 21 May 2018 12:53:03 +0100 Subject: Add "host_name_separator" variable to Context class This feature will provide Kubernetes context the ability to handle the context name inside the class itself, providing to the developer an abstraction of the possible naming limitations in Kubernetes. E.g.: "dot" character in Pod names is no allowed [1]. [1] https://github.com/fabric8io/fluent-plugin-kubernetes_metadata_filter/issues/58 JIRA: YARDSTICK-1188 Change-Id: I82121f970b550170357a443b6340be7900602a57 Signed-off-by: Rodolfo Alonso Hernandez --- yardstick/benchmark/contexts/base.py | 22 +++++----- yardstick/benchmark/contexts/heat.py | 2 +- yardstick/benchmark/contexts/kubernetes.py | 3 +- yardstick/benchmark/contexts/node.py | 2 +- .../benchmark/contexts/standalone/ovs_dpdk.py | 2 +- yardstick/benchmark/contexts/standalone/sriov.py | 2 +- yardstick/benchmark/core/task.py | 33 +++++++-------- yardstick/common/exceptions.py | 2 +- .../tests/unit/benchmark/contexts/test_base.py | 49 ++++++++++++++++++++-- 9 files changed, 78 insertions(+), 39 deletions(-) diff --git a/yardstick/benchmark/contexts/base.py b/yardstick/benchmark/contexts/base.py index 692c16892..64cee8376 100644 --- a/yardstick/benchmark/contexts/base.py +++ b/yardstick/benchmark/contexts/base.py @@ -45,20 +45,12 @@ class Context(object): list = [] SHORT_TASK_ID_LEN = 8 - @staticmethod - def split_name(name, sep='.'): - try: - name_iter = iter(name.split(sep)) - except AttributeError: - # name is not a string - return None, None - return next(name_iter), next(name_iter, None) - - def __init__(self): + def __init__(self, host_name_separator='.'): Context.list.append(self) self._flags = Flags() self._name = None self._task_id = None + self._host_name_separator = host_name_separator def init(self, attrs): """Initiate context""" @@ -68,6 +60,12 @@ class Context(object): self._name_task_id = '{}-{}'.format( self._name, self._task_id[:self.SHORT_TASK_ID_LEN]) + def split_host_name(self, name): + if (isinstance(name, six.string_types) + and self._host_name_separator in name): + return tuple(name.split(self._host_name_separator, 1)) + return None, None + @property def name(self): if self._flags.no_setup or self._flags.no_teardown: @@ -79,6 +77,10 @@ class Context(object): def assigned_name(self): return self._name + @property + def host_name_separator(self): + return self._host_name_separator + @staticmethod def get_cls(context_type): """Return class of specified type.""" diff --git a/yardstick/benchmark/contexts/heat.py b/yardstick/benchmark/contexts/heat.py index 82861829e..cc87176d5 100644 --- a/yardstick/benchmark/contexts/heat.py +++ b/yardstick/benchmark/contexts/heat.py @@ -465,7 +465,7 @@ class HeatContext(Context): with attribute name mapping when using external heat templates """ if isinstance(attr_name, collections.Mapping): - node_name, cname = self.split_name(attr_name['name']) + node_name, cname = self.split_host_name(attr_name['name']) if cname is None or cname != self.name: return None diff --git a/yardstick/benchmark/contexts/kubernetes.py b/yardstick/benchmark/contexts/kubernetes.py index 4bea991ea..82435d40c 100644 --- a/yardstick/benchmark/contexts/kubernetes.py +++ b/yardstick/benchmark/contexts/kubernetes.py @@ -33,8 +33,7 @@ class KubernetesContext(Context): self.key_path = '' self.public_key_path = '' self.template = None - - super(KubernetesContext, self).__init__() + super(KubernetesContext, self).__init__(host_name_separator='-') def init(self, attrs): super(KubernetesContext, self).init(attrs) diff --git a/yardstick/benchmark/contexts/node.py b/yardstick/benchmark/contexts/node.py index fa619a9aa..93888ef41 100644 --- a/yardstick/benchmark/contexts/node.py +++ b/yardstick/benchmark/contexts/node.py @@ -139,7 +139,7 @@ class NodeContext(Context): """lookup server info by name from context attr_name: a name for a server listed in nodes config file """ - node_name, name = self.split_name(attr_name) + node_name, name = self.split_host_name(attr_name) if name is None or self.name != name: return None diff --git a/yardstick/benchmark/contexts/standalone/ovs_dpdk.py b/yardstick/benchmark/contexts/standalone/ovs_dpdk.py index b9e66a481..8a1482c07 100644 --- a/yardstick/benchmark/contexts/standalone/ovs_dpdk.py +++ b/yardstick/benchmark/contexts/standalone/ovs_dpdk.py @@ -304,7 +304,7 @@ class OvsDpdkContext(Context): Keyword arguments: attr_name -- A name for a server listed in nodes config file """ - node_name, name = self.split_name(attr_name) + node_name, name = self.split_host_name(attr_name) if name is None or self.name != name: return None diff --git a/yardstick/benchmark/contexts/standalone/sriov.py b/yardstick/benchmark/contexts/standalone/sriov.py index 95472fdda..1b6bab27b 100644 --- a/yardstick/benchmark/contexts/standalone/sriov.py +++ b/yardstick/benchmark/contexts/standalone/sriov.py @@ -112,7 +112,7 @@ class SriovContext(Context): Keyword arguments: attr_name -- A name for a server listed in nodes config file """ - node_name, name = self.split_name(attr_name) + node_name, name = self.split_host_name(attr_name) if name is None or self.name != name: return None diff --git a/yardstick/benchmark/core/task.py b/yardstick/benchmark/core/task.py index 697cc007f..f050e8d0f 100644 --- a/yardstick/benchmark/core/task.py +++ b/yardstick/benchmark/core/task.py @@ -619,27 +619,22 @@ class TaskParser(object): # pragma: no cover nodes: tg__0: tg_0.yardstick vnf__0: vnf_0.yardstick + + NOTE: in Kubernetes context, the separator character between the server + name and the context name is "-": + scenario: + host: host-k8s + target: target-k8s """ def qualified_name(name): - try: - # for openstack - node_name, context_name = name.split('.') - sep = '.' - except ValueError: - # for kubernetes, some kubernetes resources don't support - # name format like 'xxx.xxx', so we use '-' instead - # need unified later - node_name, context_name = name.split('-') - sep = '-' - - try: - ctx = next((context for context in contexts - if context.assigned_name == context_name)) - except StopIteration: - raise y_exc.ScenarioConfigContextNameNotFound( - context_name=context_name) - - return '{}{}{}'.format(node_name, sep, ctx.name) + for context in contexts: + host_name, ctx_name = context.split_host_name(name) + if context.assigned_name == ctx_name: + return '{}{}{}'.format(host_name, + context.host_name_separator, + context.name) + + raise y_exc.ScenarioConfigContextNameNotFound(host_name=name) if 'host' in scenario: scenario['host'] = qualified_name(scenario['host']) diff --git a/yardstick/common/exceptions.py b/yardstick/common/exceptions.py index c7ba56268..3ae49d812 100644 --- a/yardstick/common/exceptions.py +++ b/yardstick/common/exceptions.py @@ -138,7 +138,7 @@ class LibvirtQemuImageCreateError(YardstickException): class ScenarioConfigContextNameNotFound(YardstickException): - message = 'Context name "%(context_name)s" not found' + message = 'Context for host name "%(host_name)s" not found' class StackCreationInterrupt(YardstickException): diff --git a/yardstick/tests/unit/benchmark/contexts/test_base.py b/yardstick/tests/unit/benchmark/contexts/test_base.py index b19883479..81267cf98 100644 --- a/yardstick/tests/unit/benchmark/contexts/test_base.py +++ b/yardstick/tests/unit/benchmark/contexts/test_base.py @@ -12,12 +12,26 @@ # See the License for the specific language governing permissions and # limitations under the License. -import unittest - from yardstick.benchmark.contexts import base +from yardstick.tests.unit import base as ut_base + + +class DummyContextClass(base.Context): + + def _get_network(self, *args): + pass + + def _get_server(self, *args): + pass + + def deploy(self): + pass + + def undeploy(self): + pass -class FlagsTestCase(unittest.TestCase): +class FlagsTestCase(ut_base.BaseUnitTestCase): def setUp(self): self.flags = base.Flags() @@ -44,3 +58,32 @@ class FlagsTestCase(unittest.TestCase): self.flags.parse(foo=42) with self.assertRaises(AttributeError): _ = self.flags.foo + + +class ContextTestCase(ut_base.BaseUnitTestCase): + + @staticmethod + def _remove_ctx(ctx_obj): + if ctx_obj in base.Context.list: + base.Context.list.remove(ctx_obj) + + def test_split_host_name(self): + ctx_obj = DummyContextClass() + self.addCleanup(self._remove_ctx, ctx_obj) + config_name = 'host_name.ctx_name' + self.assertEqual(('host_name', 'ctx_name'), + ctx_obj.split_host_name(config_name)) + + def test_split_host_name_wrong_separator(self): + ctx_obj = DummyContextClass() + self.addCleanup(self._remove_ctx, ctx_obj) + config_name = 'host_name-ctx_name' + self.assertEqual((None, None), + ctx_obj.split_host_name(config_name)) + + def test_split_host_name_other_separator(self): + ctx_obj = DummyContextClass(host_name_separator='-') + self.addCleanup(self._remove_ctx, ctx_obj) + config_name = 'host_name-ctx_name' + self.assertEqual(('host_name', 'ctx_name'), + ctx_obj.split_host_name(config_name)) -- cgit 1.2.3-korg