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