Add "host_name_separator" variable to Context class 19/58819/1
authorRodolfo Alonso Hernandez <rodolfo.alonso.hernandez@intel.com>
Mon, 21 May 2018 11:53:03 +0000 (12:53 +0100)
committerEmma Foley <emma.l.foley@intel.com>
Wed, 20 Jun 2018 16:46:02 +0000 (16:46 +0000)
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 <rodolfo.alonso.hernandez@intel.com>
(cherry picked from commit a2ee61016721386b40caa4e2d72f61be8adec94a)

yardstick/benchmark/contexts/base.py
yardstick/benchmark/contexts/heat.py
yardstick/benchmark/contexts/kubernetes.py
yardstick/benchmark/contexts/node.py
yardstick/benchmark/contexts/standalone/ovs_dpdk.py
yardstick/benchmark/contexts/standalone/sriov.py
yardstick/benchmark/core/task.py
yardstick/common/exceptions.py
yardstick/tests/unit/benchmark/contexts/test_base.py

index ae8319e..0707c1c 100644 (file)
@@ -42,20 +42,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"""
@@ -65,6 +57,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:
@@ -76,6 +74,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."""
index 0d1dfb8..0640d2c 100644 (file)
@@ -466,7 +466,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
 
index 4bea991..82435d4 100644 (file)
@@ -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)
index fa619a9..93888ef 100644 (file)
@@ -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
 
index 30b685e..ccb0f8f 100644 (file)
@@ -305,7 +305,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
 
index 5db419e..c5a01bf 100644 (file)
@@ -115,7 +115,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
 
index 697cc00..f050e8d 100644 (file)
@@ -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'])
index fb4d33a..55bcfdb 100644 (file)
@@ -113,7 +113,7 @@ class LibvirtCreateError(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):
index 153c6a5..1311317 100644 (file)
 # 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()
@@ -41,3 +55,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))