Merge "Add audit.planner events"

This commit is contained in:
Jenkins
2016-11-16 16:52:13 +00:00
committed by Gerrit Code Review
10 changed files with 331 additions and 68 deletions

View File

@@ -0,0 +1,70 @@
{
"priority": "INFO",
"payload": {
"watcher_object.data": {
"audit_type": "ONESHOT",
"parameters": {
"para2": "hello",
"para1": 3.2
},
"state": "ONGOING",
"updated_at": null,
"deleted_at": null,
"fault": null,
"goal": {
"watcher_object.data": {
"uuid": "bc830f84-8ae3-4fc6-8bc6-e3dd15e8b49a",
"name": "dummy",
"updated_at": null,
"deleted_at": null,
"efficacy_specification": [],
"created_at": "2016-11-04T16:25:35Z",
"display_name": "Dummy goal"
},
"watcher_object.name": "GoalPayload",
"watcher_object.version": "1.0",
"watcher_object.namespace": "watcher"
},
"interval": null,
"scope": [],
"strategy": {
"watcher_object.data": {
"parameters_spec": {
"properties": {
"para2": {
"type": "string",
"default": "hello",
"description": "string parameter example"
},
"para1": {
"description": "number parameter example",
"maximum": 10.2,
"type": "number",
"default": 3.2,
"minimum": 1.0
}
}
},
"name": "dummy",
"uuid": "75234dfe-87e3-4f11-a0e0-3c3305d86a39",
"updated_at": null,
"deleted_at": null,
"created_at": "2016-11-04T16:25:35Z",
"display_name": "Dummy strategy"
},
"watcher_object.name": "StrategyPayload",
"watcher_object.version": "1.0",
"watcher_object.namespace": "watcher"
},
"created_at": "2016-11-04T16:29:20Z",
"uuid": "4a97b9dd-2023-43dc-b713-815bdd94d4d6"
},
"watcher_object.name": "AuditActionPayload",
"watcher_object.version": "1.0",
"watcher_object.namespace": "watcher"
},
"publisher_id": "infra-optim:localhost",
"timestamp": "2016-11-04 16:31:36.264673 ",
"event_type": "audit.planner.end",
"message_id": "cbcf9f2c-7c53-4b4d-91ec-db49cca024b6"
}

View File

@@ -0,0 +1,80 @@
{
"priority": "ERROR",
"payload": {
"watcher_object.data": {
"audit_type": "ONESHOT",
"parameters": {
"para2": "hello",
"para1": 3.2
},
"state": "ONGOING",
"updated_at": null,
"deleted_at": null,
"fault": {
"watcher_object.data": {
"exception": "WatcherException",
"exception_message": "TEST",
"function_name": "test_send_audit_action_with_error",
"module_name": "watcher.tests.notifications.test_audit_notification"
},
"watcher_object.name": "ExceptionPayload",
"watcher_object.namespace": "watcher",
"watcher_object.version": "1.0"
},
"goal": {
"watcher_object.data": {
"uuid": "bc830f84-8ae3-4fc6-8bc6-e3dd15e8b49a",
"name": "dummy",
"updated_at": null,
"deleted_at": null,
"efficacy_specification": [],
"created_at": "2016-11-04T16:25:35Z",
"display_name": "Dummy goal"
},
"watcher_object.name": "GoalPayload",
"watcher_object.version": "1.0",
"watcher_object.namespace": "watcher"
},
"interval": null,
"scope": [],
"strategy": {
"watcher_object.data": {
"parameters_spec": {
"properties": {
"para2": {
"type": "string",
"default": "hello",
"description": "string parameter example"
},
"para1": {
"description": "number parameter example",
"maximum": 10.2,
"type": "number",
"default": 3.2,
"minimum": 1.0
}
}
},
"name": "dummy",
"uuid": "75234dfe-87e3-4f11-a0e0-3c3305d86a39",
"updated_at": null,
"deleted_at": null,
"created_at": "2016-11-04T16:25:35Z",
"display_name": "Dummy strategy"
},
"watcher_object.name": "StrategyPayload",
"watcher_object.version": "1.0",
"watcher_object.namespace": "watcher"
},
"created_at": "2016-11-04T16:29:20Z",
"uuid": "4a97b9dd-2023-43dc-b713-815bdd94d4d6"
},
"watcher_object.name": "AuditActionPayload",
"watcher_object.version": "1.0",
"watcher_object.namespace": "watcher"
},
"publisher_id": "infra-optim:localhost",
"timestamp": "2016-11-04 16:31:36.264673 ",
"event_type": "audit.planner.error",
"message_id": "cbcf9f2c-7c53-4b4d-91ec-db49cca024b6"
}

