From 1a0ccd1414a889ca5c52edc0b57e5194bba579bc Mon Sep 17 00:00:00 2001 From: Nikolay Mahotkin Date: Thu, 11 Jun 2015 16:28:51 +0300 Subject: [PATCH] Implementing run-action command in client * Introduced new command: mistral run-action [--save-result] [--target TARGET] * Short options: -s (--save-result), -t (--target) Implements blueprint mistral-run-individual-action Change-Id: Iad86f805e8bb13027946a7da9b0d79dc220d44d6 --- mistralclient/api/v2/action_executions.py | 23 ++++++ .../commands/v2/action_executions.py | 76 ++++++++++++++++++- mistralclient/shell.py | 1 + .../tests/unit/v2/test_action_executions.py | 19 +++++ .../tests/unit/v2/test_cli_action_execs.py | 32 ++++++++ 5 files changed, 150 insertions(+), 1 deletion(-) diff --git a/mistralclient/api/v2/action_executions.py b/mistralclient/api/v2/action_executions.py index b50d66d1..c35fa7bd 100644 --- a/mistralclient/api/v2/action_executions.py +++ b/mistralclient/api/v2/action_executions.py @@ -12,6 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +import json + from mistralclient.api import base @@ -22,6 +24,27 @@ class ActionExecution(base.Resource): class ActionExecutionManager(base.ResourceManager): resource_class = ActionExecution + def create(self, name, input=None, **params): + self._ensure_not_empty(name=name) + + data = {'name': name} + + if input: + data['input'] = json.dumps(input) + + if params: + data['params'] = params + + resp = self.client.http_client.post( + '/action_executions', + json.dumps(data) + ) + + if resp.status_code != 201: + self._raise_api_exception(resp) + + return self.resource_class(self, base.get_json(resp)) + def update(self, id, state=None, output=None): self._ensure_not_empty(id=id) diff --git a/mistralclient/commands/v2/action_executions.py b/mistralclient/commands/v2/action_executions.py index 45e7576f..64feb3ab 100644 --- a/mistralclient/commands/v2/action_executions.py +++ b/mistralclient/commands/v2/action_executions.py @@ -49,7 +49,7 @@ def format(action_ex=None, lister=False): action_ex.id, action_ex.name, action_ex.workflow_name, - action_ex.task_name, + action_ex.task_name if hasattr(action_ex, 'task_name') else None, action_ex.state, state_info, action_ex.accepted, @@ -60,6 +60,80 @@ def format(action_ex=None, lister=False): return columns, data +class Create(show.ShowOne): + """Create new Action execution or just run specific action.""" + + def produce_output(self, parsed_args, column_names, data): + if not column_names: + return 0 + + return super(Create, self).produce_output( + parsed_args, + column_names, + data + ) + + def get_parser(self, prog_name): + parser = super(Create, self).get_parser(prog_name) + + parser.add_argument( + 'name', + help='Action name to execute.' + ) + parser.add_argument( + dest='input', + nargs='?', + help='Action input.' + ) + parser.add_argument( + '-s', + '--save-result', + dest='save_result', + action='store_true', + help='Save the result into DB.' + ) + parser.add_argument( + '-t', + '--target', + dest='target', + help='Action will be executed on executor.' + ) + + return parser + + def take_action(self, parsed_args): + params = {} + + if parsed_args.save_result: + params['save_result'] = parsed_args.save_result + + if parsed_args.target: + params['target'] = parsed_args.target + + action_input = None + + if parsed_args.input: + try: + action_input = json.loads(parsed_args.input) + except: + action_input = json.load(open(parsed_args.input)) + + action_ex = action_executions.ActionExecutionManager( + self.app.client + ).create( + parsed_args.name, + action_input, + **params + ) + + if parsed_args.save_result: + return format(action_ex) + else: + self.app.stdout.write("%s\n" % action_ex.output) + + return None, None + + class List(base.MistralLister): """List all Action executions.""" diff --git a/mistralclient/shell.py b/mistralclient/shell.py index a8112ff5..65ca3dac 100644 --- a/mistralclient/shell.py +++ b/mistralclient/shell.py @@ -324,6 +324,7 @@ class MistralShell(app.App): mistralclient.commands.v2.environments.Update, 'environment-list': mistralclient.commands.v2.environments.List, 'environment-get': mistralclient.commands.v2.environments.Get, + 'run-action': mistralclient.commands.v2.action_executions.Create, 'action-execution-list': mistralclient.commands.v2.action_executions.List, 'action-execution-get': diff --git a/mistralclient/tests/unit/v2/test_action_executions.py b/mistralclient/tests/unit/v2/test_action_executions.py index 33081678..d4236f54 100644 --- a/mistralclient/tests/unit/v2/test_action_executions.py +++ b/mistralclient/tests/unit/v2/test_action_executions.py @@ -32,6 +32,25 @@ URL_TEMPLATE_ID = '/action_executions/%s' class TestActionExecutions(base.BaseClientV2Test): + def test_create(self): + mock = self.mock_http_post(content=ACTION_EXEC) + body = { + 'name': ACTION_EXEC['name'] + } + + action_execution = self.action_executions.create( + 'my_action_execution', + {} + ) + + self.assertIsNotNone(action_execution) + self.assertEqual(action_executions.ActionExecution( + self.action_executions, ACTION_EXEC + ).__dict__, action_execution.__dict__) + + mock.assert_called_once_with( + URL_TEMPLATE, json.dumps(body)) + def test_update(self): mock = self.mock_http_put(content=ACTION_EXEC) body = { diff --git a/mistralclient/tests/unit/v2/test_cli_action_execs.py b/mistralclient/tests/unit/v2/test_cli_action_execs.py index 62f1d576..93f3af2f 100644 --- a/mistralclient/tests/unit/v2/test_cli_action_execs.py +++ b/mistralclient/tests/unit/v2/test_cli_action_execs.py @@ -50,6 +50,38 @@ ACTION_EX_WITH_INPUT = action_ex.ActionExecution( class TestCLIActionExecutions(base.BaseCommandTest): + @mock.patch( + 'mistralclient.api.v2.action_executions.ActionExecutionManager.create' + ) + def test_create(self, mock): + mock.return_value = ACTION_EX_WITH_OUTPUT + + self.call( + action_ex_cmd.Create, + app_args=['some', '{"output": "Hello!"}'] + ) + + self.app.stdout.write.assert_called_with( + json.dumps(ACTION_EX_RESULT) + "\n") + + @mock.patch( + 'mistralclient.api.v2.action_executions.ActionExecutionManager.create' + ) + def test_create_save_result(self, mock): + mock.return_value = ACTION_EX_WITH_OUTPUT + + result = self.call( + action_ex_cmd.Create, + app_args=[ + 'some', '{"output": "Hello!"}', '--save-result' + ] + ) + + self.assertEqual( + ('123', 'some', 'thing', 'task1', 'RUNNING', + 'RUNNING somehow.', True), result[1] + ) + @mock.patch( 'mistralclient.api.v2.action_executions.ActionExecutionManager.update' )