From e2e624ea2d94f68a36e3ca7c7c758afbc6a78a14 Mon Sep 17 00:00:00 2001 From: Tomaz Muraus Date: Sun, 7 Feb 2021 17:51:46 +0100 Subject: [PATCH 1/7] Fix broken st2 action-alias execute command. There were two bugs: 1. If user it's not specified it will return an error 2. It didn't correctly de-serialize the result so it failed --- st2client/st2client/commands/action_alias.py | 2 +- st2client/st2client/models/core.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/st2client/st2client/commands/action_alias.py b/st2client/st2client/commands/action_alias.py index a9a15e7bed..32a65776cc 100644 --- a/st2client/st2client/commands/action_alias.py +++ b/st2client/st2client/commands/action_alias.py @@ -115,7 +115,7 @@ def __init__(self, resource, *args, **kwargs): def run(self, args, **kwargs): payload = core.Resource() payload.command = args.command_text - payload.user = args.user + payload.user = args.user or "" payload.source_channel = 'cli' alias_execution_mgr = self.app.client.managers['ActionAliasExecution'] diff --git a/st2client/st2client/models/core.py b/st2client/st2client/models/core.py index d102d3158f..255c91534f 100644 --- a/st2client/st2client/models/core.py +++ b/st2client/st2client/models/core.py @@ -373,7 +373,7 @@ def match_and_execute(self, instance, **kwargs): if response.status_code != http_client.OK: self.handle_error(response) - instance = self.resource.deserialize(response.json()) + instance = self.resource.deserialize(response.json()["results"][0]) return instance From 5df4e8e51acf1c32587b6edbc9f4fb2a353e83f7 Mon Sep 17 00:00:00 2001 From: Tomaz Muraus Date: Mon, 8 Feb 2021 15:58:46 +0100 Subject: [PATCH 2/7] Add indirect test case for match and execute client bug. --- .../unit/controllers/v1/test_action_alias.py | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/st2api/tests/unit/controllers/v1/test_action_alias.py b/st2api/tests/unit/controllers/v1/test_action_alias.py index e9cdf0c52e..b507c2a161 100644 --- a/st2api/tests/unit/controllers/v1/test_action_alias.py +++ b/st2api/tests/unit/controllers/v1/test_action_alias.py @@ -24,7 +24,8 @@ FIXTURES_PACK = 'aliases' TEST_MODELS = { - 'aliases': ['alias1.yaml', 'alias2.yaml', 'alias_with_undefined_jinja_in_ack_format.yaml'] + 'aliases': ['alias1.yaml', 'alias2.yaml', 'alias_with_undefined_jinja_in_ack_format.yaml'], + 'actions': ['action1.yaml'], } TEST_LOAD_MODELS = { @@ -34,7 +35,8 @@ GENERIC_FIXTURES_PACK = 'generic' TEST_LOAD_MODELS_GENERIC = { - 'aliases': ['alias3.yaml'] + 'aliases': ['alias3.yaml'], + 'runners': ['testrunner1.yaml'] } @@ -180,6 +182,18 @@ def test_match(self): self.assertEqual(resp.json['actionalias']['name'], 'alias_with_undefined_jinja_in_ack_format') + def test_match_and_execute_success(self): + data = { + 'command': 'run whoami on localhost1', + 'source_channel': 'hubot', + 'user': "user", + } + resp = self.app.post_json("/v1/aliasexecution/match_and_execute", data) + self.assertEqual(resp.status_int, 201) + self.assertEqual(len(resp.json["results"]), 1) + self.assertTrue(resp.json["results"][0]["actionalias"]["ref"], + "aliases.alias_with_undefined_jinja_in_ack_format") + def test_help(self): resp = self.app.get("/v1/actionalias/help") self.assertEqual(resp.status_int, 200) From d95d3f1f25c370c5bd349b396102a8981c4a77ea Mon Sep 17 00:00:00 2001 From: Tomaz Muraus Date: Mon, 8 Feb 2021 16:03:18 +0100 Subject: [PATCH 3/7] Add changelog entry. --- CHANGELOG.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 94db66b6db..ce9fd132d2 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -53,6 +53,11 @@ Fixed * StackStorm now explicitly decodes pack files as utf-8 instead of implicitly as ascii (bug fix) #5106, #5107 +* Fix broken ``st2 action-alias execute`` command and make sure it works + correctly. (bug fix) #5138 + + Contributed by @Kami. + Removed ~~~~~~~~ * Removed --python3 pack install option #5100 From ec03d14058ecaa7d0aaf12ec62ac66e8c3516dc8 Mon Sep 17 00:00:00 2001 From: Tomaz Muraus Date: Mon, 8 Feb 2021 16:20:13 +0100 Subject: [PATCH 4/7] Update fixture. --- st2tests/st2tests/fixtures/aliases/actions/action1.yaml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/st2tests/st2tests/fixtures/aliases/actions/action1.yaml b/st2tests/st2tests/fixtures/aliases/actions/action1.yaml index c9be03ce3d..7a0d9c7bdf 100644 --- a/st2tests/st2tests/fixtures/aliases/actions/action1.yaml +++ b/st2tests/st2tests/fixtures/aliases/actions/action1.yaml @@ -1,7 +1,7 @@ --- name: "action1" description: "" - runner_type: "test-runner" + runner_type: "noop" pack: "wolfpack" entry_point: "/tmp/test/action1.sh" enabled: true @@ -15,3 +15,7 @@ param4: type: "string" secret: true + hosts: + type: "string" + cmd: + type: "string" From 19e220698978a5cfe8129d1f207d390d1a343c1a Mon Sep 17 00:00:00 2001 From: Tomaz Muraus Date: Mon, 8 Feb 2021 16:20:53 +0100 Subject: [PATCH 5/7] Add a direct st2 CLI test case for st2 alias-execution execute command. --- st2client/tests/unit/test_action_alias.py | 64 +++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 st2client/tests/unit/test_action_alias.py diff --git a/st2client/tests/unit/test_action_alias.py b/st2client/tests/unit/test_action_alias.py new file mode 100644 index 0000000000..0864d053d2 --- /dev/null +++ b/st2client/tests/unit/test_action_alias.py @@ -0,0 +1,64 @@ +# Copyright 2020 The StackStorm Authors. +# Copyright 2019 Extreme Networks, Inc. +# +# 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 __future__ import absolute_import +import json +import mock +import logging + +from tests import base + +from st2client import shell +from st2client import models +from st2client.utils import httpclient + +MOCK_MATCH_AND_EXECUTE_RESULT = { + "results": [ + { + "execution": { + "id": "mock-id", + }, + "actionalias": { + "ref": "mock-ref" + } + } + ] +} + + +class ActionAliasCommandTestCase(base.BaseCLITestCase): + def __init__(self, *args, **kwargs): + super(ActionAliasCommandTestCase, self).__init__(*args, **kwargs) + self.shell = shell.Shell() + + @mock.patch.object( + httpclient.HTTPClient, 'post', + mock.MagicMock(return_value=base.FakeResponse(json.dumps(MOCK_MATCH_AND_EXECUTE_RESULT), 200, 'OK'))) + def test_match_and_execute(self): + ret = self.shell.run(['action-alias', 'execute', "run whoami on localhost"]) + self.assertEqual(ret, 0) + + expected_args = { + 'command': 'run whoami on localhost', + 'user': '', + 'source_channel': 'cli' + } + httpclient.HTTPClient.post.assert_called_with('/aliasexecution/match_and_execute', expected_args) + + mock_stdout = self.stdout.getvalue() + + self.assertTrue("Matching Action-alias: 'mock-ref'" in mock_stdout) + self.assertTrue("st2 execution get mock-id" in mock_stdout) From 75a114c81089fffc5d7550fc4a65f2ed33d734a1 Mon Sep 17 00:00:00 2001 From: Tomaz Muraus Date: Mon, 8 Feb 2021 16:21:21 +0100 Subject: [PATCH 6/7] Update base CLI test case class where we capture and don't display captured stdout and stderr to display captured stdout + stderr on test failure. This should make troubleshooting those tests much easier and faster. --- st2client/tests/base.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/st2client/tests/base.py b/st2client/tests/base.py index d0e7b2253d..307f00f74b 100644 --- a/st2client/tests/base.py +++ b/st2client/tests/base.py @@ -109,6 +109,20 @@ def tearDown(self): sys.stdout = sys.__stdout__ sys.stderr = sys.__stderr__ + # On failure, we also print values of accumulated stdout and stderr + # to make troubleshooting easier + # TODO: nosetests specific make sure to update when / if switching to pytest + errors = getattr(self.__dict__.get("_outcome", None), "errors", []) + + if len(errors) >= 1: + stdout = self.stdout.getvalue() + stderr = self.stderr.getvalue() + + print("") + print("Captured stdout: %s" % (stdout)) + print("Captured stdoerr: %s" % (stderr)) + print("") + def _reset_output_streams(self): """ Reset / clear stdout and stderr stream. From f3409252cef0a415f5ae6d8532718f847cc1ccc0 Mon Sep 17 00:00:00 2001 From: Tomaz Muraus Date: Mon, 8 Feb 2021 16:22:42 +0100 Subject: [PATCH 7/7] Fix lint. --- st2client/tests/unit/test_action_alias.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/st2client/tests/unit/test_action_alias.py b/st2client/tests/unit/test_action_alias.py index 0864d053d2..a360fd5139 100644 --- a/st2client/tests/unit/test_action_alias.py +++ b/st2client/tests/unit/test_action_alias.py @@ -13,16 +13,14 @@ # See the License for the specific language governing permissions and # limitations under the License. - from __future__ import absolute_import + import json import mock -import logging from tests import base from st2client import shell -from st2client import models from st2client.utils import httpclient MOCK_MATCH_AND_EXECUTE_RESULT = { @@ -46,7 +44,8 @@ def __init__(self, *args, **kwargs): @mock.patch.object( httpclient.HTTPClient, 'post', - mock.MagicMock(return_value=base.FakeResponse(json.dumps(MOCK_MATCH_AND_EXECUTE_RESULT), 200, 'OK'))) + mock.MagicMock(return_value=base.FakeResponse(json.dumps(MOCK_MATCH_AND_EXECUTE_RESULT), + 200, 'OK'))) def test_match_and_execute(self): ret = self.shell.run(['action-alias', 'execute', "run whoami on localhost"]) self.assertEqual(ret, 0) @@ -56,7 +55,8 @@ def test_match_and_execute(self): 'user': '', 'source_channel': 'cli' } - httpclient.HTTPClient.post.assert_called_with('/aliasexecution/match_and_execute', expected_args) + httpclient.HTTPClient.post.assert_called_with('/aliasexecution/match_and_execute', + expected_args) mock_stdout = self.stdout.getvalue()