View File

@@ -0,0 +1,70 @@
{
"priority": "INFO",
"payload": {
"watcher_object.data": {
"audit_type": "ONESHOT",
"parameters": {
"para2": "hello",
"para1": 3.2
},
"state": "ONGOING",
"updated_at": null,
"deleted_at": null,
"fault": null,
"goal": {
"watcher_object.data": {
"uuid": "bc830f84-8ae3-4fc6-8bc6-e3dd15e8b49a",
"name": "dummy",
"updated_at": null,
"deleted_at": null,
"efficacy_specification": [],
"created_at": "2016-11-04T16:25:35Z",
"display_name": "Dummy goal"
},
"watcher_object.name": "GoalPayload",
"watcher_object.version": "1.0",
"watcher_object.namespace": "watcher"
},
"interval": null,
"scope": [],
"strategy": {
"watcher_object.data": {
"parameters_spec": {
"properties": {
"para2": {
"type": "string",
"default": "hello",
"description": "string parameter example"
},
"para1": {
"description": "number parameter example",
"maximum": 10.2,
"type": "number",
"default": 3.2,
"minimum": 1.0
}
}
},
"name": "dummy",
"uuid": "75234dfe-87e3-4f11-a0e0-3c3305d86a39",
"updated_at": null,
"deleted_at": null,
"created_at": "2016-11-04T16:25:35Z",
"display_name": "Dummy strategy"
},
"watcher_object.name": "StrategyPayload",
"watcher_object.version": "1.0",
"watcher_object.namespace": "watcher"
},
"created_at": "2016-11-04T16:29:20Z",
"uuid": "4a97b9dd-2023-43dc-b713-815bdd94d4d6"
},
"watcher_object.name": "AuditActionPayload",
"watcher_object.version": "1.0",
"watcher_object.namespace": "watcher"
},
"publisher_id": "infra-optim:localhost",
"timestamp": "2016-11-04 16:31:36.264673 ",
"event_type": "audit.planner.start",
"message_id": "cbcf9f2c-7c53-4b4d-91ec-db49cca024b6"
}

View File

@@ -24,13 +24,16 @@ from oslo_log import log
from watcher.decision_engine.planner import manager as planner_manager
from watcher.decision_engine.strategy.context import default as default_context
from watcher import notifications
from watcher import objects
from watcher.objects import fields
LOG = log.getLogger(__name__)
@six.add_metaclass(abc.ABCMeta)
class BaseAuditHandler(object):
@abc.abstractmethod
def execute(self, audit_uuid, request_context):
raise NotImplementedError()
@@ -70,6 +73,25 @@ class AuditHandler(BaseAuditHandler):
def strategy_context(self):
return self._strategy_context
def do_schedule(self, request_context, audit, solution):
try:
notifications.audit.send_action_notification(
request_context, audit,
action=fields.NotificationAction.PLANNER,
phase=fields.NotificationPhase.START)
self.planner.schedule(request_context, audit.id, solution)
notifications.audit.send_action_notification(
request_context, audit,
action=fields.NotificationAction.PLANNER,
phase=fields.NotificationPhase.END)
except Exception:
notifications.audit.send_action_notification(
request_context, audit,
action=fields.NotificationAction.PLANNER,
priority=fields.NotificationPriority.ERROR,
phase=fields.NotificationPhase.ERROR)
raise
@staticmethod
def update_audit_state(audit, state):
LOG.debug("Update audit state: %s", state)
@@ -82,8 +104,7 @@ class AuditHandler(BaseAuditHandler):
self.update_audit_state(audit, objects.audit.State.ONGOING)
def post_execute(self, audit, solution, request_context):
self.planner.schedule(request_context, audit.id, solution)
self.do_schedule(request_context, audit, solution)
# change state of the audit to SUCCEEDED
self.update_audit_state(audit, objects.audit.State.SUCCEEDED)

View File

@@ -91,7 +91,7 @@ class ContinuousAuditHandler(base.AuditHandler):
self.execute(audit, request_context)
def post_execute(self, audit, solution, request_context):
self.planner.schedule(request_context, audit.id, solution)
self.do_schedule(request_context, audit, solution)
def launch_audits_periodically(self):
audit_context = context.RequestContext(is_admin=True)

