Audit API supports new force option

Depends-on:Ia08694d2fb76907ea14e64116af2e722fe930063

Change-Id: Ib2d221ea9c994dea396c54cc8d2d32237025a1d4
Implements: blueprint add-force-field-to-audit
This commit is contained in:
licanwei 2019-05-09 14:48:25 +08:00
parent 3b9364d4c7
commit 2afd0dfcf5
7 changed files with 67 additions and 3 deletions

View File

@ -0,0 +1,7 @@
---
features:
- |
Add force field to Audit. User can set --force to enable the new option when
launching audit. If force is True, audit will be executed despite of ongoing
actionplan. The new audit may create a wrong actionplan if they use the same
data model.

View File

@ -73,6 +73,8 @@ def hide_fields_in_newer_versions(obj):
if not api_utils.allow_start_end_audit_time():
obj.start_time = wtypes.Unset
obj.end_time = wtypes.Unset
if not api_utils.allow_force():
obj.force = wtypes.Unset
class AuditPostType(wtypes.Base):
@ -194,7 +196,8 @@ class AuditPostType(wtypes.Base):
scope=self.scope,
auto_trigger=self.auto_trigger,
start_time=self.start_time,
end_time=self.end_time)
end_time=self.end_time,
force=self.force)
class AuditPatchType(types.JsonPatchType):

View File

@ -165,3 +165,12 @@ def allow_start_end_audit_time():
audits.
"""
return pecan.request.version.minor >= versions.MINOR_1_START_END_TIMING
def allow_force():
"""Check if we should support optional force attribute for Audit.
Version 1.2 of the API added support for forced audits that allows to
launch audit when other action plan is ongoing.
"""
return pecan.request.version.minor >= versions.MINOR_2_FORCE

View File

@ -22,11 +22,13 @@ BASE_VERSION = 1
#
# v1.0: corresponds to Rocky API
# v1.1: Add start/end time for continuous audit
# v1.2: Add force field to audit
MINOR_0_ROCKY = 0
MINOR_1_START_END_TIMING = 1
MINOR_2_FORCE = 2
MINOR_MAX_VERSION = MINOR_1_START_END_TIMING
MINOR_MAX_VERSION = MINOR_2_FORCE
# String representations of the minor and maximum versions
_MIN_VERSION_STRING = '{}.{}'.format(BASE_VERSION, MINOR_0_ROCKY)

View File

@ -121,7 +121,10 @@ class AuditHandler(BaseAuditHandler):
def pre_execute(self, audit, request_context):
LOG.debug("Trigger audit %s", audit.uuid)
self.check_ongoing_action_plans(request_context)
# If audit.force is true, audit will be executed
# despite of ongoing actionplan
if not audit.force:
self.check_ongoing_action_plans(request_context)
# Write hostname that will execute this audit.
audit.hostname = CONF.host
# change state of the audit to ONGOING

View File

@ -950,6 +950,39 @@ class TestPost(api_base.FunctionalTest):
self.assertIn(expected_error_msg, response.json['error_message'])
assert not mock_trigger_audit.called
@mock.patch.object(deapi.DecisionEngineAPI, 'trigger_audit')
def test_create_audit_with_force_false(self, mock_trigger_audit):
mock_trigger_audit.return_value = mock.ANY
audit_dict = post_get_test_audit(
params_to_exclude=['uuid', 'state', 'interval', 'scope',
'next_run_time', 'hostname', 'goal'])
response = self.post_json(
'/audits',
audit_dict,
headers={'OpenStack-API-Version': 'infra-optim 1.2'})
self.assertEqual('application/json', response.content_type)
self.assertEqual(201, response.status_int)
self.assertFalse(response.json['force'])
@mock.patch.object(deapi.DecisionEngineAPI, 'trigger_audit')
def test_create_audit_with_force_true(self, mock_trigger_audit):
mock_trigger_audit.return_value = mock.ANY
audit_dict = post_get_test_audit(
params_to_exclude=['uuid', 'state', 'interval', 'scope',
'next_run_time', 'hostname', 'goal'])
audit_dict['force'] = True
response = self.post_json(
'/audits',
audit_dict,
headers={'OpenStack-API-Version': 'infra-optim 1.2'})
self.assertEqual('application/json', response.content_type)
self.assertEqual(201, response.status_int)
self.assertTrue(response.json['force'])
class TestDelete(api_base.FunctionalTest):

View File

@ -227,6 +227,13 @@ class TestAutoTriggerActionPlan(base.DbTestCase):
mock_applier.assert_called_once_with(self.context,
self.recommended_action_plan.uuid)
@mock.patch.object(oneshot.OneShotAuditHandler, 'do_execute')
def test_trigger_audit_with_force(self, mock_do_execute):
audit_handler = oneshot.OneShotAuditHandler()
self.audit.force = True
audit_handler.execute(self.audit, self.context)
self.assertTrue(mock_do_execute.called)
class TestContinuousAuditHandler(base.DbTestCase):