def delete_task(self, start_response, task_id): """ Delete given task """ if validators.validate_task_id(task_id) != task_id: return response.send_error(start_response, 400, constants.ERROR_TASK_INVALID_ID) if not os.path.isdir(self._task_dir(task_id)): return response.send_error(start_response, 404, constants.ERROR_TASK_NOT_FOUND) shutil.rmtree(self._task_dir(task_id)) return response.send_response(start_response, 204)
def update_task(self, environ, start_response, task_id): """ Update data configuration for an existing task """ if validators.validate_task_id(task_id) != task_id: self.log.error("Failed to pass validation: '%s'" % task_id) return response.send_error(start_response, 400, constants.ERROR_TASK_INVALID_ID) if not os.path.isdir(self._task_dir(task_id)): self.log.debug("Task not found '%s'" % task_id) return response.send_error(start_response, 404, constants.ERROR_TASK_NOT_FOUND) try: new_task_description = json.loads( request.read_request_data(environ)) except ValueError: self.log.error("Decoding task data failed '%s'" % task_id) return response.send_error(start_response, 400, constants.ERROR_TASK_INVALID_PAYLOAD) if self.zknodes: lock = distlocks.ZooKeeperLock(self.zknodes, 'task-lock-%s' % task_id) if lock.try_lock() != True: lock.close() self.log.debug("Task locked '%s'" % task_id) return response.send_response(start_response, 409, constants.ERROR_TASK_LOCKED) else: lock = None try: old_task_description = self._load_task_config(task_id) except: if lock: lock.unlock() lock.close() self.log.error("Failed to read task data '%s'" % task_id) return response.send_response(start_response, 500) if old_task_description.has_key( 'assignee') and new_task_description.has_key( 'assignee') and old_task_description[ 'assignee'] != new_task_description['assignee']: if lock: lock.unlock() lock.close() self.log.debug("Task assignment conflict '%s'" % task_id) return response.send_response(start_response, 409, constants.ERROR_TASK_WRONG_ACTOR) self._save_task_config(task_id, new_task_description) if lock: lock.unlock() lock.close() return response.send_response( start_response, 200, json.dumps({ 'id': task_id, 'data': new_task_description }))
def get_task(self, start_response, task_id): """ Return information on a specific task """ if validators.validate_task_id(task_id) != task_id: return response.send_error(start_response, 400, constants.ERROR_TASK_INVALID_ID) if not os.path.isdir(self._task_dir(task_id)): return response.send_error(start_response, 404, constants.ERROR_TASK_NOT_FOUND) task_data = None for _ in range(10): try: task_data = json.dumps(self._prepare_task_data(task_id)) break except: time.sleep(0.1) if not task_data: return response.send_error(start_response, 409, constants.ERROR_TASK_LOCKED) return response.send_response(start_response, 200, task_data)
def handle_request(self, request, parts): """ Parse and dispatch task API requests """ if len(parts) == 0: if request.method == 'GET': return self.get_tasks() elif request.method == 'POST': return self.create_new_task(request) elif len(parts) == 1: if validators.validate_task_id(parts[0]) != parts[0]: return webob.Response(status=400, body=constants.ERROR_TASK_INVALID_ID) if request.method == 'GET': return self.get_task(parts[0]) elif request.method == 'PUT': return self.update_task(request, parts[0]) elif request.method == 'DELETE': return self.delete_task(parts[0]) return webob.Response(status=400)
def update_task(self, environ, start_response, task_id): """ Update data configuration for an existing task """ if validators.validate_task_id(task_id) != task_id: self.log.error("Failed to pass validation: '%s'" % task_id) return response.send_error(start_response, 400, constants.ERROR_TASK_INVALID_ID) if not os.path.isdir(self._task_dir(task_id)): self.log.debug("Task not found '%s'" % task_id) return response.send_error(start_response, 404, constants.ERROR_TASK_NOT_FOUND) try: new_task_description = json.loads(request.read_request_data(environ)) except ValueError: self.log.error("Decoding task data failed '%s'" % task_id) return response.send_error(start_response, 400, constants.ERROR_TASK_INVALID_PAYLOAD) if self.zknodes: lock = distlocks.ZooKeeperLock(self.zknodes, 'task-lock-%s' % task_id) if lock.try_lock() != True: lock.close() self.log.debug("Task locked '%s'" % task_id) return response.send_response(start_response, 409, constants.ERROR_TASK_LOCKED) else: lock = None try: old_task_description = self._load_task_config(task_id) except: if lock: lock.unlock() lock.close() self.log.error("Failed to read task data '%s'" % task_id) return response.send_response(start_response, 500) if old_task_description.has_key('assignee') and new_task_description.has_key('assignee') and old_task_description['assignee'] != new_task_description['assignee']: if lock: lock.unlock() lock.close() self.log.debug("Task assignment conflict '%s'" % task_id) return response.send_response(start_response, 409, constants.ERROR_TASK_WRONG_ACTOR) self._save_task_config(task_id, new_task_description) if lock: lock.unlock() lock.close() return response.send_response(start_response, 200, json.dumps({'id': task_id, 'data': new_task_description}))
def test_02_invalid_task_ids(self): for task_id in self.invalid_task_ids: assert validators.validate_task_id(task_id) is None, "Validator accepted invalid task_id %s" % task_id
def test_01_valid_task_ids(self): for task_id in self.valid_task_ids: assert validators.validate_task_id(task_id) == task_id, "Validator declined valid task_id %s" % task_id