Add Action Notification
This patch set adds the following action notifications: - action.create - action.update - action.delete - action.execution.start - action.execution.end - action.execution.error Partially Implements: blueprint action-versioned-notifications-api Change-Id: If0bc25bfb7cb1bff3bfa2c5d5fb9ad48b0794168
This commit is contained in:
committed by
alexchadin
parent
62cb8a8d29
commit
25789c9c5a
355
watcher/tests/notifications/test_action_notification.py
Normal file
355
watcher/tests/notifications/test_action_notification.py
Normal file
@@ -0,0 +1,355 @@
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
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 TestActionNotification(base.DbTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestActionNotification, 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())
|
||||
self.audit = utils.create_test_audit(mock.Mock(),
|
||||
strategy_id=self.strategy.id)
|
||||
self.action_plan = utils.create_test_action_plan(mock.Mock())
|
||||
|
||||
def test_send_invalid_action_plan(self):
|
||||
action_plan = utils.get_test_action_plan(
|
||||
mock.Mock(), state='DOESNOTMATTER', audit_id=1)
|
||||
|
||||
self.assertRaises(
|
||||
exception.InvalidActionPlan,
|
||||
notifications.action_plan.send_update,
|
||||
mock.MagicMock(), action_plan, host='node0')
|
||||
|
||||
def test_send_action_update(self):
|
||||
action = utils.create_test_action(
|
||||
mock.Mock(), state=objects.action.State.ONGOING,
|
||||
action_type='nop', input_parameters={'param1': 1, 'param2': 2},
|
||||
parents=[], action_plan_id=self.action_plan.id)
|
||||
notifications.action.send_update(
|
||||
mock.MagicMock(), action, host='node0',
|
||||
old_state=objects.action.State.PENDING)
|
||||
|
||||
# The 1st notification is because we created the object.
|
||||
# The 2nd notification is because we created the action plan object.
|
||||
self.assertEqual(4, 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',
|
||||
'watcher_object.version': '1.0',
|
||||
'watcher_object.name': 'ActionUpdatePayload',
|
||||
'watcher_object.data': {
|
||||
'uuid': '10a47dd1-4874-4298-91cf-eff046dbdb8d',
|
||||
'input_parameters': {
|
||||
'param2': 2,
|
||||
'param1': 1
|
||||
},
|
||||
'created_at': '2016-10-18T09:52:05Z',
|
||||
'updated_at': None,
|
||||
'state_update': {
|
||||
'watcher_object.namespace': 'watcher',
|
||||
'watcher_object.version': '1.0',
|
||||
'watcher_object.name': 'ActionStateUpdatePayload',
|
||||
'watcher_object.data': {
|
||||
'old_state': 'PENDING',
|
||||
'state': 'ONGOING'
|
||||
}
|
||||
},
|
||||
'state': 'ONGOING',
|
||||
'action_plan': {
|
||||
'watcher_object.namespace': 'watcher',
|
||||
'watcher_object.version': '1.0',
|
||||
'watcher_object.name': 'TerseActionPlanPayload',
|
||||
'watcher_object.data': {
|
||||
'uuid': '76be87bd-3422-43f9-93a0-e85a577e3061',
|
||||
'global_efficacy': {},
|
||||
'created_at': '2016-10-18T09:52:05Z',
|
||||
'updated_at': None,
|
||||
'state': 'ONGOING',
|
||||
'audit_uuid': '10a47dd1-4874-4298'
|
||||
'-91cf-eff046dbdb8d',
|
||||
'strategy_uuid': 'cb3d0b58-4415-4d90'
|
||||
'-b75b-1e96878730e3',
|
||||
'deleted_at': None
|
||||
}
|
||||
},
|
||||
'parents': [],
|
||||
'action_type': 'nop',
|
||||
'deleted_at': None
|
||||
}
|
||||
},
|
||||
payload
|
||||
)
|
||||
|
||||
def test_send_action_plan_create(self):
|
||||
action = utils.create_test_action(
|
||||
mock.Mock(), state=objects.action.State.PENDING,
|
||||
action_type='nop', input_parameters={'param1': 1, 'param2': 2},
|
||||
parents=[], action_plan_id=self.action_plan.id)
|
||||
notifications.action.send_create(mock.MagicMock(), action,
|
||||
host='node0')
|
||||
|
||||
self.assertEqual(4, 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',
|
||||
'watcher_object.version': '1.0',
|
||||
'watcher_object.name': 'ActionCreatePayload',
|
||||
'watcher_object.data': {
|
||||
'uuid': '10a47dd1-4874-4298-91cf-eff046dbdb8d',
|
||||
'input_parameters': {
|
||||
'param2': 2,
|
||||
'param1': 1
|
||||
},
|
||||
'created_at': '2016-10-18T09:52:05Z',
|
||||
'updated_at': None,
|
||||
'state': 'PENDING',
|
||||
'action_plan': {
|
||||
'watcher_object.namespace': 'watcher',
|
||||
'watcher_object.version': '1.0',
|
||||
'watcher_object.name': 'TerseActionPlanPayload',
|
||||
'watcher_object.data': {
|
||||
'uuid': '76be87bd-3422-43f9-93a0-e85a577e3061',
|
||||
'global_efficacy': {},
|
||||
'created_at': '2016-10-18T09:52:05Z',
|
||||
'updated_at': None,
|
||||
'state': 'ONGOING',
|
||||
'audit_uuid': '10a47dd1-4874-4298'
|
||||
'-91cf-eff046dbdb8d',
|
||||
'strategy_uuid': 'cb3d0b58-4415-4d90'
|
||||
'-b75b-1e96878730e3',
|
||||
'deleted_at': None
|
||||
}
|
||||
},
|
||||
'parents': [],
|
||||
'action_type': 'nop',
|
||||
'deleted_at': None
|
||||
}
|
||||
},
|
||||
payload
|
||||
)
|
||||
|
||||
def test_send_action_delete(self):
|
||||
action = utils.create_test_action(
|
||||
mock.Mock(), state=objects.action.State.DELETED,
|
||||
action_type='nop', input_parameters={'param1': 1, 'param2': 2},
|
||||
parents=[], action_plan_id=self.action_plan.id)
|
||||
notifications.action.send_delete(mock.MagicMock(), action,
|
||||
host='node0')
|
||||
|
||||
# The 1st notification is because we created the audit object.
|
||||
# The 2nd notification is because we created the action plan object.
|
||||
self.assertEqual(4, 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',
|
||||
'watcher_object.version': '1.0',
|
||||
'watcher_object.name': 'ActionDeletePayload',
|
||||
'watcher_object.data': {
|
||||
'uuid': '10a47dd1-4874-4298-91cf-eff046dbdb8d',
|
||||
'input_parameters': {
|
||||
'param2': 2,
|
||||
'param1': 1
|
||||
},
|
||||
'created_at': '2016-10-18T09:52:05Z',
|
||||
'updated_at': None,
|
||||
'state': 'DELETED',
|
||||
'action_plan': {
|
||||
'watcher_object.namespace': 'watcher',
|
||||
'watcher_object.version': '1.0',
|
||||
'watcher_object.name': 'TerseActionPlanPayload',
|
||||
'watcher_object.data': {
|
||||
'uuid': '76be87bd-3422-43f9-93a0-e85a577e3061',
|
||||
'global_efficacy': {},
|
||||
'created_at': '2016-10-18T09:52:05Z',
|
||||
'updated_at': None,
|
||||
'state': 'ONGOING',
|
||||
'audit_uuid': '10a47dd1-4874-4298'
|
||||
'-91cf-eff046dbdb8d',
|
||||
'strategy_uuid': 'cb3d0b58-4415-4d90'
|
||||
'-b75b-1e96878730e3',
|
||||
'deleted_at': None
|
||||
}
|
||||
},
|
||||
'parents': [],
|
||||
'action_type': 'nop',
|
||||
'deleted_at': None
|
||||
}
|
||||
},
|
||||
payload
|
||||
)
|
||||
|
||||
def test_send_action_execution(self):
|
||||
action = utils.create_test_action(
|
||||
mock.Mock(), state=objects.action.State.PENDING,
|
||||
action_type='nop', input_parameters={'param1': 1, 'param2': 2},
|
||||
parents=[], action_plan_id=self.action_plan.id)
|
||||
notifications.action.send_execution_notification(
|
||||
mock.MagicMock(), action, 'execution', phase='start', host='node0')
|
||||
|
||||
# The 1st notification is because we created the audit object.
|
||||
# The 2nd notification is because we created the action plan object.
|
||||
self.assertEqual(4, self.m_notifier.info.call_count)
|
||||
notification = self.m_notifier.info.call_args[1]
|
||||
|
||||
self.assertEqual("infra-optim:node0", self.m_notifier.publisher_id)
|
||||
self.assertDictEqual(
|
||||
{
|
||||
'event_type': 'action.execution.start',
|
||||
'payload': {
|
||||
'watcher_object.namespace': 'watcher',
|
||||
'watcher_object.version': '1.0',
|
||||
'watcher_object.name': 'ActionExecutionPayload',
|
||||
'watcher_object.data': {
|
||||
'uuid': '10a47dd1-4874-4298-91cf-eff046dbdb8d',
|
||||
'input_parameters': {
|
||||
'param2': 2,
|
||||
'param1': 1
|
||||
},
|
||||
'created_at': '2016-10-18T09:52:05Z',
|
||||
'fault': None,
|
||||
'updated_at': None,
|
||||
'state': 'PENDING',
|
||||
'action_plan': {
|
||||
'watcher_object.namespace': 'watcher',
|
||||
'watcher_object.version': '1.0',
|
||||
'watcher_object.name': 'TerseActionPlanPayload',
|
||||
'watcher_object.data': {
|
||||
'uuid': '76be87bd-3422-43f9-93a0-e85a577e3061',
|
||||
'global_efficacy': {},
|
||||
'created_at': '2016-10-18T09:52:05Z',
|
||||
'updated_at': None,
|
||||
'state': 'ONGOING',
|
||||
'audit_uuid': '10a47dd1-4874-4298'
|
||||
'-91cf-eff046dbdb8d',
|
||||
'strategy_uuid': 'cb3d0b58-4415-4d90'
|
||||
'-b75b-1e96878730e3',
|
||||
'deleted_at': None
|
||||
}
|
||||
},
|
||||
'parents': [],
|
||||
'action_type': 'nop',
|
||||
'deleted_at': None
|
||||
}
|
||||
}
|
||||
},
|
||||
notification
|
||||
)
|
||||
|
||||
def test_send_action_execution_with_error(self):
|
||||
action = utils.create_test_action(
|
||||
mock.Mock(), state=objects.action.State.FAILED,
|
||||
action_type='nop', input_parameters={'param1': 1, 'param2': 2},
|
||||
parents=[], action_plan_id=self.action_plan.id)
|
||||
|
||||
try:
|
||||
# This is to load the exception in sys.exc_info()
|
||||
raise exception.WatcherException("TEST")
|
||||
except exception.WatcherException:
|
||||
notifications.action.send_execution_notification(
|
||||
mock.MagicMock(), action, 'execution', phase='error',
|
||||
host='node0', priority='error')
|
||||
|
||||
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': 'action.execution.error',
|
||||
'payload': {
|
||||
'watcher_object.namespace': 'watcher',
|
||||
'watcher_object.version': '1.0',
|
||||
'watcher_object.name': 'ActionExecutionPayload',
|
||||
'watcher_object.data': {
|
||||
'uuid': '10a47dd1-4874-4298-91cf-eff046dbdb8d',
|
||||
'input_parameters': {
|
||||
'param2': 2,
|
||||
'param1': 1
|
||||
},
|
||||
'created_at': '2016-10-18T09:52:05Z',
|
||||
'fault': {
|
||||
'watcher_object.data': {
|
||||
'exception': u'WatcherException',
|
||||
'exception_message': u'TEST',
|
||||
'function_name': (
|
||||
'test_send_action_execution_with_error'),
|
||||
'module_name': (
|
||||
'watcher.tests.notifications.'
|
||||
'test_action_notification')
|
||||
},
|
||||
'watcher_object.name': 'ExceptionPayload',
|
||||
'watcher_object.namespace': 'watcher',
|
||||
'watcher_object.version': '1.0'
|
||||
},
|
||||
'updated_at': None,
|
||||
'state': 'FAILED',
|
||||
'action_plan': {
|
||||
'watcher_object.namespace': 'watcher',
|
||||
'watcher_object.version': '1.0',
|
||||
'watcher_object.name': 'TerseActionPlanPayload',
|
||||
'watcher_object.data': {
|
||||
'uuid': '76be87bd-3422-43f9-93a0-e85a577e3061',
|
||||
'global_efficacy': {},
|
||||
'created_at': '2016-10-18T09:52:05Z',
|
||||
'updated_at': None,
|
||||
'state': 'ONGOING',
|
||||
'audit_uuid': '10a47dd1-4874-4298'
|
||||
'-91cf-eff046dbdb8d',
|
||||
'strategy_uuid': 'cb3d0b58-4415-4d90'
|
||||
'-b75b-1e96878730e3',
|
||||
'deleted_at': None
|
||||
}
|
||||
},
|
||||
'parents': [],
|
||||
'action_type': 'nop',
|
||||
'deleted_at': None
|
||||
}
|
||||
}
|
||||
},
|
||||
notification
|
||||
)
|
||||
@@ -267,16 +267,27 @@ expected_notification_fingerprints = {
|
||||
'AuditActionPayload': '1.0-09f5d005f94ba9e5f6b9200170332c52',
|
||||
'GoalPayload': '1.0-fa1fecb8b01dd047eef808ded4d50d1a',
|
||||
'StrategyPayload': '1.0-94f01c137b083ac236ae82573c1fcfc1',
|
||||
'ActionPlanActionPayload': '1.0-34871caf18e9b43a28899953c1c9733a',
|
||||
'ActionPlanActionPayload': '1.0-d9f134708e06cf2ff2d3b8d522ac2aa8',
|
||||
'ActionPlanCreateNotification': '1.0-9b69de0724fda8310d05e18418178866',
|
||||
'ActionPlanCreatePayload': '1.0-ffc3087acd73351b14f3dcc30e105027',
|
||||
'ActionPlanCreatePayload': '1.0-23d0abbfa43acfd49b2b3097770efdce',
|
||||
'ActionPlanDeleteNotification': '1.0-9b69de0724fda8310d05e18418178866',
|
||||
'ActionPlanDeletePayload': '1.0-ffc3087acd73351b14f3dcc30e105027',
|
||||
'ActionPlanPayload': '1.0-ffc3087acd73351b14f3dcc30e105027',
|
||||
'ActionPlanDeletePayload': '1.0-23d0abbfa43acfd49b2b3097770efdce',
|
||||
'ActionPlanPayload': '1.0-23d0abbfa43acfd49b2b3097770efdce',
|
||||
'ActionPlanStateUpdatePayload': '1.0-1a1b606bf14a2c468800c2b010801ce5',
|
||||
'ActionPlanUpdateNotification': '1.0-9b69de0724fda8310d05e18418178866',
|
||||
'ActionPlanUpdatePayload': '1.0-7912a45fe53775c721f42aa87f06a023',
|
||||
'ActionPlanUpdatePayload': '1.0-3e1a348a0579c6c43c1c3d7257e3f26b',
|
||||
'ActionPlanActionNotification': '1.0-9b69de0724fda8310d05e18418178866',
|
||||
'ActionCreateNotification': '1.0-9b69de0724fda8310d05e18418178866',
|
||||
'ActionCreatePayload': '1.0-519b93b7450319d8928b4b6e6362df31',
|
||||
'ActionDeleteNotification': '1.0-9b69de0724fda8310d05e18418178866',
|
||||
'ActionDeletePayload': '1.0-519b93b7450319d8928b4b6e6362df31',
|
||||
'ActionExecutionNotification': '1.0-9b69de0724fda8310d05e18418178866',
|
||||
'ActionExecutionPayload': '1.0-bff9f820a2abf7bb6d7027b7450157df',
|
||||
'ActionPayload': '1.0-519b93b7450319d8928b4b6e6362df31',
|
||||
'ActionStateUpdatePayload': '1.0-1a1b606bf14a2c468800c2b010801ce5',
|
||||
'ActionUpdateNotification': '1.0-9b69de0724fda8310d05e18418178866',
|
||||
'ActionUpdatePayload': '1.0-03306c7e7f4d49ac328c261eff6b30b8',
|
||||
'TerseActionPlanPayload': '1.0-42bf7a5585cc111a9a4dbc008a04c67e',
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user