Merge "New cron type for audit interval"

This commit is contained in:
Jenkins
2017-07-19 02:46:25 +00:00
committed by Gerrit Code Review
20 changed files with 326 additions and 54 deletions

View File

@@ -481,6 +481,7 @@ class TestPost(api_base.FunctionalTest):
del audit_dict['state']
del audit_dict['interval']
del audit_dict['scope']
del audit_dict['next_run_time']
response = self.post_json('/audits', audit_dict)
self.assertEqual('application/json', response.content_type)
@@ -523,6 +524,7 @@ class TestPost(api_base.FunctionalTest):
del audit_dict['state']
del audit_dict['interval']
del audit_dict['scope']
del audit_dict['next_run_time']
# Make the audit template UUID some garbage value
audit_dict['audit_template_uuid'] = (
'01234567-8910-1112-1314-151617181920')
@@ -545,6 +547,7 @@ class TestPost(api_base.FunctionalTest):
del audit_dict['state']
del audit_dict['interval']
del audit_dict['scope']
del audit_dict['next_run_time']
with mock.patch.object(self.dbapi, 'create_audit',
wraps=self.dbapi.create_audit) as cn_mock:
response = self.post_json('/audits', audit_dict)
@@ -562,6 +565,7 @@ class TestPost(api_base.FunctionalTest):
del audit_dict['state']
del audit_dict['interval']
del audit_dict['scope']
del audit_dict['next_run_time']
response = self.post_json('/audits', audit_dict)
self.assertEqual('application/json', response.content_type)
@@ -571,15 +575,16 @@ class TestPost(api_base.FunctionalTest):
self.assertTrue(utils.is_uuid_like(response.json['uuid']))
@mock.patch.object(deapi.DecisionEngineAPI, 'trigger_audit')
def test_create_continuous_audit_with_period(self, mock_trigger_audit):
def test_create_continuous_audit_with_interval(self, mock_trigger_audit):
mock_trigger_audit.return_value = mock.ANY
audit_dict = post_get_test_audit()
del audit_dict['uuid']
del audit_dict['state']
del audit_dict['scope']
del audit_dict['next_run_time']
audit_dict['audit_type'] = objects.audit.AuditType.CONTINUOUS.value
audit_dict['interval'] = 1200
audit_dict['interval'] = '1200'
response = self.post_json('/audits', audit_dict)
self.assertEqual('application/json', response.content_type)
@@ -589,6 +594,48 @@ class TestPost(api_base.FunctionalTest):
self.assertEqual(audit_dict['interval'], response.json['interval'])
self.assertTrue(utils.is_uuid_like(response.json['uuid']))
@mock.patch.object(deapi.DecisionEngineAPI, 'trigger_audit')
def test_create_continuous_audit_with_cron_interval(self,
mock_trigger_audit):
mock_trigger_audit.return_value = mock.ANY
audit_dict = post_get_test_audit()
del audit_dict['uuid']
del audit_dict['state']
del audit_dict['scope']
del audit_dict['next_run_time']
audit_dict['audit_type'] = objects.audit.AuditType.CONTINUOUS.value
audit_dict['interval'] = '* * * * *'
response = self.post_json('/audits', audit_dict)
self.assertEqual('application/json', response.content_type)
self.assertEqual(201, response.status_int)
self.assertEqual(objects.audit.State.PENDING,
response.json['state'])
self.assertEqual(audit_dict['interval'], response.json['interval'])
self.assertTrue(utils.is_uuid_like(response.json['uuid']))
@mock.patch.object(deapi.DecisionEngineAPI, 'trigger_audit')
def test_create_continuous_audit_with_wrong_interval(self,
mock_trigger_audit):
mock_trigger_audit.return_value = mock.ANY
audit_dict = post_get_test_audit()
del audit_dict['uuid']
del audit_dict['state']
del audit_dict['scope']
del audit_dict['next_run_time']
audit_dict['audit_type'] = objects.audit.AuditType.CONTINUOUS.value
audit_dict['interval'] = 'zxc'
response = self.post_json('/audits', audit_dict, expect_errors=True)
self.assertEqual('application/json', response.content_type)
self.assertEqual(500, response.status_int)
expected_error_msg = ('Exactly 5 or 6 columns has to be '
'specified for iteratorexpression.')
self.assertTrue(response.json['error_message'])
self.assertIn(expected_error_msg, response.json['error_message'])
@mock.patch.object(deapi.DecisionEngineAPI, 'trigger_audit')
def test_create_continuous_audit_without_period(self, mock_trigger_audit):
mock_trigger_audit.return_value = mock.ANY
@@ -599,6 +646,7 @@ class TestPost(api_base.FunctionalTest):
audit_dict['audit_type'] = objects.audit.AuditType.CONTINUOUS.value
del audit_dict['interval']
del audit_dict['scope']
del audit_dict['next_run_time']
response = self.post_json('/audits', audit_dict, expect_errors=True)
self.assertEqual(400, response.status_int)
@@ -616,8 +664,8 @@ class TestPost(api_base.FunctionalTest):
del audit_dict['uuid']
del audit_dict['state']
audit_dict['audit_type'] = objects.audit.AuditType.ONESHOT.value
audit_dict['interval'] = 1200
del audit_dict['scope']
del audit_dict['next_run_time']
response = self.post_json('/audits', audit_dict, expect_errors=True)
self.assertEqual(400, response.status_int)
@@ -634,6 +682,7 @@ class TestPost(api_base.FunctionalTest):
del audit_dict['state']
del audit_dict['interval']
del audit_dict['scope']
del audit_dict['next_run_time']
response = self.post_json('/audits', audit_dict)
de_mock.assert_called_once_with(mock.ANY, response.json['uuid'])
@@ -657,6 +706,7 @@ class TestPost(api_base.FunctionalTest):
del audit_dict['state']
del audit_dict['interval']
del audit_dict['scope']
del audit_dict['next_run_time']
response = self.post_json('/audits', audit_dict, expect_errors=True)
self.assertEqual('application/json', response.content_type)
@@ -678,6 +728,7 @@ class TestPost(api_base.FunctionalTest):
del audit_dict['state']
del audit_dict['interval']
del audit_dict['scope']
del audit_dict['next_run_time']
response = self.post_json('/audits', audit_dict, expect_errors=True)
self.assertEqual('application/json', response.content_type)
@@ -700,7 +751,7 @@ class TestPost(api_base.FunctionalTest):
audit_dict['audit_template_uuid'] = audit_template['uuid']
del_keys = ['uuid', 'goal_id', 'strategy_id', 'state', 'interval',
'scope']
'scope', 'next_run_time']
for k in del_keys:
del audit_dict[k]
@@ -839,6 +890,7 @@ class TestAuditPolicyEnforcement(api_base.FunctionalTest):
del audit_dict['uuid']
del audit_dict['state']
del audit_dict['scope']
del audit_dict['next_run_time']
self._common_policy_check(
"audit:create", self.post_json, '/audits', audit_dict,
expect_errors=True)

