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 ##############################################################################
9 from __future__ import absolute_import
18 from six.moves import configparser
19 from oslo_serialization import jsonutils
20 from docker import Client
22 from api import ApiResource
23 from api.utils import influx
24 from api.database.v2.handlers import V2ContainerHandler
25 from api.database.v2.handlers import V2EnvironmentHandler
26 from yardstick.common import constants as consts
27 from yardstick.common import utils
28 from yardstick.common.utils import result_handler
29 from yardstick.common.utils import get_free_port
30 from yardstick.common.httpClient import HttpClient
33 LOG = logging.getLogger(__name__)
34 LOG.setLevel(logging.DEBUG)
36 environment_handler = V2EnvironmentHandler()
37 container_handler = V2ContainerHandler()
40 class V2Containers(ApiResource):
43 return self._dispatch_post()
45 def create_influxdb(self, args):
47 environment_id = args['environment_id']
49 return result_handler(consts.API_ERROR, 'environment_id must be provided')
52 uuid.UUID(environment_id)
54 return result_handler(consts.API_ERROR, 'invalid environment id')
57 environment = environment_handler.get_by_uuid(environment_id)
59 return result_handler(consts.API_ERROR, 'no such environment id')
61 container_info = environment.container_id
62 container_info = jsonutils.loads(container_info) if container_info else {}
64 if container_info.get('influxdb'):
65 return result_handler(consts.API_ERROR, 'influxdb container already exist')
67 name = 'influxdb-{}'.format(environment_id[:8])
68 port = get_free_port(consts.SERVER_IP)
69 container_id = str(uuid.uuid4())
70 LOG.info('%s will launch on : %s', name, port)
72 LOG.info('launch influxdb background')
73 args = (name, port, container_id)
74 thread = threading.Thread(target=self._create_influxdb, args=args)
77 LOG.info('record container in database')
78 container_init_data = {
80 'environment_id': environment_id,
85 container_handler.insert(container_init_data)
87 LOG.info('update container in environment')
88 container_info['influxdb'] = container_id
89 environment_info = {'container_id': jsonutils.dumps(container_info)}
90 environment_handler.update_attr(environment_id, environment_info)
92 return result_handler(consts.API_SUCCESS, {'uuid': container_id})
94 def _check_image_exist(self, client, t):
95 return any(t in a['RepoTags'][0]
96 for a in client.images() if a['RepoTags'])
98 def _create_influxdb(self, name, port, container_id):
99 client = Client(base_url=consts.DOCKER_URL)
102 LOG.info('Checking if influxdb image exist')
103 if not self._check_image_exist(client, '%s:%s' %
104 (consts.INFLUXDB_IMAGE,
105 consts.INFLUXDB_TAG)):
106 LOG.info('Influxdb image not exist, start pulling')
107 client.pull(consts.INFLUXDB_IMAGE, tag=consts.INFLUXDB_TAG)
109 LOG.info('Createing influxdb container')
110 container = self._create_influxdb_container(client, name, port)
111 LOG.info('Influxdb container is created')
115 container = client.inspect_container(container['Id'])
116 ip = container['NetworkSettings']['Networks']['bridge']['IPAddress']
117 LOG.debug('container ip is: %s', ip)
119 LOG.info('Changing output to influxdb')
120 self._change_output_to_influxdb(ip)
122 LOG.info('Config influxdb')
123 self._config_influxdb()
125 container_handler.update_attr(container_id, {'status': 1})
129 container_handler.update_attr(container_id, {'status': 2})
130 LOG.exception('Creating influxdb failed')
132 def _create_influxdb_container(self, client, name, port):
135 port_bindings = {8086: port}
136 restart_policy = {"MaximumRetryCount": 0, "Name": "always"}
137 host_config = client.create_host_config(port_bindings=port_bindings,
138 restart_policy=restart_policy)
140 LOG.info('Creating container')
141 container = client.create_container(image='%s:%s' %
142 (consts.INFLUXDB_IMAGE,
143 consts.INFLUXDB_TAG),
148 host_config=host_config)
149 LOG.info('Starting container')
150 client.start(container)
153 def _config_influxdb(self):
155 client = influx.get_data_db_client()
156 client.create_user(consts.INFLUXDB_USER,
157 consts.INFLUXDB_PASS,
158 consts.INFLUXDB_DB_NAME)
159 client.create_database(consts.INFLUXDB_DB_NAME)
160 LOG.info('Success to config influxDB')
162 LOG.exception('Config influxdb failed')
164 def _change_output_to_influxdb(self, ip):
165 utils.makedirs(consts.CONF_DIR)
167 parser = configparser.ConfigParser()
168 LOG.info('Reading output sample configuration')
169 parser.read(consts.CONF_SAMPLE_FILE)
171 LOG.info('Set dispatcher to influxdb')
172 parser.set('DEFAULT', 'dispatcher', 'influxdb')
173 parser.set('dispatcher_influxdb', 'target',
174 'http://{}:{}'.format(ip, 8086))
176 LOG.info('Writing to %s', consts.CONF_FILE)
177 with open(consts.CONF_FILE, 'w') as f:
180 def create_grafana(self, args):
182 environment_id = args['environment_id']
184 return result_handler(consts.API_ERROR, 'environment_id must be provided')
187 uuid.UUID(environment_id)
189 return result_handler(consts.API_ERROR, 'invalid environment id')
192 environment = environment_handler.get_by_uuid(environment_id)
194 return result_handler(consts.API_ERROR, 'no such environment id')
196 container_info = environment.container_id
197 container_info = jsonutils.loads(container_info) if container_info else {}
199 if not container_info.get('influxdb'):
200 return result_handler(consts.API_ERROR, 'influxdb not set')
202 if container_info.get('grafana'):
203 return result_handler(consts.API_ERROR, 'grafana container already exists')
205 name = 'grafana-{}'.format(environment_id[:8])
206 port = get_free_port(consts.SERVER_IP)
207 container_id = str(uuid.uuid4())
209 args = (name, port, container_id)
210 thread = threading.Thread(target=self._create_grafana, args=args)
213 container_init_data = {
214 'uuid': container_id,
215 'environment_id': environment_id,
220 container_handler.insert(container_init_data)
222 container_info['grafana'] = container_id
223 environment_info = {'container_id': jsonutils.dumps(container_info)}
224 environment_handler.update_attr(environment_id, environment_info)
226 return result_handler(consts.API_SUCCESS, {'uuid': container_id})
228 def _create_grafana(self, name, port, container_id):
229 client = Client(base_url=consts.DOCKER_URL)
232 LOG.info('Checking if grafana image exist')
233 image = '{}:{}'.format(consts.GRAFANA_IMAGE, consts.GRAFANA_TAG)
234 if not self._check_image_exist(client, image):
235 LOG.info('Grafana image not exist, start pulling')
236 client.pull(consts.GRAFANA_IMAGE, consts.GRAFANA_TAG)
238 LOG.info('Createing grafana container')
239 container = self._create_grafana_container(client, name, port)
240 LOG.info('Grafana container is created')
244 container = client.inspect_container(container['Id'])
245 ip = container['NetworkSettings']['Networks']['bridge']['IPAddress']
246 LOG.debug('container ip is: %s', ip)
248 LOG.info('Creating data source for grafana')
249 self._create_data_source(ip)
251 LOG.info('Creating dashboard for grafana')
252 self._create_dashboard(ip)
254 container_handler.update_attr(container_id, {'status': 1})
257 container_handler.update_attr(container_id, {'status': 2})
258 LOG.exception('Create grafana failed')
260 def _create_dashboard(self, ip):
261 url = 'http://admin:admin@{}:{}/api/dashboards/db'.format(ip, 3000)
262 path = os.path.join(consts.REPOS_DIR, 'dashboard', 'opnfv_yardstick_tc*.json')
264 for i in sorted(glob.iglob(path)):
266 data = jsonutils.load(f)
268 HttpClient().post(url, {'dashboard': data})
270 LOG.exception('Create dashboard %s failed', i)
273 def _create_data_source(self, ip):
274 url = 'http://admin:admin@{}:{}/api/datasources'.format(ip, 3000)
275 influx_conf = utils.parse_ini_file(consts.CONF_FILE).get('dispatcher_influxdb', {})
281 "url": influx_conf.get('target', ''),
282 "password": influx_conf.get('password', ''),
283 "user": influx_conf.get('username', ''),
284 "database": "yardstick",
286 "basicAuthUser": "admin",
287 "basicAuthPassword": "admin",
291 HttpClient().post(url, data)
293 LOG.exception('Create datasources failed')
296 def _create_grafana_container(self, client, name, port):
298 port_bindings = {3000: port}
299 restart_policy = {"MaximumRetryCount": 0, "Name": "always"}
300 host_config = client.create_host_config(port_bindings=port_bindings,
301 restart_policy=restart_policy)
303 LOG.info('Creating container')
304 container = client.create_container(image='%s:%s' %
305 (consts.GRAFANA_IMAGE,
311 host_config=host_config)
312 LOG.info('Starting container')
313 client.start(container)
317 class V2Container(ApiResource):
319 def get(self, container_id):
321 uuid.UUID(container_id)
323 return result_handler(consts.API_ERROR, 'invalid container id')
326 container = container_handler.get_by_uuid(container_id)
328 return result_handler(consts.API_ERROR, 'no such container id')
330 name = container.name
331 client = Client(base_url=consts.DOCKER_URL)
332 info = client.inspect_container(name)
336 'status': info.get('State', {}).get('Status', 'error'),
337 'time': info.get('Created'),
338 'port': container.port
341 return result_handler(consts.API_SUCCESS, {'container': data})
343 def delete(self, container_id):
345 uuid.UUID(container_id)
347 return result_handler(consts.API_ERROR, 'invalid container id')
350 container = container_handler.get_by_uuid(container_id)
352 return result_handler(consts.API_ERROR, 'no such container id')
354 environment_id = container.environment_id
356 client = Client(base_url=consts.DOCKER_URL)
357 LOG.info('delete container: %s', container.name)
359 client.remove_container(container.name, force=True)
361 LOG.exception('delete container failed')
362 return result_handler(consts.API_ERROR, 'delete container failed')
364 LOG.info('delete container in database')
365 container_handler.delete_by_uuid(container_id)
367 LOG.info('update container in environment')
368 environment = environment_handler.get_by_uuid(environment_id)
369 container_info = jsonutils.loads(environment.container_id)
370 key = next((k for k, v in container_info.items() if v == container_id))
371 container_info.pop(key)
372 environment_delete_data = {
373 'container_id': jsonutils.dumps(container_info)
375 environment_handler.update_attr(environment_id, environment_delete_data)
377 return result_handler(consts.API_SUCCESS, {'container': container_id})