kubernetes_utils: avoid 404 error code in delete_replication_controller()
[yardstick.git] / yardstick / benchmark / contexts / 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 collections
11 import logging
12 import pkg_resources
13 import time
14
15 import paramiko
16
17 from yardstick.benchmark import contexts
18 from yardstick.benchmark.contexts import base as ctx_base
19 from yardstick.benchmark.contexts import model
20 from yardstick.common import constants
21 from yardstick.common import exceptions
22 from yardstick.common import kubernetes_utils as k8s_utils
23 from yardstick.common import utils
24 from yardstick.orchestrator import kubernetes
25
26
27 LOG = logging.getLogger(__name__)
28 BITS_LENGTH = 2048
29
30
31 class KubernetesContext(ctx_base.Context):
32     """Class that handle nodes info"""
33
34     __context_type__ = contexts.CONTEXT_KUBERNETES
35
36     def __init__(self):
37         self.ssh_key = ''
38         self.key_path = ''
39         self.public_key_path = ''
40         self.template = None
41         super(KubernetesContext, self).__init__(host_name_separator='-')
42
43     def init(self, attrs):
44         super(KubernetesContext, self).init(attrs)
45
46         networks = attrs.get('networks', {})
47         self.template = kubernetes.KubernetesTemplate(self.name, attrs)
48         self.ssh_key = '{}-key'.format(self.name)
49         self.key_path = self._get_key_path()
50         self.public_key_path = '{}.pub'.format(self.key_path)
51         self._networks = collections.OrderedDict(
52             (net_name, model.Network(net_name, self, network))
53             for net_name, network in networks.items())
54
55     def deploy(self):
56         LOG.info('Creating ssh key')
57         self._set_ssh_key()
58
59         self._create_crd()
60         self._create_networks()
61         LOG.info('Launch containers')
62         self._create_rcs()
63         self._create_services()
64         time.sleep(1)
65         self.template.get_rc_pods()
66
67         self._wait_until_running()
68
69     def undeploy(self):
70         self._delete_ssh_key()
71         self._delete_rcs()
72         self._delete_pods()
73         self._delete_services()
74         self._delete_networks()
75         self._delete_crd()
76
77         super(KubernetesContext, self).undeploy()
78
79     def _wait_until_running(self):
80         while not all(self._check_pod_status(p) for p in self.template.pods):
81             time.sleep(1)
82
83     def _check_pod_status(self, pod):
84         status = k8s_utils.read_pod_status(pod)
85         LOG.debug('%s:%s', pod, status)
86         if status == 'Failed':
87             LOG.error('Pod %s status is failed', pod)
88             raise RuntimeError
89         if status != 'Running':
90             return False
91         return True
92
93     def _create_services(self):
94         for obj in self.template.service_objs:
95             obj.create()
96
97     def _delete_services(self):
98         for obj in self.template.service_objs:
99             obj.delete()
100
101     def _create_rcs(self):
102         for obj in self.template.rc_objs:
103             self._create_rc(obj.get_template())
104
105     def _create_rc(self, template):
106         k8s_utils.create_replication_controller(template)
107
108     def _delete_rcs(self):
109         for rc in self.template.rcs:
110             self._delete_rc(rc)
111
112     def _delete_rc(self, rc):
113         k8s_utils.delete_replication_controller(rc, skip_codes=[404])
114
115     def _delete_pods(self):
116         for pod in self.template.pods:
117             self._delete_pod(pod)
118
119     def _delete_pod(self, pod):
120         k8s_utils.delete_pod(pod, skip_codes=[404])
121
122     def _create_crd(self):
123         LOG.info('Create Custom Resource Definition elements')
124         for crd in self.template.crd:
125             crd.create()
126
127     def _delete_crd(self):
128         LOG.info('Delete Custom Resource Definition elements')
129         for crd in self.template.crd:
130             crd.delete()
131
132     def _create_networks(self):  # pragma: no cover
133         LOG.info('Create Network elements')
134         for net in self.template.network_objs:
135             net.create()
136
137     def _delete_networks(self):  # pragma: no cover
138         LOG.info('Create Network elements')
139         for net in self.template.network_objs:
140             net.delete()
141
142     def _get_key_path(self):
143         task_id = self.name.split('-')[-1]
144         k = 'files/yardstick_key-{}'.format(task_id)
145         return pkg_resources.resource_filename('yardstick.resources', k)
146
147     def _set_ssh_key(self):
148         rsa_key = paramiko.RSAKey.generate(bits=BITS_LENGTH)
149
150         LOG.info('Writing private key')
151         rsa_key.write_private_key_file(self.key_path)
152
153         LOG.info('Writing public key')
154         key = '{} {}\n'.format(rsa_key.get_name(), rsa_key.get_base64())
155         with open(self.public_key_path, 'w') as f:
156             f.write(key)
157
158         LOG.info('Create configmap for ssh key')
159         k8s_utils.create_config_map(self.ssh_key, {'authorized_keys': key})
160
161     def _delete_ssh_key(self):
162         k8s_utils.delete_config_map(self.ssh_key)
163         utils.remove_file(self.key_path)
164         utils.remove_file(self.public_key_path)
165
166     def _get_server(self, name):
167         node_ports = self._get_service_ports(name)
168         for sn_port in (sn_port for sn_port in node_ports
169                         if sn_port['port'] == constants.SSH_PORT):
170             node_port = sn_port['node_port']
171             break
172         else:
173             raise exceptions.KubernetesSSHPortNotDefined()
174
175         return {
176             'name': name,
177             'ip': self._get_node_ip(),
178             'private_ip': k8s_utils.get_pod_by_name(name).status.pod_ip,
179             'ssh_port': node_port,
180             'user': 'root',
181             'key_filename': self.key_path,
182             'interfaces': self._get_interfaces(name),
183             'service_ports': node_ports
184         }
185
186     def _get_network(self, net_name):
187         """Retrieves the network object, searching by name
188
189         :param net_name: (str) replication controller name
190         :return: (dict) network information (name)
191         """
192         network = self._networks.get(net_name)
193         if not network:
194             return
195         return {'name': net_name}
196
197     def _get_interfaces(self, rc_name):
198         """Retrieves the network list of a replication controller
199
200         :param rc_name: (str) replication controller name
201         :return: (dict) names and information of the networks used in this
202                  replication controller; those networks must be defined in the
203                  Kubernetes cluster
204         """
205         rc = self.template.get_rc_by_name(rc_name)
206         if not rc:
207             return {}
208         return {name: {'network_name': name,
209                        'local_mac': None,
210                        'local_ip': None}
211                 for name in rc.networks}
212
213     def _get_node_ip(self):
214         return k8s_utils.get_node_list().items[0].status.addresses[0].address
215
216     def _get_physical_nodes(self):
217         return None
218
219     def _get_physical_node_for_server(self, server_name):
220         return None
221
222     def _get_service_ports(self, name):
223         service_name = '{}-service'.format(name)
224         service = k8s_utils.get_service_by_name(service_name)
225         if not service:
226             raise exceptions.KubernetesServiceObjectNotDefined()
227         ports = []
228         for port in service.ports:
229             ports.append({'name': port.name,
230                           'node_port': port.node_port,
231                           'port': port.port,
232                           'protocol': port.protocol,
233                           'target_port': port.target_port})
234         return ports