View File

@@ -89,11 +89,12 @@ def get_test_audit(**kwargs):
'updated_at': kwargs.get('updated_at'),
'deleted_at': kwargs.get('deleted_at'),
'parameters': kwargs.get('parameters', {}),
'interval': kwargs.get('interval', 3600),
'interval': kwargs.get('interval', '3600'),
'goal_id': kwargs.get('goal_id', 1),
'strategy_id': kwargs.get('strategy_id', None),
'scope': kwargs.get('scope', []),
'auto_trigger': kwargs.get('auto_trigger', False)
'auto_trigger': kwargs.get('auto_trigger', False),
'next_run_time': kwargs.get('next_run_time')
}
# ObjectField doesn't allow None nor dict, so if we want to simulate a
# non-eager object loading, the field should not be referenced at all.

View File

@@ -14,12 +14,15 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import datetime
import mock
from oslo_utils import uuidutils
from apscheduler import job
from watcher.applier import rpcapi
from watcher.common import exception
from watcher.common import scheduling
from watcher.db.sqlalchemy import api as sq_api
from watcher.decision_engine.audit import continuous
@@ -241,20 +244,65 @@ class TestContinuousAuditHandler(base.DbTestCase):
@mock.patch.object(scheduling.BackgroundSchedulerService, 'add_job')
@mock.patch.object(scheduling.BackgroundSchedulerService, 'get_jobs')
@mock.patch.object(objects.audit.Audit, 'list')
def test_launch_audits_periodically(self, mock_list, mock_jobs,
m_add_job, m_engine, m_service):
def test_launch_audits_periodically_with_interval(
self, mock_list, mock_jobs, m_add_job, m_engine, m_service):
audit_handler = continuous.ContinuousAuditHandler()
mock_list.return_value = self.audits
self.audits[0].next_run_time = (datetime.datetime.now() -
datetime.timedelta(seconds=1800))
mock_jobs.return_value = mock.MagicMock()
m_engine.return_value = mock.MagicMock()
m_add_job.return_value = audit_handler.execute_audit(
self.audits[0], self.context)
m_add_job.return_value = mock.MagicMock()
audit_handler.launch_audits_periodically()
m_service.assert_called()
m_engine.assert_called()
m_add_job.assert_called()
mock_jobs.assert_called()
self.assertIsNotNone(self.audits[0].next_run_time)
self.assertIsNone(self.audits[1].next_run_time)
@mock.patch.object(objects.service.Service, 'list')
@mock.patch.object(sq_api, 'get_engine')
@mock.patch.object(scheduling.BackgroundSchedulerService, 'add_job')
@mock.patch.object(scheduling.BackgroundSchedulerService, 'get_jobs')
@mock.patch.object(objects.audit.Audit, 'list')
def test_launch_audits_periodically_with_cron(
self, mock_list, mock_jobs, m_add_job, m_engine, m_service):
audit_handler = continuous.ContinuousAuditHandler()
mock_list.return_value = self.audits
self.audits[0].interval = "*/5 * * * *"
mock_jobs.return_value = mock.MagicMock()
m_engine.return_value = mock.MagicMock()
m_add_job.return_value = mock.MagicMock()
audit_handler.launch_audits_periodically()
m_service.assert_called()
m_engine.assert_called()
m_add_job.assert_called()
mock_jobs.assert_called()
self.assertIsNotNone(self.audits[0].next_run_time)
self.assertIsNone(self.audits[1].next_run_time)
@mock.patch.object(continuous.ContinuousAuditHandler, '_next_cron_time')
@mock.patch.object(objects.service.Service, 'list')
@mock.patch.object(sq_api, 'get_engine')
@mock.patch.object(scheduling.BackgroundSchedulerService, 'add_job')
@mock.patch.object(scheduling.BackgroundSchedulerService, 'get_jobs')
@mock.patch.object(objects.audit.Audit, 'list')
def test_launch_audits_periodically_with_invalid_cron(
self, mock_list, mock_jobs, m_add_job, m_engine, m_service,
mock_cron):
audit_handler = continuous.ContinuousAuditHandler()
mock_list.return_value = self.audits
self.audits[0].interval = "*/5* * * *"
mock_cron.side_effect = exception.CronFormatIsInvalid
mock_jobs.return_value = mock.MagicMock()
m_engine.return_value = mock.MagicMock()
m_add_job.return_value = mock.MagicMock()
self.assertRaises(exception.CronFormatIsInvalid,
audit_handler.launch_audits_periodically)
@mock.patch.object(objects.service.Service, 'list')
@mock.patch.object(sq_api, 'get_engine')
@@ -273,7 +321,7 @@ class TestContinuousAuditHandler(base.DbTestCase):
args=[mock.ANY, mock.ANY],
seconds=3600,
name='execute_audit',
next_run_time=mock.ANY) for audit in self.audits]
next_run_time=mock.ANY) for _ in self.audits]
audit_handler.launch_audits_periodically()
m_add_job.assert_has_calls(calls)

