diff options
Diffstat (limited to 'api')
-rw-r--r-- | api/__init__.py | 0 | ||||
-rw-r--r-- | api/actions/__init__.py | 0 | ||||
-rw-r--r-- | api/actions/env.py | 258 | ||||
-rw-r--r-- | api/actions/result.py | 63 | ||||
-rw-r--r-- | api/actions/samples.py | 37 | ||||
-rw-r--r-- | api/actions/test.py | 38 | ||||
-rwxr-xr-x | api/api-prepare.sh | 49 | ||||
-rw-r--r-- | api/conf.py | 27 | ||||
-rw-r--r-- | api/server.py | 34 | ||||
-rw-r--r-- | api/swagger/__init__.py | 0 | ||||
-rw-r--r-- | api/swagger/docs/results.yaml | 41 | ||||
-rw-r--r-- | api/swagger/docs/testcases.yaml | 50 | ||||
-rw-r--r-- | api/swagger/models.py | 51 | ||||
-rw-r--r-- | api/urls.py | 18 | ||||
-rw-r--r-- | api/utils/__init__.py | 0 | ||||
-rw-r--r-- | api/utils/common.py | 71 | ||||
-rw-r--r-- | api/utils/daemonthread.py | 44 | ||||
-rw-r--r-- | api/utils/influx.py | 73 | ||||
-rw-r--r-- | api/views.py | 82 | ||||
-rw-r--r-- | api/yardstick.ini | 16 | ||||
-rw-r--r-- | api/yardstick.sock | 0 |
21 files changed, 952 insertions, 0 deletions
diff --git a/api/__init__.py b/api/__init__.py new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/api/__init__.py diff --git a/api/actions/__init__.py b/api/actions/__init__.py new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/api/actions/__init__.py diff --git a/api/actions/env.py b/api/actions/env.py new file mode 100644 index 000000000..78f9b72ed --- /dev/null +++ b/api/actions/env.py @@ -0,0 +1,258 @@ +############################################################################## +# Copyright (c) 2016 Huawei Technologies Co.,Ltd and others. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +############################################################################## +import logging +import threading +import subprocess +import time +import json +import os +import errno + +from docker import Client + +from yardstick.common import constants as config +from yardstick.common import utils as yardstick_utils +from yardstick.common.httpClient import HttpClient +from api import conf as api_conf +from api.utils import influx +from api.utils.common import result_handler + +logger = logging.getLogger(__name__) + + +def createGrafanaContainer(args): + thread = threading.Thread(target=_create_grafana) + thread.start() + return result_handler('success', []) + + +def _create_grafana(): + client = Client(base_url=config.DOCKER_URL) + + try: + if not _check_image_exist(client, '%s:%s' % (config.GRAFANA_IMAGE, + config.GRAFANA_TAGS)): + client.pull(config.GRAFANA_IMAGE, config.GRAFANA_TAGS) + + _create_grafana_container(client) + + time.sleep(5) + + _create_data_source() + + _create_dashboard() + except Exception as e: + logger.debug('Error: %s', e) + + +def _create_dashboard(): + url = 'http://admin:admin@%s:3000/api/dashboards/db' % api_conf.GATEWAY_IP + data = json.load(file('../dashboard/ping_dashboard.json')) + HttpClient().post(url, data) + + +def _create_data_source(): + url = 'http://admin:admin@%s:3000/api/datasources' % api_conf.GATEWAY_IP + data = { + "name": "yardstick", + "type": "influxdb", + "access": "proxy", + "url": "http://%s:8086" % api_conf.GATEWAY_IP, + "password": "root", + "user": "root", + "database": "yardstick", + "basicAuth": True, + "basicAuthUser": "admin", + "basicAuthPassword": "admin", + "isDefault": False, + } + HttpClient().post(url, data) + + +def _create_grafana_container(client): + ports = [3000] + port_bindings = {k: k for k in ports} + host_config = client.create_host_config(port_bindings=port_bindings) + + container = client.create_container(image='%s:%s' % (config.GRAFANA_IMAGE, + config.GRAFANA_TAGS), + ports=ports, + detach=True, + tty=True, + host_config=host_config) + client.start(container) + + +def _check_image_exist(client, t): + return any(t in a['RepoTags'][0] for a in client.images() if a['RepoTags']) + + +def createInfluxDBContainer(args): + thread = threading.Thread(target=_create_influxdb) + thread.start() + return result_handler('success', []) + + +def _create_influxdb(): + client = Client(base_url=config.DOCKER_URL) + + try: + _config_output_file() + + if not _check_image_exist(client, '%s:%s' % (config.INFLUXDB_IMAGE, + config.INFLUXDB_TAG)): + client.pull(config.INFLUXDB_IMAGE, tag=config.INFLUXDB_TAG) + + _create_influxdb_container(client) + + time.sleep(5) + + _config_influxdb() + except Exception as e: + logger.debug('Error: %s', e) + + +def _create_influxdb_container(client): + + ports = [8083, 8086] + port_bindings = {k: k for k in ports} + host_config = client.create_host_config(port_bindings=port_bindings) + + container = client.create_container(image='%s:%s' % (config.INFLUXDB_IMAGE, + config.INFLUXDB_TAG), + ports=ports, + detach=True, + tty=True, + host_config=host_config) + client.start(container) + + +def _config_influxdb(): + try: + client = influx.get_data_db_client() + client.create_user(config.USER, config.PASSWORD, config.DATABASE) + client.create_database(config.DATABASE) + logger.info('Success to config influxDB') + except Exception as e: + logger.debug('Failed to config influxDB: %s', e) + + +def _config_output_file(): + yardstick_utils.makedirs(config.YARDSTICK_CONFIG_DIR) + with open(config.YARDSTICK_CONFIG_FILE, 'w') as f: + f.write("""\ +[DEFAULT] +debug = False +dispatcher = influxdb + +[dispatcher_file] +file_path = /tmp/yardstick.out + +[dispatcher_http] +timeout = 5 +# target = http://127.0.0.1:8000/results + +[dispatcher_influxdb] +timeout = 5 +target = http://%s:8086 +db_name = yardstick +username = root +password = root +""" + % api_conf.GATEWAY_IP) + + +def prepareYardstickEnv(args): + thread = threading.Thread(target=_prepare_env_daemon) + thread.start() + return result_handler('success', []) + + +def _prepare_env_daemon(): + + installer_ip = os.environ.get('INSTALLER_IP', 'undefined') + installer_type = os.environ.get('INSTALLER_TYPE', 'undefined') + + _check_variables(installer_ip, installer_type) + + _create_directories() + + rc_file = config.OPENSTACK_RC_FILE + + _get_remote_rc_file(rc_file, installer_ip, installer_type) + + _source_file(rc_file) + + _append_external_network(rc_file) + + # update the external_network + _source_file(rc_file) + + _load_images() + + +def _check_variables(installer_ip, installer_type): + + if installer_ip == 'undefined': + raise SystemExit('Missing INSTALLER_IP') + + if installer_type == 'undefined': + raise SystemExit('Missing INSTALLER_TYPE') + elif installer_type not in config.INSTALLERS: + raise SystemExit('INSTALLER_TYPE is not correct') + + +def _create_directories(): + yardstick_utils.makedirs(config.YARDSTICK_CONFIG_DIR) + + +def _source_file(rc_file): + yardstick_utils.source_env(rc_file) + + +def _get_remote_rc_file(rc_file, installer_ip, installer_type): + + os_fetch_script = os.path.join(config.RELENG_DIR, config.OS_FETCH_SCRIPT) + + try: + cmd = [os_fetch_script, '-d', rc_file, '-i', installer_type, + '-a', installer_ip] + p = subprocess.Popen(cmd, stdout=subprocess.PIPE) + p.communicate()[0] + + if p.returncode != 0: + logger.debug('Failed to fetch credentials from installer') + except OSError as e: + if e.errno != errno.EEXIST: + raise + + +def _append_external_network(rc_file): + neutron_client = yardstick_utils.get_neutron_client() + networks = neutron_client.list_networks()['networks'] + try: + ext_network = next(n['name'] for n in networks if n['router:external']) + except StopIteration: + logger.warning("Can't find external network") + else: + cmd = 'export EXTERNAL_NETWORK=%s' % ext_network + try: + with open(rc_file, 'a') as f: + f.write(cmd + '\n') + except OSError as e: + if e.errno != errno.EEXIST: + raise + + +def _load_images(): + cmd = [config.LOAD_IMAGES_SCRIPT] + p = subprocess.Popen(cmd, stdout=subprocess.PIPE, + cwd=config.YARDSTICK_REPOS_DIR) + output = p.communicate()[0] + logger.debug('The result is: %s', output) diff --git a/api/actions/result.py b/api/actions/result.py new file mode 100644 index 000000000..1f200fbcc --- /dev/null +++ b/api/actions/result.py @@ -0,0 +1,63 @@ +############################################################################## +# Copyright (c) 2016 Huawei Technologies Co.,Ltd and others. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +############################################################################## +import logging +import uuid +import re + +from api.utils import influx as influx_utils +from api.utils import common as common_utils +from api import conf + +logger = logging.getLogger(__name__) + + +def getResult(args): + try: + measurement = args['measurement'] + task_id = args['task_id'] + + if re.search("[^a-zA-Z0-9_-]", measurement): + raise ValueError('invalid measurement parameter') + + uuid.UUID(task_id) + except KeyError: + message = 'measurement and task_id must be provided' + return common_utils.error_handler(message) + + query_template = "select * from %s where task_id='%s'" + query_sql = query_template % ('tasklist', task_id) + data = common_utils.translate_to_str(influx_utils.query(query_sql)) + + def _unfinished(): + return common_utils.result_handler(0, []) + + def _finished(): + query_sql = query_template % (conf.TEST_CASE_PRE + measurement, + task_id) + data = common_utils.translate_to_str(influx_utils.query(query_sql)) + if not data: + query_sql = query_template % (measurement, task_id) + data = common_utils.translate_to_str(influx_utils.query(query_sql)) + + return common_utils.result_handler(1, data) + + def _error(): + return common_utils.result_handler(2, data[0]['error']) + + try: + status = data[0]['status'] + + switcher = { + 0: _unfinished, + 1: _finished, + 2: _error + } + return switcher.get(status, lambda: 'nothing')() + except IndexError: + return common_utils.error_handler('no such task') diff --git a/api/actions/samples.py b/api/actions/samples.py new file mode 100644 index 000000000..545447aec --- /dev/null +++ b/api/actions/samples.py @@ -0,0 +1,37 @@ +############################################################################## +# Copyright (c) 2016 Huawei Technologies Co.,Ltd and others. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +############################################################################## +import uuid +import os +import logging + +from api import conf +from api.utils import common as common_utils + +logger = logging.getLogger(__name__) + + +def runTestCase(args): + try: + opts = args.get('opts', {}) + testcase = args['testcase'] + except KeyError: + return common_utils.error_handler('Lack of testcase argument') + + testcase = os.path.join(conf.SAMPLE_PATH, testcase + '.yaml') + + task_id = str(uuid.uuid4()) + + command_list = ['task', 'start'] + command_list = common_utils.get_command_list(command_list, opts, testcase) + logger.debug('The command_list is: %s', command_list) + + logger.debug('Start to execute command list') + common_utils.exec_command_task(command_list, task_id) + + return common_utils.result_handler('success', task_id) diff --git a/api/actions/test.py b/api/actions/test.py new file mode 100644 index 000000000..fda0ffd32 --- /dev/null +++ b/api/actions/test.py @@ -0,0 +1,38 @@ +############################################################################## +# Copyright (c) 2016 Huawei Technologies Co.,Ltd and others. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +############################################################################## +import uuid +import os +import logging + +from api import conf +from api.utils import common as common_utils + +logger = logging.getLogger(__name__) + + +def runTestCase(args): + try: + opts = args.get('opts', {}) + testcase = args['testcase'] + except KeyError: + return common_utils.error_handler('Lack of testcase argument') + + testcase = os.path.join(conf.TEST_CASE_PATH, + conf.TEST_CASE_PRE + testcase + '.yaml') + + task_id = str(uuid.uuid4()) + + command_list = ['task', 'start'] + command_list = common_utils.get_command_list(command_list, opts, testcase) + logger.debug('The command_list is: %s', command_list) + + logger.debug('Start to execute command list') + common_utils.exec_command_task(command_list, task_id) + + return common_utils.result_handler('success', task_id) diff --git a/api/api-prepare.sh b/api/api-prepare.sh new file mode 100755 index 000000000..fade8ccc6 --- /dev/null +++ b/api/api-prepare.sh @@ -0,0 +1,49 @@ +#!/bin/bash +############################################################################## +# Copyright (c) 2016 Huawei Technologies Co.,Ltd and others. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +############################################################################## + +# nginx config +nginx_config='/etc/nginx/conf.d/yardstick.conf' + +if [[ ! -e "${nginx_config}" ]];then + + cat << EOF > "${nginx_config}" +server { + listen 5000; + server_name localhost; + index index.htm index.html; + location / { + include uwsgi_params; + uwsgi_pass unix:///home/opnfv/repos/yardstick/api/yardstick.sock; + } +} +EOF +echo "daemon off;" >> /etc/nginx/nginx.conf +fi + +# nginx service start when boot +supervisor_config='/etc/supervisor/conf.d/yardstick.conf' + +if [[ ! -e "${supervisor_config}" ]];then + cat << EOF > "${supervisor_config}" +[supervisord] +nodaemon = true + +[program:yardstick_nginx] +user = root +command = service nginx restart +autorestart = true + +[program:yardstick_uwsgi] +user = root +directory = /home/opnfv/repos/yardstick/api +command = uwsgi -i yardstick.ini +autorestart = true +EOF +fi diff --git a/api/conf.py b/api/conf.py new file mode 100644 index 000000000..df44042b1 --- /dev/null +++ b/api/conf.py @@ -0,0 +1,27 @@ +############################################################################## +# Copyright (c) 2016 Huawei Technologies Co.,Ltd and others. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +############################################################################## +from pyroute2 import IPDB + + +# configuration for influxdb +with IPDB() as ip: + GATEWAY_IP = ip.routes['default'].gateway +PORT = 8086 + +TEST_ACTION = ['runTestCase'] + +TEST_CASE_PATH = '../tests/opnfv/test_cases/' + +SAMPLE_PATH = '../samples/' + +TEST_CASE_PRE = 'opnfv_yardstick_' + +TEST_SUITE_PATH = '../tests/opnfv/test_suites/' + +OUTPUT_CONFIG_FILE_PATH = '/etc/yardstick/yardstick.conf' diff --git a/api/server.py b/api/server.py new file mode 100644 index 000000000..64a2b4f96 --- /dev/null +++ b/api/server.py @@ -0,0 +1,34 @@ +############################################################################## +# Copyright (c) 2016 Huawei Technologies Co.,Ltd and others. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +############################################################################## +import logging + +from flask import Flask +from flask_restful import Api +from flasgger import Swagger + +from api.urls import urlpatterns +from yardstick import _init_logging + +logger = logging.getLogger(__name__) + +app = Flask(__name__) + +Swagger(app) + +api = Api(app) + + +reduce(lambda a, b: a.add_resource(b.resource, b.url, + endpoint=b.endpoint) or a, urlpatterns, api) + +if __name__ == '__main__': + _init_logging() + logger.setLevel(logging.DEBUG) + logger.info('Starting server') + app.run(host='0.0.0.0') diff --git a/api/swagger/__init__.py b/api/swagger/__init__.py new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/api/swagger/__init__.py diff --git a/api/swagger/docs/results.yaml b/api/swagger/docs/results.yaml new file mode 100644 index 000000000..7bdab3eb6 --- /dev/null +++ b/api/swagger/docs/results.yaml @@ -0,0 +1,41 @@ +Query task result data + +This api offer the interface to get the result data via task_id +We will return a result json dict +--- +tags: + - Results +parameters: + - + in: query + name: action + type: string + default: getResult + required: true + - + in: query + name: measurement + type: string + description: test case name + required: true + - + in: query + name: task_id + type: string + description: the task_id you get before + required: true +responses: + 200: + description: a result json dict + schema: + id: ResultModel + properties: + status: + type: string + description: the status of the certain task + default: success + result: + schema: + type: array + items: + type: object diff --git a/api/swagger/docs/testcases.yaml b/api/swagger/docs/testcases.yaml new file mode 100644 index 000000000..7bfe5e647 --- /dev/null +++ b/api/swagger/docs/testcases.yaml @@ -0,0 +1,50 @@ +TestCases Actions
+
+This API may offer many actions, including runTestCase
+
+action: runTestCase
+This api offer the interface to run a test case in yardstick
+we will return a task_id for querying
+you can use the returned task_id to get the result data
+---
+tags:
+ - Release Action
+parameters:
+ - in: body
+ name: body
+ description: this is the input json dict
+ schema:
+ id: TestCaseActionModel
+ required:
+ - action
+ - args
+ properties:
+ action:
+ type: string
+ description: this is action for testcases
+ default: runTestCase
+ args:
+ schema:
+ id: TestCaseActionArgsModel
+ required:
+ - testcase
+ properties:
+ testcase:
+ type: string
+ description: this is the test case name
+ default: tc002
+ opts:
+ schema:
+ id: TestCaseActionArgsOptsModel
+responses:
+ 200:
+ description: A result json dict
+ schema:
+ id: result
+ properties:
+ status:
+ type: string
+ default: success
+ result:
+ type: string
+ description: task_id of this task
diff --git a/api/swagger/models.py b/api/swagger/models.py new file mode 100644 index 000000000..7c65fbbf5 --- /dev/null +++ b/api/swagger/models.py @@ -0,0 +1,51 @@ +############################################################################## +# Copyright (c) 2016 Huawei Technologies Co.,Ltd and others. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +############################################################################## +from flask_restful import fields +from flask_restful_swagger import swagger + + +# for testcases/action runTestCase action +@swagger.model +class TestCaseActionArgsOptsTaskArgModel: + resource_fields = { + } + + +@swagger.model +class TestCaseActionArgsOptsModel: + resource_fields = { + 'task-args': TestCaseActionArgsOptsTaskArgModel, + 'keep-deploy': fields.String, + 'suite': fields.String + } + + +@swagger.model +class TestCaseActionArgsModel: + resource_fields = { + 'testcase': fields.String, + 'opts': TestCaseActionArgsOptsModel + } + + +@swagger.model +class TestCaseActionModel: + resource_fields = { + 'action': fields.String, + 'args': TestCaseActionArgsModel + } + + +# for results +@swagger.model +class ResultModel: + resource_fields = { + 'status': fields.String, + 'result': fields.List + } diff --git a/api/urls.py b/api/urls.py new file mode 100644 index 000000000..50be91ead --- /dev/null +++ b/api/urls.py @@ -0,0 +1,18 @@ +############################################################################## +# Copyright (c) 2016 Huawei Technologies Co.,Ltd and others. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +############################################################################## +from api import views +from api.utils.common import Url + + +urlpatterns = [ + Url('/yardstick/testcases/release/action', views.Release, 'release'), + Url('/yardstick/testcases/samples/action', views.Samples, 'samples'), + Url('/yardstick/results', views.Results, 'results'), + Url('/yardstick/env/action', views.Env, 'env') +] diff --git a/api/utils/__init__.py b/api/utils/__init__.py new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/api/utils/__init__.py diff --git a/api/utils/common.py b/api/utils/common.py new file mode 100644 index 000000000..e3e64a72b --- /dev/null +++ b/api/utils/common.py @@ -0,0 +1,71 @@ +############################################################################## +# Copyright (c) 2016 Huawei Technologies Co.,Ltd and others. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +############################################################################## +import collections +import logging + +from flask import jsonify + +from api.utils.daemonthread import DaemonThread +from yardstick.cmd.cli import YardstickCLI + +logger = logging.getLogger(__name__) + + +def translate_to_str(object): + if isinstance(object, collections.Mapping): + return {str(k): translate_to_str(v) for k, v in object.items()} + elif isinstance(object, list): + return [translate_to_str(ele) for ele in object] + elif isinstance(object, unicode): + return str(object) + return object + + +def get_command_list(command_list, opts, args): + + command_list.append(args) + + command_list.extend(('--{}'.format(k) for k in opts if 'task-args' != k)) + + task_args = opts.get('task-args', '') + if task_args: + command_list.extend(['--task-args', str(task_args)]) + + return command_list + + +def exec_command_task(command_list, task_id): # pragma: no cover + daemonthread = DaemonThread(YardstickCLI().api, (command_list, task_id)) + daemonthread.start() + + +def error_handler(message): + logger.debug(message) + result = { + 'status': 'error', + 'message': message + } + return jsonify(result) + + +def result_handler(status, data): + result = { + 'status': status, + 'result': data + } + return jsonify(result) + + +class Url(object): + + def __init__(self, url, resource, endpoint): + super(Url, self).__init__() + self.url = url + self.resource = resource + self.endpoint = endpoint diff --git a/api/utils/daemonthread.py b/api/utils/daemonthread.py new file mode 100644 index 000000000..47c0b9108 --- /dev/null +++ b/api/utils/daemonthread.py @@ -0,0 +1,44 @@ +############################################################################## +# Copyright (c) 2016 Huawei Technologies Co.,Ltd and others. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +############################################################################## +import threading +import os +import datetime +import errno + +from api import conf +from api.utils.influx import write_data_tasklist + + +class DaemonThread(threading.Thread): + + def __init__(self, method, args): + super(DaemonThread, self).__init__(target=method, args=args) + self.method = method + self.command_list = args[0] + self.task_id = args[1] + + def run(self): + timestamp = datetime.datetime.now() + + try: + write_data_tasklist(self.task_id, timestamp, 0) + self.method(self.command_list, self.task_id) + write_data_tasklist(self.task_id, timestamp, 1) + except Exception as e: + write_data_tasklist(self.task_id, timestamp, 2, error=str(e)) + finally: + _handle_testsuite_file(self.task_id) + + +def _handle_testsuite_file(task_id): + try: + os.remove(os.path.join(conf.TEST_SUITE_PATH, task_id + '.yaml')) + except OSError as e: + if e.errno != errno.ENOENT: + raise diff --git a/api/utils/influx.py b/api/utils/influx.py new file mode 100644 index 000000000..9366ed3e9 --- /dev/null +++ b/api/utils/influx.py @@ -0,0 +1,73 @@ +############################################################################## +# Copyright (c) 2016 Huawei Technologies Co.,Ltd and others. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +############################################################################## +import logging +from urlparse import urlsplit + +from influxdb import InfluxDBClient +import ConfigParser + +from api import conf + +logger = logging.getLogger(__name__) + + +def get_data_db_client(): + parser = ConfigParser.ConfigParser() + try: + parser.read(conf.OUTPUT_CONFIG_FILE_PATH) + dispatcher = parser.get('DEFAULT', 'dispatcher') + + if 'influxdb' != dispatcher: + raise RuntimeError + + ip = _get_ip(parser.get('dispatcher_influxdb', 'target')) + username = parser.get('dispatcher_influxdb', 'username') + password = parser.get('dispatcher_influxdb', 'password') + db_name = parser.get('dispatcher_influxdb', 'db_name') + return InfluxDBClient(ip, conf.PORT, username, password, db_name) + except ConfigParser.NoOptionError: + logger.error('can not find the key') + raise + + +def _get_ip(url): + return urlsplit(url).hostname + + +def _write_data(measurement, field, timestamp, tags): + point = { + 'measurement': measurement, + 'fields': field, + 'time': timestamp, + 'tags': tags + } + + try: + client = get_data_db_client() + + logger.debug('Start to write data: %s', point) + client.write_points([point]) + except RuntimeError: + logger.debug('dispatcher is not influxdb') + + +def write_data_tasklist(task_id, timestamp, status, error=''): + field = {'status': status, 'error': error} + tags = {'task_id': task_id} + _write_data('tasklist', field, timestamp, tags) + + +def query(query_sql): + try: + client = get_data_db_client() + logger.debug('Start to query: %s', query_sql) + return list(client.query(query_sql).get_points()) + except RuntimeError: + logger.error('dispatcher is not influxdb') + raise diff --git a/api/views.py b/api/views.py new file mode 100644 index 000000000..928d8e9eb --- /dev/null +++ b/api/views.py @@ -0,0 +1,82 @@ +############################################################################## +# Copyright (c) 2016 Huawei Technologies Co.,Ltd and others. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +############################################################################## +import logging +import os + +from flask import request +from flask_restful import Resource +from flasgger.utils import swag_from + +from api.utils import common as common_utils +from api.swagger import models +from api.actions import test as test_action +from api.actions import samples as samples_action +from api.actions import result as result_action +from api.actions import env as env_action + +logger = logging.getLogger(__name__) + + +TestCaseActionModel = models.TestCaseActionModel +TestCaseActionArgsModel = models.TestCaseActionArgsModel +TestCaseActionArgsOptsModel = models.TestCaseActionArgsOptsModel +TestCaseActionArgsOptsTaskArgModel = models.TestCaseActionArgsOptsTaskArgModel + + +class Release(Resource): + @swag_from(os.getcwd() + '/swagger/docs/testcases.yaml') + def post(self): + action = common_utils.translate_to_str(request.json.get('action', '')) + args = common_utils.translate_to_str(request.json.get('args', {})) + logger.debug('Input args is: action: %s, args: %s', action, args) + + try: + return getattr(test_action, action)(args) + except AttributeError: + return common_utils.error_handler('Wrong action') + + +class Samples(Resource): + def post(self): + action = common_utils.translate_to_str(request.json.get('action', '')) + args = common_utils.translate_to_str(request.json.get('args', {})) + logger.debug('Input args is: action: %s, args: %s', action, args) + + try: + return getattr(samples_action, action)(args) + except AttributeError: + return common_utils.error_handler('Wrong action') + + +ResultModel = models.ResultModel + + +class Results(Resource): + @swag_from(os.getcwd() + '/swagger/docs/results.yaml') + def get(self): + args = common_utils.translate_to_str(request.args) + action = args.get('action', '') + logger.debug('Input args is: action: %s, args: %s', action, args) + + try: + return getattr(result_action, action)(args) + except AttributeError: + return common_utils.error_handler('Wrong action') + + +class Env(Resource): + def post(self): + action = common_utils.translate_to_str(request.json.get('action', '')) + args = common_utils.translate_to_str(request.json.get('args', {})) + logger.debug('Input args is: action: %s, args: %s', action, args) + + try: + return getattr(env_action, action)(args) + except AttributeError: + return common_utils.error_handler('Wrong action') diff --git a/api/yardstick.ini b/api/yardstick.ini new file mode 100644 index 000000000..01025c2ef --- /dev/null +++ b/api/yardstick.ini @@ -0,0 +1,16 @@ +[uwsgi] +master = true +debug = true +chdir = /home/opnfv/repos/yardstick/api +module = server +plugins = python +processes = 10 +threads = 5 +async = true +max-requests = 5000 +chmod-socket = 666 +callable = app +enable-threads = true +close-on-exec = 1 +daemonize=/home/opnfv/repos/yardstick/api/uwsgi.log +socket = /home/opnfv/repos/yardstick/api/yardstick.sock diff --git a/api/yardstick.sock b/api/yardstick.sock new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/api/yardstick.sock |