diff --git a/mistralclient/api/v2/actions.py b/mistralclient/api/v2/actions.py index d722467f..cccdaaab 100644 --- a/mistralclient/api/v2/actions.py +++ b/mistralclient/api/v2/actions.py @@ -46,15 +46,17 @@ class ActionManager(base.ResourceManager): return [self.resource_class(self, resource_data) for resource_data in base.extract_json(resp, 'actions')] - def update(self, definition, scope='private'): + def update(self, definition, scope='private', id=None): self._ensure_not_empty(definition=definition) + url_pre = ('/actions/%s' % id) if id else '/actions' + # If the specified definition is actually a file, read in the # definition file definition = utils.get_contents_if_file(definition) resp = self.client.http_client.put( - '/actions?scope=%s' % scope, + '%s?scope=%s' % (url_pre, scope), definition, headers={'content-type': 'text/plain'} ) @@ -88,15 +90,15 @@ class ActionManager(base.ResourceManager): response_key='actions', ) - def get(self, name): - self._ensure_not_empty(name=name) + def get(self, identifier): + self._ensure_not_empty(identifier=identifier) - return self._get('/actions/%s' % name) + return self._get('/actions/%s' % identifier) - def delete(self, name): - self._ensure_not_empty(name=name) + def delete(self, identifier): + self._ensure_not_empty(identifier=identifier) - self._delete('/actions/%s' % name) + self._delete('/actions/%s' % identifier) def validate(self, definition): self._ensure_not_empty(definition=definition) diff --git a/mistralclient/commands/v2/actions.py b/mistralclient/commands/v2/actions.py index 27720a0a..37ecb13f 100644 --- a/mistralclient/commands/v2/actions.py +++ b/mistralclient/commands/v2/actions.py @@ -31,6 +31,7 @@ def format_list(action=None): def format(action=None, lister=False): columns = ( + 'ID', 'Name', 'Is system', 'Input', @@ -47,6 +48,7 @@ def format(action=None, lister=False): else base.cut(action.description)) data = ( + action.id, action.name, action.is_system, input, @@ -137,7 +139,11 @@ class Delete(command.Command): def get_parser(self, prog_name): parser = super(Delete, self).get_parser(prog_name) - parser.add_argument('name', nargs='+', help='Name of action(s).') + parser.add_argument( + 'action', + nargs='+', + help='Name or ID of action(s).' + ) return parser @@ -146,7 +152,7 @@ class Delete(command.Command): utils.do_action_on_many( lambda s: mistral_client.actions.delete(s), - parsed_args.name, + parsed_args.action, "Request to delete action %s has been accepted.", "Unable to delete the specified action(s)." ) @@ -163,6 +169,7 @@ class Update(base.MistralLister): type=argparse.FileType('r'), help='Action definition file' ) + parser.add_argument('--id', help='Action ID.') parser.add_argument( '--public', action='store_true', @@ -181,7 +188,8 @@ class Update(base.MistralLister): return mistral_client.actions.update( parsed_args.definition.read(), - scope=scope + scope=scope, + id=parsed_args.id ) diff --git a/mistralclient/tests/functional/cli/v2/cli_tests_v2.py b/mistralclient/tests/functional/cli/v2/cli_tests_v2.py index 28867af5..3ab85a9f 100644 --- a/mistralclient/tests/functional/cli/v2/cli_tests_v2.py +++ b/mistralclient/tests/functional/cli/v2/cli_tests_v2.py @@ -752,6 +752,36 @@ class ActionCLITests(base_v2.MistralClientTestBase): self.assertNotEqual(created_action['Updated at'], updated_action['Updated at']) + def test_action_update_with_id(self): + acts = self.action_create(self.act_def) + + created_action = self.get_item_info( + get_from=acts, + get_by='Name', + value='greeting' + ) + + action_id = created_action['ID'] + + params = '{0} --id {1}'.format(self.act_tag_def, action_id) + acts = self.mistral_admin('action-update', params=params) + + updated_action = self.get_item_info( + get_from=acts, + get_by='ID', + value=action_id + ) + + self.assertEqual( + created_action['Created at'].split(".")[0], + updated_action['Created at'] + ) + self.assertEqual(created_action['Name'], updated_action['Name']) + self.assertNotEqual( + created_action['Updated at'], + updated_action['Updated at'] + ) + def test_action_update_truncate_input(self): input_value = "very_long_input_parameter_name_that_should_be_truncated" act_def = """ @@ -777,6 +807,15 @@ class ActionCLITests(base_v2.MistralClientTestBase): 'action-get-definition', params='greeting') self.assertNotIn('404 Not Found', definition) + def test_action_get_with_id(self): + created = self.action_create(self.act_def) + action_name = created[0]['Name'] + action_id = created[0]['ID'] + + fetched = self.mistral_admin('action-get', params=action_id) + fetched_action_name = self.get_field_value(fetched, 'Name') + self.assertEqual(action_name, fetched_action_name) + class EnvironmentCLITests(base_v2.MistralClientTestBase): """Test suite checks commands to work with environments.""" diff --git a/mistralclient/tests/unit/v2/test_actions.py b/mistralclient/tests/unit/v2/test_actions.py index 91d6fdcc..8e9ca62a 100644 --- a/mistralclient/tests/unit/v2/test_actions.py +++ b/mistralclient/tests/unit/v2/test_actions.py @@ -94,6 +94,20 @@ class TestActionsV2(base.BaseClientV2Test): headers={'content-type': 'text/plain'} ) + def test_update_with_id(self): + mock = self.mock_http_put(content={'actions': [ACTION]}) + + actions = self.actions.update(ACTION_DEF, id=123) + + self.assertIsNotNone(actions) + self.assertEqual(ACTION_DEF, actions[0].definition) + + mock.assert_called_once_with( + '/actions/123?scope=private', + ACTION_DEF, + headers={'content-type': 'text/plain'} + ) + def test_update(self): mock = self.mock_http_put(content={'actions': [ACTION]}) diff --git a/mistralclient/tests/unit/v2/test_cli_actions.py b/mistralclient/tests/unit/v2/test_cli_actions.py index 15f8a7ee..b2e48720 100644 --- a/mistralclient/tests/unit/v2/test_cli_actions.py +++ b/mistralclient/tests/unit/v2/test_cli_actions.py @@ -24,6 +24,7 @@ from mistralclient.tests.unit import base ACTION_DICT = { + 'id': '1234-4567-7894-7895', 'name': 'a', 'is_system': True, 'input': "param1", @@ -57,7 +58,8 @@ class TestCLIActionsV2(base.BaseCommandTest): result = self.call(action_cmd.Create, app_args=['1.txt']) self.assertEqual( - [('a', True, "param1", 'My cool action', 'test', '1', '1')], + [('1234-4567-7894-7895', 'a', True, "param1", + 'My cool action', 'test', '1', '1')], result[1] ) @@ -71,7 +73,8 @@ class TestCLIActionsV2(base.BaseCommandTest): ) self.assertEqual( - [('a', True, "param1", 'My cool action', 'test', '1', '1')], + [('1234-4567-7894-7895', 'a', True, "param1", + 'My cool action', 'test', '1', '1')], result[1] ) @@ -96,7 +99,7 @@ class TestCLIActionsV2(base.BaseCommandTest): result = self.call(action_cmd.Create, app_args=['1.txt']) self.assertEqual( - [('a', True, cmd_base.cut(long_input), + [('1234-4567-7894-7895', 'a', True, cmd_base.cut(long_input), 'My cool action', 'test', '1', '1')], result[1] ) @@ -108,7 +111,8 @@ class TestCLIActionsV2(base.BaseCommandTest): result = self.call(action_cmd.Update, app_args=['my_action.yaml']) self.assertEqual( - [('a', True, "param1", 'My cool action', 'test', '1', '1')], + [('1234-4567-7894-7895', 'a', True, "param1", + 'My cool action', 'test', '1', '1')], result[1] ) @@ -122,7 +126,8 @@ class TestCLIActionsV2(base.BaseCommandTest): ) self.assertEqual( - [('a', True, "param1", 'My cool action', 'test', '1', '1')], + [('1234-4567-7894-7895', 'a', True, "param1", + 'My cool action', 'test', '1', '1')], result[1] ) @@ -137,7 +142,8 @@ class TestCLIActionsV2(base.BaseCommandTest): result = self.call(action_cmd.List) self.assertEqual( - [('a', True, "param1", 'My cool action', 'test', '1', '1')], + [('1234-4567-7894-7895', 'a', True, "param1", + 'My cool action', 'test', '1', '1')], result[1] ) @@ -147,7 +153,8 @@ class TestCLIActionsV2(base.BaseCommandTest): result = self.call(action_cmd.Get, app_args=['name']) self.assertEqual( - ('a', True, "param1", 'My cool action', 'test', '1', '1'), + ('1234-4567-7894-7895', 'a', True, "param1", + 'My cool action', 'test', '1', '1'), result[1] )