f6f43e5ac7811272d56d1f8ba549c0bccb0f6582
[yardstick.git] / api / resources / env_action.py
1 ##############################################################################
2 # Copyright (c) 2016 Huawei Technologies Co.,Ltd and others.
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 from __future__ import absolute_import
10
11 import errno
12 import logging
13 import os
14 import subprocess
15 import threading
16 import time
17 import uuid
18 import glob
19
20 from six.moves import configparser
21 from oslo_serialization import jsonutils
22 from docker import Client
23
24 from api.database.handler import AsyncTaskHandler
25 from api.utils import influx
26 from api.utils.common import result_handler
27 from yardstick.common import constants as consts
28 from yardstick.common import utils as yardstick_utils
29 from yardstick.common import openstack_utils
30 from yardstick.common.httpClient import HttpClient
31
32
33 logger = logging.getLogger(__name__)
34 logger.setLevel(logging.DEBUG)
35
36
37 def createGrafanaContainer(args):
38     task_id = str(uuid.uuid4())
39
40     thread = threading.Thread(target=_create_grafana, args=(task_id,))
41     thread.start()
42
43     return result_handler('success', {'task_id': task_id})
44
45
46 def _create_grafana(task_id):
47     _create_task(task_id)
48
49     client = Client(base_url=consts.DOCKER_URL)
50
51     try:
52         image = '{}:{}'.format(consts.GRAFANA_IMAGE, consts.GRAFANA_TAG)
53         if not _check_image_exist(client, image):
54             client.pull(consts.GRAFANA_IMAGE, consts.GRAFANA_TAG)
55
56         _create_grafana_container(client)
57
58         time.sleep(5)
59
60         _create_data_source()
61
62         _create_dashboard()
63
64         _update_task_status(task_id)
65     except Exception as e:
66         _update_task_error(task_id, str(e))
67         logger.exception('Error: %s', e)
68
69
70 def _create_dashboard():
71     url = 'http://admin:admin@%s:3000/api/dashboards/db' % consts.GRAFANA_IP
72     path = os.path.join(consts.REPOS_DIR, 'dashboard', '*dashboard.json')
73
74     for i in sorted(glob.iglob(path)):
75         with open(i) as f:
76             data = jsonutils.load(f)
77         HttpClient().post(url, data)
78
79
80 def _create_data_source():
81     url = 'http://admin:admin@%s:3000/api/datasources' % consts.GRAFANA_IP
82     data = {
83         "name": "yardstick",
84         "type": "influxdb",
85         "access": "proxy",
86         "url": "http://%s:8086" % consts.INFLUXDB_IP,
87         "password": "root",
88         "user": "root",
89         "database": "yardstick",
90         "basicAuth": True,
91         "basicAuthUser": "admin",
92         "basicAuthPassword": "admin",
93         "isDefault": False,
94     }
95     HttpClient().post(url, data)
96
97
98 def _create_grafana_container(client):
99     ports = [3000]
100     port_bindings = {k: k for k in ports}
101     host_config = client.create_host_config(port_bindings=port_bindings)
102
103     container = client.create_container(image='%s:%s' % (consts.GRAFANA_IMAGE,
104                                                          consts.GRAFANA_TAG),
105                                         ports=ports,
106                                         detach=True,
107                                         tty=True,
108                                         host_config=host_config)
109     client.start(container)
110
111
112 def _check_image_exist(client, t):
113     return any(t in a['RepoTags'][0] for a in client.images() if a['RepoTags'])
114
115
116 def createInfluxDBContainer(args):
117     task_id = str(uuid.uuid4())
118
119     thread = threading.Thread(target=_create_influxdb, args=(task_id,))
120     thread.start()
121
122     return result_handler('success', {'task_id': task_id})
123
124
125 def _create_influxdb(task_id):
126     _create_task(task_id)
127
128     client = Client(base_url=consts.DOCKER_URL)
129
130     try:
131         _change_output_to_influxdb()
132
133         if not _check_image_exist(client, '%s:%s' % (consts.INFLUXDB_IMAGE,
134                                                      consts.INFLUXDB_TAG)):
135             client.pull(consts.INFLUXDB_IMAGE, tag=consts.INFLUXDB_TAG)
136
137         _create_influxdb_container(client)
138
139         time.sleep(5)
140
141         _config_influxdb()
142
143         _update_task_status(task_id)
144     except Exception as e:
145         _update_task_error(task_id, str(e))
146         logger.debug('Error: %s', e)
147
148
149 def _create_influxdb_container(client):
150
151     ports = [8083, 8086]
152     port_bindings = {k: k for k in ports}
153     host_config = client.create_host_config(port_bindings=port_bindings)
154
155     container = client.create_container(image='%s:%s' % (consts.INFLUXDB_IMAGE,
156                                                          consts.INFLUXDB_TAG),
157                                         ports=ports,
158                                         detach=True,
159                                         tty=True,
160                                         host_config=host_config)
161     client.start(container)
162
163
164 def _config_influxdb():
165     try:
166         client = influx.get_data_db_client()
167         client.create_user(consts.INFLUXDB_USER,
168                            consts.INFLUXDB_PASS,
169                            consts.INFLUXDB_DB_NAME)
170         client.create_database(consts.INFLUXDB_DB_NAME)
171         logger.info('Success to config influxDB')
172     except Exception as e:
173         logger.debug('Failed to config influxDB: %s', e)
174
175
176 def _change_output_to_influxdb():
177     yardstick_utils.makedirs(consts.CONF_DIR)
178
179     parser = configparser.ConfigParser()
180     parser.read(consts.CONF_SAMPLE_FILE)
181
182     parser.set('DEFAULT', 'dispatcher', 'influxdb')
183     parser.set('dispatcher_influxdb', 'target',
184                'http://%s:8086' % consts.INFLUXDB_IP)
185
186     with open(consts.CONF_FILE, 'w') as f:
187         parser.write(f)
188
189
190 def prepareYardstickEnv(args):
191     task_id = str(uuid.uuid4())
192
193     thread = threading.Thread(target=_prepare_env_daemon, args=(task_id,))
194     thread.start()
195
196     return result_handler('success', {'task_id': task_id})
197
198
199 def _already_source_openrc():
200     """Check if openrc is sourced already"""
201     return all(os.environ.get(k) for k in ['OS_AUTH_URL', 'OS_USERNAME',
202                                            'OS_PASSWORD', 'OS_TENANT_NAME',
203                                            'EXTERNAL_NETWORK'])
204
205
206 def _prepare_env_daemon(task_id):
207     _create_task(task_id)
208
209     installer_ip = os.environ.get('INSTALLER_IP', 'undefined')
210     installer_type = os.environ.get('INSTALLER_TYPE', 'undefined')
211
212     try:
213         _check_variables(installer_ip, installer_type)
214
215         _create_directories()
216
217         rc_file = consts.OPENRC
218
219         if not _already_source_openrc():
220             _get_remote_rc_file(rc_file, installer_ip, installer_type)
221             _source_file(rc_file)
222             _append_external_network(rc_file)
223
224         # update the external_network
225         _source_file(rc_file)
226
227         _clean_images()
228
229         _load_images()
230
231         _update_task_status(task_id)
232     except Exception as e:
233         _update_task_error(task_id, str(e))
234         logger.debug('Error: %s', e)
235
236
237 def _check_variables(installer_ip, installer_type):
238
239     if installer_ip == 'undefined':
240         raise SystemExit('Missing INSTALLER_IP')
241
242     if installer_type == 'undefined':
243         raise SystemExit('Missing INSTALLER_TYPE')
244     elif installer_type not in consts.INSTALLERS:
245         raise SystemExit('INSTALLER_TYPE is not correct')
246
247
248 def _create_directories():
249     yardstick_utils.makedirs(consts.CONF_DIR)
250
251
252 def _source_file(rc_file):
253     yardstick_utils.source_env(rc_file)
254
255
256 def _get_remote_rc_file(rc_file, installer_ip, installer_type):
257
258     os_fetch_script = os.path.join(consts.RELENG_DIR, consts.FETCH_SCRIPT)
259
260     try:
261         cmd = [os_fetch_script, '-d', rc_file, '-i', installer_type,
262                '-a', installer_ip]
263         p = subprocess.Popen(cmd, stdout=subprocess.PIPE)
264         p.communicate()
265
266         if p.returncode != 0:
267             logger.debug('Failed to fetch credentials from installer')
268     except OSError as e:
269         if e.errno != errno.EEXIST:
270             raise
271
272
273 def _append_external_network(rc_file):
274     neutron_client = openstack_utils.get_neutron_client()
275     networks = neutron_client.list_networks()['networks']
276     try:
277         ext_network = next(n['name'] for n in networks if n['router:external'])
278     except StopIteration:
279         logger.warning("Can't find external network")
280     else:
281         cmd = 'export EXTERNAL_NETWORK=%s' % ext_network
282         try:
283             with open(rc_file, 'a') as f:
284                 f.write(cmd + '\n')
285         except OSError as e:
286             if e.errno != errno.EEXIST:
287                 raise
288
289
290 def _clean_images():
291     cmd = [consts.CLEAN_IMAGES_SCRIPT]
292     p = subprocess.Popen(cmd, stdout=subprocess.PIPE, cwd=consts.REPOS_DIR)
293     output = p.communicate()[0]
294     logger.debug('The result is: %s', output)
295
296
297 def _load_images():
298     cmd = [consts.LOAD_IMAGES_SCRIPT]
299     p = subprocess.Popen(cmd, stdout=subprocess.PIPE, cwd=consts.REPOS_DIR)
300     output = p.communicate()[0]
301     logger.debug('The result is: %s', output)
302
303
304 def _create_task(task_id):
305     async_handler = AsyncTaskHandler()
306     task_dict = {
307         'task_id': task_id,
308         'status': 0
309     }
310     async_handler.insert(task_dict)
311
312
313 def _update_task_status(task_id):
314     async_handler = AsyncTaskHandler()
315
316     task = async_handler.get_task_by_taskid(task_id)
317     async_handler.update_status(task, 1)
318
319
320 def _update_task_error(task_id, error):
321     async_handler = AsyncTaskHandler()
322
323     task = async_handler.get_task_by_taskid(task_id)
324     async_handler.update_status(task, 2)
325     async_handler.update_error(task, error)