Merge "Cleanup CGNAPT unit tests"
[yardstick.git] / yardstick / orchestrator / kubernetes.py
1 ##############################################################################
2 # Copyright (c) 2017 Huawei Technologies Co.,Ltd.
3 #
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 ##############################################################################
9
10 import copy
11
12 from yardstick.common import exceptions
13 from yardstick.common import utils
14 from yardstick.common import kubernetes_utils as k8s_utils
15
16
17 class KubernetesObject(object):
18
19     SSH_MOUNT_PATH = '/tmp/.ssh/'
20     IMAGE_DEFAULT = 'openretriever/yardstick'
21     COMMAND_DEFAULT = '/bin/bash'
22     SSHKEY_DEFAULT = 'yardstick_key'
23
24     def __init__(self, name, **kwargs):
25         super(KubernetesObject, self).__init__()
26         self.name = name
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.ssh_key = kwargs.get('ssh_key', self.SSHKEY_DEFAULT)
31         self.node_selector = kwargs.get('nodeSelector', {})
32         self._volumes = kwargs.get('volumes', [])
33         self._volume_mounts = kwargs.get('volumeMounts', [])
34
35         self.template = {
36             "apiVersion": "v1",
37             "kind": "ReplicationController",
38             "metadata": {
39                 "name": ""
40             },
41             "spec": {
42                 "replicas": 1,
43                 "template": {
44                     "metadata": {
45                         "labels": {
46                             "app": name
47                         }
48                     },
49                     "spec": {
50                         "containers": [],
51                         "volumes": [],
52                         "nodeSelector": {}
53                     }
54                 }
55             }
56         }
57
58         self._change_value_according_name(name)
59         self._add_containers()
60         self._add_node_selector()
61         self._add_volumes()
62
63     def get_template(self):
64         return self.template
65
66     def _change_value_according_name(self, name):
67         utils.set_dict_value(self.template, 'metadata.name', name)
68
69         utils.set_dict_value(self.template,
70                              'spec.template.metadata.labels.app',
71                              name)
72
73     def _add_containers(self):
74         containers = [self._create_container_item()]
75         utils.set_dict_value(self.template,
76                              'spec.template.spec.containers',
77                              containers)
78
79     def _create_container_item(self):
80         """Create a "container" item"""
81         container_name = '{}-container'.format(self.name)
82         return {'args': self.args,
83                 'command': self.command,
84                 'image': self.image,
85                 'name': container_name,
86                 'volumeMounts': self._create_volume_mounts()}
87
88     def _add_node_selector(self):
89         utils.set_dict_value(self.template,
90                              'spec.template.spec.nodeSelector',
91                              self.node_selector)
92
93     def _add_volumes(self):
94         """Add "volume" items to container specs, including the SSH one"""
95         volume_items = [self._create_volume_item(vol) for vol in self._volumes]
96         volume_items.append(self._create_ssh_key_volume())
97         utils.set_dict_value(self.template,
98                              'spec.template.spec.volumes',
99                              volume_items)
100
101     def _create_ssh_key_volume(self):
102         """Create a "volume" item of type "configMap" for the SSH key"""
103         return {'name': self.ssh_key,
104                 'configMap': {'name': self.ssh_key}}
105
106     @staticmethod
107     def _create_volume_item(volume):
108         """Create a "volume" item"""
109         volume = copy.deepcopy(volume)
110         name = volume.pop('name')
111         for key in (k for k in volume if k in k8s_utils.get_volume_types()):
112             type_name = key
113             type_data = volume[key]
114             break
115         else:
116             raise exceptions.KubernetesTemplateInvalidVolumeType(volume=volume)
117
118         return {'name': name,
119                 type_name: type_data}
120
121     def _create_volume_mounts(self):
122         """Return all "volumeMounts" items per container"""
123         volume_mounts_items = [self._create_volume_mounts_item(vol)
124                                for vol in self._volume_mounts]
125         ssh_vol = {'name': self.ssh_key,
126                    'mountPath': self.SSH_MOUNT_PATH}
127         volume_mounts_items.append(self._create_volume_mounts_item(ssh_vol))
128         return volume_mounts_items
129
130     @staticmethod
131     def _create_volume_mounts_item(volume_mount):
132         """Create a "volumeMounts" item"""
133         return {'name': volume_mount['name'],
134                 'mountPath': volume_mount['mountPath'],
135                 'readOnly': volume_mount.get('readOnly', False)}
136
137
138 class ServiceObject(object):
139
140     def __init__(self, name):
141         self.name = '{}-service'.format(name)
142         self.template = {
143             'metadata': {
144                 'name': '{}-service'.format(name)
145             },
146             'spec': {
147                 'type': 'NodePort',
148                 'ports': [
149                     {
150                         'port': 22,
151                         'protocol': 'TCP'
152                     }
153                 ],
154                 'selector': {
155                     'app': name
156                 }
157             }
158         }
159
160     def create(self):
161         k8s_utils.create_service(self.template)
162
163     def delete(self):
164         k8s_utils.delete_service(self.name)
165
166
167 class KubernetesTemplate(object):
168
169     def __init__(self, name, context_cfg):
170         """KubernetesTemplate object initialization
171
172         :param name: (str) name of the Kubernetes context
173         :param context_cfg: (dict) context definition
174         """
175         context_cfg = copy.deepcopy(context_cfg)
176         servers_cfg = context_cfg.pop('servers', {})
177         self.name = name
178         self.ssh_key = '{}-key'.format(name)
179
180         self.rcs = [self._get_rc_name(rc) for rc in servers_cfg]
181         self.k8s_objs = [KubernetesObject(self._get_rc_name(rc),
182                                           ssh_key=self.ssh_key,
183                                           **cfg)
184                          for rc, cfg in servers_cfg.items()]
185         self.service_objs = [ServiceObject(s) for s in self.rcs]
186
187         self.pods = []
188
189     def _get_rc_name(self, rc_name):
190         return '{}-{}'.format(rc_name, self.name)
191
192     def get_rc_pods(self):
193         resp = k8s_utils.get_pod_list()
194         self.pods = [p.metadata.name for p in resp.items for s in self.rcs
195                      if p.metadata.name.startswith(s)]
196
197         return self.pods