1 ##############################################################################
2 # Copyright (c) 2017 Huawei Technologies Co.,Ltd.
4 # All rights reserved. This program and the accompanying materials
5 # are made available under the terms of the Apache License, Version 2.0
6 # which accompanies this distribution, and is available at
7 # http://www.apache.org/licenses/LICENSE-2.0
8 ##############################################################################
12 from yardstick.common import constants
13 from yardstick.common import exceptions
14 from yardstick.common import utils
15 from yardstick.common import kubernetes_utils as k8s_utils
18 class ContainerObject(object):
20 SSH_MOUNT_PATH = '/tmp/.ssh/'
21 IMAGE_DEFAULT = 'openretriever/yardstick'
22 COMMAND_DEFAULT = '/bin/bash'
24 def __init__(self, name, ssh_key, **kwargs):
26 self._ssh_key = ssh_key
27 self._image = kwargs.get('image', self.IMAGE_DEFAULT)
28 self._command = [kwargs.get('command', self.COMMAND_DEFAULT)]
29 self._args = kwargs.get('args', [])
30 self._volume_mounts = kwargs.get('volumeMounts', [])
31 self._security_context = kwargs.get('securityContext')
33 def _create_volume_mounts(self):
34 """Return all "volumeMounts" items per container"""
35 volume_mounts_items = [self._create_volume_mounts_item(vol)
36 for vol in self._volume_mounts]
37 ssh_vol = {'name': self._ssh_key,
38 'mountPath': self.SSH_MOUNT_PATH}
39 volume_mounts_items.append(self._create_volume_mounts_item(ssh_vol))
40 return volume_mounts_items
43 def _create_volume_mounts_item(volume_mount):
44 """Create a "volumeMounts" item"""
45 return {'name': volume_mount['name'],
46 'mountPath': volume_mount['mountPath'],
47 'readOnly': volume_mount.get('readOnly', False)}
49 def get_container_item(self):
50 """Create a "container" item"""
51 container_name = '{}-container'.format(self._name)
52 container = {'args': self._args,
53 'command': self._command,
55 'name': container_name,
56 'volumeMounts': self._create_volume_mounts()}
57 if self._security_context:
58 container['securityContext'] = self._security_context
62 class KubernetesObject(object):
64 SSHKEY_DEFAULT = 'yardstick_key'
66 def __init__(self, name, **kwargs):
67 super(KubernetesObject, self).__init__()
68 parameters = copy.deepcopy(kwargs)
70 self.node_selector = parameters.pop('nodeSelector', {})
71 self.ssh_key = parameters.pop('ssh_key', self.SSHKEY_DEFAULT)
72 self._volumes = parameters.pop('volumes', [])
73 self._security_context = parameters.pop('securityContext', None)
75 containers = parameters.pop('containers', None)
78 ContainerObject(self.name, self.ssh_key, **container)
79 for container in containers]
82 ContainerObject(self.name, self.ssh_key, **parameters)]
86 "kind": "ReplicationController",
94 "labels": {"app": name}
105 self._change_value_according_name(name)
106 self._add_containers()
107 self._add_node_selector()
109 self._add_security_context()
111 def get_template(self):
114 def _change_value_according_name(self, name):
115 utils.set_dict_value(self.template, 'metadata.name', name)
117 utils.set_dict_value(self.template,
118 'spec.template.metadata.labels.app',
121 def _add_containers(self):
122 containers = [container.get_container_item()
123 for container in self._containers]
124 utils.set_dict_value(self.template,
125 'spec.template.spec.containers',
128 def _add_node_selector(self):
129 utils.set_dict_value(self.template,
130 'spec.template.spec.nodeSelector',
133 def _add_volumes(self):
134 """Add "volume" items to container specs, including the SSH one"""
135 volume_items = [self._create_volume_item(vol) for vol in self._volumes]
136 volume_items.append(self._create_ssh_key_volume())
137 utils.set_dict_value(self.template,
138 'spec.template.spec.volumes',
141 def _create_ssh_key_volume(self):
142 """Create a "volume" item of type "configMap" for the SSH key"""
143 return {'name': self.ssh_key,
144 'configMap': {'name': self.ssh_key}}
147 def _create_volume_item(volume):
148 """Create a "volume" item"""
149 volume = copy.deepcopy(volume)
150 name = volume.pop('name')
151 for key in (k for k in volume if k in k8s_utils.get_volume_types()):
153 type_data = volume[key]
156 raise exceptions.KubernetesTemplateInvalidVolumeType(volume=volume)
158 return {'name': name,
159 type_name: type_data}
161 def _add_security_context(self):
162 if self._security_context:
163 utils.set_dict_value(self.template,
164 'spec.template.spec.securityContext',
165 self._security_context)
168 class ServiceObject(object):
170 def __init__(self, name):
171 self.name = '{}-service'.format(name)
174 'name': '{}-service'.format(name)
191 k8s_utils.create_service(self.template)
194 k8s_utils.delete_service(self.name)
197 class CustomResourceDefinitionObject(object):
199 MANDATORY_PARAMETERS = {'name'}
201 def __init__(self, ctx_name, **kwargs):
202 if not self.MANDATORY_PARAMETERS.issubset(kwargs):
203 missing_parameters = ', '.join(
204 str(param) for param in
205 (self.MANDATORY_PARAMETERS - set(kwargs)))
206 raise exceptions.KubernetesCRDObjectDefinitionError(
207 missing_parameters=missing_parameters)
209 singular = kwargs['name']
210 plural = singular + 's'
211 kind = singular.title()
212 version = kwargs.get('version', 'v1')
213 scope = kwargs.get('scope', constants.SCOPE_NAMESPACED)
214 group = ctx_name + '.com'
215 self._name = metadata_name = plural + '.' + group
219 'name': metadata_name
225 'names': {'plural': plural,
226 'singular': singular,
232 k8s_utils.create_custom_resource_definition(self._template)
235 k8s_utils.delete_custom_resource_definition(self._name)
238 class NetworkObject(object):
240 MANDATORY_PARAMETERS = {'name', 'plugin', 'args'}
243 def __init__(self, **kwargs):
244 if not self.MANDATORY_PARAMETERS.issubset(kwargs):
245 missing_parameters = ', '.join(
246 str(param) for param in
247 (self.MANDATORY_PARAMETERS - set(kwargs)))
248 raise exceptions.KubernetesNetworkObjectDefinitionError(
249 missing_parameters=missing_parameters)
251 self._name = kwargs['name']
252 self._plugin = kwargs['plugin']
253 self._args = kwargs['args']
255 self._template = None
265 crd = k8s_utils.get_custom_resource_definition(self.KIND)
267 raise exceptions.KubernetesNetworkObjectKindMissing()
275 self._group = self.crd.spec.group
282 self._version = self.crd.spec.version
289 self._plural = self.crd.spec.names.plural
296 self._scope = self.crd.spec.scope
301 """"Network" object template
303 This template can be rendered only once the CRD "Network" is created in
304 Kubernetes. This function call must be delayed until the creation of
308 return self._template
311 'apiVersion': '{}/{}'.format(self.group, self.version),
316 'plugin': self._plugin,
319 return self._template
322 k8s_utils.create_network(self.scope, self.group, self.version,
323 self.plural, self.template)
326 k8s_utils.delete_network(self.scope, self.group, self.version,
327 self.plural, self._name)
330 class KubernetesTemplate(object):
332 def __init__(self, name, context_cfg):
333 """KubernetesTemplate object initialization
335 :param name: (str) name of the Kubernetes context
336 :param context_cfg: (dict) context definition
338 context_cfg = copy.deepcopy(context_cfg)
339 servers_cfg = context_cfg.pop('servers', {})
340 crd_cfg = context_cfg.pop('custom_resources', [])
341 networks_cfg = context_cfg.pop('networks', [])
343 self.ssh_key = '{}-key'.format(name)
345 self.rcs = [self._get_rc_name(rc) for rc in servers_cfg]
346 self.k8s_objs = [KubernetesObject(self._get_rc_name(rc),
347 ssh_key=self.ssh_key,
349 for rc, cfg in servers_cfg.items()]
350 self.service_objs = [ServiceObject(s) for s in self.rcs]
351 self.crd = [CustomResourceDefinitionObject(self.name, **crd)
353 self.network_objs = [NetworkObject(**nobj) for nobj in networks_cfg]
356 def _get_rc_name(self, rc_name):
357 return '{}-{}'.format(rc_name, self.name)
359 def get_rc_pods(self):
360 resp = k8s_utils.get_pod_list()
361 self.pods = [p.metadata.name for p in resp.items for s in self.rcs
362 if p.metadata.name.startswith(s)]