From 01edaefa20775921200a6a1b17fbfd67f7aca77e Mon Sep 17 00:00:00 2001 From: Rodolfo Alonso Hernandez Date: Fri, 4 May 2018 16:38:52 +0100 Subject: Add "volumeMounts" parameter in Kubernetes context This new parameter, "volumeMounts", will allow the user to automatically create new volumes mounted inside the container. Example of Kubernetes context definition: context: type: Kubernetes servers: host: volumeMounts: - name: volume1 # mandatory mountPath: /dev/hugepages # mandatory readOnly: True # optional, default=False JIRA: YARDSTICK-1151 Change-Id: Ic00b45e6d603a9f85e3f0e25becdf0bce14e637c Signed-off-by: Rodolfo Alonso Hernandez --- yardstick/orchestrator/kubernetes.py | 58 ++++++++++++--------- .../tests/unit/orchestrator/test_kubernetes.py | 59 ++++++++++++++++++++-- 2 files changed, 89 insertions(+), 28 deletions(-) (limited to 'yardstick') diff --git a/yardstick/orchestrator/kubernetes.py b/yardstick/orchestrator/kubernetes.py index ae6c9459b..e05c971ac 100644 --- a/yardstick/orchestrator/kubernetes.py +++ b/yardstick/orchestrator/kubernetes.py @@ -16,15 +16,21 @@ from yardstick.common import kubernetes_utils as k8s_utils class KubernetesObject(object): + SSH_MOUNT_PATH = '/tmp/.ssh/' + IMAGE_DEFAULT = 'openretriever/yardstick' + COMMAND_DEFAULT = '/bin/bash' + SSHKEY_DEFAULT = 'yardstick_key' + def __init__(self, name, **kwargs): super(KubernetesObject, self).__init__() self.name = name - self.image = kwargs.get('image', 'openretriever/yardstick') - self.command = [kwargs.get('command', '/bin/bash')] + self.image = kwargs.get('image', self.IMAGE_DEFAULT) + self.command = [kwargs.get('command', self.COMMAND_DEFAULT)] self.args = kwargs.get('args', []) - self.ssh_key = kwargs.get('ssh_key', 'yardstick_key') + self.ssh_key = kwargs.get('ssh_key', self.SSHKEY_DEFAULT) self.node_selector = kwargs.get('nodeSelector', {}) self._volumes = kwargs.get('volumes', []) + self._volume_mounts = kwargs.get('volumeMounts', []) self.template = { "apiVersion": "v1", @@ -65,29 +71,19 @@ class KubernetesObject(object): name) def _add_containers(self): - containers = [self._add_container()] + containers = [self._create_container_item()] utils.set_dict_value(self.template, 'spec.template.spec.containers', containers) - def _add_container(self): + def _create_container_item(self): + """Create a "container" item""" container_name = '{}-container'.format(self.name) - ssh_key_mount_path = '/tmp/.ssh/' - - container = { - "args": self.args, - "command": self.command, - "image": self.image, - "name": container_name, - "volumeMounts": [ - { - "mountPath": ssh_key_mount_path, - "name": self.ssh_key - } - ] - } - - return container + return {'args': self.args, + 'command': self.command, + 'image': self.image, + 'name': container_name, + 'volumeMounts': self._create_volume_mounts()} def _add_node_selector(self): utils.set_dict_value(self.template, @@ -96,7 +92,7 @@ class KubernetesObject(object): def _add_volumes(self): """Add "volume" items to container specs, including the SSH one""" - volume_items = [self._create_volume(vol) for vol in self._volumes] + volume_items = [self._create_volume_item(vol) for vol in self._volumes] volume_items.append(self._create_ssh_key_volume()) utils.set_dict_value(self.template, 'spec.template.spec.volumes', @@ -108,7 +104,7 @@ class KubernetesObject(object): 'configMap': {'name': self.ssh_key}} @staticmethod - def _create_volume(volume): + def _create_volume_item(volume): """Create a "volume" item""" volume = copy.deepcopy(volume) name = volume.pop('name') @@ -122,6 +118,22 @@ class KubernetesObject(object): return {'name': name, type_name: type_data} + def _create_volume_mounts(self): + """Return all "volumeMounts" items per container""" + volume_mounts_items = [self._create_volume_mounts_item(vol) + for vol in self._volume_mounts] + ssh_vol = {'name': self.ssh_key, + 'mountPath': self.SSH_MOUNT_PATH} + volume_mounts_items.append(self._create_volume_mounts_item(ssh_vol)) + return volume_mounts_items + + @staticmethod + def _create_volume_mounts_item(volume_mount): + """Create a "volumeMounts" item""" + return {'name': volume_mount['name'], + 'mountPath': volume_mount['mountPath'], + 'readOnly': volume_mount.get('readOnly', False)} + class ServiceObject(object): diff --git a/yardstick/tests/unit/orchestrator/test_kubernetes.py b/yardstick/tests/unit/orchestrator/test_kubernetes.py index e3e5516ca..21a12a0d3 100644 --- a/yardstick/tests/unit/orchestrator/test_kubernetes.py +++ b/yardstick/tests/unit/orchestrator/test_kubernetes.py @@ -7,6 +7,8 @@ # http://www.apache.org/licenses/LICENSE-2.0 ############################################################################## +import copy + import mock from yardstick.common import exceptions @@ -48,7 +50,8 @@ service ssh restart;while true ; do sleep 10000; done" "volumeMounts": [ { "mountPath": "/tmp/.ssh/", - "name": "k8s-86096c30-key" + "name": "k8s-86096c30-key", + "readOnly": False } ] } @@ -133,15 +136,61 @@ class KubernetesObjectTestCase(base.BaseUnitTestCase): k8s_obj = kubernetes.KubernetesObject('name', ssh_key='fake_sshkey') self.assertEqual(expected, k8s_obj._create_ssh_key_volume()) - def test__create_volume(self): + def test__create_volume_item(self): for vol_type in kubernetes_utils.get_volume_types(): volume = {'name': 'vol_name', vol_type: 'data'} self.assertEqual( - volume, kubernetes.KubernetesObject._create_volume(volume)) + volume, + kubernetes.KubernetesObject._create_volume_item(volume)) - def test__create_volume_invalid_type(self): + def test__create_volume_item_invalid_type(self): volume = {'name': 'vol_name', 'invalid_type': 'data'} with self.assertRaises(exceptions.KubernetesTemplateInvalidVolumeType): - kubernetes.KubernetesObject._create_volume(volume) + kubernetes.KubernetesObject._create_volume_item(volume) + + def test__create_volume_mounts(self): + volume_mount = {'name': 'fake_name', + 'mountPath': 'fake_path'} + ssh_vol = {'name': kubernetes.KubernetesObject.SSHKEY_DEFAULT, + 'mountPath': kubernetes.KubernetesObject.SSH_MOUNT_PATH, + 'readOnly': False} + expected = copy.deepcopy(volume_mount) + expected['readOnly'] = False + expected = [expected, ssh_vol] + k8s_obj = kubernetes.KubernetesObject('name', + volumeMounts=[volume_mount]) + output = k8s_obj._create_volume_mounts() + self.assertEqual(expected, output) + + def test__create_volume_mounts_no_volume_mounts(self): + ssh_vol = {'name': kubernetes.KubernetesObject.SSHKEY_DEFAULT, + 'mountPath': kubernetes.KubernetesObject.SSH_MOUNT_PATH, + 'readOnly': False} + k8s_obj = kubernetes.KubernetesObject('name') + output = k8s_obj._create_volume_mounts() + self.assertEqual([ssh_vol], output) + + def test__create_volume_mounts_item(self): + volume_mount = {'name': 'fake_name', + 'mountPath': 'fake_path'} + expected = copy.deepcopy(volume_mount) + expected['readOnly'] = False + output = kubernetes.KubernetesObject._create_volume_mounts_item( + volume_mount) + self.assertEqual(expected, output) + + def test__create_container_item(self): + volume_mount = {'name': 'fake_name', + 'mountPath': 'fake_path'} + args = ['arg1', 'arg2'] + k8s_obj = kubernetes.KubernetesObject( + 'cname', ssh_key='fake_sshkey', volumeMount=[volume_mount], + args=args) + expected = {'args': args, + 'command': [kubernetes.KubernetesObject.COMMAND_DEFAULT], + 'image': kubernetes.KubernetesObject.IMAGE_DEFAULT, + 'name': 'cname-container', + 'volumeMounts': k8s_obj._create_volume_mounts()} + self.assertEqual(expected, k8s_obj._create_container_item()) -- cgit 1.2.3-korg