def get(self, request, import_queue=None): # pylint: disable=too-many-return-statements task_id = request.GET.get('task') result_format = request.GET.get('result') username = request.GET.get('username') user = self.request.user if task_id: parsed_task = parse_bulk_import_task_id(task_id) username = parsed_task['username'] if not user.is_staff and user.username != username: return Response(status=status.HTTP_403_FORBIDDEN) task = AsyncResult(task_id) if task.successful(): result = task.get() if result_format == 'json': response = Response(result.json, content_type="application/json") response['Content-Encoding'] = 'gzip' return response if result_format == 'report': return Response(result.report) return Response(result.detailed_summary) if task.failed(): return Response(dict(exception=str(task.result)), status=status.HTTP_400_BAD_REQUEST) if task.state == 'PENDING' and not task_exists(task_id): return Response(dict(exception='task ' + task_id + ' not found'), status=status.HTTP_404_NOT_FOUND) return Response(dict(task=task.id, state=task.state, username=username, queue=parsed_task['queue']), status=status.HTTP_202_ACCEPTED) flower_tasks = flower_get('api/tasks').json() tasks = [] for task_id, value in flower_tasks.items(): if not value['name'].startswith('tasks.bulk_import'): continue task = parse_bulk_import_task_id(task_id) if user.is_staff or user.username == task['username']: if (not import_queue or task['queue'] == import_queue) and \ (not username or task['username'] == username): tasks.append( dict(task=task_id, state=value['state'], queue=task['queue'], username=task['username'])) return Response(tasks)
def test_parse_bulk_import_task_id(self): task_uuid = str(uuid.uuid4()) task_id = "{}-{}~{}".format(task_uuid, 'username', 'queue') self.assertEqual( parse_bulk_import_task_id(task_id), dict(uuid=task_uuid + '-', username='******', queue='queue')) task_id = "{}-{}".format(task_uuid, 'username') self.assertEqual( parse_bulk_import_task_id(task_id), dict(uuid=task_uuid + '-', username='******', queue='default'))
def import_response(request, import_queue, data, threads=None, inline=False): if not data: return Response(dict(exception=NO_CONTENT_TO_IMPORT), status=status.HTTP_400_BAD_REQUEST) user = request.user username = user.username update_if_exists = request.GET.get('update_if_exists', 'true') if update_if_exists not in ['true', 'false']: return Response(dict(exception=INVALID_UPDATE_IF_EXISTS), status=status.HTTP_400_BAD_REQUEST) update_if_exists = update_if_exists == 'true' data = data.decode('utf-8') if isinstance(data, bytes) else data try: task = queue_bulk_import(data, import_queue, username, update_if_exists, threads, inline) except AlreadyQueued: return Response(dict(exception=ALREADY_QUEUED), status=status.HTTP_409_CONFLICT) parsed_task = parse_bulk_import_task_id(task.id) return Response(dict(task=task.id, state=task.state, username=username, queue=parsed_task['queue']), status=status.HTTP_202_ACCEPTED)
def delete(request, _=None): # pylint: disable=unused-argument task_id = request.data.get('task_id', None) signal = request.data.get('signal', None) or 'SIGKILL' if not task_id: return Response(status=status.HTTP_400_BAD_REQUEST) result = AsyncResult(task_id) user = request.user if not user.is_staff: # non-admin users should be able to cancel their own tasks task_info = parse_bulk_import_task_id(task_id) username = task_info.get('username', None) if not username: username = get(result, 'args.1') # for parallel child tasks if username != user.username: return Response(status=status.HTTP_403_FORBIDDEN) try: app.control.revoke(task_id, terminate=True, signal=signal) # Below code is needed for removing the lock from QueueOnce if (get(result, 'name') or '').startswith('core.common.tasks.bulk_import'): celery_once_key = get_bulk_import_celery_once_lock_key(result) if celery_once_key: celery_once = QueueOnce() celery_once.name = result.name celery_once.once_backend.clear_lock(celery_once_key) except Exception as ex: return Response(dict(errors=ex.args), status=status.HTTP_400_BAD_REQUEST) return Response(status=status.HTTP_204_NO_CONTENT)
def post(self, request, import_queue=None): user = self.request.user username = user.username update_if_exists = request.GET.get('update_if_exists', 'true') if update_if_exists not in ['true', 'false']: return Response(dict(exception=INVALID_UPDATE_IF_EXISTS), status=status.HTTP_400_BAD_REQUEST) update_if_exists = update_if_exists == 'true' try: data = request.body.decode('utf-8') if isinstance( request.body, bytes) else request.body task = queue_bulk_import(data, import_queue, username, update_if_exists) except AlreadyQueued: return Response(dict(exception=ALREADY_QUEUED), status=status.HTTP_409_CONFLICT) parsed_task = parse_bulk_import_task_id(task.id) return Response(dict(task=task.id, state=task.state, username=username, queue=parsed_task['queue']), status=status.HTTP_202_ACCEPTED)
def get(self, request, import_queue=None): # pylint: disable=too-many-return-statements,too-many-locals,too-many-branches task_id = request.GET.get('task') result_format = request.GET.get('result') username = request.GET.get('username') user = self.request.user if task_id: parsed_task = parse_bulk_import_task_id(task_id) username = parsed_task['username'] if not user.is_staff and user.username != username: return Response(status=status.HTTP_403_FORBIDDEN) task = AsyncResult(task_id) if task.successful(): result = task.get() if result and result_format == 'json': return Response(result.get('json', None), content_type="application/json") if result and result_format == 'report': return Response(result.get('report', None)) if result: return Response(result.get('detailed_summary', None)) if task.failed(): return Response(dict(exception=str(task.result)), status=status.HTTP_400_BAD_REQUEST) if task.state == 'STARTED': service = RedisService() if service.exists(task_id): return Response(dict( details=service.get_formatted(task_id), task=task.id, state=task.state, username=username, queue=parsed_task['queue']), status=status.HTTP_200_OK) if task.state == 'PENDING' and not task_exists(task_id): return Response(dict(exception='task ' + task_id + ' not found'), status=status.HTTP_404_NOT_FOUND) return Response(dict(task=task.id, state=task.state, username=username, queue=parsed_task['queue']), status=status.HTTP_202_ACCEPTED) try: response = flower_get('api/tasks') flower_tasks = response.json() except Exception as ex: return Response(dict( detail= 'Flower service returned unexpected result. Maybe check healthcheck.', exception=str(ex)), status=status.HTTP_422_UNPROCESSABLE_ENTITY) tasks = [] for task_id, value in flower_tasks.items(): if not value.get('name', None) or not value['name'].startswith( 'core.common.tasks.bulk_import'): continue task = parse_bulk_import_task_id(task_id) if user.is_staff or user.username == task['username']: if (not import_queue or task['queue'] == import_queue) and \ (not username or task['username'] == username): tasks.append( dict(task=task_id, state=value['state'], queue=task['queue'], username=task['username'])) return Response(tasks)