Notification Cancel Action Plan
This patch adds Notifications for cancel action plan operation. Change-Id: I5a89a80729349e3db43ca35ff9fbe8579e86b3b1 Implements: blueprint notifications-actionplan-cancel
This commit is contained in:
41
doc/notification_samples/action-cancel-end.json
Normal file
41
doc/notification_samples/action-cancel-end.json
Normal file
@@ -0,0 +1,41 @@
|
||||
{
|
||||
"priority": "INFO",
|
||||
"payload": {
|
||||
"watcher_object.namespace": "watcher",
|
||||
"watcher_object.version": "1.0",
|
||||
"watcher_object.name": "ActionCancelPayload",
|
||||
"watcher_object.data": {
|
||||
"uuid": "10a47dd1-4874-4298-91cf-eff046dbdb8d",
|
||||
"input_parameters": {
|
||||
"param2": 2,
|
||||
"param1": 1
|
||||
},
|
||||
"fault": null,
|
||||
"created_at": "2016-10-18T09:52:05Z",
|
||||
"updated_at": null,
|
||||
"state": "CANCELLED",
|
||||
"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": null,
|
||||
"state": "CANCELLING",
|
||||
"audit_uuid": "10a47dd1-4874-4298-91cf-eff046dbdb8d",
|
||||
"strategy_uuid": "cb3d0b58-4415-4d90-b75b-1e96878730e3",
|
||||
"deleted_at": null
|
||||
}
|
||||
},
|
||||
"parents": [],
|
||||
"action_type": "nop",
|
||||
"deleted_at": null
|
||||
}
|
||||
},
|
||||
"event_type": "action.cancel.end",
|
||||
"publisher_id": "infra-optim:node0",
|
||||
"timestamp": "2017-01-01 00:00:00.000000",
|
||||
"message_id": "530b409c-9b6b-459b-8f08-f93dbfeb4d41"
|
||||
}
|
51
doc/notification_samples/action-cancel-error.json
Normal file
51
doc/notification_samples/action-cancel-error.json
Normal file
@@ -0,0 +1,51 @@
|
||||
{
|
||||
"priority": "ERROR",
|
||||
"payload": {
|
||||
"watcher_object.namespace": "watcher",
|
||||
"watcher_object.version": "1.0",
|
||||
"watcher_object.name": "ActionCancelPayload",
|
||||
"watcher_object.data": {
|
||||
"uuid": "10a47dd1-4874-4298-91cf-eff046dbdb8d",
|
||||
"input_parameters": {
|
||||
"param2": 2,
|
||||
"param1": 1
|
||||
},
|
||||
"fault": {
|
||||
"watcher_object.namespace": "watcher",
|
||||
"watcher_object.version": "1.0",
|
||||
"watcher_object.name": "ExceptionPayload",
|
||||
"watcher_object.data": {
|
||||
"module_name": "watcher.tests.notifications.test_action_notification",
|
||||
"exception": "WatcherException",
|
||||
"exception_message": "TEST",
|
||||
"function_name": "test_send_action_cancel_with_error"
|
||||
}
|
||||
},
|
||||
"created_at": "2016-10-18T09:52:05Z",
|
||||
"updated_at": null,
|
||||
"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": null,
|
||||
"state": "CANCELLING",
|
||||
"audit_uuid": "10a47dd1-4874-4298-91cf-eff046dbdb8d",
|
||||
"strategy_uuid": "cb3d0b58-4415-4d90-b75b-1e96878730e3",
|
||||
"deleted_at": null
|
||||
}
|
||||
},
|
||||
"parents": [],
|
||||
"action_type": "nop",
|
||||
"deleted_at": null
|
||||
}
|
||||
},
|
||||
"event_type": "action.cancel.error",
|
||||
"publisher_id": "infra-optim:node0",
|
||||
"timestamp": "2017-01-01 00:00:00.000000",
|
||||
"message_id": "530b409c-9b6b-459b-8f08-f93dbfeb4d41"
|
||||
}
|
41
doc/notification_samples/action-cancel-start.json
Normal file
41
doc/notification_samples/action-cancel-start.json
Normal file
@@ -0,0 +1,41 @@
|
||||
{
|
||||
"priority": "INFO",
|
||||
"payload": {
|
||||
"watcher_object.namespace": "watcher",
|
||||
"watcher_object.version": "1.0",
|
||||
"watcher_object.name": "ActionCancelPayload",
|
||||
"watcher_object.data": {
|
||||
"uuid": "10a47dd1-4874-4298-91cf-eff046dbdb8d",
|
||||
"input_parameters": {
|
||||
"param2": 2,
|
||||
"param1": 1
|
||||
},
|
||||
"fault": null,
|
||||
"created_at": "2016-10-18T09:52:05Z",
|
||||
"updated_at": null,
|
||||
"state": "CANCELLING",
|
||||
"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": null,
|
||||
"state": "CANCELLING",
|
||||
"audit_uuid": "10a47dd1-4874-4298-91cf-eff046dbdb8d",
|
||||
"strategy_uuid": "cb3d0b58-4415-4d90-b75b-1e96878730e3",
|
||||
"deleted_at": null
|
||||
}
|
||||
},
|
||||
"parents": [],
|
||||
"action_type": "nop",
|
||||
"deleted_at": null
|
||||
}
|
||||
},
|
||||
"event_type": "action.cancel.start",
|
||||
"publisher_id": "infra-optim:node0",
|
||||
"timestamp": "2017-01-01 00:00:00.000000",
|
||||
"message_id": "530b409c-9b6b-459b-8f08-f93dbfeb4d41"
|
||||
}
|
55
doc/notification_samples/action_plan-cancel-end.json
Normal file
55
doc/notification_samples/action_plan-cancel-end.json
Normal file
@@ -0,0 +1,55 @@
|
||||
{
|
||||
"event_type": "action_plan.cancel.end",
|
||||
"payload": {
|
||||
"watcher_object.namespace": "watcher",
|
||||
"watcher_object.name": "ActionPlanCancelPayload",
|
||||
"watcher_object.version": "1.0",
|
||||
"watcher_object.data": {
|
||||
"created_at": "2016-10-18T09:52:05Z",
|
||||
"deleted_at": null,
|
||||
"audit_uuid": "10a47dd1-4874-4298-91cf-eff046dbdb8d",
|
||||
"audit": {
|
||||
"watcher_object.namespace": "watcher",
|
||||
"watcher_object.name": "TerseAuditPayload",
|
||||
"watcher_object.version": "1.0",
|
||||
"watcher_object.data": {
|
||||
"created_at": "2016-10-18T09:52:05Z",
|
||||
"deleted_at": null,
|
||||
"uuid": "10a47dd1-4874-4298-91cf-eff046dbdb8d",
|
||||
"goal_uuid": "bc830f84-8ae3-4fc6-8bc6-e3dd15e8b49a",
|
||||
"strategy_uuid": "75234dfe-87e3-4f11-a0e0-3c3305d86a39",
|
||||
"scope": [],
|
||||
"audit_type": "ONESHOT",
|
||||
"state": "SUCCEEDED",
|
||||
"parameters": {},
|
||||
"interval": null,
|
||||
"updated_at": null
|
||||
}
|
||||
},
|
||||
"uuid": "76be87bd-3422-43f9-93a0-e85a577e3061",
|
||||
"fault": null,
|
||||
"state": "CANCELLED",
|
||||
"global_efficacy": {},
|
||||
"strategy_uuid": "cb3d0b58-4415-4d90-b75b-1e96878730e3",
|
||||
"strategy": {
|
||||
"watcher_object.namespace": "watcher",
|
||||
"watcher_object.name": "StrategyPayload",
|
||||
"watcher_object.version": "1.0",
|
||||
"watcher_object.data": {
|
||||
"created_at": "2016-10-18T09:52:05Z",
|
||||
"deleted_at": null,
|
||||
"name": "TEST",
|
||||
"uuid": "cb3d0b58-4415-4d90-b75b-1e96878730e3",
|
||||
"parameters_spec": {},
|
||||
"display_name": "test strategy",
|
||||
"updated_at": null
|
||||
}
|
||||
},
|
||||
"updated_at": null
|
||||
}
|
||||
},
|
||||
"priority": "INFO",
|
||||
"message_id": "3984dc2b-8aef-462b-a220-8ae04237a56e",
|
||||
"timestamp": "2016-10-18 09:52:05.219414",
|
||||
"publisher_id": "infra-optim:node0"
|
||||
}
|
65
doc/notification_samples/action_plan-cancel-error.json
Normal file
65
doc/notification_samples/action_plan-cancel-error.json
Normal file
@@ -0,0 +1,65 @@
|
||||
{
|
||||
"event_type": "action_plan.cancel.error",
|
||||
"publisher_id": "infra-optim:node0",
|
||||
"priority": "ERROR",
|
||||
"message_id": "9a45c5ae-0e21-4300-8fa0-5555d52a66d9",
|
||||
"payload": {
|
||||
"watcher_object.version": "1.0",
|
||||
"watcher_object.namespace": "watcher",
|
||||
"watcher_object.name": "ActionPlanCancelPayload",
|
||||
"watcher_object.data": {
|
||||
"fault": {
|
||||
"watcher_object.version": "1.0",
|
||||
"watcher_object.namespace": "watcher",
|
||||
"watcher_object.name": "ExceptionPayload",
|
||||
"watcher_object.data": {
|
||||
"exception_message": "TEST",
|
||||
"module_name": "watcher.tests.notifications.test_action_plan_notification",
|
||||
"function_name": "test_send_action_plan_cancel_with_error",
|
||||
"exception": "WatcherException"
|
||||
}
|
||||
},
|
||||
"uuid": "76be87bd-3422-43f9-93a0-e85a577e3061",
|
||||
"created_at": "2016-10-18T09:52:05Z",
|
||||
"strategy_uuid": "cb3d0b58-4415-4d90-b75b-1e96878730e3",
|
||||
"strategy": {
|
||||
"watcher_object.version": "1.0",
|
||||
"watcher_object.namespace": "watcher",
|
||||
"watcher_object.name": "StrategyPayload",
|
||||
"watcher_object.data": {
|
||||
"uuid": "cb3d0b58-4415-4d90-b75b-1e96878730e3",
|
||||
"created_at": "2016-10-18T09:52:05Z",
|
||||
"name": "TEST",
|
||||
"updated_at": null,
|
||||
"display_name": "test strategy",
|
||||
"parameters_spec": {},
|
||||
"deleted_at": null
|
||||
}
|
||||
},
|
||||
"updated_at": null,
|
||||
"deleted_at": null,
|
||||
"audit_uuid": "10a47dd1-4874-4298-91cf-eff046dbdb8d",
|
||||
"audit": {
|
||||
"watcher_object.version": "1.0",
|
||||
"watcher_object.namespace": "watcher",
|
||||
"watcher_object.name": "TerseAuditPayload",
|
||||
"watcher_object.data": {
|
||||
"parameters": {},
|
||||
"uuid": "10a47dd1-4874-4298-91cf-eff046dbdb8d",
|
||||
"goal_uuid": "bc830f84-8ae3-4fc6-8bc6-e3dd15e8b49a",
|
||||
"strategy_uuid": "75234dfe-87e3-4f11-a0e0-3c3305d86a39",
|
||||
"created_at": "2016-10-18T09:52:05Z",
|
||||
"scope": [],
|
||||
"updated_at": null,
|
||||
"audit_type": "ONESHOT",
|
||||
"interval": null,
|
||||
"deleted_at": null,
|
||||
"state": "SUCCEEDED"
|
||||
}
|
||||
},
|
||||
"global_efficacy": {},
|
||||
"state": "CANCELLING"
|
||||
}
|
||||
},
|
||||
"timestamp": "2016-10-18 09:52:05.219414"
|
||||
}
|
55
doc/notification_samples/action_plan-cancel-start.json
Normal file
55
doc/notification_samples/action_plan-cancel-start.json
Normal file
@@ -0,0 +1,55 @@
|
||||
{
|
||||
"event_type": "action_plan.cancel.start",
|
||||
"payload": {
|
||||
"watcher_object.namespace": "watcher",
|
||||
"watcher_object.name": "ActionPlanCancelPayload",
|
||||
"watcher_object.version": "1.0",
|
||||
"watcher_object.data": {
|
||||
"created_at": "2016-10-18T09:52:05Z",
|
||||
"deleted_at": null,
|
||||
"audit_uuid": "10a47dd1-4874-4298-91cf-eff046dbdb8d",
|
||||
"audit": {
|
||||
"watcher_object.namespace": "watcher",
|
||||
"watcher_object.name": "TerseAuditPayload",
|
||||
"watcher_object.version": "1.0",
|
||||
"watcher_object.data": {
|
||||
"created_at": "2016-10-18T09:52:05Z",
|
||||
"deleted_at": null,
|
||||
"uuid": "10a47dd1-4874-4298-91cf-eff046dbdb8d",
|
||||
"goal_uuid": "bc830f84-8ae3-4fc6-8bc6-e3dd15e8b49a",
|
||||
"strategy_uuid": "75234dfe-87e3-4f11-a0e0-3c3305d86a39",
|
||||
"scope": [],
|
||||
"audit_type": "ONESHOT",
|
||||
"state": "SUCCEEDED",
|
||||
"parameters": {},
|
||||
"interval": null,
|
||||
"updated_at": null
|
||||
}
|
||||
},
|
||||
"uuid": "76be87bd-3422-43f9-93a0-e85a577e3061",
|
||||
"fault": null,
|
||||
"state": "CANCELLING",
|
||||
"global_efficacy": {},
|
||||
"strategy_uuid": "cb3d0b58-4415-4d90-b75b-1e96878730e3",
|
||||
"strategy": {
|
||||
"watcher_object.namespace": "watcher",
|
||||
"watcher_object.name": "StrategyPayload",
|
||||
"watcher_object.version": "1.0",
|
||||
"watcher_object.data": {
|
||||
"created_at": "2016-10-18T09:52:05Z",
|
||||
"deleted_at": null,
|
||||
"name": "TEST",
|
||||
"uuid": "cb3d0b58-4415-4d90-b75b-1e96878730e3",
|
||||
"parameters_spec": {},
|
||||
"display_name": "test strategy",
|
||||
"updated_at": null
|
||||
}
|
||||
},
|
||||
"updated_at": null
|
||||
}
|
||||
},
|
||||
"priority": "INFO",
|
||||
"message_id": "3984dc2b-8aef-462b-a220-8ae04237a56e",
|
||||
"timestamp": "2016-10-18 09:52:05.219414",
|
||||
"publisher_id": "infra-optim:node0"
|
||||
}
|
@@ -54,6 +54,7 @@ class DefaultActionPlanHandler(base.BaseActionPlanHandler):
|
||||
applier.execute(self.action_plan_uuid)
|
||||
|
||||
action_plan.state = objects.action_plan.State.SUCCEEDED
|
||||
action_plan.save()
|
||||
notifications.action_plan.send_action_notification(
|
||||
self.ctx, action_plan,
|
||||
action=fields.NotificationAction.EXECUTION,
|
||||
@@ -63,17 +64,32 @@ class DefaultActionPlanHandler(base.BaseActionPlanHandler):
|
||||
LOG.exception(e)
|
||||
action_plan.state = objects.action_plan.State.CANCELLED
|
||||
self._update_action_from_pending_to_cancelled()
|
||||
action_plan.save()
|
||||
notifications.action_plan.send_cancel_notification(
|
||||
self.ctx, action_plan,
|
||||
action=fields.NotificationAction.CANCEL,
|
||||
phase=fields.NotificationPhase.END)
|
||||
|
||||
except Exception as e:
|
||||
LOG.exception(e)
|
||||
action_plan.state = objects.action_plan.State.FAILED
|
||||
notifications.action_plan.send_action_notification(
|
||||
self.ctx, action_plan,
|
||||
action=fields.NotificationAction.EXECUTION,
|
||||
priority=fields.NotificationPriority.ERROR,
|
||||
phase=fields.NotificationPhase.ERROR)
|
||||
finally:
|
||||
action_plan.save()
|
||||
action_plan = objects.ActionPlan.get_by_uuid(
|
||||
self.ctx, self.action_plan_uuid, eager=True)
|
||||
if action_plan.state == objects.action_plan.State.CANCELLING:
|
||||
action_plan.state = objects.action_plan.State.FAILED
|
||||
action_plan.save()
|
||||
notifications.action_plan.send_cancel_notification(
|
||||
self.ctx, action_plan,
|
||||
action=fields.NotificationAction.CANCEL,
|
||||
priority=fields.NotificationPriority.ERROR,
|
||||
phase=fields.NotificationPhase.ERROR)
|
||||
else:
|
||||
action_plan.state = objects.action_plan.State.FAILED
|
||||
action_plan.save()
|
||||
notifications.action_plan.send_action_notification(
|
||||
self.ctx, action_plan,
|
||||
action=fields.NotificationAction.EXECUTION,
|
||||
priority=fields.NotificationPriority.ERROR,
|
||||
phase=fields.NotificationPhase.ERROR)
|
||||
|
||||
def _update_action_from_pending_to_cancelled(self):
|
||||
filters = {'action_plan_uuid': self.action_plan_uuid,
|
||||
|
@@ -57,6 +57,7 @@ class BaseWorkFlowEngine(loadable.Loadable):
|
||||
self._applier_manager = applier_manager
|
||||
self._action_factory = factory.ActionFactory()
|
||||
self._osc = None
|
||||
self._is_notified = False
|
||||
|
||||
@classmethod
|
||||
def get_config_opts(cls):
|
||||
@@ -92,6 +93,17 @@ class BaseWorkFlowEngine(loadable.Loadable):
|
||||
db_action.save()
|
||||
return db_action
|
||||
|
||||
def notify_cancel_start(self, action_plan_uuid):
|
||||
action_plan = objects.ActionPlan.get_by_uuid(self.context,
|
||||
action_plan_uuid,
|
||||
eager=True)
|
||||
if not self._is_notified:
|
||||
self._is_notified = True
|
||||
notifications.action_plan.send_cancel_notification(
|
||||
self._context, action_plan,
|
||||
action=fields.NotificationAction.CANCEL,
|
||||
phase=fields.NotificationPhase.START)
|
||||
|
||||
@abc.abstractmethod
|
||||
def execute(self, actions):
|
||||
raise NotImplementedError()
|
||||
@@ -157,6 +169,7 @@ class BaseTaskFlowActionContainer(flow_task.Task):
|
||||
fields.NotificationPhase.START)
|
||||
except exception.ActionPlanCancelled as e:
|
||||
LOG.exception(e)
|
||||
self.engine.notify_cancel_start(action_plan.uuid)
|
||||
raise
|
||||
except Exception as e:
|
||||
LOG.exception(e)
|
||||
@@ -218,6 +231,7 @@ class BaseTaskFlowActionContainer(flow_task.Task):
|
||||
# taskflow will call revert for the action,
|
||||
# we will redirect it to abort.
|
||||
except eventlet.greenlet.GreenletExit:
|
||||
self.engine.notify_cancel_start(action_plan_object.uuid)
|
||||
raise exception.ActionPlanCancelled(uuid=action_plan_object.uuid)
|
||||
|
||||
except Exception as e:
|
||||
@@ -249,15 +263,42 @@ class BaseTaskFlowActionContainer(flow_task.Task):
|
||||
|
||||
action_object = objects.Action.get_by_uuid(
|
||||
self.engine.context, self._db_action.uuid, eager=True)
|
||||
if action_object.state == objects.action.State.ONGOING:
|
||||
action_object.state = objects.action.State.CANCELLING
|
||||
try:
|
||||
if action_object.state == objects.action.State.ONGOING:
|
||||
action_object.state = objects.action.State.CANCELLING
|
||||
action_object.save()
|
||||
notifications.action.send_cancel_notification(
|
||||
self.engine.context, action_object,
|
||||
fields.NotificationAction.CANCEL,
|
||||
fields.NotificationPhase.START)
|
||||
action_object = self.abort()
|
||||
|
||||
notifications.action.send_cancel_notification(
|
||||
self.engine.context, action_object,
|
||||
fields.NotificationAction.CANCEL,
|
||||
fields.NotificationPhase.END)
|
||||
|
||||
if action_object.state == objects.action.State.PENDING:
|
||||
notifications.action.send_cancel_notification(
|
||||
self.engine.context, action_object,
|
||||
fields.NotificationAction.CANCEL,
|
||||
fields.NotificationPhase.START)
|
||||
action_object.state = objects.action.State.CANCELLED
|
||||
action_object.save()
|
||||
notifications.action.send_cancel_notification(
|
||||
self.engine.context, action_object,
|
||||
fields.NotificationAction.CANCEL,
|
||||
fields.NotificationPhase.END)
|
||||
|
||||
except Exception as e:
|
||||
LOG.exception(e)
|
||||
action_object.state = objects.action.State.FAILED
|
||||
action_object.save()
|
||||
self.abort()
|
||||
elif action_object.state == objects.action.State.PENDING:
|
||||
action_object.state = objects.action.State.CANCELLED
|
||||
action_object.save()
|
||||
else:
|
||||
pass
|
||||
notifications.action.send_cancel_notification(
|
||||
self.engine.context, action_object,
|
||||
fields.NotificationAction.CANCEL,
|
||||
fields.NotificationPhase.ERROR,
|
||||
priority=fields.NotificationPriority.ERROR)
|
||||
|
||||
def abort(self, *args, **kwargs):
|
||||
self.do_abort(*args, **kwargs)
|
||||
return self.do_abort(*args, **kwargs)
|
||||
|
@@ -120,6 +120,21 @@ class ActionExecutionPayload(ActionPayload):
|
||||
**kwargs)
|
||||
|
||||
|
||||
@base.WatcherObjectRegistry.register_notification
|
||||
class ActionCancelPayload(ActionPayload):
|
||||
# Version 1.0: Initial version
|
||||
VERSION = '1.0'
|
||||
fields = {
|
||||
'fault': wfields.ObjectField('ExceptionPayload', nullable=True),
|
||||
}
|
||||
|
||||
def __init__(self, action, action_plan, **kwargs):
|
||||
super(ActionCancelPayload, self).__init__(
|
||||
action=action,
|
||||
action_plan=action_plan,
|
||||
**kwargs)
|
||||
|
||||
|
||||
@base.WatcherObjectRegistry.register_notification
|
||||
class ActionDeletePayload(ActionPayload):
|
||||
# Version 1.0: Initial version
|
||||
@@ -178,6 +193,19 @@ class ActionDeleteNotification(notificationbase.NotificationBase):
|
||||
}
|
||||
|
||||
|
||||
@notificationbase.notification_sample('action-cancel-error.json')
|
||||
@notificationbase.notification_sample('action-cancel-end.json')
|
||||
@notificationbase.notification_sample('action-cancel-start.json')
|
||||
@base.WatcherObjectRegistry.register_notification
|
||||
class ActionCancelNotification(notificationbase.NotificationBase):
|
||||
# Version 1.0: Initial version
|
||||
VERSION = '1.0'
|
||||
|
||||
fields = {
|
||||
'payload': wfields.ObjectField('ActionCancelPayload')
|
||||
}
|
||||
|
||||
|
||||
def _get_action_plan_payload(action):
|
||||
action_plan = None
|
||||
strategy_uuid = None
|
||||
@@ -300,3 +328,33 @@ def send_execution_notification(context, action, notification_action, phase,
|
||||
payload=versioned_payload)
|
||||
|
||||
notification.emit(context)
|
||||
|
||||
|
||||
def send_cancel_notification(context, action, notification_action, phase,
|
||||
priority=wfields.NotificationPriority.INFO,
|
||||
service='infra-optim', host=None):
|
||||
"""Emit an action cancel notification."""
|
||||
action_plan_payload = _get_action_plan_payload(action)
|
||||
|
||||
fault = None
|
||||
if phase == wfields.NotificationPhase.ERROR:
|
||||
fault = exception_notifications.ExceptionPayload.from_exception()
|
||||
|
||||
versioned_payload = ActionCancelPayload(
|
||||
action=action,
|
||||
action_plan=action_plan_payload,
|
||||
fault=fault,
|
||||
)
|
||||
|
||||
notification = ActionCancelNotification(
|
||||
priority=priority,
|
||||
event_type=notificationbase.EventType(
|
||||
object='action',
|
||||
action=notification_action,
|
||||
phase=phase),
|
||||
publisher=notificationbase.NotificationPublisher(
|
||||
host=host or CONF.host,
|
||||
binary=service),
|
||||
payload=versioned_payload)
|
||||
|
||||
notification.emit(context)
|
||||
|
@@ -167,6 +167,22 @@ class ActionPlanDeletePayload(ActionPlanPayload):
|
||||
strategy=strategy)
|
||||
|
||||
|
||||
@base.WatcherObjectRegistry.register_notification
|
||||
class ActionPlanCancelPayload(ActionPlanPayload):
|
||||
# Version 1.0: Initial version
|
||||
VERSION = '1.0'
|
||||
fields = {
|
||||
'fault': wfields.ObjectField('ExceptionPayload', nullable=True),
|
||||
}
|
||||
|
||||
def __init__(self, action_plan, audit, strategy, **kwargs):
|
||||
super(ActionPlanCancelPayload, self).__init__(
|
||||
action_plan=action_plan,
|
||||
audit=audit,
|
||||
strategy=strategy,
|
||||
**kwargs)
|
||||
|
||||
|
||||
@notificationbase.notification_sample('action_plan-execution-error.json')
|
||||
@notificationbase.notification_sample('action_plan-execution-end.json')
|
||||
@notificationbase.notification_sample('action_plan-execution-start.json')
|
||||
@@ -213,6 +229,19 @@ class ActionPlanDeleteNotification(notificationbase.NotificationBase):
|
||||
}
|
||||
|
||||
|
||||
@notificationbase.notification_sample('action_plan-cancel-error.json')
|
||||
@notificationbase.notification_sample('action_plan-cancel-end.json')
|
||||
@notificationbase.notification_sample('action_plan-cancel-start.json')
|
||||
@base.WatcherObjectRegistry.register_notification
|
||||
class ActionPlanCancelNotification(notificationbase.NotificationBase):
|
||||
# Version 1.0: Initial version
|
||||
VERSION = '1.0'
|
||||
|
||||
fields = {
|
||||
'payload': wfields.ObjectField('ActionPlanCancelPayload')
|
||||
}
|
||||
|
||||
|
||||
def _get_common_payload(action_plan):
|
||||
audit = None
|
||||
strategy = None
|
||||
@@ -338,3 +367,34 @@ def send_action_notification(context, action_plan, action, phase=None,
|
||||
payload=versioned_payload)
|
||||
|
||||
notification.emit(context)
|
||||
|
||||
|
||||
def send_cancel_notification(context, action_plan, action, phase=None,
|
||||
priority=wfields.NotificationPriority.INFO,
|
||||
service='infra-optim', host=None):
|
||||
"""Emit an action_plan cancel notification."""
|
||||
audit_payload, strategy_payload = _get_common_payload(action_plan)
|
||||
|
||||
fault = None
|
||||
if phase == wfields.NotificationPhase.ERROR:
|
||||
fault = exception_notifications.ExceptionPayload.from_exception()
|
||||
|
||||
versioned_payload = ActionPlanCancelPayload(
|
||||
action_plan=action_plan,
|
||||
audit=audit_payload,
|
||||
strategy=strategy_payload,
|
||||
fault=fault,
|
||||
)
|
||||
|
||||
notification = ActionPlanCancelNotification(
|
||||
priority=priority,
|
||||
event_type=notificationbase.EventType(
|
||||
object='action_plan',
|
||||
action=action,
|
||||
phase=phase),
|
||||
publisher=notificationbase.NotificationPublisher(
|
||||
host=host or CONF.host,
|
||||
binary=service),
|
||||
payload=versioned_payload)
|
||||
|
||||
notification.emit(context)
|
||||
|
@@ -153,7 +153,10 @@ class NotificationAction(BaseWatcherEnum):
|
||||
PLANNER = 'planner'
|
||||
EXECUTION = 'execution'
|
||||
|
||||
ALL = (CREATE, UPDATE, EXCEPTION, DELETE, STRATEGY, PLANNER, EXECUTION)
|
||||
CANCEL = 'cancel'
|
||||
|
||||
ALL = (CREATE, UPDATE, EXCEPTION, DELETE, STRATEGY, PLANNER, EXECUTION,
|
||||
CANCEL)
|
||||
|
||||
|
||||
class NotificationPriorityField(BaseEnumField):
|
||||
|
@@ -353,3 +353,133 @@ class TestActionNotification(base.DbTestCase):
|
||||
},
|
||||
notification
|
||||
)
|
||||
|
||||
def test_send_action_cancel(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_cancel_notification(
|
||||
mock.MagicMock(), action, 'cancel', 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.cancel.start',
|
||||
'payload': {
|
||||
'watcher_object.namespace': 'watcher',
|
||||
'watcher_object.version': '1.0',
|
||||
'watcher_object.name': 'ActionCancelPayload',
|
||||
'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_cancel_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_cancel_notification(
|
||||
mock.MagicMock(), action, 'cancel', 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.cancel.error',
|
||||
'payload': {
|
||||
'watcher_object.namespace': 'watcher',
|
||||
'watcher_object.version': '1.0',
|
||||
'watcher_object.name': 'ActionCancelPayload',
|
||||
'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_cancel_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
|
||||
)
|
||||
|
@@ -427,3 +427,164 @@ class TestActionPlanNotification(base.DbTestCase):
|
||||
},
|
||||
notification
|
||||
)
|
||||
|
||||
def test_send_action_plan_cancel(self):
|
||||
action_plan = utils.create_test_action_plan(
|
||||
mock.Mock(), state=objects.action_plan.State.ONGOING,
|
||||
audit_id=self.audit.id, strategy_id=self.strategy.id,
|
||||
audit=self.audit, strategy=self.strategy)
|
||||
notifications.action_plan.send_cancel_notification(
|
||||
mock.MagicMock(), action_plan, host='node0',
|
||||
action='cancel', phase='start')
|
||||
|
||||
# The 1st notification is because we created the audit object.
|
||||
# The 2nd notification is because we created the action plan object.
|
||||
self.assertEqual(3, 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_plan.cancel.start",
|
||||
"payload": {
|
||||
"watcher_object.data": {
|
||||
"created_at": "2016-10-18T09:52:05Z",
|
||||
"deleted_at": None,
|
||||
"fault": None,
|
||||
"audit_uuid": "10a47dd1-4874-4298-91cf-eff046dbdb8d",
|
||||
"audit": {
|
||||
"watcher_object.namespace": "watcher",
|
||||
"watcher_object.name": "TerseAuditPayload",
|
||||
"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,
|
||||
"goal_uuid": (
|
||||
"f7ad87ae-4298-91cf-93a0-f35a852e3652"),
|
||||
"deleted_at": None,
|
||||
"scope": [],
|
||||
"state": "PENDING",
|
||||
"updated_at": None,
|
||||
"created_at": "2016-10-18T09:52:05Z",
|
||||
"audit_type": "ONESHOT"
|
||||
}
|
||||
},
|
||||
"global_efficacy": {},
|
||||
"state": "ONGOING",
|
||||
"strategy_uuid": (
|
||||
"cb3d0b58-4415-4d90-b75b-1e96878730e3"),
|
||||
"strategy": {
|
||||
"watcher_object.data": {
|
||||
"created_at": "2016-10-18T09:52:05Z",
|
||||
"deleted_at": None,
|
||||
"display_name": "test strategy",
|
||||
"name": "TEST",
|
||||
"parameters_spec": {},
|
||||
"updated_at": None,
|
||||
"uuid": "cb3d0b58-4415-4d90-b75b-1e96878730e3"
|
||||
},
|
||||
"watcher_object.name": "StrategyPayload",
|
||||
"watcher_object.namespace": "watcher",
|
||||
"watcher_object.version": "1.0"
|
||||
},
|
||||
"updated_at": None,
|
||||
"uuid": "76be87bd-3422-43f9-93a0-e85a577e3061"
|
||||
},
|
||||
"watcher_object.name": "ActionPlanCancelPayload",
|
||||
"watcher_object.namespace": "watcher",
|
||||
"watcher_object.version": "1.0"
|
||||
}
|
||||
},
|
||||
notification
|
||||
)
|
||||
|
||||
def test_send_action_plan_cancel_with_error(self):
|
||||
action_plan = utils.create_test_action_plan(
|
||||
mock.Mock(), state=objects.action_plan.State.ONGOING,
|
||||
audit_id=self.audit.id, strategy_id=self.strategy.id,
|
||||
audit=self.audit, strategy=self.strategy)
|
||||
|
||||
try:
|
||||
# This is to load the exception in sys.exc_info()
|
||||
raise exception.WatcherException("TEST")
|
||||
except exception.WatcherException:
|
||||
notifications.action_plan.send_cancel_notification(
|
||||
mock.MagicMock(), action_plan, host='node0',
|
||||
action='cancel', priority='error', phase='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_plan.cancel.error",
|
||||
"payload": {
|
||||
"watcher_object.data": {
|
||||
"created_at": "2016-10-18T09:52:05Z",
|
||||
"deleted_at": None,
|
||||
"fault": {
|
||||
"watcher_object.data": {
|
||||
"exception": "WatcherException",
|
||||
"exception_message": "TEST",
|
||||
"function_name": (
|
||||
"test_send_action_plan_cancel_with_error"),
|
||||
"module_name": "watcher.tests.notifications."
|
||||
"test_action_plan_notification"
|
||||
},
|
||||
"watcher_object.name": "ExceptionPayload",
|
||||
"watcher_object.namespace": "watcher",
|
||||
"watcher_object.version": "1.0"
|
||||
},
|
||||
"audit_uuid": "10a47dd1-4874-4298-91cf-eff046dbdb8d",
|
||||
"audit": {
|
||||
"watcher_object.data": {
|
||||
"interval": None,
|
||||
"next_run_time": None,
|
||||
"auto_trigger": False,
|
||||
"parameters": {},
|
||||
"uuid": "10a47dd1-4874-4298-91cf-eff046dbdb8d",
|
||||
"strategy_uuid": None,
|
||||
"goal_uuid": (
|
||||
"f7ad87ae-4298-91cf-93a0-f35a852e3652"),
|
||||
"deleted_at": None,
|
||||
"scope": [],
|
||||
"state": "PENDING",
|
||||
"updated_at": None,
|
||||
"created_at": "2016-10-18T09:52:05Z",
|
||||
"audit_type": "ONESHOT"
|
||||
},
|
||||
"watcher_object.name": "TerseAuditPayload",
|
||||
"watcher_object.namespace": "watcher",
|
||||
"watcher_object.version": "1.1"
|
||||
},
|
||||
"global_efficacy": {},
|
||||
"state": "ONGOING",
|
||||
"strategy_uuid": (
|
||||
"cb3d0b58-4415-4d90-b75b-1e96878730e3"),
|
||||
"strategy": {
|
||||
"watcher_object.data": {
|
||||
"created_at": "2016-10-18T09:52:05Z",
|
||||
"deleted_at": None,
|
||||
"display_name": "test strategy",
|
||||
"name": "TEST",
|
||||
"parameters_spec": {},
|
||||
"updated_at": None,
|
||||
"uuid": "cb3d0b58-4415-4d90-b75b-1e96878730e3"
|
||||
},
|
||||
"watcher_object.name": "StrategyPayload",
|
||||
"watcher_object.namespace": "watcher",
|
||||
"watcher_object.version": "1.0"
|
||||
},
|
||||
"updated_at": None,
|
||||
"uuid": "76be87bd-3422-43f9-93a0-e85a577e3061"
|
||||
},
|
||||
"watcher_object.name": "ActionPlanCancelPayload",
|
||||
"watcher_object.namespace": "watcher",
|
||||
"watcher_object.version": "1.0"
|
||||
}
|
||||
},
|
||||
notification
|
||||
)
|
||||
|
@@ -250,7 +250,7 @@ class TestNotificationBase(testbase.TestCase):
|
||||
|
||||
|
||||
expected_notification_fingerprints = {
|
||||
'EventType': '1.3-4258a2c86eca79fd34a7dffe1278eab9',
|
||||
'EventType': '1.3-bc4f4bc4a497d789e5a3c30f921edae1',
|
||||
'ExceptionNotification': '1.0-9b69de0724fda8310d05e18418178866',
|
||||
'ExceptionPayload': '1.0-4516ae282a55fe2fd5c754967ee6248b',
|
||||
'NotificationPublisher': '1.0-bbbc1402fb0e443a3eb227cc52b61545',
|
||||
@@ -277,6 +277,8 @@ expected_notification_fingerprints = {
|
||||
'ActionPlanUpdateNotification': '1.0-9b69de0724fda8310d05e18418178866',
|
||||
'ActionPlanUpdatePayload': '1.0-3e1a348a0579c6c43c1c3d7257e3f26b',
|
||||
'ActionPlanActionNotification': '1.0-9b69de0724fda8310d05e18418178866',
|
||||
'ActionPlanCancelNotification': '1.0-9b69de0724fda8310d05e18418178866',
|
||||
'ActionCancelNotification': '1.0-9b69de0724fda8310d05e18418178866',
|
||||
'ActionCreateNotification': '1.0-9b69de0724fda8310d05e18418178866',
|
||||
'ActionCreatePayload': '1.0-519b93b7450319d8928b4b6e6362df31',
|
||||
'ActionDeleteNotification': '1.0-9b69de0724fda8310d05e18418178866',
|
||||
@@ -287,6 +289,8 @@ expected_notification_fingerprints = {
|
||||
'ActionStateUpdatePayload': '1.0-1a1b606bf14a2c468800c2b010801ce5',
|
||||
'ActionUpdateNotification': '1.0-9b69de0724fda8310d05e18418178866',
|
||||
'ActionUpdatePayload': '1.0-03306c7e7f4d49ac328c261eff6b30b8',
|
||||
'ActionPlanCancelPayload': '1.0-d9f134708e06cf2ff2d3b8d522ac2aa8',
|
||||
'ActionCancelPayload': '1.0-bff9f820a2abf7bb6d7027b7450157df',
|
||||
'TerseActionPlanPayload': '1.0-42bf7a5585cc111a9a4dbc008a04c67e',
|
||||
'ServiceUpdateNotification': '1.0-9b69de0724fda8310d05e18418178866',
|
||||
'ServicePayload': '1.0-9c5a9bc51e6606e0ec3cf95baf698f4f',
|
||||
|
Reference in New Issue
Block a user