Add "tolerations" parameter in Kubernetes context 31/58931/4
authorRodolfo Alonso Hernandez <rodolfo.alonso.hernandez@intel.com>
Fri, 22 Jun 2018 13:53:22 +0000 (14:53 +0100)
committerRodolfo Alonso Hernandez <rodolfo.alonso.hernandez@intel.com>
Tue, 10 Jul 2018 09:32:38 +0000 (09:32 +0000)
This new parameter, "torelations", is applied to pods and allow (but not
require) the pods to schedule onto node with matching tains [1].

Example of "tolerations" definition in a Kubernetes pod:

  spec:
    containers: [...]
    tolerations:
      - key: <key defined in the taint>
        value: <key value to match with the taint>
        effect: <effect in case of match>
        operator: <matching operator>
      - key: ...

Example of "tolerations" definition in a Yardstick test case:

  context:
    type: Kubernetes
    servers:
      host:
        containers: [...]
        tolerations:
          - key: ...
            value: ...
            effect: ...
            operator: ...

NOTE: if any toleration is defined, a default one will be applied in
order to allow any replication controller to create the pods in any
Kubernetes node. This default toleration is defined as:

  spec:
    tolerations:
      - operator: "Exists"

[1] https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/

JIRA: YARDSTICK-1254

Change-Id: I32fb9c7086b4218c323218738057f634eb6ffff4
Signed-off-by: Rodolfo Alonso Hernandez <rodolfo.alonso.hernandez@intel.com>
yardstick/orchestrator/kubernetes.py
yardstick/tests/unit/orchestrator/test_kubernetes.py

index 6fd3fa6..3c7559c 100644 (file)
@@ -89,6 +89,7 @@ class ReplicationControllerObject(object):
 
     SSHKEY_DEFAULT = 'yardstick_key'
     RESTART_POLICY = ('Always', 'OnFailure', 'Never')
+    TOLERATIONS_KEYS = ('key', 'value', 'effect', 'operator')
 
     def __init__(self, name, **kwargs):
         super(ReplicationControllerObject, self).__init__()
@@ -99,6 +100,7 @@ class ReplicationControllerObject(object):
         self._volumes = parameters.pop('volumes', [])
         self._security_context = parameters.pop('securityContext', None)
         self._networks = parameters.pop('networks', [])
+        self._tolerations = parameters.pop('tolerations', [])
         self._restart_policy = parameters.pop('restartPolicy', 'Always')
         if self._restart_policy not in self.RESTART_POLICY:
             raise exceptions.KubernetesWrongRestartPolicy(
@@ -129,7 +131,8 @@ class ReplicationControllerObject(object):
                         "containers": [],
                         "volumes": [],
                         "nodeSelector": {},
-                        "restartPolicy": self._restart_policy
+                        "restartPolicy": self._restart_policy,
+                        "tolerations": []
                     }
                 }
             }
@@ -141,6 +144,7 @@ class ReplicationControllerObject(object):
         self._add_volumes()
         self._add_security_context()
         self._add_networks()
+        self._add_tolerations()
 
     def get_template(self):
         return self.template
@@ -211,6 +215,18 @@ class ReplicationControllerObject(object):
                              'spec.template.metadata.annotations',
                              annotations)
 
+    def _add_tolerations(self):
+        tolerations = []
+        for tol in self._tolerations:
+            tolerations.append({k: tol[k] for k in tol
+                                if k in self.TOLERATIONS_KEYS})
+
+        tolerations = ([{'operator': 'Exists'}] if not tolerations
+                       else tolerations)
+        utils.set_dict_value(self.template,
+                             'spec.template.spec.tolerations',
+                             tolerations)
+
 
 class ServiceNodePortObject(object):
 
index afadf74..cc1b375 100644 (file)
@@ -67,7 +67,10 @@ service ssh restart;while true ; do sleep 10000; done"
                         "nodeSelector": {
                             "kubernetes.io/hostname": "node-01"
                         },
-                        "restartPolicy": "Always"
+                        "restartPolicy": "Always",
+                        "tolerations": [
+                            {"operator": "Exists"}
+                        ]
                     }
                 }
             }
@@ -231,6 +234,30 @@ class ReplicationControllerObjectTestCase(base.BaseUnitTestCase):
                     '{"name": "network3"}]')
         self.assertEqual(expected, networks)
 
+    def test__add_tolerations(self):
+        _kwargs = {'tolerations': [{'key': 'key1',
+                                    'value': 'value2',
+                                    'effect': 'effect3',
+                                    'operator': 'operator4',
+                                    'wrong_key': 'error_key'}]
+                   }
+        k8s_obj = kubernetes.ReplicationControllerObject('pod_name', **_kwargs)
+        k8s_obj._add_tolerations()
+        _tol = k8s_obj.template['spec']['template']['spec']['tolerations']
+        self.assertEqual(1, len(_tol))
+        self.assertEqual({'key': 'key1',
+                          'value': 'value2',
+                          'effect': 'effect3',
+                          'operator': 'operator4'},
+                         _tol[0])
+
+    def test__add_tolerations_default(self):
+        k8s_obj = kubernetes.ReplicationControllerObject('pod_name')
+        k8s_obj._add_tolerations()
+        _tol = k8s_obj.template['spec']['template']['spec']['tolerations']
+        self.assertEqual(1, len(_tol))
+        self.assertEqual({'operator': 'Exists'}, _tol[0])
+
 
 class ContainerObjectTestCase(base.BaseUnitTestCase):