View File

@@ -94,6 +94,8 @@ class TestActionPlanNotification(base.DbTestCase):
"audit": {
"watcher_object.data": {
"interval": None,
"next_run_time": None,
"auto_trigger": False,
"parameters": {},
"uuid": "10a47dd1-4874-4298-91cf-eff046dbdb8d",
"strategy_uuid": None,
@@ -108,7 +110,7 @@ class TestActionPlanNotification(base.DbTestCase):
},
"watcher_object.name": "TerseAuditPayload",
"watcher_object.namespace": "watcher",
"watcher_object.version": "1.0"
"watcher_object.version": "1.1"
},
"deleted_at": None,
"state": "ONGOING",
@@ -168,6 +170,8 @@ class TestActionPlanNotification(base.DbTestCase):
"audit": {
"watcher_object.data": {
"interval": None,
"next_run_time": None,
"auto_trigger": False,
"parameters": {},
"uuid": "10a47dd1-4874-4298-91cf-eff046dbdb8d",
"strategy_uuid": None,
@@ -182,7 +186,7 @@ class TestActionPlanNotification(base.DbTestCase):
},
"watcher_object.name": "TerseAuditPayload",
"watcher_object.namespace": "watcher",
"watcher_object.version": "1.0"
"watcher_object.version": "1.1"
},
"deleted_at": None,
"state": "PENDING",
@@ -234,6 +238,8 @@ class TestActionPlanNotification(base.DbTestCase):
"audit": {
"watcher_object.data": {
"interval": None,
"next_run_time": None,
"auto_trigger": False,
"parameters": {},
"uuid": "10a47dd1-4874-4298-91cf-eff046dbdb8d",
"strategy_uuid": None,
@@ -248,7 +254,7 @@ class TestActionPlanNotification(base.DbTestCase):
},
"watcher_object.name": "TerseAuditPayload",
"watcher_object.namespace": "watcher",
"watcher_object.version": "1.0"
"watcher_object.version": "1.1"
},
"deleted_at": None,
"state": "DELETED",
@@ -287,9 +293,11 @@ class TestActionPlanNotification(base.DbTestCase):
"audit": {
"watcher_object.namespace": "watcher",
"watcher_object.name": "TerseAuditPayload",
"watcher_object.version": "1.0",
"watcher_object.version": "1.1",
"watcher_object.data": {
"interval": None,
"next_run_time": None,
"auto_trigger": False,
"parameters": {},
"uuid": "10a47dd1-4874-4298-91cf-eff046dbdb8d",
"strategy_uuid": None,
@@ -373,6 +381,8 @@ class TestActionPlanNotification(base.DbTestCase):
"audit": {
"watcher_object.data": {
"interval": None,
"next_run_time": None,
"auto_trigger": False,
"parameters": {},
"uuid": "10a47dd1-4874-4298-91cf-eff046dbdb8d",
"strategy_uuid": None,
@@ -387,7 +397,7 @@ class TestActionPlanNotification(base.DbTestCase):
},
"watcher_object.name": "TerseAuditPayload",
"watcher_object.namespace": "watcher",
"watcher_object.version": "1.0"
"watcher_object.version": "1.1"
},
"global_efficacy": {},
"state": "ONGOING",

View File

@@ -69,9 +69,11 @@ class TestAuditNotification(base.DbTestCase):
self.assertDictEqual(
{
"watcher_object.namespace": "watcher",
"watcher_object.version": "1.0",
"watcher_object.version": "1.1",
"watcher_object.data": {
"interval": None,
"next_run_time": None,
"auto_trigger": False,
"strategy_uuid": "cb3d0b58-4415-4d90-b75b-1e96878730e3",
"strategy": {
"watcher_object.namespace": "watcher",
@@ -141,9 +143,11 @@ class TestAuditNotification(base.DbTestCase):
self.assertDictEqual(
{
"watcher_object.namespace": "watcher",
"watcher_object.version": "1.0",
"watcher_object.version": "1.1",
"watcher_object.data": {
"interval": None,
"next_run_time": None,
"auto_trigger": False,
"parameters": {},
"uuid": "10a47dd1-4874-4298-91cf-eff046dbdb8d",
"goal_uuid": "f7ad87ae-4298-91cf-93a0-f35a852e3652",
@@ -200,9 +204,11 @@ class TestAuditNotification(base.DbTestCase):
self.assertDictEqual(
{
"watcher_object.namespace": "watcher",
"watcher_object.version": "1.0",
"watcher_object.version": "1.1",
"watcher_object.data": {
"interval": None,
"next_run_time": None,
"auto_trigger": False,
"strategy_uuid": "cb3d0b58-4415-4d90-b75b-1e96878730e3",
"strategy": {
"watcher_object.namespace": "watcher",
@@ -263,9 +269,11 @@ class TestAuditNotification(base.DbTestCase):
self.assertDictEqual(
{
"watcher_object.namespace": "watcher",
"watcher_object.version": "1.0",
"watcher_object.version": "1.1",
"watcher_object.data": {
"interval": None,
"next_run_time": None,
"auto_trigger": False,
"strategy_uuid": "cb3d0b58-4415-4d90-b75b-1e96878730e3",
"strategy": {
"watcher_object.namespace": "watcher",
@@ -350,6 +358,8 @@ class TestAuditNotification(base.DbTestCase):
"watcher_object.version": "1.0"
},
"interval": None,
"next_run_time": None,
"auto_trigger": False,
"parameters": {},
"scope": [],
"state": "ONGOING",
@@ -374,7 +384,7 @@ class TestAuditNotification(base.DbTestCase):
},
"watcher_object.name": "AuditActionPayload",
"watcher_object.namespace": "watcher",
"watcher_object.version": "1.0"
"watcher_object.version": "1.1"
}
},
notification
@@ -434,6 +444,8 @@ class TestAuditNotification(base.DbTestCase):
"watcher_object.version": "1.0"
},
"interval": None,
"next_run_time": None,
"auto_trigger": False,
"parameters": {},
"scope": [],
"state": "ONGOING",
@@ -458,7 +470,7 @@ class TestAuditNotification(base.DbTestCase):
},
"watcher_object.name": "AuditActionPayload",
"watcher_object.namespace": "watcher",
"watcher_object.version": "1.0"
"watcher_object.version": "1.1"
}
},
notification

View File

@@ -254,17 +254,17 @@ expected_notification_fingerprints = {
'ExceptionNotification': '1.0-9b69de0724fda8310d05e18418178866',
'ExceptionPayload': '1.0-4516ae282a55fe2fd5c754967ee6248b',
'NotificationPublisher': '1.0-bbbc1402fb0e443a3eb227cc52b61545',
'TerseAuditPayload': '1.0-aaf31166b8698f08d12cae98c380b8e0',
'AuditPayload': '1.0-30c85c834648c8ca11f54fc5e084d86b',
'TerseAuditPayload': '1.1-19b0e9224c0953366418a30ed785f267',
'AuditPayload': '1.1-4c59e0cc5d30c42d3b842ce0332709d5',
'AuditStateUpdatePayload': '1.0-1a1b606bf14a2c468800c2b010801ce5',
'AuditUpdateNotification': '1.0-9b69de0724fda8310d05e18418178866',
'AuditUpdatePayload': '1.0-d3aace28d9eb978c1ecf833e108f61f7',
'AuditUpdatePayload': '1.1-9b1f725e736051b976571701e5cc1e55',
'AuditCreateNotification': '1.0-9b69de0724fda8310d05e18418178866',
'AuditCreatePayload': '1.0-30c85c834648c8ca11f54fc5e084d86b',
'AuditCreatePayload': '1.1-4c59e0cc5d30c42d3b842ce0332709d5',
'AuditDeleteNotification': '1.0-9b69de0724fda8310d05e18418178866',
'AuditDeletePayload': '1.0-30c85c834648c8ca11f54fc5e084d86b',
'AuditDeletePayload': '1.1-4c59e0cc5d30c42d3b842ce0332709d5',
'AuditActionNotification': '1.0-9b69de0724fda8310d05e18418178866',
'AuditActionPayload': '1.0-09f5d005f94ba9e5f6b9200170332c52',
'AuditActionPayload': '1.1-5a43e7321495c19f98ef5663efa0a821',
'GoalPayload': '1.0-fa1fecb8b01dd047eef808ded4d50d1a',
'StrategyPayload': '1.0-94f01c137b083ac236ae82573c1fcfc1',
'ActionPlanActionPayload': '1.0-d9f134708e06cf2ff2d3b8d522ac2aa8',

View File

@@ -412,7 +412,7 @@ expected_object_fingerprints = {
'Goal': '1.0-93881622db05e7b67a65ca885b4a022e',
'Strategy': '1.1-73f164491bdd4c034f48083a51bdeb7b',
'AuditTemplate': '1.1-b291973ffc5efa2c61b24fe34fdccc0b',
'Audit': '1.2-910522db78b7b1cb59df614754656db4',
'Audit': '1.3-f47ffb1ee79d8248eb991674bda565ce',
'ActionPlan': '2.0-394f1abbf5d73d7b6675a118fe1a0284',
'Action': '2.0-1dd4959a7e7ac30c62ef170fe08dd935',
'EfficacyIndicator': '1.0-655b71234a82bc7478aff964639c4bb0',