From a8fa969379a32349953d518df948a10f7c5c7381 Mon Sep 17 00:00:00 2001
From: licanwei
Date: Fri, 15 Dec 2017 01:25:57 -0800
Subject: [PATCH] check audit state when deleting audit
If audit is 'ONGOING' or 'PENDING', don't delete audit.
Change-Id: Iac714e7e78e7bb5b52f401e5b2ad0e1d8af8bb45
Closes-Bug: #1738358
---
watcher/api/controllers/v1/audit.py | 7 +++++++
watcher/common/exception.py | 4 ++++
watcher/tests/api/v1/test_actions_plans.py | 5 +++++
watcher/tests/api/v1/test_audits.py | 17 +++++++++++++++++
4 files changed, 33 insertions(+)
diff --git a/watcher/api/controllers/v1/audit.py b/watcher/api/controllers/v1/audit.py
index 7a247dc11..8fe2a22e7 100644
--- a/watcher/api/controllers/v1/audit.py
+++ b/watcher/api/controllers/v1/audit.py
@@ -636,4 +636,11 @@ class AuditsController(rest.RestController):
policy.enforce(context, 'audit:update', audit_to_delete,
action='audit:update')
+ initial_state = audit_to_delete.state
+ new_state = objects.audit.State.DELETED
+ if not objects.audit.AuditStateTransitionManager(
+ ).check_transition(initial_state, new_state):
+ raise exception.DeleteError(
+ state=initial_state)
+
audit_to_delete.soft_delete()
diff --git a/watcher/common/exception.py b/watcher/common/exception.py
index f4d7404c4..afae2f307 100644
--- a/watcher/common/exception.py
+++ b/watcher/common/exception.py
@@ -332,6 +332,10 @@ class PatchError(Invalid):
msg_fmt = _("Couldn't apply patch '%(patch)s'. Reason: %(reason)s")
+class DeleteError(Invalid):
+ msg_fmt = _("Couldn't delete when state is '%(state)s'.")
+
+
# decision engine
class WorkflowExecutionException(WatcherException):
diff --git a/watcher/tests/api/v1/test_actions_plans.py b/watcher/tests/api/v1/test_actions_plans.py
index 0f5d5d4ef..950ece523 100644
--- a/watcher/tests/api/v1/test_actions_plans.py
+++ b/watcher/tests/api/v1/test_actions_plans.py
@@ -147,6 +147,11 @@ class TestListActionPlan(api_base.FunctionalTest):
audit_id=audit2.id)
action_plan_list.append(action_plan.uuid)
+ new_state = objects.audit.State.CANCELLED
+ self.patch_json(
+ '/audits/%s' % audit1.uuid,
+ [{'path': '/state', 'value': new_state,
+ 'op': 'replace'}])
self.delete('/audits/%s' % audit1.uuid)
response = self.get_json('/action_plans')
diff --git a/watcher/tests/api/v1/test_audits.py b/watcher/tests/api/v1/test_audits.py
index d3ea0ffd3..1b425b02b 100644
--- a/watcher/tests/api/v1/test_audits.py
+++ b/watcher/tests/api/v1/test_audits.py
@@ -828,6 +828,23 @@ class TestDelete(api_base.FunctionalTest):
def test_delete_audit(self, mock_utcnow):
test_time = datetime.datetime(2000, 1, 1, 0, 0)
mock_utcnow.return_value = test_time
+
+ new_state = objects.audit.State.ONGOING
+ self.patch_json(
+ '/audits/%s' % self.audit.uuid,
+ [{'path': '/state', 'value': new_state,
+ 'op': 'replace'}])
+ response = self.delete('/audits/%s' % self.audit.uuid,
+ expect_errors=True)
+ self.assertEqual(400, response.status_int)
+ self.assertEqual('application/json', response.content_type)
+ self.assertTrue(response.json['error_message'])
+
+ new_state = objects.audit.State.CANCELLED
+ self.patch_json(
+ '/audits/%s' % self.audit.uuid,
+ [{'path': '/state', 'value': new_state,
+ 'op': 'replace'}])
self.delete('/audits/%s' % self.audit.uuid)
response = self.get_json('/audits/%s' % self.audit.uuid,
expect_errors=True)