Added action_plan.create|update|delete notifs
In this changeset, I added 3 notifications: - action_plan.create - action_plan.update - action_plan.delete Partially Implements: blueprint action-plan-versioned-notifications-api Change-Id: I8821fc6f47e7486037839d81bed9e28020b02fdd
This commit is contained in:
parent
ea1fd5967a
commit
e51e7e4317
54
doc/notification_samples/action_plan-create.json
Normal file
54
doc/notification_samples/action_plan-create.json
Normal file
@ -0,0 +1,54 @@
|
||||
{
|
||||
"publisher_id": "infra-optim:node0",
|
||||
"payload": {
|
||||
"watcher_object.version": "1.0",
|
||||
"watcher_object.data": {
|
||||
"strategy_uuid": "cb3d0b58-4415-4d90-b75b-1e96878730e3",
|
||||
"strategy": {
|
||||
"watcher_object.version": "1.0",
|
||||
"watcher_object.data": {
|
||||
"uuid": "cb3d0b58-4415-4d90-b75b-1e96878730e3",
|
||||
"display_name": "test strategy",
|
||||
"name": "TEST",
|
||||
"updated_at": null,
|
||||
"parameters_spec": {},
|
||||
"created_at": "2016-10-18T09:52:05Z",
|
||||
"deleted_at": null
|
||||
},
|
||||
"watcher_object.namespace": "watcher",
|
||||
"watcher_object.name": "StrategyPayload"
|
||||
},
|
||||
"created_at": null,
|
||||
"audit_uuid": "10a47dd1-4874-4298-91cf-eff046dbdb8d",
|
||||
"audit": {
|
||||
"watcher_object.version": "1.0",
|
||||
"watcher_object.data": {
|
||||
"audit_type": "ONESHOT",
|
||||
"scope": [],
|
||||
"uuid": "10a47dd1-4874-4298-91cf-eff046dbdb8d",
|
||||
"goal_uuid": "bc830f84-8ae3-4fc6-8bc6-e3dd15e8b49a",
|
||||
"strategy_uuid": "75234dfe-87e3-4f11-a0e0-3c3305d86a39",
|
||||
"parameters": {},
|
||||
"interval": null,
|
||||
"deleted_at": null,
|
||||
"state": "PENDING",
|
||||
"created_at": "2016-10-18T09:52:05Z",
|
||||
"updated_at": null
|
||||
},
|
||||
"watcher_object.namespace": "watcher",
|
||||
"watcher_object.name": "TerseAuditPayload"
|
||||
},
|
||||
"uuid": "76be87bd-3422-43f9-93a0-e85a577e3061",
|
||||
"global_efficacy": {},
|
||||
"deleted_at": null,
|
||||
"state": "RECOMMENDED",
|
||||
"updated_at": null
|
||||
},
|
||||
"watcher_object.namespace": "watcher",
|
||||
"watcher_object.name": "ActionPlanCreatePayload"
|
||||
},
|
||||
"priority": "INFO",
|
||||
"message_id": "5148bff1-ea06-4ad6-8e4e-8c85ca5eb629",
|
||||
"event_type": "action_plan.create",
|
||||
"timestamp": "2016-10-18 09:52:05.219414"
|
||||
}
|
54
doc/notification_samples/action_plan-delete.json
Normal file
54
doc/notification_samples/action_plan-delete.json
Normal file
@ -0,0 +1,54 @@
|
||||
{
|
||||
"publisher_id": "infra-optim:node0",
|
||||
"timestamp": "2016-10-18 09:52:05.219414",
|
||||
"payload": {
|
||||
"watcher_object.data": {
|
||||
"uuid": "76be87bd-3422-43f9-93a0-e85a577e3061",
|
||||
"created_at": "2016-10-18T09:52:05Z",
|
||||
"audit_uuid": "10a47dd1-4874-4298-91cf-eff046dbdb8d",
|
||||
"audit": {
|
||||
"watcher_object.data": {
|
||||
"uuid": "10a47dd1-4874-4298-91cf-eff046dbdb8d",
|
||||
"goal_uuid": "bc830f84-8ae3-4fc6-8bc6-e3dd15e8b49a",
|
||||
"strategy_uuid": "75234dfe-87e3-4f11-a0e0-3c3305d86a39",
|
||||
"interval": null,
|
||||
"audit_type": "ONESHOT",
|
||||
"scope": [],
|
||||
"updated_at": null,
|
||||
"deleted_at": null,
|
||||
"state": "PENDING",
|
||||
"created_at": "2016-10-18T09:52:05Z",
|
||||
"parameters": {}
|
||||
},
|
||||
"watcher_object.version": "1.0",
|
||||
"watcher_object.name": "TerseAuditPayload",
|
||||
"watcher_object.namespace": "watcher"
|
||||
},
|
||||
"global_efficacy": {},
|
||||
"updated_at": null,
|
||||
"deleted_at": null,
|
||||
"strategy_uuid": "cb3d0b58-4415-4d90-b75b-1e96878730e3",
|
||||
"strategy": {
|
||||
"watcher_object.data": {
|
||||
"uuid": "cb3d0b58-4415-4d90-b75b-1e96878730e3",
|
||||
"created_at": "2016-10-18T09:52:05Z",
|
||||
"name": "TEST",
|
||||
"display_name": "test strategy",
|
||||
"deleted_at": null,
|
||||
"updated_at": null,
|
||||
"parameters_spec": {}
|
||||
},
|
||||
"watcher_object.version": "1.0",
|
||||
"watcher_object.name": "StrategyPayload",
|
||||
"watcher_object.namespace": "watcher"
|
||||
},
|
||||
"state": "DELETED"
|
||||
},
|
||||
"watcher_object.version": "1.0",
|
||||
"watcher_object.name": "ActionPlanDeletePayload",
|
||||
"watcher_object.namespace": "watcher"
|
||||
},
|
||||
"event_type": "action_plan.delete",
|
||||
"message_id": "3d137686-a1fd-4683-ab40-c4210aac2140",
|
||||
"priority": "INFO"
|
||||
}
|
63
doc/notification_samples/action_plan-update.json
Normal file
63
doc/notification_samples/action_plan-update.json
Normal file
@ -0,0 +1,63 @@
|
||||
{
|
||||
"payload": {
|
||||
"watcher_object.version": "1.0",
|
||||
"watcher_object.data": {
|
||||
"audit_uuid": "10a47dd1-4874-4298-91cf-eff046dbdb8d",
|
||||
"audit": {
|
||||
"watcher_object.version": "1.0",
|
||||
"watcher_object.data": {
|
||||
"audit_type": "ONESHOT",
|
||||
"scope": [],
|
||||
"created_at": "2016-10-18T09:52:05Z",
|
||||
"uuid": "10a47dd1-4874-4298-91cf-eff046dbdb8d",
|
||||
"goal_uuid": "bc830f84-8ae3-4fc6-8bc6-e3dd15e8b49a",
|
||||
"strategy_uuid": "75234dfe-87e3-4f11-a0e0-3c3305d86a39",
|
||||
"interval": null,
|
||||
"updated_at": null,
|
||||
"state": "PENDING",
|
||||
"deleted_at": null,
|
||||
"parameters": {}
|
||||
},
|
||||
"watcher_object.namespace": "watcher",
|
||||
"watcher_object.name": "TerseAuditPayload"
|
||||
},
|
||||
"created_at": "2016-10-18T09:52:05Z",
|
||||
"uuid": "76be87bd-3422-43f9-93a0-e85a577e3061",
|
||||
"updated_at": null,
|
||||
"state_update": {
|
||||
"watcher_object.version": "1.0",
|
||||
"watcher_object.data": {
|
||||
"old_state": "PENDING",
|
||||
"state": "ONGOING"
|
||||
},
|
||||
"watcher_object.namespace": "watcher",
|
||||
"watcher_object.name": "ActionPlanStateUpdatePayload"
|
||||
},
|
||||
"state": "ONGOING",
|
||||
"deleted_at": null,
|
||||
"strategy_uuid": "cb3d0b58-4415-4d90-b75b-1e96878730e3",
|
||||
"strategy": {
|
||||
"watcher_object.version": "1.0",
|
||||
"watcher_object.data": {
|
||||
"name": "TEST",
|
||||
"uuid": "cb3d0b58-4415-4d90-b75b-1e96878730e3",
|
||||
"display_name": "test strategy",
|
||||
"created_at": "2016-10-18T09:52:05Z",
|
||||
"updated_at": null,
|
||||
"deleted_at": null,
|
||||
"parameters_spec": {}
|
||||
},
|
||||
"watcher_object.namespace": "watcher",
|
||||
"watcher_object.name": "StrategyPayload"
|
||||
},
|
||||
"global_efficacy": {}
|
||||
},
|
||||
"watcher_object.namespace": "watcher",
|
||||
"watcher_object.name": "ActionPlanUpdatePayload"
|
||||
},
|
||||
"publisher_id": "infra-optim:node0",
|
||||
"priority": "INFO",
|
||||
"timestamp": "2016-10-18 09:52:05.219414",
|
||||
"event_type": "action_plan.update",
|
||||
"message_id": "0a8a7329-fd5a-4ec6-97d7-2b776ce51a4c"
|
||||
}
|
@ -10,6 +10,7 @@
|
||||
"state": "PENDING",
|
||||
"updated_at": null,
|
||||
"deleted_at": null,
|
||||
"goal_uuid": "bc830f84-8ae3-4fc6-8bc6-e3dd15e8b49a",
|
||||
"goal": {
|
||||
"watcher_object.data": {
|
||||
"uuid": "bc830f84-8ae3-4fc6-8bc6-e3dd15e8b49a",
|
||||
@ -26,6 +27,7 @@
|
||||
},
|
||||
"interval": null,
|
||||
"scope": [],
|
||||
"strategy_uuid": "75234dfe-87e3-4f11-a0e0-3c3305d86a39",
|
||||
"strategy": {
|
||||
"watcher_object.data": {
|
||||
"parameters_spec": {
|
||||
|
@ -10,6 +10,7 @@
|
||||
"state": "DELETED",
|
||||
"updated_at": null,
|
||||
"deleted_at": null,
|
||||
"goal_uuid": "bc830f84-8ae3-4fc6-8bc6-e3dd15e8b49a",
|
||||
"goal": {
|
||||
"watcher_object.data": {
|
||||
"uuid": "bc830f84-8ae3-4fc6-8bc6-e3dd15e8b49a",
|
||||
@ -26,6 +27,7 @@
|
||||
},
|
||||
"interval": null,
|
||||
"scope": [],
|
||||
"strategy_uuid": "75234dfe-87e3-4f11-a0e0-3c3305d86a39",
|
||||
"strategy": {
|
||||
"watcher_object.data": {
|
||||
"parameters_spec": {
|
||||
|
@ -11,6 +11,7 @@
|
||||
"updated_at": null,
|
||||
"deleted_at": null,
|
||||
"fault": null,
|
||||
"goal_uuid": "bc830f84-8ae3-4fc6-8bc6-e3dd15e8b49a",
|
||||
"goal": {
|
||||
"watcher_object.data": {
|
||||
"uuid": "bc830f84-8ae3-4fc6-8bc6-e3dd15e8b49a",
|
||||
@ -27,6 +28,7 @@
|
||||
},
|
||||
"interval": null,
|
||||
"scope": [],
|
||||
"strategy_uuid": "75234dfe-87e3-4f11-a0e0-3c3305d86a39",
|
||||
"strategy": {
|
||||
"watcher_object.data": {
|
||||
"parameters_spec": {
|
||||
|
@ -21,6 +21,7 @@
|
||||
"watcher_object.namespace": "watcher",
|
||||
"watcher_object.version": "1.0"
|
||||
},
|
||||
"goal_uuid": "bc830f84-8ae3-4fc6-8bc6-e3dd15e8b49a",
|
||||
"goal": {
|
||||
"watcher_object.data": {
|
||||
"uuid": "bc830f84-8ae3-4fc6-8bc6-e3dd15e8b49a",
|
||||
@ -37,6 +38,7 @@
|
||||
},
|
||||
"interval": null,
|
||||
"scope": [],
|
||||
"strategy_uuid": "75234dfe-87e3-4f11-a0e0-3c3305d86a39",
|
||||
"strategy": {
|
||||
"watcher_object.data": {
|
||||
"parameters_spec": {
|
||||
|
@ -11,6 +11,7 @@
|
||||
"updated_at": null,
|
||||
"deleted_at": null,
|
||||
"fault": null,
|
||||
"goal_uuid": "bc830f84-8ae3-4fc6-8bc6-e3dd15e8b49a",
|
||||
"goal": {
|
||||
"watcher_object.data": {
|
||||
"uuid": "bc830f84-8ae3-4fc6-8bc6-e3dd15e8b49a",
|
||||
@ -27,6 +28,7 @@
|
||||
},
|
||||
"interval": null,
|
||||
"scope": [],
|
||||
"strategy_uuid": "75234dfe-87e3-4f11-a0e0-3c3305d86a39",
|
||||
"strategy": {
|
||||
"watcher_object.data": {
|
||||
"parameters_spec": {
|
||||
|
@ -11,6 +11,7 @@
|
||||
"updated_at": null,
|
||||
"deleted_at": null,
|
||||
"fault": null,
|
||||
"goal_uuid": "bc830f84-8ae3-4fc6-8bc6-e3dd15e8b49a",
|
||||
"goal": {
|
||||
"watcher_object.data": {
|
||||
"uuid": "bc830f84-8ae3-4fc6-8bc6-e3dd15e8b49a",
|
||||
@ -27,6 +28,7 @@
|
||||
},
|
||||
"interval": null,
|
||||
"scope": [],
|
||||
"strategy_uuid": "75234dfe-87e3-4f11-a0e0-3c3305d86a39",
|
||||
"strategy": {
|
||||
"watcher_object.data": {
|
||||
"parameters_spec": {
|
||||
|
@ -21,6 +21,7 @@
|
||||
"watcher_object.namespace": "watcher",
|
||||
"watcher_object.version": "1.0"
|
||||
},
|
||||
"goal_uuid": "bc830f84-8ae3-4fc6-8bc6-e3dd15e8b49a",
|
||||
"goal": {
|
||||
"watcher_object.data": {
|
||||
"uuid": "bc830f84-8ae3-4fc6-8bc6-e3dd15e8b49a",
|
||||
@ -37,6 +38,7 @@
|
||||
},
|
||||
"interval": null,
|
||||
"scope": [],
|
||||
"strategy_uuid": "75234dfe-87e3-4f11-a0e0-3c3305d86a39",
|
||||
"strategy": {
|
||||
"watcher_object.data": {
|
||||
"parameters_spec": {
|
||||
|
@ -11,6 +11,7 @@
|
||||
"updated_at": null,
|
||||
"deleted_at": null,
|
||||
"fault": null,
|
||||
"goal_uuid": "bc830f84-8ae3-4fc6-8bc6-e3dd15e8b49a",
|
||||
"goal": {
|
||||
"watcher_object.data": {
|
||||
"uuid": "bc830f84-8ae3-4fc6-8bc6-e3dd15e8b49a",
|
||||
@ -27,6 +28,7 @@
|
||||
},
|
||||
"interval": null,
|
||||
"scope": [],
|
||||
"strategy_uuid": "75234dfe-87e3-4f11-a0e0-3c3305d86a39",
|
||||
"strategy": {
|
||||
"watcher_object.data": {
|
||||
"parameters_spec": {
|
||||
|
@ -4,6 +4,7 @@
|
||||
"payload": {
|
||||
"watcher_object.name": "AuditUpdatePayload",
|
||||
"watcher_object.data": {
|
||||
"strategy_uuid": "75234dfe-87e3-4f11-a0e0-3c3305d86a39",
|
||||
"strategy": {
|
||||
"watcher_object.name": "StrategyPayload",
|
||||
"watcher_object.data": {
|
||||
@ -36,6 +37,7 @@
|
||||
"scope": [],
|
||||
"created_at": "2016-11-04T16:51:21Z",
|
||||
"uuid": "f1e0d912-afd9-4bf2-91ef-c99cd08cc1ef",
|
||||
"goal_uuid": "bc830f84-8ae3-4fc6-8bc6-e3dd15e8b49a",
|
||||
"goal": {
|
||||
"watcher_object.name": "GoalPayload",
|
||||
"watcher_object.data": {
|
||||
|
@ -455,7 +455,8 @@ class ActionPlansController(rest.RestController):
|
||||
:param action_plan_uuid: UUID of a action.
|
||||
"""
|
||||
context = pecan.request.context
|
||||
action_plan = api_utils.get_resource('ActionPlan', action_plan_uuid)
|
||||
action_plan = api_utils.get_resource(
|
||||
'ActionPlan', action_plan_uuid, eager=True)
|
||||
policy.enforce(context, 'action_plan:delete', action_plan,
|
||||
action='action_plan:delete')
|
||||
|
||||
@ -474,8 +475,8 @@ class ActionPlansController(rest.RestController):
|
||||
raise exception.OperationNotPermitted
|
||||
|
||||
context = pecan.request.context
|
||||
action_plan_to_update = api_utils.get_resource('ActionPlan',
|
||||
action_plan_uuid)
|
||||
action_plan_to_update = api_utils.get_resource(
|
||||
'ActionPlan', action_plan_uuid, eager=True)
|
||||
policy.enforce(context, 'action_plan:update', action_plan_to_update,
|
||||
action='action_plan:update')
|
||||
|
||||
|
@ -33,7 +33,8 @@ class DefaultActionPlanHandler(base.BaseActionPlanHandler):
|
||||
self.action_plan_uuid = action_plan_uuid
|
||||
|
||||
def update_action_plan(self, uuid, state):
|
||||
action_plan = objects.ActionPlan.get_by_uuid(self.ctx, uuid)
|
||||
action_plan = objects.ActionPlan.get_by_uuid(
|
||||
self.ctx, uuid, eager=True)
|
||||
action_plan.state = state
|
||||
action_plan.save()
|
||||
|
||||
|
@ -174,6 +174,14 @@ class EagerlyLoadedAuditRequired(InvalidAudit):
|
||||
msg_fmt = _("Audit %(audit)s was not eagerly loaded")
|
||||
|
||||
|
||||
class InvalidActionPlan(Invalid):
|
||||
msg_fmt = _("Action plan %(action_plan)s is invalid")
|
||||
|
||||
|
||||
class EagerlyLoadedActionPlanRequired(InvalidActionPlan):
|
||||
msg_fmt = _("Action plan %(action_plan)s was not eagerly loaded")
|
||||
|
||||
|
||||
class InvalidUUID(Invalid):
|
||||
msg_fmt = _("Expected a uuid but received %(uuid)s")
|
||||
|
||||
|
@ -350,7 +350,7 @@ class Syncer(object):
|
||||
for strategy_id, synced_strategy in self.strategy_mapping.items():
|
||||
filters = {"strategy_id": strategy_id}
|
||||
stale_action_plans = objects.ActionPlan.list(
|
||||
self.ctx, filters=filters)
|
||||
self.ctx, filters=filters, eager=True)
|
||||
|
||||
# Update strategy IDs for all stale action plans (w/o saving)
|
||||
for action_plan in stale_action_plans:
|
||||
@ -369,7 +369,7 @@ class Syncer(object):
|
||||
for audit_id, synced_audit in self.stale_audits_map.items():
|
||||
filters = {"audit_id": audit_id}
|
||||
stale_action_plans = objects.ActionPlan.list(
|
||||
self.ctx, filters=filters)
|
||||
self.ctx, filters=filters, eager=True)
|
||||
|
||||
# Update audit IDs for all stale action plans (w/o saving)
|
||||
for action_plan in stale_action_plans:
|
||||
@ -448,7 +448,7 @@ class Syncer(object):
|
||||
audit.id].state = objects.audit.State.CANCELLED
|
||||
|
||||
stale_action_plans = objects.ActionPlan.list(
|
||||
self.ctx, filters=filters)
|
||||
self.ctx, filters=filters, eager=True)
|
||||
for action_plan in stale_action_plans:
|
||||
LOG.warning(
|
||||
_LW("Action Plan '%(action_plan)s' references a "
|
||||
|
@ -20,6 +20,7 @@
|
||||
# need to be changed after we moved these function inside the package
|
||||
# Todo(gibi): remove these imports after legacy notifications using these are
|
||||
# transformed to versioned notifications
|
||||
from watcher.notifications import action_plan # noqa
|
||||
from watcher.notifications import audit # noqa
|
||||
from watcher.notifications import exception # noqa
|
||||
from watcher.notifications import goal # noqa
|
||||
|
267
watcher/notifications/action_plan.py
Normal file
267
watcher/notifications/action_plan.py
Normal file
@ -0,0 +1,267 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
# Copyright (c) 2017 b<>com
|
||||
#
|
||||
# Authors: Vincent FRANCOISE <vincent.francoise@b-com.com>
|
||||
#
|
||||
# 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.
|
||||
|
||||
from oslo_config import cfg
|
||||
|
||||
from watcher.common import context as wcontext
|
||||
from watcher.common import exception
|
||||
from watcher.notifications import audit as audit_notifications
|
||||
from watcher.notifications import base as notificationbase
|
||||
from watcher.notifications import strategy as strategy_notifications
|
||||
from watcher import objects
|
||||
from watcher.objects import base
|
||||
from watcher.objects import fields as wfields
|
||||
|
||||
CONF = cfg.CONF
|
||||
|
||||
|
||||
@base.WatcherObjectRegistry.register_notification
|
||||
class ActionPlanPayload(notificationbase.NotificationPayloadBase):
|
||||
SCHEMA = {
|
||||
'uuid': ('action_plan', 'uuid'),
|
||||
|
||||
'state': ('action_plan', 'state'),
|
||||
'global_efficacy': ('action_plan', 'global_efficacy'),
|
||||
'audit_uuid': ('audit', 'uuid'),
|
||||
'strategy_uuid': ('strategy', 'uuid'),
|
||||
|
||||
'created_at': ('action_plan', 'created_at'),
|
||||
'updated_at': ('action_plan', 'updated_at'),
|
||||
'deleted_at': ('action_plan', 'deleted_at'),
|
||||
}
|
||||
|
||||
# Version 1.0: Initial version
|
||||
VERSION = '1.0'
|
||||
|
||||
fields = {
|
||||
'uuid': wfields.UUIDField(),
|
||||
'state': wfields.StringField(),
|
||||
'global_efficacy': wfields.FlexibleDictField(nullable=True),
|
||||
'audit_uuid': wfields.UUIDField(),
|
||||
'strategy_uuid': wfields.UUIDField(),
|
||||
'audit': wfields.ObjectField('TerseAuditPayload'),
|
||||
'strategy': wfields.ObjectField('StrategyPayload'),
|
||||
|
||||
'created_at': wfields.DateTimeField(nullable=True),
|
||||
'updated_at': wfields.DateTimeField(nullable=True),
|
||||
'deleted_at': wfields.DateTimeField(nullable=True),
|
||||
}
|
||||
|
||||
def __init__(self, action_plan, audit, strategy, **kwargs):
|
||||
super(ActionPlanPayload, self).__init__(
|
||||
audit=audit, strategy=strategy, **kwargs)
|
||||
self.populate_schema(
|
||||
action_plan=action_plan, audit=audit, strategy=strategy)
|
||||
|
||||
|
||||
@base.WatcherObjectRegistry.register_notification
|
||||
class ActionPlanStateUpdatePayload(notificationbase.NotificationPayloadBase):
|
||||
# Version 1.0: Initial version
|
||||
VERSION = '1.0'
|
||||
|
||||
fields = {
|
||||
'old_state': wfields.StringField(nullable=True),
|
||||
'state': wfields.StringField(nullable=True),
|
||||
}
|
||||
|
||||
|
||||
@base.WatcherObjectRegistry.register_notification
|
||||
class ActionPlanCreatePayload(ActionPlanPayload):
|
||||
# Version 1.0: Initial version
|
||||
VERSION = '1.0'
|
||||
fields = {}
|
||||
|
||||
def __init__(self, action_plan, audit, strategy):
|
||||
super(ActionPlanCreatePayload, self).__init__(
|
||||
action_plan=action_plan,
|
||||
audit=audit,
|
||||
strategy=strategy)
|
||||
|
||||
|
||||
@base.WatcherObjectRegistry.register_notification
|
||||
class ActionPlanUpdatePayload(ActionPlanPayload):
|
||||
# Version 1.0: Initial version
|
||||
VERSION = '1.0'
|
||||
fields = {
|
||||
'state_update': wfields.ObjectField('ActionPlanStateUpdatePayload'),
|
||||
}
|
||||
|
||||
def __init__(self, action_plan, state_update, audit, strategy):
|
||||
super(ActionPlanUpdatePayload, self).__init__(
|
||||
action_plan=action_plan,
|
||||
state_update=state_update,
|
||||
audit=audit,
|
||||
strategy=strategy)
|
||||
|
||||
|
||||
@base.WatcherObjectRegistry.register_notification
|
||||
class ActionPlanActionPayload(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(ActionPlanActionPayload, self).__init__(
|
||||
action_plan=action_plan,
|
||||
audit=audit,
|
||||
strategy=strategy,
|
||||
**kwargs)
|
||||
|
||||
|
||||
@base.WatcherObjectRegistry.register_notification
|
||||
class ActionPlanDeletePayload(ActionPlanPayload):
|
||||
# Version 1.0: Initial version
|
||||
VERSION = '1.0'
|
||||
fields = {}
|
||||
|
||||
def __init__(self, action_plan, audit, strategy):
|
||||
super(ActionPlanDeletePayload, self).__init__(
|
||||
action_plan=action_plan,
|
||||
audit=audit,
|
||||
strategy=strategy)
|
||||
|
||||
|
||||
@notificationbase.notification_sample('action_plan-create.json')
|
||||
@base.WatcherObjectRegistry.register_notification
|
||||
class ActionPlanCreateNotification(notificationbase.NotificationBase):
|
||||
# Version 1.0: Initial version
|
||||
VERSION = '1.0'
|
||||
|
||||
fields = {
|
||||
'payload': wfields.ObjectField('ActionPlanCreatePayload')
|
||||
}
|
||||
|
||||
|
||||
@notificationbase.notification_sample('action_plan-update.json')
|
||||
@base.WatcherObjectRegistry.register_notification
|
||||
class ActionPlanUpdateNotification(notificationbase.NotificationBase):
|
||||
# Version 1.0: Initial version
|
||||
VERSION = '1.0'
|
||||
|
||||
fields = {
|
||||
'payload': wfields.ObjectField('ActionPlanUpdatePayload')
|
||||
}
|
||||
|
||||
|
||||
@notificationbase.notification_sample('action_plan-delete.json')
|
||||
@base.WatcherObjectRegistry.register_notification
|
||||
class ActionPlanDeleteNotification(notificationbase.NotificationBase):
|
||||
# Version 1.0: Initial version
|
||||
VERSION = '1.0'
|
||||
|
||||
fields = {
|
||||
'payload': wfields.ObjectField('ActionPlanDeletePayload')
|
||||
}
|
||||
|
||||
|
||||
def _get_common_payload(action_plan):
|
||||
audit = None
|
||||
strategy = None
|
||||
try:
|
||||
audit = action_plan.audit
|
||||
strategy = action_plan.strategy
|
||||
except NotImplementedError:
|
||||
raise exception.EagerlyLoadedActionPlanRequired(
|
||||
action_plan=action_plan.uuid)
|
||||
|
||||
goal = objects.Goal.get(
|
||||
wcontext.make_context(show_deleted=True), audit.goal_id)
|
||||
audit_payload = audit_notifications.TerseAuditPayload(
|
||||
audit=audit, goal_uuid=goal.uuid)
|
||||
|
||||
strategy_payload = strategy_notifications.StrategyPayload(
|
||||
strategy=strategy)
|
||||
|
||||
return audit_payload, strategy_payload
|
||||
|
||||
|
||||
def send_create(context, action_plan, service='infra-optim', host=None):
|
||||
"""Emit an action_plan.create notification."""
|
||||
audit_payload, strategy_payload = _get_common_payload(action_plan)
|
||||
|
||||
versioned_payload = ActionPlanCreatePayload(
|
||||
action_plan=action_plan,
|
||||
audit=audit_payload,
|
||||
strategy=strategy_payload,
|
||||
)
|
||||
|
||||
notification = ActionPlanCreateNotification(
|
||||
priority=wfields.NotificationPriority.INFO,
|
||||
event_type=notificationbase.EventType(
|
||||
object='action_plan',
|
||||
action=wfields.NotificationAction.CREATE),
|
||||
publisher=notificationbase.NotificationPublisher(
|
||||
host=host or CONF.host,
|
||||
binary=service),
|
||||
payload=versioned_payload)
|
||||
|
||||
notification.emit(context)
|
||||
|
||||
|
||||
def send_update(context, action_plan, service='infra-optim',
|
||||
host=None, old_state=None):
|
||||
"""Emit an action_plan.update notification."""
|
||||
audit_payload, strategy_payload = _get_common_payload(action_plan)
|
||||
|
||||
state_update = ActionPlanStateUpdatePayload(
|
||||
old_state=old_state,
|
||||
state=action_plan.state if old_state else None)
|
||||
|
||||
versioned_payload = ActionPlanUpdatePayload(
|
||||
action_plan=action_plan,
|
||||
state_update=state_update,
|
||||
audit=audit_payload,
|
||||
strategy=strategy_payload,
|
||||
)
|
||||
|
||||
notification = ActionPlanUpdateNotification(
|
||||
priority=wfields.NotificationPriority.INFO,
|
||||
event_type=notificationbase.EventType(
|
||||
object='action_plan',
|
||||
action=wfields.NotificationAction.UPDATE),
|
||||
publisher=notificationbase.NotificationPublisher(
|
||||
host=host or CONF.host,
|
||||
binary=service),
|
||||
payload=versioned_payload)
|
||||
|
||||
notification.emit(context)
|
||||
|
||||
|
||||
def send_delete(context, action_plan, service='infra-optim', host=None):
|
||||
"""Emit an action_plan.delete notification."""
|
||||
audit_payload, strategy_payload = _get_common_payload(action_plan)
|
||||
|
||||
versioned_payload = ActionPlanDeletePayload(
|
||||
action_plan=action_plan,
|
||||
audit=audit_payload,
|
||||
strategy=strategy_payload,
|
||||
)
|
||||
|
||||
notification = ActionPlanDeleteNotification(
|
||||
priority=wfields.NotificationPriority.INFO,
|
||||
event_type=notificationbase.EventType(
|
||||
object='action_plan',
|
||||
action=wfields.NotificationAction.DELETE),
|
||||
publisher=notificationbase.NotificationPublisher(
|
||||
host=host or CONF.host,
|
||||
binary=service),
|
||||
payload=versioned_payload)
|
||||
|
||||
notification.emit(context)
|
@ -30,7 +30,7 @@ CONF = cfg.CONF
|
||||
|
||||
|
||||
@base.WatcherObjectRegistry.register_notification
|
||||
class AuditPayload(notificationbase.NotificationPayloadBase):
|
||||
class TerseAuditPayload(notificationbase.NotificationPayloadBase):
|
||||
SCHEMA = {
|
||||
'uuid': ('audit', 'uuid'),
|
||||
|
||||
@ -57,19 +57,54 @@ class AuditPayload(notificationbase.NotificationPayloadBase):
|
||||
'scope': wfields.FlexibleListOfDictField(nullable=True),
|
||||
'goal_uuid': wfields.UUIDField(),
|
||||
'strategy_uuid': wfields.UUIDField(nullable=True),
|
||||
'goal': wfields.ObjectField('GoalPayload'),
|
||||
'strategy': wfields.ObjectField('StrategyPayload', nullable=True),
|
||||
|
||||
'created_at': wfields.DateTimeField(nullable=True),
|
||||
'updated_at': wfields.DateTimeField(nullable=True),
|
||||
'deleted_at': wfields.DateTimeField(nullable=True),
|
||||
}
|
||||
|
||||
def __init__(self, audit, **kwargs):
|
||||
super(AuditPayload, self).__init__(**kwargs)
|
||||
def __init__(self, audit, goal_uuid, strategy_uuid=None, **kwargs):
|
||||
super(TerseAuditPayload, self).__init__(
|
||||
goal_uuid=goal_uuid, strategy_uuid=strategy_uuid, **kwargs)
|
||||
self.populate_schema(audit=audit)
|
||||
|
||||
|
||||
@base.WatcherObjectRegistry.register_notification
|
||||
class AuditPayload(TerseAuditPayload):
|
||||
SCHEMA = {
|
||||
'uuid': ('audit', 'uuid'),
|
||||
|
||||
'audit_type': ('audit', 'audit_type'),
|
||||
'state': ('audit', 'state'),
|
||||
'parameters': ('audit', 'parameters'),
|
||||
'interval': ('audit', 'interval'),
|
||||
'scope': ('audit', 'scope'),
|
||||
|
||||
'created_at': ('audit', 'created_at'),
|
||||
'updated_at': ('audit', 'updated_at'),
|
||||
'deleted_at': ('audit', 'deleted_at'),
|
||||
}
|
||||
|
||||
# Version 1.0: Initial version
|
||||
VERSION = '1.0'
|
||||
|
||||
fields = {
|
||||
'goal': wfields.ObjectField('GoalPayload'),
|
||||
'strategy': wfields.ObjectField('StrategyPayload', nullable=True),
|
||||
}
|
||||
|
||||
def __init__(self, audit, goal, strategy=None, **kwargs):
|
||||
if not kwargs.get('goal_uuid'):
|
||||
kwargs['goal_uuid'] = goal.uuid
|
||||
|
||||
if strategy and not kwargs.get('strategy_uuid'):
|
||||
kwargs['strategy_uuid'] = strategy.uuid
|
||||
|
||||
super(AuditPayload, self).__init__(
|
||||
audit=audit, goal=goal,
|
||||
strategy=strategy, **kwargs)
|
||||
|
||||
|
||||
@base.WatcherObjectRegistry.register_notification
|
||||
class AuditStateUpdatePayload(notificationbase.NotificationPayloadBase):
|
||||
# Version 1.0: Initial version
|
||||
@ -91,6 +126,7 @@ class AuditCreatePayload(AuditPayload):
|
||||
super(AuditCreatePayload, self).__init__(
|
||||
audit=audit,
|
||||
goal=goal,
|
||||
goal_uuid=goal.uuid,
|
||||
strategy=strategy)
|
||||
|
||||
|
||||
@ -107,6 +143,7 @@ class AuditUpdatePayload(AuditPayload):
|
||||
audit=audit,
|
||||
state_update=state_update,
|
||||
goal=goal,
|
||||
goal_uuid=goal.uuid,
|
||||
strategy=strategy)
|
||||
|
||||
|
||||
@ -122,6 +159,7 @@ class AuditActionPayload(AuditPayload):
|
||||
super(AuditActionPayload, self).__init__(
|
||||
audit=audit,
|
||||
goal=goal,
|
||||
goal_uuid=goal.uuid,
|
||||
strategy=strategy,
|
||||
**kwargs)
|
||||
|
||||
@ -136,6 +174,7 @@ class AuditDeletePayload(AuditPayload):
|
||||
super(AuditDeletePayload, self).__init__(
|
||||
audit=audit,
|
||||
goal=goal,
|
||||
goal_uuid=goal.uuid,
|
||||
strategy=strategy)
|
||||
|
||||
|
||||
|
@ -13,6 +13,7 @@
|
||||
# under the License.
|
||||
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log
|
||||
|
||||
from watcher.common import exception
|
||||
from watcher.common import rpc
|
||||
@ -20,6 +21,7 @@ from watcher.objects import base
|
||||
from watcher.objects import fields as wfields
|
||||
|
||||
CONF = cfg.CONF
|
||||
LOG = log.getLogger(__name__)
|
||||
|
||||
# Definition of notification levels in increasing order of severity
|
||||
NOTIFY_LEVELS = {
|
||||
@ -59,7 +61,8 @@ class EventType(NotificationObject):
|
||||
# Version 1.0: Initial version
|
||||
# Version 1.1: Added STRATEGY action in NotificationAction enum
|
||||
# Version 1.2: Added PLANNER action in NotificationAction enum
|
||||
VERSION = '1.2'
|
||||
# Version 1.3: Added EXECUTION action in NotificationAction enum
|
||||
VERSION = '1.3'
|
||||
|
||||
fields = {
|
||||
'object': wfields.StringField(),
|
||||
@ -171,6 +174,7 @@ class NotificationBase(NotificationObject):
|
||||
def _emit(self, context, event_type, publisher_id, payload):
|
||||
notifier = rpc.get_notifier(publisher_id)
|
||||
notify = getattr(notifier, self.priority)
|
||||
LOG.debug("Emitting notification `%s`", event_type)
|
||||
notify(context, event_type=event_type, payload=payload)
|
||||
|
||||
def emit(self, context):
|
||||
|
@ -72,6 +72,7 @@ state may be one of the following:
|
||||
from watcher.common import exception
|
||||
from watcher.common import utils
|
||||
from watcher.db import api as db_api
|
||||
from watcher import notifications
|
||||
from watcher import objects
|
||||
from watcher.objects import base
|
||||
from watcher.objects import fields as wfields
|
||||
@ -117,6 +118,39 @@ class ActionPlan(base.WatcherPersistentObject, base.WatcherObject,
|
||||
'strategy': (objects.Strategy, 'strategy_id'),
|
||||
}
|
||||
|
||||
# Proxified field so we can keep the previous value after an update
|
||||
_state = None
|
||||
_old_state = None
|
||||
|
||||
# NOTE(v-francoise): The way oslo.versionedobjects works is by using a
|
||||
# __new__ that will automatically create the attributes referenced in
|
||||
# fields. These attributes are properties that raise an exception if no
|
||||
# value has been assigned, which means that they store the actual field
|
||||
# value in an "_obj_%(field)s" attribute. So because we want to proxify a
|
||||
# value that is already proxified, we have to do what you see below.
|
||||
@property
|
||||
def _obj_state(self):
|
||||
return self._state
|
||||
|
||||
@property
|
||||
def _obj_old_state(self):
|
||||
return self._old_state
|
||||
|
||||
@property
|
||||
def old_state(self):
|
||||
return self._old_state
|
||||
|
||||
@_obj_old_state.setter
|
||||
def _obj_old_state(self, value):
|
||||
self._old_state = value
|
||||
|
||||
@_obj_state.setter
|
||||
def _obj_state(self, value):
|
||||
if self._old_state is None and self._state is None:
|
||||
self._state = value
|
||||
else:
|
||||
self._old_state, self._state = self._state, value
|
||||
|
||||
@base.remotable_classmethod
|
||||
def get(cls, context, action_plan_id, eager=False):
|
||||
"""Find a action_plan based on its id or uuid and return a Action object.
|
||||
@ -198,6 +232,11 @@ class ActionPlan(base.WatcherPersistentObject, base.WatcherObject,
|
||||
# notifications containing information about the related relationships
|
||||
self._from_db_object(self, db_action_plan, eager=True)
|
||||
|
||||
def _notify():
|
||||
notifications.action_plan.send_create(self._context, self)
|
||||
|
||||
_notify()
|
||||
|
||||
@base.remotable
|
||||
def destroy(self):
|
||||
"""Delete the action plan from the DB"""
|
||||
@ -221,8 +260,16 @@ class ActionPlan(base.WatcherPersistentObject, base.WatcherObject,
|
||||
"""
|
||||
updates = self.obj_get_changes()
|
||||
db_obj = self.dbapi.update_action_plan(self.uuid, updates)
|
||||
obj = self._from_db_object(self, db_obj, eager=False)
|
||||
obj = self._from_db_object(
|
||||
self.__class__(self._context), db_obj, eager=False)
|
||||
self.obj_refresh(obj)
|
||||
|
||||
def _notify():
|
||||
notifications.action_plan.send_update(
|
||||
self._context, self, old_state=self.old_state)
|
||||
|
||||
_notify()
|
||||
|
||||
self.obj_reset_changes()
|
||||
|
||||
@base.remotable
|
||||
@ -262,3 +309,8 @@ class ActionPlan(base.WatcherPersistentObject, base.WatcherObject,
|
||||
obj = self._from_db_object(
|
||||
self.__class__(self._context), db_obj, eager=False)
|
||||
self.obj_refresh(obj)
|
||||
|
||||
def _notify():
|
||||
notifications.action_plan.send_delete(self._context, self)
|
||||
|
||||
_notify()
|
||||
|
@ -128,8 +128,9 @@ class NotificationAction(BaseWatcherEnum):
|
||||
|
||||
STRATEGY = 'strategy'
|
||||
PLANNER = 'planner'
|
||||
EXECUTION = 'execution'
|
||||
|
||||
ALL = (CREATE, UPDATE, EXCEPTION, DELETE, STRATEGY, PLANNER)
|
||||
ALL = (CREATE, UPDATE, EXCEPTION, DELETE, STRATEGY, PLANNER, EXECUTION)
|
||||
|
||||
|
||||
class NotificationPriorityField(BaseEnumField):
|
||||
|
@ -89,7 +89,7 @@ def get_test_audit(**kwargs):
|
||||
'updated_at': kwargs.get('updated_at'),
|
||||
'deleted_at': kwargs.get('deleted_at'),
|
||||
'parameters': kwargs.get('parameters', {}),
|
||||
'interval': kwargs.get('period', 3600),
|
||||
'interval': kwargs.get('interval', 3600),
|
||||
'goal_id': kwargs.get('goal_id', 1),
|
||||
'strategy_id': kwargs.get('strategy_id', None),
|
||||
'scope': kwargs.get('scope', []),
|
||||
|
@ -175,12 +175,19 @@ class TestAutoTriggerActionPlan(base.DbTestCase):
|
||||
self.ongoing_action_plan = obj_utils.create_test_action_plan(
|
||||
self.context,
|
||||
uuid=uuidutils.generate_uuid(),
|
||||
audit_id=self.audit.id)
|
||||
audit_id=self.audit.id,
|
||||
strategy_id=self.strategy.id,
|
||||
audit=self.audit,
|
||||
strategy=self.strategy,
|
||||
)
|
||||
self.recommended_action_plan = obj_utils.create_test_action_plan(
|
||||
self.context,
|
||||
uuid=uuidutils.generate_uuid(),
|
||||
state=objects.action_plan.State.ONGOING,
|
||||
audit_id=self.audit.id
|
||||
audit_id=self.audit.id,
|
||||
strategy_id=self.strategy.id,
|
||||
audit=self.audit,
|
||||
strategy=self.strategy,
|
||||
)
|
||||
|
||||
@mock.patch.object(objects.action_plan.ActionPlan, 'list')
|
||||
|
@ -153,7 +153,6 @@ class FakeMonascaMetrics(object):
|
||||
# measurements[uuid] = random.randint(1, 4)
|
||||
measurements[uuid] = 8
|
||||
|
||||
# import ipdb; ipdb.set_trace()
|
||||
return [{'columns': ['avg'],
|
||||
'statistics': [[float(measurements[str(uuid)])]]}]
|
||||
# return float(measurements[str(uuid)])
|
||||
|
@ -60,6 +60,7 @@ class TestActionScheduling(base.DbTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestActionScheduling, self).setUp()
|
||||
self.goal = db_utils.create_test_goal(name="dummy")
|
||||
self.strategy = db_utils.create_test_strategy(name="dummy")
|
||||
self.audit = db_utils.create_test_audit(
|
||||
uuid=utils.generate_uuid(), strategy_id=self.strategy.id)
|
||||
|
@ -61,6 +61,7 @@ class TestActionScheduling(base.DbTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestActionScheduling, self).setUp()
|
||||
self.goal = db_utils.create_test_goal(name="dummy")
|
||||
self.strategy = db_utils.create_test_strategy(name="dummy")
|
||||
self.audit = db_utils.create_test_audit(
|
||||
uuid=utils.generate_uuid(), strategy_id=self.strategy.id)
|
||||
|
261
watcher/tests/notifications/test_action_plan_notification.py
Normal file
261
watcher/tests/notifications/test_action_plan_notification.py
Normal file
@ -0,0 +1,261 @@
|
||||
# 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 TestActionPlanNotification(base.DbTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestActionPlanNotification, 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.audit = utils.create_test_audit(mock.Mock(), interval=None)
|
||||
self.strategy = utils.create_test_strategy(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_plan_update(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_update(
|
||||
mock.MagicMock(), action_plan, host='node0',
|
||||
old_state=objects.action_plan.State.PENDING)
|
||||
|
||||
# The 1st notification is because we created the 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]
|
||||
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.data": {
|
||||
"global_efficacy": {},
|
||||
"strategy_uuid": "cb3d0b58-4415-4d90-b75b-1e96878730e3",
|
||||
"strategy": {
|
||||
"watcher_object.namespace": "watcher",
|
||||
"watcher_object.version": "1.0",
|
||||
"watcher_object.data": {
|
||||
"updated_at": None,
|
||||
"uuid": "cb3d0b58-4415-4d90-b75b-1e96878730e3",
|
||||
"name": "TEST",
|
||||
"parameters_spec": {},
|
||||
"created_at": "2016-10-18T09:52:05Z",
|
||||
"display_name": "test strategy",
|
||||
"deleted_at": None
|
||||
},
|
||||
"watcher_object.name": "StrategyPayload"
|
||||
},
|
||||
"uuid": "76be87bd-3422-43f9-93a0-e85a577e3061",
|
||||
"audit_uuid": "10a47dd1-4874-4298-91cf-eff046dbdb8d",
|
||||
"audit": {
|
||||
"watcher_object.data": {
|
||||
"interval": None,
|
||||
"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.0"
|
||||
},
|
||||
"deleted_at": None,
|
||||
"state": "ONGOING",
|
||||
"updated_at": None,
|
||||
"created_at": "2016-10-18T09:52:05Z",
|
||||
"state_update": {
|
||||
"watcher_object.namespace": "watcher",
|
||||
"watcher_object.version": "1.0",
|
||||
"watcher_object.data": {
|
||||
"old_state": "PENDING",
|
||||
"state": "ONGOING"
|
||||
},
|
||||
"watcher_object.name": "ActionPlanStateUpdatePayload"
|
||||
},
|
||||
},
|
||||
"watcher_object.name": "ActionPlanUpdatePayload"
|
||||
},
|
||||
payload
|
||||
)
|
||||
|
||||
def test_send_action_plan_create(self):
|
||||
action_plan = utils.get_test_action_plan(
|
||||
mock.Mock(), state=objects.action_plan.State.PENDING,
|
||||
audit_id=self.audit.id, strategy_id=self.strategy.id,
|
||||
audit=self.audit.as_dict(), strategy=self.strategy.as_dict())
|
||||
notifications.action_plan.send_create(
|
||||
mock.MagicMock(), action_plan, host='node0')
|
||||
|
||||
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",
|
||||
"watcher_object.version": "1.0",
|
||||
"watcher_object.data": {
|
||||
"global_efficacy": {},
|
||||
"strategy_uuid": "cb3d0b58-4415-4d90-b75b-1e96878730e3",
|
||||
"strategy": {
|
||||
"watcher_object.namespace": "watcher",
|
||||
"watcher_object.version": "1.0",
|
||||
"watcher_object.data": {
|
||||
"updated_at": None,
|
||||
"uuid": "cb3d0b58-4415-4d90-b75b-1e96878730e3",
|
||||
"name": "TEST",
|
||||
"parameters_spec": {},
|
||||
"created_at": "2016-10-18T09:52:05Z",
|
||||
"display_name": "test strategy",
|
||||
"deleted_at": None
|
||||
},
|
||||
"watcher_object.name": "StrategyPayload"
|
||||
},
|
||||
"uuid": "76be87bd-3422-43f9-93a0-e85a577e3061",
|
||||
"audit_uuid": "10a47dd1-4874-4298-91cf-eff046dbdb8d",
|
||||
"audit": {
|
||||
"watcher_object.data": {
|
||||
"interval": None,
|
||||
"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.0"
|
||||
},
|
||||
"deleted_at": None,
|
||||
"state": "PENDING",
|
||||
"updated_at": None,
|
||||
"created_at": None,
|
||||
},
|
||||
"watcher_object.name": "ActionPlanCreatePayload"
|
||||
},
|
||||
payload
|
||||
)
|
||||
|
||||
def test_send_action_plan_delete(self):
|
||||
action_plan = utils.create_test_action_plan(
|
||||
mock.Mock(), state=objects.action_plan.State.DELETED,
|
||||
audit_id=self.audit.id, strategy_id=self.strategy.id)
|
||||
notifications.action_plan.send_delete(
|
||||
mock.MagicMock(), action_plan, 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(3, 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.data": {
|
||||
"global_efficacy": {},
|
||||
"strategy_uuid": "cb3d0b58-4415-4d90-b75b-1e96878730e3",
|
||||
"strategy": {
|
||||
"watcher_object.namespace": "watcher",
|
||||
"watcher_object.version": "1.0",
|
||||
"watcher_object.data": {
|
||||
"updated_at": None,
|
||||
"uuid": "cb3d0b58-4415-4d90-b75b-1e96878730e3",
|
||||
"name": "TEST",
|
||||
"parameters_spec": {},
|
||||
"created_at": "2016-10-18T09:52:05Z",
|
||||
"display_name": "test strategy",
|
||||
"deleted_at": None
|
||||
},
|
||||
"watcher_object.name": "StrategyPayload"
|
||||
},
|
||||
"uuid": "76be87bd-3422-43f9-93a0-e85a577e3061",
|
||||
"audit_uuid": "10a47dd1-4874-4298-91cf-eff046dbdb8d",
|
||||
"audit": {
|
||||
"watcher_object.data": {
|
||||
"interval": None,
|
||||
"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.0"
|
||||
},
|
||||
"deleted_at": None,
|
||||
"state": "DELETED",
|
||||
"updated_at": None,
|
||||
"created_at": "2016-10-18T09:52:05Z",
|
||||
},
|
||||
"watcher_object.name": "ActionPlanDeletePayload"
|
||||
},
|
||||
payload
|
||||
)
|
@ -43,8 +43,8 @@ class TestAuditNotification(base.DbTestCase):
|
||||
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)
|
||||
audit = utils.get_test_audit(
|
||||
mock.Mock(), interval=None, state='DOESNOTMATTER', goal_id=1)
|
||||
|
||||
self.assertRaises(
|
||||
exception.InvalidAudit,
|
||||
@ -53,7 +53,7 @@ class TestAuditNotification(base.DbTestCase):
|
||||
|
||||
def test_send_audit_update_with_strategy(self):
|
||||
audit = utils.create_test_audit(
|
||||
mock.Mock(), state=objects.audit.State.ONGOING,
|
||||
mock.Mock(), interval=None, state=objects.audit.State.ONGOING,
|
||||
goal_id=self.goal.id, strategy_id=self.strategy.id,
|
||||
goal=self.goal, strategy=self.strategy)
|
||||
notifications.audit.send_update(
|
||||
@ -71,7 +71,8 @@ class TestAuditNotification(base.DbTestCase):
|
||||
"watcher_object.namespace": "watcher",
|
||||
"watcher_object.version": "1.0",
|
||||
"watcher_object.data": {
|
||||
"interval": 3600,
|
||||
"interval": None,
|
||||
"strategy_uuid": "cb3d0b58-4415-4d90-b75b-1e96878730e3",
|
||||
"strategy": {
|
||||
"watcher_object.namespace": "watcher",
|
||||
"watcher_object.version": "1.0",
|
||||
@ -88,6 +89,7 @@ class TestAuditNotification(base.DbTestCase):
|
||||
},
|
||||
"parameters": {},
|
||||
"uuid": "10a47dd1-4874-4298-91cf-eff046dbdb8d",
|
||||
"goal_uuid": "f7ad87ae-4298-91cf-93a0-f35a852e3652",
|
||||
"goal": {
|
||||
"watcher_object.namespace": "watcher",
|
||||
"watcher_object.version": "1.0",
|
||||
@ -125,7 +127,7 @@ class TestAuditNotification(base.DbTestCase):
|
||||
|
||||
def test_send_audit_update_without_strategy(self):
|
||||
audit = utils.get_test_audit(
|
||||
mock.Mock(), state=objects.audit.State.ONGOING,
|
||||
mock.Mock(), interval=None, state=objects.audit.State.ONGOING,
|
||||
goal_id=self.goal.id, goal=self.goal)
|
||||
notifications.audit.send_update(
|
||||
mock.MagicMock(), audit, host='node0',
|
||||
@ -141,9 +143,10 @@ class TestAuditNotification(base.DbTestCase):
|
||||
"watcher_object.namespace": "watcher",
|
||||
"watcher_object.version": "1.0",
|
||||
"watcher_object.data": {
|
||||
"interval": 3600,
|
||||
"interval": None,
|
||||
"parameters": {},
|
||||
"uuid": "10a47dd1-4874-4298-91cf-eff046dbdb8d",
|
||||
"goal_uuid": "f7ad87ae-4298-91cf-93a0-f35a852e3652",
|
||||
"goal": {
|
||||
"watcher_object.namespace": "watcher",
|
||||
"watcher_object.version": "1.0",
|
||||
@ -158,6 +161,7 @@ class TestAuditNotification(base.DbTestCase):
|
||||
},
|
||||
"watcher_object.name": "GoalPayload"
|
||||
},
|
||||
"strategy_uuid": None,
|
||||
"strategy": None,
|
||||
"deleted_at": None,
|
||||
"scope": [],
|
||||
@ -182,7 +186,7 @@ class TestAuditNotification(base.DbTestCase):
|
||||
|
||||
def test_send_audit_create(self):
|
||||
audit = utils.get_test_audit(
|
||||
mock.Mock(), state=objects.audit.State.PENDING,
|
||||
mock.Mock(), interval=None, state=objects.audit.State.PENDING,
|
||||
goal_id=self.goal.id, strategy_id=self.strategy.id,
|
||||
goal=self.goal.as_dict(), strategy=self.strategy.as_dict())
|
||||
notifications.audit.send_create(
|
||||
@ -198,7 +202,8 @@ class TestAuditNotification(base.DbTestCase):
|
||||
"watcher_object.namespace": "watcher",
|
||||
"watcher_object.version": "1.0",
|
||||
"watcher_object.data": {
|
||||
"interval": 3600,
|
||||
"interval": None,
|
||||
"strategy_uuid": "cb3d0b58-4415-4d90-b75b-1e96878730e3",
|
||||
"strategy": {
|
||||
"watcher_object.namespace": "watcher",
|
||||
"watcher_object.version": "1.0",
|
||||
@ -215,6 +220,7 @@ class TestAuditNotification(base.DbTestCase):
|
||||
},
|
||||
"parameters": {},
|
||||
"uuid": "10a47dd1-4874-4298-91cf-eff046dbdb8d",
|
||||
"goal_uuid": "f7ad87ae-4298-91cf-93a0-f35a852e3652",
|
||||
"goal": {
|
||||
"watcher_object.namespace": "watcher",
|
||||
"watcher_object.version": "1.0",
|
||||
@ -243,7 +249,7 @@ class TestAuditNotification(base.DbTestCase):
|
||||
|
||||
def test_send_audit_delete(self):
|
||||
audit = utils.create_test_audit(
|
||||
mock.Mock(), state=objects.audit.State.DELETED,
|
||||
mock.Mock(), interval=None, state=objects.audit.State.DELETED,
|
||||
goal_id=self.goal.id, strategy_id=self.strategy.id)
|
||||
notifications.audit.send_delete(
|
||||
mock.MagicMock(), audit, host='node0')
|
||||
@ -259,7 +265,8 @@ class TestAuditNotification(base.DbTestCase):
|
||||
"watcher_object.namespace": "watcher",
|
||||
"watcher_object.version": "1.0",
|
||||
"watcher_object.data": {
|
||||
"interval": 3600,
|
||||
"interval": None,
|
||||
"strategy_uuid": "cb3d0b58-4415-4d90-b75b-1e96878730e3",
|
||||
"strategy": {
|
||||
"watcher_object.namespace": "watcher",
|
||||
"watcher_object.version": "1.0",
|
||||
@ -276,6 +283,7 @@ class TestAuditNotification(base.DbTestCase):
|
||||
},
|
||||
"parameters": {},
|
||||
"uuid": "10a47dd1-4874-4298-91cf-eff046dbdb8d",
|
||||
"goal_uuid": "f7ad87ae-4298-91cf-93a0-f35a852e3652",
|
||||
"goal": {
|
||||
"watcher_object.namespace": "watcher",
|
||||
"watcher_object.version": "1.0",
|
||||
@ -304,7 +312,7 @@ class TestAuditNotification(base.DbTestCase):
|
||||
|
||||
def test_send_audit_action(self):
|
||||
audit = utils.create_test_audit(
|
||||
mock.Mock(), state=objects.audit.State.ONGOING,
|
||||
mock.Mock(), interval=None, state=objects.audit.State.ONGOING,
|
||||
goal_id=self.goal.id, strategy_id=self.strategy.id,
|
||||
goal=self.goal, strategy=self.strategy)
|
||||
notifications.audit.send_action_notification(
|
||||
@ -326,6 +334,7 @@ class TestAuditNotification(base.DbTestCase):
|
||||
"created_at": "2016-10-18T09:52:05Z",
|
||||
"deleted_at": None,
|
||||
"fault": None,
|
||||
"goal_uuid": "f7ad87ae-4298-91cf-93a0-f35a852e3652",
|
||||
"goal": {
|
||||
"watcher_object.data": {
|
||||
"created_at": "2016-10-18T09:52:05Z",
|
||||
@ -340,10 +349,12 @@ class TestAuditNotification(base.DbTestCase):
|
||||
"watcher_object.namespace": "watcher",
|
||||
"watcher_object.version": "1.0"
|
||||
},
|
||||
"interval": 3600,
|
||||
"interval": None,
|
||||
"parameters": {},
|
||||
"scope": [],
|
||||
"state": "ONGOING",
|
||||
"strategy_uuid": (
|
||||
"cb3d0b58-4415-4d90-b75b-1e96878730e3"),
|
||||
"strategy": {
|
||||
"watcher_object.data": {
|
||||
"created_at": "2016-10-18T09:52:05Z",
|
||||
@ -371,7 +382,7 @@ class TestAuditNotification(base.DbTestCase):
|
||||
|
||||
def test_send_audit_action_with_error(self):
|
||||
audit = utils.create_test_audit(
|
||||
mock.Mock(), state=objects.audit.State.ONGOING,
|
||||
mock.Mock(), interval=None, state=objects.audit.State.ONGOING,
|
||||
goal_id=self.goal.id, strategy_id=self.strategy.id,
|
||||
goal=self.goal, strategy=self.strategy)
|
||||
|
||||
@ -407,6 +418,7 @@ class TestAuditNotification(base.DbTestCase):
|
||||
"watcher_object.namespace": "watcher",
|
||||
"watcher_object.version": "1.0"
|
||||
},
|
||||
"goal_uuid": "f7ad87ae-4298-91cf-93a0-f35a852e3652",
|
||||
"goal": {
|
||||
"watcher_object.data": {
|
||||
"created_at": "2016-10-18T09:52:05Z",
|
||||
@ -421,10 +433,12 @@ class TestAuditNotification(base.DbTestCase):
|
||||
"watcher_object.namespace": "watcher",
|
||||
"watcher_object.version": "1.0"
|
||||
},
|
||||
"interval": 3600,
|
||||
"interval": None,
|
||||
"parameters": {},
|
||||
"scope": [],
|
||||
"state": "ONGOING",
|
||||
"strategy_uuid": (
|
||||
"cb3d0b58-4415-4d90-b75b-1e96878730e3"),
|
||||
"strategy": {
|
||||
"watcher_object.data": {
|
||||
"created_at": "2016-10-18T09:52:05Z",
|
||||
|
@ -250,10 +250,11 @@ class TestNotificationBase(testbase.TestCase):
|
||||
|
||||
|
||||
expected_notification_fingerprints = {
|
||||
'EventType': '1.2-633c2d32fa849d2a6f8bda3b0db88332',
|
||||
'EventType': '1.3-4258a2c86eca79fd34a7dffe1278eab9',
|
||||
'ExceptionNotification': '1.0-9b69de0724fda8310d05e18418178866',
|
||||
'ExceptionPayload': '1.0-4516ae282a55fe2fd5c754967ee6248b',
|
||||
'NotificationPublisher': '1.0-bbbc1402fb0e443a3eb227cc52b61545',
|
||||
'TerseAuditPayload': '1.0-aaf31166b8698f08d12cae98c380b8e0',
|
||||
'AuditPayload': '1.0-30c85c834648c8ca11f54fc5e084d86b',
|
||||
'AuditStateUpdatePayload': '1.0-1a1b606bf14a2c468800c2b010801ce5',
|
||||
'AuditUpdateNotification': '1.0-9b69de0724fda8310d05e18418178866',
|
||||
@ -266,6 +267,15 @@ expected_notification_fingerprints = {
|
||||
'AuditActionPayload': '1.0-09f5d005f94ba9e5f6b9200170332c52',
|
||||
'GoalPayload': '1.0-fa1fecb8b01dd047eef808ded4d50d1a',
|
||||
'StrategyPayload': '1.0-94f01c137b083ac236ae82573c1fcfc1',
|
||||
'ActionPlanActionPayload': '1.0-34871caf18e9b43a28899953c1c9733a',
|
||||
'ActionPlanCreateNotification': '1.0-9b69de0724fda8310d05e18418178866',
|
||||
'ActionPlanCreatePayload': '1.0-ffc3087acd73351b14f3dcc30e105027',
|
||||
'ActionPlanDeleteNotification': '1.0-9b69de0724fda8310d05e18418178866',
|
||||
'ActionPlanDeletePayload': '1.0-ffc3087acd73351b14f3dcc30e105027',
|
||||
'ActionPlanPayload': '1.0-ffc3087acd73351b14f3dcc30e105027',
|
||||
'ActionPlanStateUpdatePayload': '1.0-1a1b606bf14a2c468800c2b010801ce5',
|
||||
'ActionPlanUpdateNotification': '1.0-9b69de0724fda8310d05e18418178866',
|
||||
'ActionPlanUpdatePayload': '1.0-7912a45fe53775c721f42aa87f06a023',
|
||||
}
|
||||
|
||||
|
||||
|
@ -20,6 +20,7 @@ import mock
|
||||
|
||||
from watcher.common import exception
|
||||
from watcher.db.sqlalchemy import api as db_api
|
||||
from watcher import notifications
|
||||
from watcher import objects
|
||||
from watcher.tests.db import base
|
||||
from watcher.tests.db import utils
|
||||
@ -34,16 +35,19 @@ class TestActionPlanObject(base.DbTestCase):
|
||||
('non_eager', dict(
|
||||
eager=False,
|
||||
fake_action_plan=utils.get_test_action_plan(
|
||||
created_at=datetime.datetime.utcnow(),
|
||||
audit_id=audit_id,
|
||||
strategy_id=strategy_id))),
|
||||
('eager_with_non_eager_load', dict(
|
||||
eager=True,
|
||||
fake_action_plan=utils.get_test_action_plan(
|
||||
created_at=datetime.datetime.utcnow(),
|
||||
audit_id=audit_id,
|
||||
strategy_id=strategy_id))),
|
||||
('eager_with_eager_load', dict(
|
||||
eager=True,
|
||||
fake_action_plan=utils.get_test_action_plan(
|
||||
created_at=datetime.datetime.utcnow(),
|
||||
strategy_id=strategy_id,
|
||||
strategy=utils.get_test_strategy(id=strategy_id),
|
||||
audit_id=audit_id,
|
||||
@ -52,6 +56,13 @@ class TestActionPlanObject(base.DbTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestActionPlanObject, self).setUp()
|
||||
|
||||
p_action_plan_notifications = mock.patch.object(
|
||||
notifications, 'action_plan', autospec=True)
|
||||
self.m_action_plan_notifications = p_action_plan_notifications.start()
|
||||
self.addCleanup(p_action_plan_notifications.stop)
|
||||
self.m_send_update = self.m_action_plan_notifications.send_update
|
||||
|
||||
self.fake_audit = utils.create_test_audit(id=self.audit_id)
|
||||
self.fake_strategy = utils.create_test_strategy(
|
||||
id=self.strategy_id, name="DUMMY")
|
||||
@ -80,6 +91,7 @@ class TestActionPlanObject(base.DbTestCase):
|
||||
self.context, action_plan_id, eager=self.eager)
|
||||
self.assertEqual(self.context, action_plan._context)
|
||||
self.eager_load_action_plan_assert(action_plan)
|
||||
self.assertEqual(0, self.m_send_update.call_count)
|
||||
|
||||
@mock.patch.object(db_api.Connection, 'get_action_plan_by_uuid')
|
||||
def test_get_by_uuid(self, mock_get_action_plan):
|
||||
@ -91,6 +103,7 @@ class TestActionPlanObject(base.DbTestCase):
|
||||
self.context, uuid, eager=self.eager)
|
||||
self.assertEqual(self.context, action_plan._context)
|
||||
self.eager_load_action_plan_assert(action_plan)
|
||||
self.assertEqual(0, self.m_send_update.call_count)
|
||||
|
||||
def test_get_bad_id_and_uuid(self):
|
||||
self.assertRaises(exception.InvalidIdentity,
|
||||
@ -107,14 +120,26 @@ class TestActionPlanObject(base.DbTestCase):
|
||||
self.assertEqual(self.context, action_plans[0]._context)
|
||||
for action_plan in action_plans:
|
||||
self.eager_load_action_plan_assert(action_plan)
|
||||
self.assertEqual(0, self.m_send_update.call_count)
|
||||
|
||||
@mock.patch.object(db_api.Connection, 'update_action_plan')
|
||||
@mock.patch.object(db_api.Connection, 'get_action_plan_by_uuid')
|
||||
def test_save(self, mock_get_action_plan, mock_update_action_plan):
|
||||
mock_get_action_plan.return_value = self.fake_action_plan
|
||||
fake_saved_action_plan = self.fake_action_plan.copy()
|
||||
fake_saved_action_plan['deleted_at'] = datetime.datetime.utcnow()
|
||||
fake_saved_action_plan['state'] = objects.action_plan.State.SUCCEEDED
|
||||
fake_saved_action_plan['updated_at'] = datetime.datetime.utcnow()
|
||||
|
||||
mock_update_action_plan.return_value = fake_saved_action_plan
|
||||
|
||||
expected_action_plan = fake_saved_action_plan.copy()
|
||||
expected_action_plan[
|
||||
'created_at'] = expected_action_plan['created_at'].replace(
|
||||
tzinfo=iso8601.iso8601.Utc())
|
||||
expected_action_plan[
|
||||
'updated_at'] = expected_action_plan['updated_at'].replace(
|
||||
tzinfo=iso8601.iso8601.Utc())
|
||||
|
||||
uuid = self.fake_action_plan['uuid']
|
||||
action_plan = objects.ActionPlan.get_by_uuid(
|
||||
self.context, uuid, eager=self.eager)
|
||||
@ -127,6 +152,14 @@ class TestActionPlanObject(base.DbTestCase):
|
||||
uuid, {'state': objects.action_plan.State.SUCCEEDED})
|
||||
self.assertEqual(self.context, action_plan._context)
|
||||
self.eager_load_action_plan_assert(action_plan)
|
||||
self.m_send_update.assert_called_once_with(
|
||||
self.context, action_plan,
|
||||
old_state=self.fake_action_plan['state'])
|
||||
self.assertEqual(
|
||||
{k: v for k, v in expected_action_plan.items()
|
||||
if k not in action_plan.object_fields},
|
||||
{k: v for k, v in action_plan.as_dict().items()
|
||||
if k not in action_plan.object_fields})
|
||||
|
||||
@mock.patch.object(db_api.Connection, 'get_action_plan_by_uuid')
|
||||
def test_refresh(self, mock_get_action_plan):
|
||||
@ -150,6 +183,13 @@ class TestCreateDeleteActionPlanObject(base.DbTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestCreateDeleteActionPlanObject, self).setUp()
|
||||
|
||||
p_action_plan_notifications = mock.patch.object(
|
||||
notifications, 'action_plan', autospec=True)
|
||||
self.m_action_plan_notifications = p_action_plan_notifications.start()
|
||||
self.addCleanup(p_action_plan_notifications.stop)
|
||||
self.m_send_update = self.m_action_plan_notifications.send_update
|
||||
|
||||
self.fake_strategy = utils.create_test_strategy(name="DUMMY")
|
||||
self.fake_audit = utils.create_test_audit()
|
||||
self.fake_action_plan = utils.get_test_action_plan(
|
||||
@ -202,7 +242,8 @@ class TestCreateDeleteActionPlanObject(base.DbTestCase):
|
||||
del expected_action_plan['strategy']
|
||||
|
||||
m_get_efficacy_indicator_list.return_value = [efficacy_indicator]
|
||||
action_plan = objects.ActionPlan.get_by_uuid(self.context, uuid)
|
||||
action_plan = objects.ActionPlan.get_by_uuid(
|
||||
self.context, uuid, eager=False)
|
||||
action_plan.soft_delete()
|
||||
|
||||
m_get_action_plan.assert_called_once_with(
|
||||
|
@ -282,6 +282,7 @@ class TestAuditObjectSendNotifications(base.DbTestCase):
|
||||
def test_send_create_notification(self, m_create_audit):
|
||||
audit = objutils.get_test_audit(
|
||||
self.context,
|
||||
id=1,
|
||||
goal_id=self.fake_goal.id,
|
||||
strategy_id=self.fake_strategy.id,
|
||||
goal=self.fake_goal.as_dict(),
|
||||
|
@ -30,21 +30,27 @@ def _load_related_objects(context, cls, db_data):
|
||||
return obj_data
|
||||
|
||||
|
||||
def _load_test_obj(context, cls, obj_data, **kw):
|
||||
# Let DB generate ID if it isn't specified explicitly
|
||||
if 'id' not in kw:
|
||||
del obj_data['id']
|
||||
obj = cls(context)
|
||||
for key in obj_data:
|
||||
setattr(obj, key, obj_data[key])
|
||||
return obj
|
||||
|
||||
|
||||
def get_test_audit_template(context, **kw):
|
||||
"""Return a AuditTemplate object with appropriate attributes.
|
||||
|
||||
NOTE: The object leaves the attributes marked as changed, such
|
||||
that a create() could be used to commit it to the DB.
|
||||
"""
|
||||
db_audit_template = db_utils.get_test_audit_template(**kw)
|
||||
# Let DB generate ID if it isn't specified explicitly
|
||||
if 'id' not in kw:
|
||||
del db_audit_template['id']
|
||||
audit_template = objects.AuditTemplate(context)
|
||||
for key in db_audit_template:
|
||||
setattr(audit_template, key, db_audit_template[key])
|
||||
obj_cls = objects.AuditTemplate
|
||||
db_data = db_utils.get_test_audit_template(**kw)
|
||||
obj_data = _load_related_objects(context, obj_cls, db_data)
|
||||
|
||||
return audit_template
|
||||
return _load_test_obj(context, obj_cls, obj_data, **kw)
|
||||
|
||||
|
||||
def create_test_audit_template(context, **kw):
|
||||
@ -64,16 +70,11 @@ def get_test_audit(context, **kw):
|
||||
NOTE: The object leaves the attributes marked as changed, such
|
||||
that a create() could be used to commit it to the DB.
|
||||
"""
|
||||
db_audit = db_utils.get_test_audit(**kw)
|
||||
obj_data = _load_related_objects(context, objects.Audit, db_audit)
|
||||
obj_cls = objects.Audit
|
||||
db_data = db_utils.get_test_audit(**kw)
|
||||
obj_data = _load_related_objects(context, obj_cls, db_data)
|
||||
|
||||
# Let DB generate ID if it isn't specified explicitly
|
||||
if 'id' not in kw:
|
||||
del db_audit['id']
|
||||
audit = objects.Audit(context)
|
||||
for key in obj_data:
|
||||
setattr(audit, key, obj_data[key])
|
||||
return audit
|
||||
return _load_test_obj(context, obj_cls, obj_data, **kw)
|
||||
|
||||
|
||||
def create_test_audit(context, **kw):
|
||||
@ -93,14 +94,11 @@ def get_test_action_plan(context, **kw):
|
||||
NOTE: The object leaves the attributes marked as changed, such
|
||||
that a create() could be used to commit it to the DB.
|
||||
"""
|
||||
db_action_plan = db_utils.get_test_action_plan(**kw)
|
||||
# Let DB generate ID if it isn't specified explicitly
|
||||
if 'id' not in kw:
|
||||
del db_action_plan['id']
|
||||
action_plan = objects.ActionPlan(context)
|
||||
for key in db_action_plan:
|
||||
setattr(action_plan, key, db_action_plan[key])
|
||||
return action_plan
|
||||
obj_cls = objects.ActionPlan
|
||||
db_data = db_utils.get_test_action_plan(**kw)
|
||||
obj_data = _load_related_objects(context, obj_cls, db_data)
|
||||
|
||||
return _load_test_obj(context, obj_cls, obj_data, **kw)
|
||||
|
||||
|
||||
def create_test_action_plan(context, **kw):
|
||||
@ -120,14 +118,11 @@ def get_test_action(context, **kw):
|
||||
NOTE: The object leaves the attributes marked as changed, such
|
||||
that a create() could be used to commit it to the DB.
|
||||
"""
|
||||
db_action = db_utils.get_test_action(**kw)
|
||||
# Let DB generate ID if it isn't specified explicitly
|
||||
if 'id' not in kw:
|
||||
del db_action['id']
|
||||
action = objects.Action(context)
|
||||
for key in db_action:
|
||||
setattr(action, key, db_action[key])
|
||||
return action
|
||||
obj_cls = objects.Action
|
||||
db_data = db_utils.get_test_action(**kw)
|
||||
obj_data = _load_related_objects(context, obj_cls, db_data)
|
||||
|
||||
return _load_test_obj(context, obj_cls, obj_data, **kw)
|
||||
|
||||
|
||||
def create_test_action(context, **kw):
|
||||
@ -147,14 +142,11 @@ def get_test_goal(context, **kw):
|
||||
NOTE: The object leaves the attributes marked as changed, such
|
||||
that a create() could be used to commit it to the DB.
|
||||
"""
|
||||
db_goal = db_utils.get_test_goal(**kw)
|
||||
# Let DB generate ID if it isn't specified explicitly
|
||||
if 'id' not in kw:
|
||||
del db_goal['id']
|
||||
goal = objects.Goal(context)
|
||||
for key in db_goal:
|
||||
setattr(goal, key, db_goal[key])
|
||||
return goal
|
||||
obj_cls = objects.Goal
|
||||
db_data = db_utils.get_test_goal(**kw)
|
||||
obj_data = _load_related_objects(context, obj_cls, db_data)
|
||||
|
||||
return _load_test_obj(context, obj_cls, obj_data, **kw)
|
||||
|
||||
|
||||
def create_test_goal(context, **kw):
|
||||
@ -174,11 +166,11 @@ def get_test_scoring_engine(context, **kw):
|
||||
NOTE: The object leaves the attributes marked as changed, such
|
||||
that a create() could be used to commit it to the DB.
|
||||
"""
|
||||
db_scoring_engine = db_utils.get_test_scoring_engine(**kw)
|
||||
scoring_engine = objects.ScoringEngine(context)
|
||||
for key in db_scoring_engine:
|
||||
setattr(scoring_engine, key, db_scoring_engine[key])
|
||||
return scoring_engine
|
||||
obj_cls = objects.ScoringEngine
|
||||
db_data = db_utils.get_test_scoring_engine(**kw)
|
||||
obj_data = _load_related_objects(context, obj_cls, db_data)
|
||||
|
||||
return _load_test_obj(context, obj_cls, obj_data, **kw)
|
||||
|
||||
|
||||
def create_test_scoring_engine(context, **kw):
|
||||
@ -198,13 +190,11 @@ def get_test_service(context, **kw):
|
||||
NOTE: The object leaves the attributes marked as changed, such
|
||||
that a create() could be used to commit it to the DB.
|
||||
"""
|
||||
db_service = db_utils.get_test_service(**kw)
|
||||
service = objects.Service(context)
|
||||
for key in db_service:
|
||||
if key == 'last_seen_up':
|
||||
db_service[key] = None
|
||||
setattr(service, key, db_service[key])
|
||||
return service
|
||||
obj_cls = objects.Service
|
||||
db_data = db_utils.get_test_service(**kw)
|
||||
obj_data = _load_related_objects(context, obj_cls, db_data)
|
||||
|
||||
return _load_test_obj(context, obj_cls, obj_data, **kw)
|
||||
|
||||
|
||||
def create_test_service(context, **kw):
|
||||
@ -224,22 +214,11 @@ def get_test_strategy(context, **kw):
|
||||
NOTE: The object leaves the attributes marked as changed, such
|
||||
that a create() could be used to commit it to the DB.
|
||||
"""
|
||||
db_strategy = db_utils.get_test_strategy(**kw)
|
||||
# Let DB generate ID if it isn't specified explicitly
|
||||
if 'id' not in kw:
|
||||
del db_strategy['id']
|
||||
strategy = objects.Strategy(context)
|
||||
for key in db_strategy:
|
||||
setattr(strategy, key, db_strategy[key])
|
||||
obj_cls = objects.Strategy
|
||||
db_data = db_utils.get_test_strategy(**kw)
|
||||
obj_data = _load_related_objects(context, obj_cls, db_data)
|
||||
|
||||
# ObjectField checks for the object type, so if we want to simulate a
|
||||
# non-eager object loading, the field should not be referenced at all.
|
||||
# Contrarily, eager loading need the data to be casted to the object type
|
||||
# that was specified by the ObjectField.
|
||||
if kw.get('goal'):
|
||||
strategy.goal = objects.Goal(context, **kw.get('goal'))
|
||||
|
||||
return strategy
|
||||
return _load_test_obj(context, obj_cls, obj_data, **kw)
|
||||
|
||||
|
||||
def create_test_strategy(context, **kw):
|
||||
@ -259,14 +238,11 @@ def get_test_efficacy_indicator(context, **kw):
|
||||
NOTE: The object leaves the attributes marked as changed, such
|
||||
that a create() could be used to commit it to the DB.
|
||||
"""
|
||||
db_efficacy_indicator = db_utils.get_test_efficacy_indicator(**kw)
|
||||
# Let DB generate ID if it isn't specified explicitly
|
||||
if 'id' not in kw:
|
||||
del db_efficacy_indicator['id']
|
||||
efficacy_indicator = objects.EfficacyIndicator(context)
|
||||
for key in db_efficacy_indicator:
|
||||
setattr(efficacy_indicator, key, db_efficacy_indicator[key])
|
||||
return efficacy_indicator
|
||||
obj_cls = objects.EfficacyIndicator
|
||||
db_data = db_utils.get_test_efficacy_indicator(**kw)
|
||||
obj_data = _load_related_objects(context, obj_cls, db_data)
|
||||
|
||||
return _load_test_obj(context, obj_cls, obj_data, **kw)
|
||||
|
||||
|
||||
def create_test_efficacy_indicator(context, **kw):
|
||||
|
Loading…
Reference in New Issue
Block a user