View File

@@ -58,7 +58,8 @@ class EventType(NotificationObject):
# Version 1.0: Initial version
# Version 1.1: Added STRATEGY action in NotificationAction enum
VERSION = '1.1'
# Version 1.2: Added PLANNER action in NotificationAction enum
VERSION = '1.2'
fields = {
'object': wfields.StringField(),

View File

@@ -127,8 +127,9 @@ class NotificationAction(BaseWatcherEnum):
DELETE = 'delete'
STRATEGY = 'strategy'
PLANNER = 'planner'
ALL = (CREATE, UPDATE, EXCEPTION, DELETE, STRATEGY)
ALL = (CREATE, UPDATE, EXCEPTION, DELETE, STRATEGY, PLANNER)
class NotificationPriorityField(BaseEnumField):

View File

@@ -65,6 +65,12 @@ class TestOneShotAuditHandler(base.DbTestCase):
phase=objects.fields.NotificationPhase.START),
mock.call(self.context, self.audit,
action=objects.fields.NotificationAction.STRATEGY,
phase=objects.fields.NotificationPhase.END),
mock.call(self.context, self.audit,
action=objects.fields.NotificationAction.PLANNER,
phase=objects.fields.NotificationPhase.START),
mock.call(self.context, self.audit,
action=objects.fields.NotificationAction.PLANNER,
phase=objects.fields.NotificationPhase.END)]
self.assertEqual(
@@ -106,6 +112,12 @@ class TestOneShotAuditHandler(base.DbTestCase):
phase=objects.fields.NotificationPhase.START),
mock.call(self.context, self.audit,
action=objects.fields.NotificationAction.STRATEGY,
phase=objects.fields.NotificationPhase.END),
mock.call(self.context, self.audit,
action=objects.fields.NotificationAction.PLANNER,
phase=objects.fields.NotificationPhase.START),
mock.call(self.context, self.audit,
action=objects.fields.NotificationAction.PLANNER,
phase=objects.fields.NotificationPhase.END)]
self.assertEqual(
@@ -125,6 +137,12 @@ class TestOneShotAuditHandler(base.DbTestCase):
phase=objects.fields.NotificationPhase.START),
mock.call(self.context, self.audit,
action=objects.fields.NotificationAction.STRATEGY,
phase=objects.fields.NotificationPhase.END),
mock.call(self.context, self.audit,
action=objects.fields.NotificationAction.PLANNER,
phase=objects.fields.NotificationPhase.START),
mock.call(self.context, self.audit,
action=objects.fields.NotificationAction.PLANNER,
phase=objects.fields.NotificationPhase.END)]
self.assertEqual(

View File

@@ -14,43 +14,58 @@
import freezegun
import mock
import oslo_messaging as om
from watcher.common import exception
from watcher.common import rpc
from watcher import notifications
from watcher import objects
from watcher.tests.db import base
from watcher.tests.objects import utils
@freezegun.freeze_time('2016-10-18T09:52:05.219414')
class TestAuditNotification(base.DbTestCase):
@mock.patch.object(notifications.audit.AuditUpdateNotification, '_emit')
def test_send_version_invalid_audit(self, mock_emit):
def setUp(self):
super(TestAuditNotification, self).setUp()
p_get_notifier = mock.patch.object(rpc, 'get_notifier')
m_get_notifier = p_get_notifier.start()
self.addCleanup(p_get_notifier.stop)
self.m_notifier = mock.Mock(spec=om.Notifier)
def fake_get_notifier(publisher_id):
self.m_notifier.publisher_id = publisher_id
return self.m_notifier
m_get_notifier.side_effect = fake_get_notifier
self.goal = utils.create_test_goal(mock.Mock())
self.strategy = utils.create_test_strategy(mock.Mock())
def test_send_invalid_audit(self):
audit = utils.get_test_audit(mock.Mock(), state='DOESNOTMATTER',
goal_id=1)
self.assertRaises(
exception.InvalidAudit,
notifications.audit.send_update,
mock.MagicMock(), audit, 'host', 'node0')
mock.MagicMock(), audit, host='node0')
@freezegun.freeze_time('2016-10-18T09:52:05.219414')
@mock.patch.object(notifications.audit.AuditUpdateNotification, '_emit')
def test_send_version_audit_update_with_strategy(self, mock_emit):
goal = utils.create_test_goal(mock.Mock())
strategy = utils.create_test_strategy(mock.Mock())
def test_send_audit_update_with_strategy(self):
audit = utils.create_test_audit(
mock.Mock(), state=objects.audit.State.ONGOING,
goal_id=goal.id, strategy_id=strategy.id,
goal=goal, strategy=strategy)
goal_id=self.goal.id, strategy_id=self.strategy.id,
goal=self.goal, strategy=self.strategy)
notifications.audit.send_update(
mock.MagicMock(), audit, 'host', 'node0',
mock.MagicMock(), audit, host='node0',
old_state=objects.audit.State.PENDING)
self.assertEqual(1, mock_emit.call_count)
notification = mock_emit.call_args_list[0][1]
# The 1st notification is because we created the object.
self.assertEqual(2, self.m_notifier.info.call_count)
notification = self.m_notifier.info.call_args[1]
payload = notification['payload']
self.assertEqual("infra-optim:node0", self.m_notifier.publisher_id)
self.assertDictEqual(
{
"watcher_object.namespace": "watcher",
@@ -108,21 +123,19 @@ class TestAuditNotification(base.DbTestCase):
payload
)
@freezegun.freeze_time('2016-10-18T09:52:05.219414')
@mock.patch.object(notifications.audit.AuditUpdateNotification, '_emit')
def test_send_version_audit_update_without_strategy(self, mock_emit):
goal = utils.create_test_goal(mock.Mock(), id=1)
def test_send_audit_update_without_strategy(self):
audit = utils.get_test_audit(
mock.Mock(), state=objects.audit.State.ONGOING,
goal_id=goal.id, goal=goal)
goal_id=self.goal.id, goal=self.goal)
notifications.audit.send_update(
mock.MagicMock(), audit, 'host', 'node0',
mock.MagicMock(), audit, host='node0',
old_state=objects.audit.State.PENDING)
self.assertEqual(1, mock_emit.call_count)
notification = mock_emit.call_args_list[0][1]
self.assertEqual(1, self.m_notifier.info.call_count)
notification = self.m_notifier.info.call_args[1]
payload = notification['payload']
self.assertEqual("infra-optim:node0", self.m_notifier.publisher_id)
self.assertDictEqual(
{
"watcher_object.namespace": "watcher",
@@ -167,22 +180,19 @@ class TestAuditNotification(base.DbTestCase):
payload
)
@freezegun.freeze_time('2016-10-18T09:52:05.219414')
@mock.patch.object(notifications.audit.AuditCreateNotification, '_emit')
def test_send_version_audit_create(self, mock_emit):
goal = utils.create_test_goal(mock.Mock())
strategy = utils.create_test_strategy(mock.Mock())
def test_send_audit_create(self):
audit = utils.get_test_audit(
mock.Mock(), state=objects.audit.State.PENDING,
goal_id=goal.id, strategy_id=strategy.id,
goal=goal.as_dict(), strategy=strategy.as_dict())
goal_id=self.goal.id, strategy_id=self.strategy.id,
goal=self.goal.as_dict(), strategy=self.strategy.as_dict())
notifications.audit.send_create(
mock.MagicMock(), audit, 'host', 'node0')
mock.MagicMock(), audit, host='node0')
self.assertEqual(1, mock_emit.call_count)
notification = mock_emit.call_args_list[0][1]
self.assertEqual(1, self.m_notifier.info.call_count)
notification = self.m_notifier.info.call_args[1]
payload = notification['payload']
self.assertEqual("infra-optim:node0", self.m_notifier.publisher_id)
self.assertDictEqual(
{
"watcher_object.namespace": "watcher",
@@ -231,21 +241,19 @@ class TestAuditNotification(base.DbTestCase):
payload
)
@freezegun.freeze_time('2016-10-18T09:52:05.219414')
@mock.patch.object(notifications.audit.AuditDeleteNotification, '_emit')
def test_send_version_audit_delete(self, mock_emit):
goal = utils.create_test_goal(mock.Mock())
strategy = utils.create_test_strategy(mock.Mock())
def test_send_audit_delete(self):
audit = utils.create_test_audit(
mock.Mock(), state=objects.audit.State.DELETED,
goal_id=goal.id, strategy_id=strategy.id)
goal_id=self.goal.id, strategy_id=self.strategy.id)
notifications.audit.send_delete(
mock.MagicMock(), audit, 'host', 'node0')
mock.MagicMock(), audit, host='node0')
self.assertEqual(1, mock_emit.call_count)
notification = mock_emit.call_args_list[0][1]
# The 1st notification is because we created the object.
self.assertEqual(2, self.m_notifier.info.call_count)
notification = self.m_notifier.info.call_args[1]
payload = notification['payload']
self.assertEqual("infra-optim:node0", self.m_notifier.publisher_id)
self.assertDictEqual(
{
"watcher_object.namespace": "watcher",
@@ -294,22 +302,21 @@ class TestAuditNotification(base.DbTestCase):
payload
)
@freezegun.freeze_time('2016-10-18T09:52:05.219414')
@mock.patch.object(notifications.audit.AuditActionNotification, '_emit')
def test_send_audit_action(self, mock_emit):
goal = utils.create_test_goal(mock.Mock())
strategy = utils.create_test_strategy(mock.Mock())
def test_send_audit_action(self):
audit = utils.create_test_audit(
mock.Mock(), state=objects.audit.State.ONGOING,
goal_id=goal.id, strategy_id=strategy.id,
goal=goal, strategy=strategy)
goal_id=self.goal.id, strategy_id=self.strategy.id,
goal=self.goal, strategy=self.strategy)
notifications.audit.send_action_notification(
mock.MagicMock(), audit, host='node0',
action='strategy', phase='start')
self.assertEqual(1, mock_emit.call_count)
notification = mock_emit.call_args_list[0][1]
# The 1st notification is because we created the object.
self.assertEqual(2, self.m_notifier.info.call_count)
notification = self.m_notifier.info.call_args[1]
notification = self.m_notifier.info.call_args[1]
self.assertEqual("infra-optim:node0", self.m_notifier.publisher_id)
self.assertDictEqual(
{
"event_type": "audit.strategy.start",
@@ -357,21 +364,16 @@ class TestAuditNotification(base.DbTestCase):
"watcher_object.name": "AuditActionPayload",
"watcher_object.namespace": "watcher",
"watcher_object.version": "1.0"
},
"publisher_id": "infra-optim:node0"
}
},
notification
)
@freezegun.freeze_time('2016-10-18T09:52:05.219414')
@mock.patch.object(notifications.audit.AuditActionNotification, '_emit')
def test_send_audit_action_with_error(self, mock_emit):
goal = utils.create_test_goal(mock.Mock())
strategy = utils.create_test_strategy(mock.Mock())
def test_send_audit_action_with_error(self):
audit = utils.create_test_audit(
mock.Mock(), state=objects.audit.State.ONGOING,
goal_id=goal.id, strategy_id=strategy.id,
goal=goal, strategy=strategy)
goal_id=self.goal.id, strategy_id=self.strategy.id,
goal=self.goal, strategy=self.strategy)
try:
# This is to load the exception in sys.exc_info()
@@ -381,8 +383,9 @@ class TestAuditNotification(base.DbTestCase):
mock.MagicMock(), audit, host='node0',
action='strategy', priority='error', phase='error')
self.assertEqual(1, mock_emit.call_count)
notification = mock_emit.call_args_list[0][1]
self.assertEqual(1, self.m_notifier.error.call_count)
notification = self.m_notifier.error.call_args[1]
self.assertEqual("infra-optim:node0", self.m_notifier.publisher_id)
self.assertDictEqual(
{
"event_type": "audit.strategy.error",
@@ -442,8 +445,7 @@ class TestAuditNotification(base.DbTestCase):
"watcher_object.name": "AuditActionPayload",
"watcher_object.namespace": "watcher",
"watcher_object.version": "1.0"
},
"publisher_id": "infra-optim:node0"
}
},
notification
)

View File

@@ -250,7 +250,7 @@ class TestNotificationBase(testbase.TestCase):
expected_notification_fingerprints = {
'EventType': '1.1-652f407fcf72d2045d65974d23c78173',
'EventType': '1.2-633c2d32fa849d2a6f8bda3b0db88332',
'ExceptionNotification': '1.0-9b69de0724fda8310d05e18418178866',
'ExceptionPayload': '1.0-4516ae282a55fe2fd5c754967ee6248b',
'NotificationPublisher': '1.0-bbbc1402fb0e443a3eb227cc52b61545',