From f362444744587e43b8e420c81a2896f70af8edc6 Mon Sep 17 00:00:00 2001 From: Hang Liu Date: Fri, 2 Jan 2015 20:10:19 +0800 Subject: [PATCH 1/2] Complete DB action APIs basic functionality. --- TODO | 1 - senlin/db/api.py | 22 +-- senlin/db/sqlalchemy/api.py | 166 +++++++++++----- senlin/engine/parser.py | 22 +++ senlin/engine/scheduler.py | 8 +- senlin/tests/db/shared.py | 23 +++ senlin/tests/db/test_action_api.py | 299 +++++++++++++++++++++++++++++ 7 files changed, 474 insertions(+), 67 deletions(-) create mode 100644 senlin/tests/db/test_action_api.py diff --git a/TODO b/TODO index d9a0d488c..9031bcac8 100644 --- a/TODO +++ b/TODO @@ -4,7 +4,6 @@ High Priority DB -- - - Add action APIs - Make sure cluster-policy association is deleted when a cluster is deleted - Add field size to cluster table - Modify node_set_status to check/update cluster status diff --git a/senlin/db/api.py b/senlin/db/api.py index d3041115e..39956b58a 100644 --- a/senlin/db/api.py +++ b/senlin/db/api.py @@ -247,20 +247,12 @@ def action_get_all(context): return IMPL.action_get_all(context) -def action_add_depends_on(context, action_id, *actions): - return IMPL.action_add_depends_on(context, action_id, *actions) +def action_add_dependency(context, depended, dependent): + return IMPL.action_add_dependency(context, depended, dependent) - -def action_del_depends_on(context, action_id, *actions): - return IMPL.action_del_depends_on(context, action_id, *actions) - - -def action_add_depended_by(context, action_id, *actions): - return IMPL.action_add_depended_by(context, action_id, *actions) - - -def action_del_depended_by(context, action_id, *actions): - return IMPL.action_del_depended_by(context, action_id, *actions) + +def action_del_dependency(context, depended, dependent): + return IMPL.action_del_dependency(context, depended, dependent) def action_mark_succeeded(context, action_id): @@ -283,6 +275,10 @@ def action_update(context, action_id, values): return IMPL.action_update(context, action_id, values) +def action_delete(context, action_id, force=False): + return IMPL.action_delete(context, action_id, force) + + def db_sync(engine, version=None): """Migrate the database to `version` or the most recent version.""" return IMPL.db_sync(engine, version=version) diff --git a/senlin/db/sqlalchemy/api.py b/senlin/db/sqlalchemy/api.py index 965d79fb7..b099a83b8 100644 --- a/senlin/db/sqlalchemy/api.py +++ b/senlin/db/sqlalchemy/api.py @@ -27,8 +27,12 @@ from senlin.common.i18n import _ from senlin.db.sqlalchemy import filters as db_filters from senlin.db.sqlalchemy import migration from senlin.db.sqlalchemy import models +from senlin.openstack.common import log as logging from senlin.rpc import api as rpc_api +LOG = logging.getLogger(__name__) + + CONF = cfg.CONF CONF.import_opt('max_events_per_cluster', 'senlin.common.config') @@ -683,18 +687,20 @@ def action_get(context, action_id): def action_get_1st_ready(context): query = model_query(context, models.Action).\ - filter_by(status == ACTION_READY) + filter_by(status=ACTION_READY) + return query.first() def action_get_all_ready(context): - query = model_query(context, models.Action) + query = model_query(context, models.Action).\ + filter_by(status=ACTION_READY) return query.all() def action_get_all_by_owner(context, owner_id): query = model_query(context, models.Action).\ - filter_by(owner == owner_id) + filter_by(owner=owner_id) return query.all() @@ -706,48 +712,111 @@ def action_get_all(context): return actions -def action_add_depends_on(context, action_id, *actions): +def _action_dependency_add(context, action_id, field, adds): + if not isinstance(adds, list): + add_list = [adds] + else: + add_list = adds + action = model_query(context, models.Action).get(action_id) if not action: - raise exception.NotFound( - _('Action with id "%s" not found') % action_id) + msg = _('Action with id "%s" not found') % action_id + raise exception.NotFound(msg) - action.depends_on = list(set(actions).union(set(action.depends_on))) - action.save(_session(context)) - return action + d = {} + if action[field] is None: + d['l'] = add_list; + else: + d = action[field] + d['l'] = list(set(d['l']) + set(add_list)) + action[field] = d + if field == 'depends_on': + action.status = ACTION_WAITING + action.status_reason = ACTION_WAITING + action.status_reason = _('The action is waiting for its dependancy \ + being completed.') + + +def _action_dependency_del(context, action_id, field, dels): + if not isinstance(dels, list): + del_list = [dels] + else: + del_list = dels -def action_del_depends_on(context, action_id, *actions): action = model_query(context, models.Action).get(action_id) if not action: - raise exception.NotFound( - _('Action with id "%s" not found') % action_id) + msg = _('Action with id "%s" not found') % action_id + raise exception.NotFound(msg) - action.depends_on = list(set(action.depends_on).different(set(actions))) - action.save(_session(context)) - return action + d = {} + if action[field] is not None: + d = action[field] + d['l'] = list(set(d['l']) - set(del_list)) + action[field] = d + + if field == 'depends_on' and len(d['l']) == 0: + action.status = ACTION_READY + action.status_reason = _('The action becomes ready due to all dependancies \ + have been satisfied.') -def action_add_depended_by(context, action_id, *actions): - action = model_query(context, models.Action).get(action_id) - if not action: - raise exception.NotFound( - _('Action with id "%s" not found') % action_id) +def action_add_dependency(context, depended, dependent): + if isinstance(depended, list) and isinstance(dependent, list): + raise exception.NotSupport( + _('Multiple dependencies between lists not support')) - action.depended_by = list(set(actions).union(set(action.depended_by))) - action.save(_session(context)) - return action + if isinstance(depended, list): # e.g. D depends on A,B,C + session = get_session() + with session.begin(): + for d in depended: + _action_dependency_add(context, d, "depended_by", dependent) + _action_dependency_add(context, dependent, "depends_on", depended) + return -def action_del_depended_by(context, action_id, *actions): - action = model_query(context, models.Action).get(action_id) - if not action: - raise exception.NotFound( - _('Action with id "%s" not found') % action_id) + # Only dependent can be a list now, convert it to a list if it is not a list + if not isinstance(dependent, list): # e.g. B,C,D depend on A + dependents = [dependent] + else: + dependents = dependent - action.depended_by = list(set(action.depended_by).different(set(actions))) - action.save(_session(context)) - return action + session = get_session() + with session.begin(): + _action_dependency_add(context, depended, "depended_by", dependent) + + for d in dependents: + _action_dependency_add(context, d, "depends_on", depended) + return + + +def action_del_dependency(context, depended, dependent): + if isinstance(depended, list) and isinstance(dependent, list): + raise exception.NotSupport( + _('Multiple dependencies between lists not support')) + + if isinstance(depended, list): # e.g. D depends on A,B,C + session = get_session() + with session.begin(): + for d in depended: + _action_dependency_del(context, d, "depended_by", dependent) + + _action_dependency_del(context, dependent, "depends_on", depended) + return + + # Only dependent can be a list now, convert it to a list if it is not a list + if not isinstance(dependent, list): # e.g. B,C,D depend on A + dependents = [dependent] + else: + dependents = dependent + + session = get_session() + with session.begin(): + _action_dependency_del(context, depended, "depended_by", dependent) + + for d in dependents: + _action_dependency_del(context, d, "depends_on", depended) + return def action_mark_succeeded(context, action_id): @@ -756,27 +825,26 @@ def action_mark_succeeded(context, action_id): raise exception.NotFound( _('Action with id "%s" not found') % action_id) - session = query.session - session.begin() + session = get_session() + with session.begin(): + action.status = ACTION_SUCCEEDED - action.status = ACTION_SUCCEEDED + for a in action.depended_by['l']: + _action_dependency_del(context, a, 'depends_on', action_id) + action.depended_by = {'l':[]} - for a in action.depended_by - action_del_depends_on(context, a, action_id) - - action.depended_by = [] - - session.commit() return action def action_mark_failed(context, action_id): #TODO(liuh): Failed processing to be added + #TODO(liuh): Need mark all actions depending on it failed pass def action_mark_cancelled(context, action_id): #TODO(liuh): Cancel processing to be added + #TODO(liuh): Need mark all actions depending on it being cancelled pass @@ -793,16 +861,16 @@ def action_start_work_on(context, action_id, owner): return action -def action_update(context, action_id, values): - #TODO(liuh):Need check if 'status' is being updated? - action = model_query(context, models.Action).get(action_id) - if not action: - raise exception.NotFound( - _('Action with id "%s" not found') % action_id) +def action_delete(context, action_id, force=False): + action = action_get(context, action_id) - action.update(values) - action.save(_session(context)) - return action + if not action: + msg = _('Attempt to delete a action with id "%s" that does not' + ' exist') % action_id + raise exception.NotFound(msg) + + # TODO(liuh): Need check if and how an action can be safety deleted + action.delete() # Utils def db_sync(engine, version=None): diff --git a/senlin/engine/parser.py b/senlin/engine/parser.py index 65ef9e8e8..0ac76f026 100644 --- a/senlin/engine/parser.py +++ b/senlin/engine/parser.py @@ -71,3 +71,25 @@ def parse_policy(policy): # TODO(Qiming): Construct a policy object based on the type specified return data + + +def parse_action(action): + ''' + Parse and validate the specified string as a action. + ''' + if not isinstance(action, six.string_types): + # TODO(Qiming): Throw exception + return None + + data = {} + try: + data = yaml.load(action, Loader=Loader) + except Exception as ex: + # TODO(Qiming): Throw exception + LOG.error(_LE('Failed parsing given data as YAML: %s'), + six.text_type(ex)) + return None + + # TODO(Qiming): Construct a action object based on the type specified + + return data diff --git a/senlin/engine/scheduler.py b/senlin/engine/scheduler.py index 651f87677..580e43d49 100644 --- a/senlin/engine/scheduler.py +++ b/senlin/engine/scheduler.py @@ -528,9 +528,9 @@ class PollingTaskGroup(object): def runAction(action): -""" + """ Start a thread to run action until finished -""" + """ # TODO # Query lock for this action @@ -538,9 +538,9 @@ def runAction(action): pass def wait(handle): -""" + """ Wait an action to finish -""" + """ # TODO # Make the subthread join the main thread pass diff --git a/senlin/tests/db/shared.py b/senlin/tests/db/shared.py index 30ea1f405..809949122 100644 --- a/senlin/tests/db/shared.py +++ b/senlin/tests/db/shared.py @@ -42,6 +42,20 @@ sample_policy = ''' pause_time: PT10M ''' +sample_action = ''' + name: test_cluster_create_action + target: cluster_001 + action: create + cause: User Initiate + timeout: 60 + status: INIT + status_reason: Just Initialized + inputs: + min_size: 1 + max_size: 10 + pause_time: PT10M +''' + UUIDs = (UUID1, UUID2, UUID3) = sorted([str(uuid.uuid4()) for x in range(3)]) @@ -58,6 +72,15 @@ def create_policy(context, policy=sample_policy, **kwargs): data.update(kwargs) return db_api.policy_create(context, data) +def create_action(context, action=sample_action, **kwargs): + data = parser.parse_action(action) + #values = { + # 'depends_on': json.loads('{"l" : "[1, 2]"}'), + # 'depended_by': json.loads('{"l" : "[4, 5]"}'), + #} + #data.update(values) + data.update(kwargs) + return db_api.action_create(context, data) def create_cluster(ctx, profile, **kwargs): values = { diff --git a/senlin/tests/db/test_action_api.py b/senlin/tests/db/test_action_api.py new file mode 100644 index 000000000..4a748395d --- /dev/null +++ b/senlin/tests/db/test_action_api.py @@ -0,0 +1,299 @@ +# 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 senlin.common import exception +from senlin.db.sqlalchemy import api as db_api +from senlin.engine import parser +from senlin.tests.common import base +from senlin.tests.common import utils +from senlin.tests.db import shared +from senlin.openstack.common import log as logging + + +class DBAPIActionTest(base.SenlinTestCase): + def setUp(self): + super(DBAPIActionTest, self).setUp() + self.ctx = utils.dummy_context() + + + def test_action_create(self): + data = parser.parse_action(shared.sample_action) + action = db_api.action_create(self.ctx, data) + + self.assertIsNotNone(action) + self.assertEqual(data['name'], action.name) + self.assertEqual(data['target'], action.target) + self.assertEqual(data['action'], action.action) + self.assertEqual(data['cause'], action.cause) + self.assertEqual(data['timeout'], action.timeout) + self.assertEqual(data['status'], action.status) + self.assertEqual(data['status_reason'], action.status_reason) + self.assertEqual(10, action.inputs['max_size']) + self.assertIsNone(action.outputs) + + + def test_action_get(self): + data = parser.parse_action(shared.sample_action) + action = shared.create_action(self.ctx) + retobj = db_api.action_get(self.ctx, action.id) + + self.assertIsNotNone(retobj) + self.assertEqual(data['name'], retobj.name) + self.assertEqual(data['target'], retobj.target) + self.assertEqual(data['action'], retobj.action) + self.assertEqual(data['cause'], retobj.cause) + self.assertEqual(data['timeout'], retobj.timeout) + self.assertEqual(data['status'], retobj.status) + self.assertEqual(data['status_reason'], retobj.status_reason) + self.assertEqual(10, retobj.inputs['max_size']) + self.assertIsNone(retobj.outputs) + + + def test_action_get_1st_ready(self): + specs = [ + {'name': 'action_001', 'status': 'INIT'}, + {'name': 'action_002', 'status': 'READY'}, + {'name': 'action_003', 'status': 'INIT'}, + {'name': 'action_004', 'status': 'READY'} + ] + + for spec in specs: + shared.create_action(self.ctx, + action=shared.sample_action, + **spec) + + action = db_api.action_get_1st_ready(self.ctx) + self.assertTrue(action.name in ['action_002', 'action_004']) + + + def test_action_get_all_ready(self): + specs = [ + {'name': 'action_001', 'status': 'INIT'}, + {'name': 'action_002', 'status': 'READY'}, + {'name': 'action_003', 'status': 'INIT'}, + {'name': 'action_004', 'status': 'READY'} + ] + + for spec in specs: + shared.create_action(self.ctx, + action=shared.sample_action, + **spec) + + actions = db_api.action_get_all_ready(self.ctx) + self.assertEqual(2, len(actions)) + names = [p.name for p in actions] + for spec in ['action_002', 'action_004']: + self.assertIn(spec, names) + + + def test_action_get_all_by_owner(self): + specs = [ + {'name': 'action_001', 'owner': 'work1'}, + {'name': 'action_002', 'owner': 'work2'}, + {'name': 'action_003', 'owner': 'work1'}, + {'name': 'action_004', 'owner': 'work3'} + ] + + for spec in specs: + shared.create_action(self.ctx, + action=shared.sample_action, + **spec) + + actions = db_api.action_get_all_by_owner(self.ctx, 'work1') + self.assertEqual(2, len(actions)) + names = [p.name for p in actions] + for spec in ['action_001', 'action_003']: + self.assertIn(spec, names) + + + def test_action_get_all(self): + specs = [ + {'name': 'action_001', 'target': 'cluster_001'}, + {'name': 'action_002', 'target': 'node_001'}, + ] + + for spec in specs: + shared.create_action(self.ctx, + action=shared.sample_action, + **spec) + + actions = db_api.action_get_all(self.ctx) + self.assertEqual(2, len(actions)) + names = [p.name for p in actions] + for spec in specs: + self.assertIn(spec['name'], names) + + + def _check_action_add_dependency_depended_list(self): + specs = [ + {'name': 'action_001', 'target': 'cluster_001'}, + {'name': 'action_002', 'target': 'node_001'}, + {'name': 'action_003', 'target': 'node_002'}, + {'name': 'action_004', 'target': 'node_003'}, + ] + + id_of = {} + for spec in specs: + action = shared.create_action(self.ctx, + action=shared.sample_action, + **spec) + id_of[spec['name']] = action.id + + db_api.action_add_dependency(self.ctx, + id_of['action_001'], + [id_of['action_002'], + id_of['action_003'], + id_of['action_004']]) + + action = db_api.action_get(self.ctx, id_of['action_001']) + l = action.depended_by['l'] + self.assertEqual(3, len(l)) + self.assertIn(id_of['action_002'], l) + self.assertIn(id_of['action_003'], l) + self.assertIn(id_of['action_004'], l) + self.assertIsNone(action.depends_on) + + for id in [id_of['action_002'], + id_of['action_003'], + id_of['action_004']]: + action = db_api.action_get(self.ctx, id) + l = action.depends_on['l'] + self.assertEqual(1, len(l)) + self.assertIn(id_of['action_001'], l) + self.assertIsNone(action.depended_by) + self.assertEqual(action.status, db_api.ACTION_WAITING) + return id_of + + + def _check_action_add_dependency_dependent_list(self): + specs = [ + {'name': 'action_001', 'target': 'cluster_001'}, + {'name': 'action_002', 'target': 'node_001'}, + {'name': 'action_003', 'target': 'node_002'}, + {'name': 'action_004', 'target': 'node_003'}, + ] + + id_of = {} + for spec in specs: + action = shared.create_action(self.ctx, + action=shared.sample_action, + **spec) + id_of[spec['name']] = action.id + + db_api.action_add_dependency(self.ctx, + [id_of['action_002'], + id_of['action_003'], + id_of['action_004']], + id_of['action_001']) + + action = db_api.action_get(self.ctx, id_of['action_001']) + l = action.depends_on['l'] + self.assertEqual(3, len(l)) + self.assertIn(id_of['action_002'], l) + self.assertIn(id_of['action_003'], l) + self.assertIn(id_of['action_004'], l) + self.assertIsNone(action.depended_by) + self.assertEqual(action.status, db_api.ACTION_WAITING) + + for id in [id_of['action_002'], + id_of['action_003'], + id_of['action_004']]: + action = db_api.action_get(self.ctx, id) + l = action.depended_by['l'] + self.assertEqual(1, len(l)) + self.assertIn(id_of['action_001'], l) + self.assertIsNone(action.depends_on) + return id_of + + + def test_action_add_dependency_depended_list(self): + self._check_action_add_dependency_depended_list() + + + def test_action_add_dependency_dependent_list(self): + self._check_action_add_dependency_dependent_list() + + + def test_action_del_dependency_depended_list(self): + id_of = self._check_action_add_dependency_depended_list() + + + def test_action_del_dependency_dependent_list(self): + id_of = self._check_action_add_dependency_dependent_list() + db_api.action_del_dependency(self.ctx, + [id_of['action_002'], + id_of['action_003'], + id_of['action_004']], + id_of['action_001']) + + action = db_api.action_get(self.ctx, id_of['action_001']) + self.assertEqual(0, len(action.depends_on['l'])) + self.assertEqual(action.status, db_api.ACTION_READY) + + for id in [id_of['action_002'], + id_of['action_003'], + id_of['action_004']]: + action = db_api.action_get(self.ctx, id) + self.assertEqual(0, len(action.depended_by['l'])) + + + def test_action_del_dependency_depended_list(self): + id_of = self._check_action_add_dependency_depended_list() + db_api.action_del_dependency(self.ctx, + id_of['action_001'], + [id_of['action_002'], + id_of['action_003'], + id_of['action_004']]) + + action = db_api.action_get(self.ctx, id_of['action_001']) + self.assertEqual(0, len(action.depended_by['l'])) + + for id in [id_of['action_002'], + id_of['action_003'], + id_of['action_004']]: + action = db_api.action_get(self.ctx, id) + self.assertEqual(0, len(action.depends_on['l'])) + self.assertEqual(action.status, db_api.ACTION_READY) + + + def test_action_mark_succeeded(self): + id_of = self._check_action_add_dependency_depended_list() + db_api.action_mark_succeeded(self.ctx, id_of['action_001']) + + action = db_api.action_get(self.ctx, id_of['action_001']) + self.assertEqual(0, len(action.depended_by['l'])) + self.assertEqual(action.status, db_api.ACTION_SUCCEEDED) + + for id in [id_of['action_002'], + id_of['action_003'], + id_of['action_004']]: + action = db_api.action_get(self.ctx, id) + self.assertEqual(0, len(action.depends_on['l'])) + + + def test_action_start_work_on(self): + action = shared.create_action(self.ctx) + + action = db_api.action_start_work_on(self.ctx, action.id, 'worker1') + + self.assertEqual(action.owner, 'worker1') + self.assertEqual(action.status, db_api.ACTION_RUNNING) + + + def test_action_delete(self): + action = shared.create_action(self.ctx) + self.assertIsNotNone(action) + action_id = action.id + db_api.action_delete(self.ctx, action.id) + + self.assertRaises(exception.NotFound, db_api.action_get, + self.ctx, action_id) From 911cf21b74a446e71eb4f08ce9a7a9c6b4d6159b Mon Sep 17 00:00:00 2001 From: Hang Liu Date: Fri, 2 Jan 2015 21:41:18 +0800 Subject: [PATCH 2/2] Fix some minimal errors. --- senlin/db/sqlalchemy/api.py | 2 +- senlin/tests/db/shared.py | 17 ++++------------- senlin/tests/db/test_action_api.py | 23 ++++++++++++++--------- 3 files changed, 19 insertions(+), 23 deletions(-) diff --git a/senlin/db/sqlalchemy/api.py b/senlin/db/sqlalchemy/api.py index 0ca7bdb8d..628a31aca 100644 --- a/senlin/db/sqlalchemy/api.py +++ b/senlin/db/sqlalchemy/api.py @@ -746,7 +746,7 @@ def _action_dependency_add(context, action_id, field, adds): d['l'] = add_list; else: d = action[field] - d['l'] = list(set(d['l']) + set(add_list)) + d['l'] = list(set(d['l']).union(set(add_list))) action[field] = d if field == 'depends_on': diff --git a/senlin/tests/db/shared.py b/senlin/tests/db/shared.py index ff73e9227..af28f9f0a 100644 --- a/senlin/tests/db/shared.py +++ b/senlin/tests/db/shared.py @@ -72,15 +72,6 @@ def create_policy(context, policy=sample_policy, **kwargs): data.update(kwargs) return db_api.policy_create(context, data) -def create_action(context, action=sample_action, **kwargs): - data = parser.parse_action(action) - #values = { - # 'depends_on': json.loads('{"l" : "[1, 2]"}'), - # 'depended_by': json.loads('{"l" : "[4, 5]"}'), - #} - #data.update(values) - data.update(kwargs) - return db_api.action_create(context, data) def create_cluster(ctx, profile, **kwargs): values = { @@ -147,12 +138,12 @@ def create_action(ctx, **kwargs): 'target': kwargs.get('target'), 'action': kwargs.get('action'), 'cause': 'Reason for action', - 'owner': kwarge.get('owner'), + 'owner': kwargs.get('owner'), 'interval': -1, 'inputs': {'key': 'value'}, - 'outputs': {'result': 'value'} - 'depends_on': [], - 'depended_on': [] + 'outputs': {'result': 'value'}, + 'depends_on': {'l': []}, + 'depended_by': {'l': []} } values.update(kwargs) return db_api.action_create(ctx, values) diff --git a/senlin/tests/db/test_action_api.py b/senlin/tests/db/test_action_api.py index 4a748395d..a0bd76809 100644 --- a/senlin/tests/db/test_action_api.py +++ b/senlin/tests/db/test_action_api.py @@ -18,6 +18,11 @@ from senlin.tests.common import utils from senlin.tests.db import shared from senlin.openstack.common import log as logging +def _create_action(context, action=shared.sample_action, **kwargs): + data = parser.parse_action(action) + data.update(kwargs) + return db_api.action_create(context, data) + class DBAPIActionTest(base.SenlinTestCase): def setUp(self): @@ -43,7 +48,7 @@ class DBAPIActionTest(base.SenlinTestCase): def test_action_get(self): data = parser.parse_action(shared.sample_action) - action = shared.create_action(self.ctx) + action = _create_action(self.ctx) retobj = db_api.action_get(self.ctx, action.id) self.assertIsNotNone(retobj) @@ -67,7 +72,7 @@ class DBAPIActionTest(base.SenlinTestCase): ] for spec in specs: - shared.create_action(self.ctx, + _create_action(self.ctx, action=shared.sample_action, **spec) @@ -84,7 +89,7 @@ class DBAPIActionTest(base.SenlinTestCase): ] for spec in specs: - shared.create_action(self.ctx, + _create_action(self.ctx, action=shared.sample_action, **spec) @@ -104,7 +109,7 @@ class DBAPIActionTest(base.SenlinTestCase): ] for spec in specs: - shared.create_action(self.ctx, + _create_action(self.ctx, action=shared.sample_action, **spec) @@ -122,7 +127,7 @@ class DBAPIActionTest(base.SenlinTestCase): ] for spec in specs: - shared.create_action(self.ctx, + _create_action(self.ctx, action=shared.sample_action, **spec) @@ -143,7 +148,7 @@ class DBAPIActionTest(base.SenlinTestCase): id_of = {} for spec in specs: - action = shared.create_action(self.ctx, + action = _create_action(self.ctx, action=shared.sample_action, **spec) id_of[spec['name']] = action.id @@ -184,7 +189,7 @@ class DBAPIActionTest(base.SenlinTestCase): id_of = {} for spec in specs: - action = shared.create_action(self.ctx, + action = _create_action(self.ctx, action=shared.sample_action, **spec) id_of[spec['name']] = action.id @@ -281,7 +286,7 @@ class DBAPIActionTest(base.SenlinTestCase): def test_action_start_work_on(self): - action = shared.create_action(self.ctx) + action = _create_action(self.ctx) action = db_api.action_start_work_on(self.ctx, action.id, 'worker1') @@ -290,7 +295,7 @@ class DBAPIActionTest(base.SenlinTestCase): def test_action_delete(self): - action = shared.create_action(self.ctx) + action = _create_action(self.ctx) self.assertIsNotNone(action) action_id = action.id db_api.action_delete(self.ctx, action.id)