Merge "Log each test case status in a task"
[yardstick.git] / api / resources / v2 / tasks.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 import uuid
10 import logging
11 import os
12 import errno
13 from datetime import datetime
14
15 from oslo_serialization import jsonutils
16
17 from api import ApiResource
18 from api.database.v2.handlers import V2TaskHandler
19 from api.database.v2.handlers import V2ProjectHandler
20 from api.database.v2.handlers import V2EnvironmentHandler
21 from api.utils.thread import TaskThread
22 from yardstick.common.utils import result_handler
23 from yardstick.common.utils import change_obj_to_dict
24 from yardstick.common import constants as consts
25 from yardstick.benchmark.core.task import Task
26 from yardstick.benchmark.core import Param
27
28 LOG = logging.getLogger(__name__)
29 LOG.setLevel(logging.DEBUG)
30
31
32 class V2Tasks(ApiResource):
33
34     def get(self):
35         task_handler = V2TaskHandler()
36         tasks = [change_obj_to_dict(t) for t in task_handler.list_all()]
37
38         for t in tasks:
39             result = t['result']
40             t['result'] = jsonutils.loads(result) if result else None
41
42         return result_handler(consts.API_SUCCESS, {'tasks': tasks})
43
44     def post(self):
45         return self._dispatch_post()
46
47     def create_task(self, args):
48         try:
49             name = args['name']
50         except KeyError:
51             return result_handler(consts.API_ERROR, 'name must be provided')
52
53         try:
54             project_id = args['project_id']
55         except KeyError:
56             return result_handler(consts.API_ERROR, 'project_id must be provided')
57
58         task_id = str(uuid.uuid4())
59         create_time = datetime.now()
60         task_handler = V2TaskHandler()
61
62         LOG.info('create task in database')
63         task_init_data = {
64             'uuid': task_id,
65             'project_id': project_id,
66             'name': name,
67             'time': create_time,
68             'status': -1
69         }
70         task_handler.insert(task_init_data)
71
72         LOG.info('create task in project')
73         project_handler = V2ProjectHandler()
74         project_handler.append_attr(project_id, {'tasks': task_id})
75
76         return result_handler(consts.API_SUCCESS, {'uuid': task_id})
77
78
79 class V2Task(ApiResource):
80
81     def get(self, task_id):
82         try:
83             uuid.UUID(task_id)
84         except ValueError:
85             return result_handler(consts.API_ERROR, 'invalid task id')
86
87         task_handler = V2TaskHandler()
88         try:
89             task = task_handler.get_by_uuid(task_id)
90         except ValueError:
91             return result_handler(consts.API_ERROR, 'no such task id')
92
93         task_info = change_obj_to_dict(task)
94         result = task_info['result']
95         task_info['result'] = jsonutils.loads(result) if result else None
96
97         return result_handler(consts.API_SUCCESS, {'task': task_info})
98
99     def delete(self, task_id):
100         try:
101             uuid.UUID(task_id)
102         except ValueError:
103             return result_handler(consts.API_ERROR, 'invalid task id')
104
105         task_handler = V2TaskHandler()
106         try:
107             project_id = task_handler.get_by_uuid(task_id).project_id
108         except ValueError:
109             return result_handler(consts.API_ERROR, 'no such task id')
110
111         LOG.info('delete task in database')
112         task_handler.delete_by_uuid(task_id)
113
114         project_handler = V2ProjectHandler()
115         project = project_handler.get_by_uuid(project_id)
116
117         if project.tasks:
118             LOG.info('update tasks in project')
119             new_task_list = project.tasks.split(',')
120             new_task_list.remove(task_id)
121             if new_task_list:
122                 new_tasks = ','.join(new_task_list)
123             else:
124                 new_tasks = None
125             project_handler.update_attr(project_id, {'tasks': new_tasks})
126
127         return result_handler(consts.API_SUCCESS, {'task': task_id})
128
129     def put(self, task_id):
130
131         try:
132             uuid.UUID(task_id)
133         except ValueError:
134             return result_handler(consts.API_ERROR, 'invalid task id')
135
136         task_handler = V2TaskHandler()
137         try:
138             task_handler.get_by_uuid(task_id)
139         except ValueError:
140             return result_handler(consts.API_ERROR, 'no such task id')
141
142         return self._dispatch_post(task_id=task_id)
143
144     def add_environment(self, args):
145
146         task_id = args['task_id']
147         try:
148             environment_id = args['environment_id']
149         except KeyError:
150             return result_handler(consts.API_ERROR, 'environment_id must be provided')
151
152         try:
153             uuid.UUID(environment_id)
154         except ValueError:
155             return result_handler(consts.API_ERROR, 'invalid environment id')
156
157         environment_handler = V2EnvironmentHandler()
158         try:
159             environment_handler.get_by_uuid(environment_id)
160         except ValueError:
161             return result_handler(consts.API_ERROR, 'no such environment id')
162
163         LOG.info('update environment_id in task')
164         task_handler = V2TaskHandler()
165         task_handler.update_attr(task_id, {'environment_id': environment_id})
166
167         return result_handler(consts.API_SUCCESS, {'uuid': task_id})
168
169     def add_case(self, args):
170         task_id = args['task_id']
171         try:
172             name = args['case_name']
173         except KeyError:
174             return result_handler(consts.API_ERROR, 'case_name must be provided')
175
176         try:
177             content = args['case_content']
178         except KeyError:
179             return result_handler(consts.API_ERROR, 'case_content must be provided')
180
181         LOG.info('update case info in task')
182         task_handler = V2TaskHandler()
183         task_update_data = {
184             'case_name': name,
185             'content': content,
186             'suite': False
187         }
188         task_handler.update_attr(task_id, task_update_data)
189
190         return result_handler(consts.API_SUCCESS, {'uuid': task_id})
191
192     def add_suite(self, args):
193         task_id = args['task_id']
194         try:
195             name = args['suite_name']
196         except KeyError:
197             return result_handler(consts.API_ERROR, 'suite_name must be provided')
198
199         try:
200             content = args['suite_content']
201         except KeyError:
202             return result_handler(consts.API_ERROR, 'suite_content must be provided')
203
204         LOG.info('update suite info in task')
205         task_handler = V2TaskHandler()
206         task_update_data = {
207             'case_name': name,
208             'content': content,
209             'suite': True
210         }
211         task_handler.update_attr(task_id, task_update_data)
212
213         return result_handler(consts.API_SUCCESS, {'uuid': task_id})
214
215     def run(self, args):
216         try:
217             task_id = args['task_id']
218         except KeyError:
219             return result_handler(consts.API_ERROR, 'task_id must be provided')
220
221         try:
222             uuid.UUID(task_id)
223         except ValueError:
224             return result_handler(consts.API_ERROR, 'invalid task id')
225
226         task_handler = V2TaskHandler()
227         try:
228             task = task_handler.get_by_uuid(task_id)
229         except ValueError:
230             return result_handler(consts.API_ERROR, 'no such task id')
231
232         if not task.environment_id:
233             return result_handler(consts.API_ERROR, 'environment not set')
234
235         if not task.case_name or not task.content:
236             return result_handler(consts.API_ERROR, 'case not set')
237
238         if task.status == 0:
239             return result_handler(consts.API_ERROR, 'task is already running')
240
241         with open('/tmp/{}.yaml'.format(task.case_name), 'w') as f:
242             f.write(task.content)
243
244         data = {
245             'inputfile': ['/tmp/{}.yaml'.format(task.case_name)],
246             'task_id': task_id
247         }
248         if task.suite:
249             data.update({'suite': True})
250
251         LOG.info('start task thread')
252         param = Param(data)
253         task_thread = TaskThread(Task().start, param, task_handler)
254         task_thread.start()
255
256         return result_handler(consts.API_SUCCESS, {'uuid': task_id})
257
258
259 class V2TaskLog(ApiResource):
260
261     def get(self, task_id):
262         try:
263             uuid.UUID(task_id)
264         except ValueError:
265             return result_handler(consts.API_ERROR, 'invalid task id')
266
267         task_handler = V2TaskHandler()
268         try:
269             task = task_handler.get_by_uuid(task_id)
270         except ValueError:
271             return result_handler(consts.API_ERROR, 'no such task id')
272
273         index = int(self._get_args().get('index', 0))
274
275         try:
276             with open(os.path.join(consts.TASK_LOG_DIR, '{}.log'.format(task_id))) as f:
277                 f.seek(index)
278                 data = f.readlines()
279                 index = f.tell()
280         except OSError as e:
281             if e.errno == errno.ENOENT:
282                 return result_handler(consts.API_ERROR, 'log file does not exist')
283             return result_handler(consts.API_ERROR, 'error with log file')
284
285         return_data = {
286             'index': index,
287             'data': data
288         }
289
290         return result_handler(task.status, return_data)