diff --git a/releasenotes/notes/add-action-filter-40e775a26082f780.yaml b/releasenotes/notes/add-action-filter-40e775a26082f780.yaml new file mode 100644 index 000000000..84f3fd02d --- /dev/null +++ b/releasenotes/notes/add-action-filter-40e775a26082f780.yaml @@ -0,0 +1,6 @@ +--- +features: + - | + Add cluster_id as a parameter in query action APIs. + This allow we can filter result returned from API instead by received + so many result action. diff --git a/senlin/api/openstack/history.rst b/senlin/api/openstack/history.rst index a75fee361..cd200ba1e 100755 --- a/senlin/api/openstack/history.rst +++ b/senlin/api/openstack/history.rst @@ -126,3 +126,7 @@ it can be used by both users and developers. 1.13 ---- - Added ``tainted`` to responses returned by node APIs. + +1.14 +---- +- Added ``cluster_id`` to filters result returned action APIs. diff --git a/senlin/api/openstack/v1/actions.py b/senlin/api/openstack/v1/actions.py index 8b8a6962f..e22593a47 100644 --- a/senlin/api/openstack/v1/actions.py +++ b/senlin/api/openstack/v1/actions.py @@ -14,6 +14,7 @@ from webob import exc from senlin.api.common import util +from senlin.api.common import version_request as vr from senlin.api.common import wsgi from senlin.common import consts from senlin.common.i18n import _ @@ -54,10 +55,20 @@ class ActionController(wsgi.Controller): # (must match what is in policy file and policies in code.) REQUEST_SCOPE = 'actions' + def _remove_cluster_id(self, req, obj): + if req.version_request > vr.APIVersionRequest("1.13"): + return obj + + if 'cluster_id' in obj: + obj.pop('cluster_id') + + return obj + @util.policy_enforce def index(self, req): whitelist = { consts.ACTION_NAME: 'mixed', + consts.ACTION_CLUSTER_ID: 'mixed', consts.ACTION_TARGET: 'mixed', consts.ACTION_ACTION: 'mixed', consts.ACTION_STATUS: 'mixed', @@ -79,6 +90,7 @@ class ActionController(wsgi.Controller): obj = util.parse_request('ActionListRequest', req, params) actions = self.rpc_client.call(req.context, "action_list", obj) + actions = [self._remove_cluster_id(req, a) for a in actions] return {'actions': actions} @util.policy_enforce @@ -90,7 +102,7 @@ class ActionController(wsgi.Controller): data.action(), data.params()) - return result + return self._remove_cluster_id(req, result) @util.policy_enforce def get(self, req, action_id): @@ -98,6 +110,7 @@ class ActionController(wsgi.Controller): obj = util.parse_request('ActionGetRequest', req, params) action = self.rpc_client.call(req.context, 'action_get', obj) + action = self._remove_cluster_id(req, action) return {'action': action} @wsgi.Controller.api_version('1.12') diff --git a/senlin/api/openstack/v1/version.py b/senlin/api/openstack/v1/version.py index 4082a2bf4..1bdb2be55 100755 --- a/senlin/api/openstack/v1/version.py +++ b/senlin/api/openstack/v1/version.py @@ -23,7 +23,7 @@ class VersionController(object): # This includes any semantic changes which may not affect the input or # output formats or even originate in the API code layer. _MIN_API_VERSION = "1.0" - _MAX_API_VERSION = "1.13" + _MAX_API_VERSION = "1.14" DEFAULT_API_VERSION = _MIN_API_VERSION diff --git a/senlin/common/consts.py b/senlin/common/consts.py index c0f3099c5..09b9b2de5 100755 --- a/senlin/common/consts.py +++ b/senlin/common/consts.py @@ -211,13 +211,13 @@ EVENT_SORT_KEYS = [ ] ACTION_ATTRS = ( - ACTION_NAME, ACTION_TARGET, ACTION_ACTION, ACTION_CAUSE, + ACTION_NAME, ACTION_CLUSTER_ID, ACTION_TARGET, ACTION_ACTION, ACTION_CAUSE, ACTION_INTERVAL, ACTION_START_TIME, ACTION_END_TIME, ACTION_TIMEOUT, ACTION_STATUS, ACTION_STATUS_REASON, ACTION_INPUTS, ACTION_OUTPUTS, ACTION_DEPENDS_ON, ACTION_DEPENDED_BY, ACTION_CREATED_AT, ACTION_UPDATED_AT, ) = ( - 'name', 'target', 'action', 'cause', + 'name', 'cluster_id', 'target', 'action', 'cause', 'interval', 'start_time', 'end_time', 'timeout', 'status', 'status_reason', 'inputs', 'outputs', 'depends_on', 'depended_by', diff --git a/senlin/db/sqlalchemy/migrate_repo/versions/015_action_clusterid.py b/senlin/db/sqlalchemy/migrate_repo/versions/015_action_clusterid.py new file mode 100644 index 000000000..dc5d6805a --- /dev/null +++ b/senlin/db/sqlalchemy/migrate_repo/versions/015_action_clusterid.py @@ -0,0 +1,22 @@ +# 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 sqlalchemy import Column, MetaData, String, Table + + +def upgrade(migrate_engine): + meta = MetaData() + meta.bind = migrate_engine + + action = Table('action', meta, autoload=True) + action_cluster_id = Column('cluster_id', String(36), default="") + action_cluster_id.create(action) diff --git a/senlin/db/sqlalchemy/models.py b/senlin/db/sqlalchemy/models.py index 0f283bab7..a7dbf6fda 100644 --- a/senlin/db/sqlalchemy/models.py +++ b/senlin/db/sqlalchemy/models.py @@ -228,6 +228,7 @@ class Action(BASE, TimestampMixin, models.ModelBase): id = Column('id', String(36), primary_key=True, default=lambda: UUID4()) name = Column(String(63)) + cluster_id = Column(String(36)) context = Column(types.Dict) target = Column(String(36)) action = Column(Text) diff --git a/senlin/engine/actions/base.py b/senlin/engine/actions/base.py index b26cbcd22..a5e79b1f7 100755 --- a/senlin/engine/actions/base.py +++ b/senlin/engine/actions/base.py @@ -92,6 +92,7 @@ class Action(object): self.id = kwargs.get('id', None) self.name = kwargs.get('name', '') + self.cluster_id = kwargs.get('cluster_id', '') self.context = ctx self.user = ctx.user_id @@ -150,6 +151,7 @@ class Action(object): values = { 'name': self.name, + 'cluster_id': self.cluster_id, 'context': self.context.to_dict(), 'target': self.target, 'action': self.action, @@ -194,6 +196,7 @@ class Action(object): kwargs = { 'id': obj.id, 'name': obj.name, + 'cluster_id': obj.cluster_id, 'cause': obj.cause, 'owner': obj.owner, 'interval': obj.interval, @@ -625,6 +628,7 @@ class Action(object): action_dict = { 'id': self.id, 'name': self.name, + 'cluster_id': self.cluster_id, 'action': self.action, 'target': self.target, 'cause': self.cause, diff --git a/senlin/engine/actions/cluster_action.py b/senlin/engine/actions/cluster_action.py index 3563aa2c7..7d37fa808 100755 --- a/senlin/engine/actions/cluster_action.py +++ b/senlin/engine/actions/cluster_action.py @@ -168,6 +168,7 @@ class ClusterAction(base.Action): kwargs = { 'name': 'node_create_%s' % node.id[:8], + 'cluster_id': self.entity.id, 'cause': consts.CAUSE_DERIVED, } action_id = base.Action.create(self.context, node.id, @@ -243,6 +244,7 @@ class ClusterAction(base.Action): for node in nodes: kwargs = { 'name': 'node_update_%s' % node[:8], + 'cluster_id': self.entity.id, 'cause': consts.CAUSE_DERIVED, 'inputs': { 'new_profile_id': profile_id, @@ -349,6 +351,7 @@ class ClusterAction(base.Action): for node_id in node_ids: kwargs = { 'name': 'node_delete_%s' % node_id[:8], + 'cluster_id': self.entity.id, 'cause': consts.CAUSE_DERIVED_LCH, 'inputs': inputs or {}, } @@ -421,6 +424,7 @@ class ClusterAction(base.Action): for node_id in node_ids: kwargs = { 'name': 'node_delete_%s' % node_id[:8], + 'cluster_id': self.entity.id, 'cause': consts.CAUSE_DERIVED, 'inputs': inputs or {}, } @@ -594,6 +598,7 @@ class ClusterAction(base.Action): nid = node.id kwargs = { 'name': 'node_join_%s' % nid[:8], + 'cluster_id': self.entity.id, 'cause': consts.CAUSE_DERIVED, 'inputs': {'cluster_id': self.target}, } @@ -748,6 +753,7 @@ class ClusterAction(base.Action): children = [] for (original, replacement) in node_dict.items(): kwargs = { + 'cluster_id': self.entity.id, 'cause': consts.CAUSE_DERIVED, } diff --git a/senlin/engine/service.py b/senlin/engine/service.py index d464fbcf5..9cfc1d86d 100755 --- a/senlin/engine/service.py +++ b/senlin/engine/service.py @@ -788,6 +788,7 @@ class EngineService(service.Service): # Build an Action for cluster creation kwargs = { 'name': 'cluster_create_%s' % cluster.id[:8], + 'cluster_id': cluster.id, 'cause': consts.CAUSE_RPC, 'status': action_mod.Action.READY, } @@ -861,6 +862,7 @@ class EngineService(service.Service): kwargs = { 'name': 'cluster_update_%s' % cluster.id[:8], + 'cluster_id': cluster.id, 'cause': consts.CAUSE_RPC, 'status': action_mod.Action.READY, 'inputs': inputs, @@ -913,6 +915,7 @@ class EngineService(service.Service): params = { 'name': 'cluster_delete_%s' % cluster.id[:8], + 'cluster_id': cluster.id, 'cause': consts.CAUSE_RPC, 'status': action_mod.Action.READY, } @@ -991,6 +994,7 @@ class EngineService(service.Service): params = { 'name': 'cluster_add_nodes_%s' % db_cluster.id[:8], + 'cluster_id': db_cluster.id, 'cause': consts.CAUSE_RPC, 'status': action_mod.Action.READY, 'inputs': {'nodes': found}, @@ -1058,6 +1062,7 @@ class EngineService(service.Service): params = { 'name': 'cluster_del_nodes_%s' % db_cluster.id[:8], + 'cluster_id': db_cluster.id, 'cause': consts.CAUSE_RPC, 'status': action_mod.Action.READY, 'inputs': { @@ -1166,6 +1171,7 @@ class EngineService(service.Service): nodes = self._validate_replace_nodes(ctx, db_cluster, req.nodes) kwargs = { 'name': 'cluster_replace_nodes_%s' % db_cluster.id[:8], + 'cluster_id': db_cluster.id, 'cause': consts.CAUSE_RPC, 'status': action_mod.Action.READY, 'inputs': {'candidates': nodes}, @@ -1251,6 +1257,7 @@ class EngineService(service.Service): params = { 'name': 'cluster_resize_%s' % db_cluster.id[:8], + 'cluster_id': db_cluster.id, 'cause': consts.CAUSE_RPC, 'status': action_mod.Action.READY, 'inputs': { @@ -1297,6 +1304,7 @@ class EngineService(service.Service): params = { 'name': 'cluster_scale_out_%s' % db_cluster.id[:8], + 'cluster_id': db_cluster.id, 'cause': consts.CAUSE_RPC, 'status': action_mod.Action.READY, 'inputs': inputs, @@ -1337,6 +1345,7 @@ class EngineService(service.Service): params = { 'name': 'cluster_scale_in_%s' % db_cluster.id[:8], + 'cluster_id': db_cluster.id, 'cause': consts.CAUSE_RPC, 'status': action_mod.Action.READY, 'inputs': inputs, @@ -1393,6 +1402,7 @@ class EngineService(service.Service): kwargs = { 'name': 'cluster_check_%s' % db_cluster.id[:8], + 'cluster_id': db_cluster.id, 'cause': consts.CAUSE_RPC, 'status': action_mod.Action.READY, 'inputs': req.params if req.obj_attr_is_set('params') else {} @@ -1482,6 +1492,7 @@ class EngineService(service.Service): params = { 'name': 'cluster_recover_%s' % db_cluster.id[:8], + 'cluster_id': db_cluster.id, 'cause': consts.CAUSE_RPC, 'status': action_mod.Action.READY, 'inputs': inputs @@ -1557,6 +1568,7 @@ class EngineService(service.Service): kwargs = { 'name': 'cluster_%s_%s' % (req.operation, cluster.id[:8]), + 'cluster_id': db_cluster.id, 'cause': consts.CAUSE_RPC, 'status': action_mod.Action.READY, 'inputs': { @@ -1686,6 +1698,7 @@ class EngineService(service.Service): params = { 'name': 'node_create_%s' % node.id[:8], + 'cluster_id': cluster_id, 'cause': consts.CAUSE_RPC, 'status': action_mod.Action.READY, } @@ -1766,6 +1779,7 @@ class EngineService(service.Service): params = { 'name': 'node_update_%s' % node.id[:8], + 'cluster_id': node.cluster_id, 'cause': consts.CAUSE_RPC, 'status': action_mod.Action.READY, 'inputs': inputs, @@ -1813,6 +1827,7 @@ class EngineService(service.Service): params = { 'name': 'node_delete_%s' % node.id[:8], + 'cluster_id': node.cluster_id, 'cause': consts.CAUSE_RPC, 'status': action_mod.Action.READY, } @@ -1946,6 +1961,7 @@ class EngineService(service.Service): kwargs = { 'name': 'node_check_%s' % db_node.id[:8], + 'cluster_id': db_node.cluster_id, 'cause': consts.CAUSE_RPC, 'status': action_mod.Action.READY } @@ -1973,6 +1989,7 @@ class EngineService(service.Service): kwargs = { 'name': 'node_recover_%s' % db_node.id[:8], + 'cluster_id': db_node.cluster_id, 'cause': consts.CAUSE_RPC, 'status': action_mod.Action.READY, 'inputs': {} @@ -2036,6 +2053,7 @@ class EngineService(service.Service): kwargs = { 'name': 'node_%s_%s' % (req.operation, db_node.id[:8]), + 'cluster_id': db_node.cluster_id, 'cause': consts.CAUSE_RPC, 'status': action_mod.Action.READY, 'inputs': { @@ -2120,6 +2138,7 @@ class EngineService(service.Service): params = { 'name': 'attach_policy_%s' % db_cluster.id[:8], + 'cluster_id': db_cluster.id, 'cause': consts.CAUSE_RPC, 'status': action_mod.Action.READY, 'inputs': { @@ -2165,6 +2184,7 @@ class EngineService(service.Service): params = { 'name': 'detach_policy_%s' % db_cluster.id[:8], + 'cluster_id': db_cluster.id, 'cause': consts.CAUSE_RPC, 'status': action_mod.Action.READY, 'inputs': {'policy_id': db_policy.id}, @@ -2210,6 +2230,7 @@ class EngineService(service.Service): params = { 'name': 'update_policy_%s' % db_cluster.id[:8], + 'cluster_id': db_cluster.id, 'cause': consts.CAUSE_RPC, 'status': action_mod.Action.READY, 'inputs': inputs @@ -2246,6 +2267,17 @@ class EngineService(service.Service): filters = {} if req.obj_attr_is_set('name'): filters['name'] = req.name + # add filter with cluster_id + if req.obj_attr_is_set('cluster_id'): + cluster_ids = [] + for cid in req.cluster_id: + try: + cluster = co.Cluster.find(ctx, cid) + cluster_ids.append(cluster.id) + except exception.ResourceNotFound: + return [] + if len(cluster_ids) > 0: + filters['cluster_id'] = cluster_ids if req.obj_attr_is_set('action'): filters['action'] = req.action if req.obj_attr_is_set('target'): @@ -2280,6 +2312,7 @@ class EngineService(service.Service): # Create an action instance params = { 'name': req.name, + 'cluster_id': target.id, 'cause': consts.CAUSE_RPC, 'status': action_mod.Action.READY, 'inputs': req.inputs or {}, @@ -2572,6 +2605,7 @@ class EngineService(service.Service): kwargs = { 'name': 'webhook_%s' % receiver.id[:8], + 'cluster_id': db_cluster.id, 'cause': consts.CAUSE_RPC, 'status': action_mod.Action.READY, 'inputs': data diff --git a/senlin/objects/action.py b/senlin/objects/action.py index 8038a25c3..8aa2b6e83 100755 --- a/senlin/objects/action.py +++ b/senlin/objects/action.py @@ -30,6 +30,7 @@ class Action(base.SenlinObject, base.VersionedObjectDictCompat): 'created_at': fields.DateTimeField(), 'updated_at': fields.DateTimeField(nullable=True), 'name': fields.StringField(), + 'cluster_id': fields.StringField(), 'context': fields.JsonField(), 'target': fields.UUIDField(), 'action': fields.StringField(), @@ -191,6 +192,7 @@ class Action(base.SenlinObject, base.VersionedObjectDictCompat): action_dict = { 'id': self.id, 'name': self.name, + 'cluster_id': self.cluster_id, 'action': self.action, 'target': self.target, 'cause': self.cause, diff --git a/senlin/objects/requests/actions.py b/senlin/objects/requests/actions.py index 16b42917b..a7ae65b9d 100644 --- a/senlin/objects/requests/actions.py +++ b/senlin/objects/requests/actions.py @@ -10,6 +10,8 @@ # License for the specific language governing permissions and limitations # under the License. +from oslo_utils import versionutils + from senlin.common import consts from senlin.objects import base from senlin.objects import fields @@ -39,8 +41,14 @@ class ActionListRequest(base.SenlinObject): action_name_list = list(consts.CLUSTER_ACTION_NAMES) action_name_list.extend(list(consts.NODE_ACTION_NAMES)) + VERSION = '1.1' + VERSION_MAP = { + '1.14': '1.1' + } + fields = { 'name': fields.ListOfStringsField(nullable=True), + 'cluster_id': fields.ListOfStringsField(nullable=True), 'action': fields.ListOfEnumField( valid_values=action_name_list, nullable=True), 'target': fields.ListOfStringsField(nullable=True), @@ -53,6 +61,14 @@ class ActionListRequest(base.SenlinObject): 'project_safe': fields.FlexibleBooleanField(default=True) } + def obj_make_compatible(self, primitive, target_version): + super(ActionListRequest, self).obj_make_compatible( + primitive, target_version) + target_version = versionutils.convert_version_to_tuple(target_version) + if target_version < (1, 14): + if 'cluster_id' in primitive['senlin_object.data']: + del primitive['senlin_object.data']['cluster_id'] + @base.SenlinObjectRegistry.register class ActionGetRequest(base.SenlinObject): diff --git a/senlin/tests/unit/api/openstack/v1/test_actions.py b/senlin/tests/unit/api/openstack/v1/test_actions.py index 6893ec0b7..71ecb19fe 100644 --- a/senlin/tests/unit/api/openstack/v1/test_actions.py +++ b/senlin/tests/unit/api/openstack/v1/test_actions.py @@ -10,6 +10,7 @@ # License for the specific language governing permissions and limitations # under the License. +import copy import mock import six from webob import exc @@ -50,6 +51,7 @@ class ActionControllerTest(shared.ControllerTest, base.SenlinTestCase): { 'action': 'NODE_CREATE', 'cause': 'RPC_Request', + 'cluster_id': 'CLUSTER_FAKE_ID', 'depended_by': [], 'depends_on': [], 'end_time': 1425555000.0, @@ -79,6 +81,92 @@ class ActionControllerTest(shared.ControllerTest, base.SenlinTestCase): mock_call.assert_called_once_with( req.context, 'action_list', obj) + @mock.patch.object(util, 'parse_request') + @mock.patch.object(rpc_client.EngineClient, 'call') + def test_action_index_without_cluster_id(self, mock_call, mock_parse, + mock_enforce): + self._mock_enforce_setup(mock_enforce, 'index', True) + req = self._get('/actions', version='1.13') + + engine_resp = [ + { + 'action': 'NODE_CREATE', + 'cause': 'RPC_Request', + 'cluster_id': 'CLUSTER_FAKE_ID', + 'depended_by': [], + 'depends_on': [], + 'end_time': 1425555000.0, + 'id': '2366d400-c7e3-4961-09254-6d1c3f7ac167', + 'inputs': {}, + 'interval': -1, + 'name': 'node_create_0df0931b', + 'outputs': {}, + 'owner': None, + 'start_time': 1425550000.0, + 'status': 'SUCCEEDED', + 'status_reason': 'Action completed successfully.', + 'target': '0df0931b-e251-4f2e-8719-4effda3627ba', + 'timeout': 3600 + } + ] + + mock_call.return_value = copy.deepcopy(engine_resp) + obj = mock.Mock() + mock_parse.return_value = obj + + result = self.controller.index(req) + + # list call for version < 1.14 should have cluster_id field removed + # remove cluster_id field from expected response + engine_resp[0].pop('cluster_id') + + self.assertEqual(engine_resp, result['actions']) + mock_parse.assert_called_once_with( + 'ActionListRequest', req, {'project_safe': True}) + mock_call.assert_called_once_with( + req.context, 'action_list', obj) + + @mock.patch.object(util, 'parse_request') + @mock.patch.object(rpc_client.EngineClient, 'call') + def test_action_index_with_cluster_id(self, mock_call, mock_parse, + mock_enforce): + self._mock_enforce_setup(mock_enforce, 'index', True) + req = self._get('/actions', version='1.14') + + engine_resp = [ + { + 'action': 'NODE_CREATE', + 'cause': 'RPC_Request', + 'cluster_id': 'CLUSTER_FAKE_ID', + 'depended_by': [], + 'depends_on': [], + 'end_time': 1425555000.0, + 'id': '2366d400-c7e3-4961-09254-6d1c3f7ac167', + 'inputs': {}, + 'interval': -1, + 'name': 'node_create_0df0931b', + 'outputs': {}, + 'owner': None, + 'start_time': 1425550000.0, + 'status': 'SUCCEEDED', + 'status_reason': 'Action completed successfully.', + 'target': '0df0931b-e251-4f2e-8719-4effda3627ba', + 'timeout': 3600 + } + ] + + mock_call.return_value = copy.deepcopy(engine_resp) + obj = mock.Mock() + mock_parse.return_value = obj + + result = self.controller.index(req) + + self.assertEqual(engine_resp, result['actions']) + mock_parse.assert_called_once_with( + 'ActionListRequest', req, {'project_safe': True}) + mock_call.assert_called_once_with( + req.context, 'action_list', obj) + @mock.patch.object(util, 'parse_request') @mock.patch.object(rpc_client.EngineClient, 'call') def test_action_index_whitelists_params(self, mock_call, @@ -86,6 +174,7 @@ class ActionControllerTest(shared.ControllerTest, base.SenlinTestCase): self._mock_enforce_setup(mock_enforce, 'index', True) marker_uuid = '8216a86c-1bdc-442e-b493-329385d37cbc' params = { + 'cluster_id': 'CLUSTER_FAKE_ID', 'name': 'NODE_CREATE', 'status': 'SUCCEEDED', 'limit': 10, @@ -105,6 +194,7 @@ class ActionControllerTest(shared.ControllerTest, base.SenlinTestCase): mock_parse.assert_called_once_with( 'ActionListRequest', req, { + 'cluster_id': ['CLUSTER_FAKE_ID'], 'status': ['SUCCEEDED'], 'sort': 'status', 'name': ['NODE_CREATE'], @@ -247,6 +337,7 @@ class ActionControllerTest(shared.ControllerTest, base.SenlinTestCase): engine_resp = { 'action': 'NODE_CREATE', 'cause': 'RPC_Request', + 'cluster_id': 'CLUSTER_FAKE_ID', 'depended_by': [], 'depends_on': [], 'end_time': 1425555000.0, diff --git a/senlin/tests/unit/db/shared.py b/senlin/tests/unit/db/shared.py index cdfae0325..0a7328d9c 100644 --- a/senlin/tests/unit/db/shared.py +++ b/senlin/tests/unit/db/shared.py @@ -36,6 +36,7 @@ sample_action = """ target: cluster_001 action: create cause: User Initiate + cluster_id: cluster_001_id timeout: 60 control: READY status: INIT diff --git a/senlin/tests/unit/db/test_action_api.py b/senlin/tests/unit/db/test_action_api.py index a7dc243bc..6df74dd2d 100755 --- a/senlin/tests/unit/db/test_action_api.py +++ b/senlin/tests/unit/db/test_action_api.py @@ -44,6 +44,7 @@ class DBAPIActionTest(base.SenlinTestCase): self.assertIsNotNone(action) self.assertEqual(data['name'], action.name) + self.assertEqual(data['cluster_id'], action.cluster_id) self.assertEqual(data['target'], action.target) self.assertEqual(data['action'], action.action) self.assertEqual(data['cause'], action.cause) diff --git a/senlin/tests/unit/engine/actions/test_action_base.py b/senlin/tests/unit/engine/actions/test_action_base.py index 9ce3080ea..95fa21b34 100755 --- a/senlin/tests/unit/engine/actions/test_action_base.py +++ b/senlin/tests/unit/engine/actions/test_action_base.py @@ -62,6 +62,7 @@ class ActionBaseTest(base.SenlinTestCase): self.ctx = utils.dummy_context(project=PROJECT_ID, user_id=USER_ID) self.action_values = { 'name': 'FAKE_NAME', + 'cluster_id': 'FAKE_CLUSTER_ID', 'cause': 'FAKE_CAUSE', 'owner': OWNER_ID, 'interval': 60, @@ -80,6 +81,7 @@ class ActionBaseTest(base.SenlinTestCase): def _verify_new_action(self, obj, target, action): self.assertIsNone(obj.id) self.assertEqual('', obj.name) + self.assertEqual('', obj.cluster_id) self.assertEqual(target, obj.target) self.assertEqual(action, obj.action) self.assertEqual('', obj.cause) @@ -123,6 +125,7 @@ class ActionBaseTest(base.SenlinTestCase): self.assertEqual('FAKE_ID', obj.id) self.assertEqual('FAKE_NAME', obj.name) + self.assertEqual('FAKE_CLUSTER_ID', obj.cluster_id) self.assertEqual(OBJID, obj.target) self.assertEqual('FAKE_CAUSE', obj.cause) self.assertEqual(OWNER_ID, obj.owner) @@ -180,6 +183,7 @@ class ActionBaseTest(base.SenlinTestCase): action_obj = ab.Action._from_object(record) self.assertIsInstance(action_obj, ab.Action) self.assertEqual(obj.id, action_obj.id) + self.assertEqual(obj.cluster_id, action_obj.cluster_id) self.assertEqual(obj.action, action_obj.action) self.assertEqual(obj.name, action_obj.name) self.assertEqual(obj.target, action_obj.target) @@ -931,6 +935,7 @@ class ActionBaseTest(base.SenlinTestCase): expected = { 'id': 'FAKE_ID', 'name': 'FAKE_NAME', + 'cluster_id': 'FAKE_CLUSTER_ID', 'action': 'OBJECT_ACTION', 'target': OBJID, 'cause': 'FAKE_CAUSE', diff --git a/senlin/tests/unit/engine/actions/test_add_nodes.py b/senlin/tests/unit/engine/actions/test_add_nodes.py index 59125b02c..e7dc4052f 100644 --- a/senlin/tests/unit/engine/actions/test_add_nodes.py +++ b/senlin/tests/unit/engine/actions/test_add_nodes.py @@ -68,7 +68,8 @@ class ClusterAddNodesTest(base.SenlinTestCase): mock_count.assert_called_once_with(action.context, 'CLUSTER_ID') mock_action.assert_called_once_with( action.context, 'NODE_1', 'NODE_JOIN', - name='node_join_NODE_1', cause='Derived Action', + name='node_join_NODE_1', + cluster_id='CLUSTER_ID', cause='Derived Action', inputs={'cluster_id': 'CLUSTER_ID'}) mock_dep.assert_called_once_with(action.context, ['NODE_ACTION_ID'], 'CLUSTER_ACTION_ID') @@ -130,9 +131,11 @@ class ClusterAddNodesTest(base.SenlinTestCase): mock_action.assert_has_calls([ mock.call(action.context, 'NODE_1', 'NODE_JOIN', name='node_join_NODE_1', cause='Derived Action', + cluster_id='CLUSTER_ID', inputs={'cluster_id': 'CLUSTER_ID'}), mock.call(action.context, 'NODE_2', 'NODE_JOIN', name='node_join_NODE_2', cause='Derived Action', + cluster_id='CLUSTER_ID', inputs={'cluster_id': 'CLUSTER_ID'})]) mock_dep.assert_called_once_with( @@ -277,7 +280,8 @@ class ClusterAddNodesTest(base.SenlinTestCase): mock_count.assert_called_once_with(action.context, 'CLUSTER_ID') mock_action.assert_called_once_with( action.context, 'NODE_1', 'NODE_JOIN', - name='node_join_NODE_1', cause='Derived Action', + name='node_join_NODE_1', cluster_id='CLUSTER_ID', + cause='Derived Action', inputs={'cluster_id': 'CLUSTER_ID'}) mock_dep.assert_called_once_with(action.context, ['NODE_ACTION_ID'], 'CLUSTER_ACTION_ID') diff --git a/senlin/tests/unit/engine/actions/test_create.py b/senlin/tests/unit/engine/actions/test_create.py index 63062a088..a8ff2fbe7 100644 --- a/senlin/tests/unit/engine/actions/test_create.py +++ b/senlin/tests/unit/engine/actions/test_create.py @@ -79,10 +79,11 @@ class ClusterCreateTest(base.SenlinTestCase): mock_action.assert_called_once_with(action.context, 'NODE_ID', 'NODE_CREATE', name='node_create_NODE_ID', + cluster_id='CLUSTER_ID', cause='Derived Action') mock_dep.assert_called_once_with(action.context, ['NODE_ACTION_ID'], 'CLUSTER_ACTION_ID') - mock_update.assert_called_once_with( + mock_update.assert_called_with( action.context, 'NODE_ACTION_ID', {'status': ab.Action.READY}) mock_start.assert_called_once_with() diff --git a/senlin/tests/unit/engine/actions/test_delete.py b/senlin/tests/unit/engine/actions/test_delete.py index 5989743a9..6bdc6619d 100755 --- a/senlin/tests/unit/engine/actions/test_delete.py +++ b/senlin/tests/unit/engine/actions/test_delete.py @@ -49,6 +49,7 @@ class ClusterDeleteTest(base.SenlinTestCase): action = ca.ClusterAction(cluster.id, 'CLUSTER_ACTION', self.ctx) action.id = 'CLUSTER_ACTION_ID' action.inputs = {'destroy_after_deletion': False} + action.context = self.ctx mock_wait.return_value = (action.RES_OK, 'All dependents completed') mock_action.return_value = 'NODE_ACTION_ID' @@ -60,11 +61,13 @@ class ClusterDeleteTest(base.SenlinTestCase): self.assertEqual('All dependents completed', res_msg) mock_action.assert_called_once_with( action.context, 'NODE_ID', 'NODE_DELETE', - name='node_delete_NODE_ID', cause='Derived Action', inputs={}) + name='node_delete_NODE_ID', cause='Derived Action', + cluster_id='FAKE_CLUSTER', inputs={}) mock_dep.assert_called_once_with(action.context, ['NODE_ACTION_ID'], 'CLUSTER_ACTION_ID') - mock_update.assert_called_once_with(action.context, 'NODE_ACTION_ID', - {'status': 'READY'}) + mock_update.assert_called_with(action.context, + 'NODE_ACTION_ID', + {'status': 'READY'}) mock_start.assert_called_once_with() mock_wait.assert_called_once_with() self.assertEqual(['NODE_ID'], action.outputs['nodes_removed']) @@ -100,10 +103,12 @@ class ClusterDeleteTest(base.SenlinTestCase): mock.call(action.context, 'NODE_ID', 'NODE_OPERATION', name='node_delete_NODE_ID', cause='Derived Action', + cluster_id='FAKE_CLUSTER', inputs={'operation': 'stop', 'update_parent_status': False}), mock.call(action.context, 'NODE_ID', 'NODE_DELETE', name='node_delete_NODE_ID', + cluster_id='FAKE_CLUSTER', cause='Derived Action', inputs={}) ] mock_action.assert_has_calls(create_actions) @@ -203,7 +208,8 @@ class ClusterDeleteTest(base.SenlinTestCase): self.assertEqual('All dependents completed', res_msg) mock_action.assert_called_once_with( action.context, 'NODE_ID', 'NODE_LEAVE', - name='node_delete_NODE_ID', cause='Derived Action', inputs={}) + name='node_delete_NODE_ID', cluster_id='CLUSTER_ID', + cause='Derived Action', inputs={}) @mock.patch.object(ao.Action, 'update') @mock.patch.object(ab.Action, 'create') @@ -249,6 +255,7 @@ class ClusterDeleteTest(base.SenlinTestCase): action.context, 'NODE_ID', 'NODE_DELETE', name='node_delete_NODE_ID', cause='Derived Action with Lifecycle Hook', + cluster_id='CLUSTER_ID', inputs={}) update_calls = [ mock.call(action.context, 'NODE_ACTION_ID', @@ -323,6 +330,7 @@ class ClusterDeleteTest(base.SenlinTestCase): mock_action.assert_called_once_with( action.context, 'NODE_ID', 'NODE_DELETE', name='node_delete_NODE_ID', + cluster_id='CLUSTER_ID', cause='Derived Action with Lifecycle Hook', inputs={}) update_calls = [ mock.call(action.context, 'NODE_ACTION_ID', @@ -384,6 +392,7 @@ class ClusterDeleteTest(base.SenlinTestCase): mock_action.assert_called_once_with( action.context, 'NODE_ID', 'NODE_DELETE', name='node_delete_NODE_ID', + cluster_id='CLUSTER_ID', cause='Derived Action with Lifecycle Hook', inputs={}) update_calls = [ mock.call(action.context, 'NODE_ACTION_ID', @@ -954,7 +963,7 @@ class ClusterDeleteTest(base.SenlinTestCase): self.assertEqual(1, mock_dep.call_count) mock_action.assert_called_once_with( action.context, 'NODE_ID', 'NODE_DELETE', - name='node_delete_NODE_ID', + name='node_delete_NODE_ID', cluster_id='CLUSTER_ID', cause='Derived Action with Lifecycle Hook', inputs={}) update_calls = [ mock.call(action.context, 'NODE_ACTION_ID', @@ -1084,9 +1093,11 @@ class ClusterDeleteTest(base.SenlinTestCase): create_actions = [ mock.call(action.context, 'NODE_1', 'NODE_DELETE', name='node_delete_NODE_1', + cluster_id='CLUSTER_ID', cause='Derived Action with Lifecycle Hook', inputs={}), mock.call(action.context, 'NODE_2', 'NODE_DELETE', name='node_delete_NODE_2', + cluster_id='CLUSTER_ID', cause='Derived Action with Lifecycle Hook', inputs={}) ] mock_action.assert_has_calls(create_actions) diff --git a/senlin/tests/unit/engine/actions/test_replace_nodes.py b/senlin/tests/unit/engine/actions/test_replace_nodes.py index 4e185d943..b69aefec0 100644 --- a/senlin/tests/unit/engine/actions/test_replace_nodes.py +++ b/senlin/tests/unit/engine/actions/test_replace_nodes.py @@ -72,9 +72,11 @@ class ClusterReplaceNodesTest(base.SenlinTestCase): mock_action.assert_has_calls([ mock.call(action.context, 'O_NODE_1', 'NODE_LEAVE', name='node_leave_O_NODE_1', + cluster_id='CLUSTER_ID', cause='Derived Action'), mock.call(action.context, 'R_NODE_1', 'NODE_JOIN', name='node_join_R_NODE_1', + cluster_id='CLUSTER_ID', cause='Derived Action', inputs={'cluster_id': 'CLUSTER_ID'})]) @@ -266,9 +268,11 @@ class ClusterReplaceNodesTest(base.SenlinTestCase): mock_action.assert_has_calls([ mock.call(action.context, 'O_NODE_1', 'NODE_LEAVE', name='node_leave_O_NODE_1', + cluster_id='CLUSTER_ID', cause='Derived Action'), mock.call(action.context, 'R_NODE_1', 'NODE_JOIN', name='node_join_R_NODE_1', + cluster_id='CLUSTER_ID', cause='Derived Action', inputs={'cluster_id': 'CLUSTER_ID'})]) diff --git a/senlin/tests/unit/engine/service/test_actions.py b/senlin/tests/unit/engine/service/test_actions.py index addc42184..d4c00b4a2 100644 --- a/senlin/tests/unit/engine/service/test_actions.py +++ b/senlin/tests/unit/engine/service/test_actions.py @@ -118,6 +118,7 @@ class ActionTest(base.SenlinTestCase): mock_action.assert_called_once_with( self.ctx, 'FAKE_CLUSTER', 'CLUSTER_CREATE', name='a1', + cluster_id='FAKE_CLUSTER', cause=consts.CAUSE_RPC, status=ab.Action.READY, inputs={}) diff --git a/senlin/tests/unit/engine/service/test_cluster_op.py b/senlin/tests/unit/engine/service/test_cluster_op.py index 826ec61f1..045c642b4 100644 --- a/senlin/tests/unit/engine/service/test_cluster_op.py +++ b/senlin/tests/unit/engine/service/test_cluster_op.py @@ -42,7 +42,7 @@ class ClusterOpTest(base.SenlinTestCase): @mock.patch.object(co.Cluster, 'find') def test_cluster_op(self, mock_find, mock_cluster, mock_nodes, mock_action, mock_start): - x_db_cluster = mock.Mock() + x_db_cluster = mock.Mock(id='12345678AB') mock_find.return_value = x_db_cluster x_schema = mock.Mock() x_profile = mock.Mock(OPERATIONS={'dance': x_schema}) @@ -69,6 +69,7 @@ class ClusterOpTest(base.SenlinTestCase): mock_action.assert_called_once_with( self.ctx, '12345678AB', consts.CLUSTER_OPERATION, name='cluster_dance_12345678', + cluster_id='12345678AB', cause=consts.CAUSE_RPC, status=am.Action.READY, inputs={ @@ -147,7 +148,7 @@ class ClusterOpTest(base.SenlinTestCase): @mock.patch.object(co.Cluster, 'find') def test_cluster_op_no_parameters(self, mock_find, mock_cluster, mock_nodes, mock_action, mock_start): - x_db_cluster = mock.Mock() + x_db_cluster = mock.Mock(id='12345678AB') mock_find.return_value = x_db_cluster x_schema = mock.Mock() x_profile = mock.Mock(OPERATIONS={'dance': x_schema}) @@ -172,6 +173,7 @@ class ClusterOpTest(base.SenlinTestCase): mock_action.assert_called_once_with( self.ctx, '12345678AB', consts.CLUSTER_OPERATION, name='cluster_dance_12345678', + cluster_id='12345678AB', cause=consts.CAUSE_RPC, status=am.Action.READY, inputs={ @@ -189,7 +191,7 @@ class ClusterOpTest(base.SenlinTestCase): @mock.patch.object(co.Cluster, 'find') def test_cluster_op_no_filters(self, mock_find, mock_cluster, mock_nodes, mock_action, mock_start): - x_db_cluster = mock.Mock() + x_db_cluster = mock.Mock(id='12345678AB') mock_find.return_value = x_db_cluster x_schema = mock.Mock() x_profile = mock.Mock(OPERATIONS={'dance': x_schema}) @@ -211,6 +213,7 @@ class ClusterOpTest(base.SenlinTestCase): mock_action.assert_called_once_with( self.ctx, '12345678AB', consts.CLUSTER_OPERATION, name='cluster_dance_12345678', + cluster_id='12345678AB', cause=consts.CAUSE_RPC, status=am.Action.READY, inputs={ diff --git a/senlin/tests/unit/engine/service/test_cluster_policies.py b/senlin/tests/unit/engine/service/test_cluster_policies.py index ebeb13dd4..45f9d034b 100644 --- a/senlin/tests/unit/engine/service/test_cluster_policies.py +++ b/senlin/tests/unit/engine/service/test_cluster_policies.py @@ -194,6 +194,7 @@ class ClusterPolicyTest(base.SenlinTestCase): mock_action.assert_called_once_with( self.ctx, '12345678abcd', consts.CLUSTER_ATTACH_POLICY, name='attach_policy_12345678', + cluster_id='12345678abcd', cause=consts.CAUSE_RPC, status=action_mod.Action.READY, inputs={'policy_id': '87654321abcd', 'enabled': True}, @@ -258,6 +259,7 @@ class ClusterPolicyTest(base.SenlinTestCase): mock_action.assert_called_once_with( self.ctx, '12345678abcd', consts.CLUSTER_DETACH_POLICY, name='detach_policy_12345678', + cluster_id='12345678abcd', cause=consts.CAUSE_RPC, status=action_mod.Action.READY, inputs={'policy_id': '87654321abcd'}, @@ -345,6 +347,7 @@ class ClusterPolicyTest(base.SenlinTestCase): mock_action.assert_called_once_with( self.ctx, '12345678abcd', consts.CLUSTER_UPDATE_POLICY, name='update_policy_12345678', + cluster_id='12345678abcd', cause=consts.CAUSE_RPC, status=action_mod.Action.READY, inputs={'policy_id': '87654321abcd', 'enabled': False}, diff --git a/senlin/tests/unit/engine/service/test_clusters.py b/senlin/tests/unit/engine/service/test_clusters.py index a927777ec..4504581e6 100755 --- a/senlin/tests/unit/engine/service/test_clusters.py +++ b/senlin/tests/unit/engine/service/test_clusters.py @@ -152,6 +152,7 @@ class ClusterTest(base.SenlinTestCase): self.ctx, '12345678ABC', 'CLUSTER_CREATE', name='cluster_create_12345678', + cluster_id='12345678ABC', cause=consts.CAUSE_RPC, status=am.Action.READY, ) @@ -196,6 +197,7 @@ class ClusterTest(base.SenlinTestCase): self.ctx, '12345678ABC', 'CLUSTER_CREATE', name='cluster_create_12345678', + cluster_id='12345678ABC', cause=consts.CAUSE_RPC, status=am.Action.READY, ) @@ -330,6 +332,7 @@ class ClusterTest(base.SenlinTestCase): mock_action.assert_called_once_with( self.ctx, '12345678AB', 'CLUSTER_UPDATE', name='cluster_update_12345678', + cluster_id='12345678AB', cause=consts.CAUSE_RPC, status=am.Action.READY, inputs={ @@ -449,6 +452,7 @@ class ClusterTest(base.SenlinTestCase): mock_action.assert_called_once_with( self.ctx, '12345678AB', 'CLUSTER_UPDATE', name='cluster_update_12345678', + cluster_id='12345678AB', cause=consts.CAUSE_RPC, status=am.Action.READY, inputs={ @@ -479,6 +483,7 @@ class ClusterTest(base.SenlinTestCase): mock_action.assert_called_once_with( self.ctx, '12345678AB', 'CLUSTER_UPDATE', name='cluster_update_12345678', + cluster_id='12345678AB', status=am.Action.READY, cause=consts.CAUSE_RPC, inputs={ @@ -510,6 +515,7 @@ class ClusterTest(base.SenlinTestCase): mock_action.assert_called_once_with( self.ctx, '12345678AB', 'CLUSTER_UPDATE', name='cluster_update_12345678', + cluster_id='12345678AB', status=am.Action.READY, cause=consts.CAUSE_RPC, inputs={ @@ -541,6 +547,7 @@ class ClusterTest(base.SenlinTestCase): mock_action.assert_called_once_with( self.ctx, '12345678AB', 'CLUSTER_UPDATE', name='cluster_update_12345678', + cluster_id='12345678AB', status=am.Action.READY, cause=consts.CAUSE_RPC, inputs={ @@ -632,6 +639,7 @@ class ClusterTest(base.SenlinTestCase): mock_action.assert_called_once_with( self.ctx, '12345678AB', consts.CLUSTER_ADD_NODES, name='cluster_add_nodes_12345678', + cluster_id='12345678AB', cause=consts.CAUSE_RPC, status=am.Action.READY, inputs={'nodes': ['NODE1', 'NODE2']}, @@ -830,6 +838,7 @@ class ClusterTest(base.SenlinTestCase): mock_action.assert_called_once_with( self.ctx, '1234', consts.CLUSTER_DEL_NODES, name='cluster_del_nodes_1234', + cluster_id='1234', status=am.Action.READY, cause=consts.CAUSE_RPC, inputs={ @@ -999,6 +1008,7 @@ class ClusterTest(base.SenlinTestCase): mock_action.assert_called_once_with( self.ctx, '12345678ABCDEFGH', consts.CLUSTER_RESIZE, name='cluster_resize_12345678', + cluster_id='12345678ABCDEFGH', cause=consts.CAUSE_RPC, status=am.Action.READY, inputs={ @@ -1043,6 +1053,7 @@ class ClusterTest(base.SenlinTestCase): mock_action.assert_called_once_with( self.ctx, '12345678ABCDEFGH', consts.CLUSTER_RESIZE, name='cluster_resize_12345678', + cluster_id='12345678ABCDEFGH', cause=consts.CAUSE_RPC, status=am.Action.READY, inputs={ @@ -1087,6 +1098,7 @@ class ClusterTest(base.SenlinTestCase): mock_action.assert_called_once_with( self.ctx, '12345678ABCDEFGH', consts.CLUSTER_RESIZE, name='cluster_resize_12345678', + cluster_id='12345678ABCDEFGH', cause=consts.CAUSE_RPC, status=am.Action.READY, inputs={ @@ -1210,6 +1222,7 @@ class ClusterTest(base.SenlinTestCase): mock_action.assert_called_once_with( self.ctx, '12345678ABCDEFGH', consts.CLUSTER_SCALE_OUT, name='cluster_scale_out_12345678', + cluster_id='12345678ABCDEFGH', cause=consts.CAUSE_RPC, status=am.Action.READY, inputs={'count': 1}, @@ -1248,6 +1261,7 @@ class ClusterTest(base.SenlinTestCase): mock_action.assert_called_once_with( self.ctx, '12345678ABCDEFGH', consts.CLUSTER_SCALE_OUT, name='cluster_scale_out_12345678', + cluster_id='12345678ABCDEFGH', cause=consts.CAUSE_RPC, status=am.Action.READY, inputs={}, @@ -1305,6 +1319,7 @@ class ClusterTest(base.SenlinTestCase): mock_action.assert_called_once_with( self.ctx, '12345678ABCD', consts.CLUSTER_SCALE_IN, name='cluster_scale_in_12345678', + cluster_id='12345678ABCD', cause=consts.CAUSE_RPC, status=am.Action.READY, inputs={'count': 2}, @@ -1342,6 +1357,7 @@ class ClusterTest(base.SenlinTestCase): mock_action.assert_called_once_with( self.ctx, 'FOO', consts.CLUSTER_SCALE_IN, name='cluster_scale_in_FOO', + cluster_id='FOO', cause=consts.CAUSE_RPC, status=am.Action.READY, inputs={}, @@ -1395,6 +1411,7 @@ class ClusterTest(base.SenlinTestCase): mock_action.assert_called_once_with( self.ctx, 'CID', consts.CLUSTER_CHECK, name='cluster_check_CID', + cluster_id='CID', cause=consts.CAUSE_RPC, status=am.Action.READY, inputs={'foo': 'bar'}, @@ -1424,6 +1441,7 @@ class ClusterTest(base.SenlinTestCase): mock_action.assert_called_once_with( self.ctx, 'CID', consts.CLUSTER_CHECK, name='cluster_check_CID', + cluster_id='CID', cause=consts.CAUSE_RPC, status=am.Action.READY, inputs={'delete_check_action': True}, @@ -1447,6 +1465,7 @@ class ClusterTest(base.SenlinTestCase): mock_action.assert_called_once_with( self.ctx, 'CID', consts.CLUSTER_CHECK, name='cluster_check_CID', + cluster_id='CID', cause=consts.CAUSE_RPC, status=am.Action.READY, inputs={}, @@ -1471,6 +1490,7 @@ class ClusterTest(base.SenlinTestCase): mock_action.assert_called_once_with( self.ctx, 'CID', consts.CLUSTER_CHECK, name='cluster_check_CID', + cluster_id='CID', cause=consts.CAUSE_RPC, status=am.Action.READY, inputs={}, @@ -1509,6 +1529,7 @@ class ClusterTest(base.SenlinTestCase): mock_action.assert_called_once_with( self.ctx, 'CID', consts.CLUSTER_RECOVER, name='cluster_recover_CID', + cluster_id='CID', cause=consts.CAUSE_RPC, status=am.Action.READY, inputs={'operation': 'RECREATE'}, @@ -1532,6 +1553,7 @@ class ClusterTest(base.SenlinTestCase): mock_action.assert_called_once_with( self.ctx, 'CID', consts.CLUSTER_RECOVER, name='cluster_recover_CID', + cluster_id='CID', cause=consts.CAUSE_RPC, status=am.Action.READY, inputs={'operation': 'REBUILD'}, @@ -1555,6 +1577,7 @@ class ClusterTest(base.SenlinTestCase): mock_action.assert_called_once_with( self.ctx, 'CID', consts.CLUSTER_RECOVER, name='cluster_recover_CID', + cluster_id='CID', cause=consts.CAUSE_RPC, status=am.Action.READY, inputs={'operation': 'REBOOT'}, @@ -1577,6 +1600,7 @@ class ClusterTest(base.SenlinTestCase): mock_action.assert_called_once_with( self.ctx, 'CID', consts.CLUSTER_RECOVER, name='cluster_recover_CID', + cluster_id='CID', cause=consts.CAUSE_RPC, status=am.Action.READY, inputs={} @@ -1673,6 +1697,7 @@ class ClusterTest(base.SenlinTestCase): mock_action.assert_called_once_with( self.ctx, 'CID', consts.CLUSTER_RECOVER, name='cluster_recover_CID', + cluster_id='CID', cause=consts.CAUSE_RPC, status=am.Action.READY, inputs={}, @@ -1892,6 +1917,7 @@ class ClusterTest(base.SenlinTestCase): mock_action.assert_called_once_with( self.ctx, 'CID', consts.CLUSTER_REPLACE_NODES, name='cluster_replace_nodes_CID', + cluster_id='CID', cause=consts.CAUSE_RPC, status=am.Action.READY, inputs={'candidates': {'ORIGINAL': 'REPLACE'}}) @@ -2060,6 +2086,7 @@ class ClusterTest(base.SenlinTestCase): mock_action.assert_called_once_with( self.ctx, '12345678AB', 'CLUSTER_DELETE', name='cluster_delete_12345678', + cluster_id='12345678AB', cause=consts.CAUSE_RPC, force=True, status=am.Action.READY) @@ -2143,6 +2170,7 @@ class ClusterTest(base.SenlinTestCase): mock_action.assert_called_with( self.ctx, '12345678AB', 'CLUSTER_DELETE', name='cluster_delete_12345678', + cluster_id='12345678AB', cause=consts.CAUSE_RPC, force=True, status=am.Action.READY) diff --git a/senlin/tests/unit/engine/service/test_nodes.py b/senlin/tests/unit/engine/service/test_nodes.py index 0909eafae..21561d650 100644 --- a/senlin/tests/unit/engine/service/test_nodes.py +++ b/senlin/tests/unit/engine/service/test_nodes.py @@ -180,6 +180,7 @@ class NodeTest(base.SenlinTestCase): mock_action.assert_called_once_with( self.ctx, 'NODE_ID', consts.NODE_CREATE, name='node_create_NODE_ID', + cluster_id='', cause=consts.CAUSE_RPC, status=action_mod.Action.READY) notify.assert_called_once_with() @@ -237,6 +238,7 @@ class NodeTest(base.SenlinTestCase): }) mock_action.assert_called_once_with( self.ctx, 'NODE_ID', consts.NODE_CREATE, + cluster_id='CLUSTER_ID', name='node_create_NODE_ID', cause=consts.CAUSE_RPC, status=action_mod.Action.READY) @@ -301,6 +303,7 @@ class NodeTest(base.SenlinTestCase): mock_action.assert_called_once_with( self.ctx, 'NODE_ID', consts.NODE_CREATE, name='node_create_NODE_ID', + cluster_id='CLUSTER_ID', cause=consts.CAUSE_RPC, status=action_mod.Action.READY) notify.assert_called_once_with() @@ -447,6 +450,7 @@ class NodeTest(base.SenlinTestCase): @mock.patch.object(no.Node, 'find') def test_node_update(self, mock_find, mock_action, mock_start): x_obj = mock.Mock(id='FAKE_NODE_ID', name='NODE1', role='ROLE1', + cluster_id='FAKE_CLUSTER_ID', metadata={'KEY': 'VALUE'}) x_obj.to_dict.return_value = {'foo': 'bar'} mock_find.return_value = x_obj @@ -465,6 +469,7 @@ class NodeTest(base.SenlinTestCase): mock_action.assert_called_once_with( self.ctx, 'FAKE_NODE_ID', consts.NODE_UPDATE, name='node_update_FAKE_NOD', + cluster_id='FAKE_CLUSTER_ID', cause=consts.CAUSE_RPC, status=action_mod.Action.READY, inputs={ @@ -480,9 +485,11 @@ class NodeTest(base.SenlinTestCase): @mock.patch.object(action_mod.Action, 'create') @mock.patch.object(po.Profile, 'find') @mock.patch.object(no.Node, 'find') + # @mock.patch.object(co.Cluster, 'find') def test_node_update_new_profile(self, mock_find, mock_profile, mock_action, mock_start): x_obj = mock.Mock(id='FAKE_NODE_ID', role='ROLE1', + cluster_id='FAKE_CLUSTER_ID', metadata={'KEY': 'VALUE'}, profile_id='OLD_PROFILE_ID') x_obj.name = 'NODE1' @@ -494,7 +501,6 @@ class NodeTest(base.SenlinTestCase): mock.Mock(id='OLD_PROFILE_ID', type='PROFILE_TYPE'), ] mock_action.return_value = 'ACTION_ID' - # all properties are filtered out except for profile_id req = orno.NodeUpdateRequest(identity='FAKE_NODE', name='NODE1', @@ -512,6 +518,7 @@ class NodeTest(base.SenlinTestCase): mock_action.assert_called_once_with( self.ctx, 'FAKE_NODE_ID', consts.NODE_UPDATE, name='node_update_FAKE_NOD', + cluster_id='FAKE_CLUSTER_ID', cause=consts.CAUSE_RPC, status=action_mod.Action.READY, inputs={ @@ -623,6 +630,7 @@ class NodeTest(base.SenlinTestCase): @mock.patch.object(no.Node, 'find') def test_node_delete(self, mock_find, mock_action, mock_start): mock_find.return_value = mock.Mock(id='12345678AB', status='ACTIVE', + cluster_id='', dependents={}) mock_action.return_value = 'ACTION_ID' @@ -634,6 +642,7 @@ class NodeTest(base.SenlinTestCase): mock_action.assert_called_once_with( self.ctx, '12345678AB', consts.NODE_DELETE, name='node_delete_12345678', + cluster_id='', cause=consts.CAUSE_RPC, status=action_mod.Action.READY) mock_start.assert_called_once_with() @@ -691,7 +700,8 @@ class NodeTest(base.SenlinTestCase): mock_find.return_value = mock.Mock(id='12345678AB', status=bad_status, - dependents={}) + dependents={}, + cluster_id='',) mock_action.return_value = 'ACTION_ID' req = orno.NodeDeleteRequest(identity='FAKE_NODE', force=True) @@ -702,6 +712,7 @@ class NodeTest(base.SenlinTestCase): mock_action.assert_called_with( self.ctx, '12345678AB', consts.NODE_DELETE, name='node_delete_12345678', + cluster_id='', cause=consts.CAUSE_RPC, status=action_mod.Action.READY) mock_start.assert_called_with() @@ -821,6 +832,7 @@ class NodeTest(base.SenlinTestCase): @mock.patch.object(service.EngineService, '_node_adopt_preview') def test_node_adopt(self, mock_preview, mock_create): class FakeProfile(object): + @classmethod def create(cls, ctx, name, spec): obj = mock.Mock(spec=spec, id='PROFILE_ID') @@ -896,7 +908,8 @@ class NodeTest(base.SenlinTestCase): @mock.patch.object(action_mod.Action, 'create') @mock.patch.object(no.Node, 'find') def test_node_check(self, mock_find, mock_action, mock_start): - mock_find.return_value = mock.Mock(id='12345678AB') + mock_find.return_value = mock.Mock(id='12345678AB', + cluster_id='FAKE_CLUSTER_ID') mock_action.return_value = 'ACTION_ID' params = {'k1': 'v1'} @@ -908,6 +921,7 @@ class NodeTest(base.SenlinTestCase): mock_action.assert_called_once_with( self.ctx, '12345678AB', consts.NODE_CHECK, name='node_check_12345678', + cluster_id='FAKE_CLUSTER_ID', cause=consts.CAUSE_RPC, status=action_mod.Action.READY, inputs={'k1': 'v1'}) @@ -931,7 +945,8 @@ class NodeTest(base.SenlinTestCase): @mock.patch.object(action_mod.Action, 'create') @mock.patch.object(no.Node, 'find') def test_node_recover(self, mock_find, mock_action, mock_start): - mock_find.return_value = mock.Mock(id='12345678AB') + mock_find.return_value = mock.Mock( + id='12345678AB', cluster_id='FAKE_CLUSTER_ID') mock_action.return_value = 'ACTION_ID' params = {'operation': 'REBOOT'} @@ -943,6 +958,7 @@ class NodeTest(base.SenlinTestCase): mock_action.assert_called_once_with( self.ctx, '12345678AB', consts.NODE_RECOVER, name='node_recover_12345678', + cluster_id='FAKE_CLUSTER_ID', cause=consts.CAUSE_RPC, status=action_mod.Action.READY, inputs={'operation': 'REBOOT'}) @@ -952,7 +968,7 @@ class NodeTest(base.SenlinTestCase): @mock.patch.object(action_mod.Action, 'create') @mock.patch.object(no.Node, 'find') def test_node_recover_with_check(self, mock_find, mock_action, mock_start): - mock_find.return_value = mock.Mock(id='12345678AB') + mock_find.return_value = mock.Mock(id='12345678AB', cluster_id='') mock_action.return_value = 'ACTION_ID' params = {'check': True, 'operation': 'REBUILD'} @@ -964,6 +980,7 @@ class NodeTest(base.SenlinTestCase): mock_action.assert_called_once_with( self.ctx, '12345678AB', consts.NODE_RECOVER, name='node_recover_12345678', + cluster_id='', cause=consts.CAUSE_RPC, status=action_mod.Action.READY, inputs={'check': True, 'operation': 'REBUILD'}) @@ -974,7 +991,7 @@ class NodeTest(base.SenlinTestCase): @mock.patch.object(no.Node, 'find') def test_node_recover_with_delete_timeout(self, mock_find, mock_action, mock_start): - mock_find.return_value = mock.Mock(id='12345678AB') + mock_find.return_value = mock.Mock(id='12345678AB', cluster_id='',) mock_action.return_value = 'ACTION_ID' params = {'delete_timeout': 20, 'operation': 'RECREATE'} @@ -986,6 +1003,7 @@ class NodeTest(base.SenlinTestCase): mock_action.assert_called_once_with( self.ctx, '12345678AB', consts.NODE_RECOVER, name='node_recover_12345678', + cluster_id='', cause=consts.CAUSE_RPC, status=action_mod.Action.READY, inputs={'delete_timeout': 20, @@ -997,7 +1015,8 @@ class NodeTest(base.SenlinTestCase): @mock.patch.object(no.Node, 'find') def test_node_recover_with_force_recreate(self, mock_find, mock_action, mock_start): - mock_find.return_value = mock.Mock(id='12345678AB') + mock_find.return_value = mock.Mock( + id='12345678AB', cluster_id='FAKE_CLUSTER_ID') mock_action.return_value = 'ACTION_ID' params = {'force_recreate': True, 'operation': 'reboot', @@ -1010,6 +1029,7 @@ class NodeTest(base.SenlinTestCase): mock_action.assert_called_once_with( self.ctx, '12345678AB', consts.NODE_RECOVER, name='node_recover_12345678', + cluster_id='FAKE_CLUSTER_ID', cause=consts.CAUSE_RPC, status=action_mod.Action.READY, inputs={'force_recreate': True, @@ -1095,7 +1115,7 @@ class NodeTest(base.SenlinTestCase): @mock.patch.object(node_mod.Node, 'load') @mock.patch.object(no.Node, 'find') def test_node_op(self, mock_find, mock_node, mock_action, mock_start): - x_db_node = mock.Mock(id='12345678AB') + x_db_node = mock.Mock(id='12345678AB', cluster_id='FAKE_CLUSTER_ID') mock_find.return_value = x_db_node x_schema = mock.Mock() x_profile = mock.Mock(OPERATIONS={'dance': x_schema}) @@ -1117,6 +1137,7 @@ class NodeTest(base.SenlinTestCase): mock_action.assert_called_once_with( self.ctx, '12345678AB', consts.NODE_OPERATION, name='node_dance_12345678', + cluster_id='FAKE_CLUSTER_ID', cause=consts.CAUSE_RPC, status=action_mod.Action.READY, inputs={'operation': 'dance', 'params': {'style': 'tango'}}) diff --git a/senlin/tests/unit/engine/service/test_webhooks.py b/senlin/tests/unit/engine/service/test_webhooks.py index 9aae70494..b12006bfb 100644 --- a/senlin/tests/unit/engine/service/test_webhooks.py +++ b/senlin/tests/unit/engine/service/test_webhooks.py @@ -58,6 +58,7 @@ class WebhookTest(base.SenlinTestCase): mock_action.assert_called_once_with( self.ctx, 'FAKE_CLUSTER', 'DANCE', name='webhook_01234567', + cluster_id='FAKE_CLUSTER', cause=consts.CAUSE_RPC, status=action_mod.Action.READY, inputs={'kee': 'vee', 'foo': 'bar'}, @@ -89,6 +90,7 @@ class WebhookTest(base.SenlinTestCase): mock_action.assert_called_once_with( self.ctx, 'FAKE_CLUSTER', 'DANCE', name='webhook_01234567', + cluster_id='FAKE_CLUSTER', cause=consts.CAUSE_RPC, status=action_mod.Action.READY, inputs={'foo': 'bar'}, @@ -157,6 +159,7 @@ class WebhookTest(base.SenlinTestCase): mock_action.assert_called_once_with( self.ctx, 'FAKE_CLUSTER', 'DANCE', name='webhook_01234567', + cluster_id='FAKE_CLUSTER', cause=consts.CAUSE_RPC, status=action_mod.Action.READY, inputs={'kee': 'vee', 'foo': 'bar'}, @@ -188,6 +191,7 @@ class WebhookTest(base.SenlinTestCase): mock_action.assert_called_once_with( self.ctx, 'FAKE_CLUSTER', 'DANCE', name='webhook_01234567', + cluster_id='FAKE_CLUSTER', cause=consts.CAUSE_RPC, status=action_mod.Action.READY, inputs={'foo': 'bar'},