From 1e8aa64d3b20fd8522742887626ee1fd279b631d Mon Sep 17 00:00:00 2001 From: Tristan Struthers Date: Tue, 17 Sep 2019 12:16:35 -0700 Subject: [PATCH 1/5] Add ActionResourceManager and implement GET entrypoint --- st2client/st2client/client.py | 3 ++- st2client/st2client/models/action.py | 1 + st2client/st2client/models/core.py | 12 ++++++++++++ 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/st2client/st2client/client.py b/st2client/st2client/client.py index 280174edb5..fe1d4cc1b0 100644 --- a/st2client/st2client/client.py +++ b/st2client/st2client/client.py @@ -25,6 +25,7 @@ from st2client.models.core import ResourceManager from st2client.models.core import ActionAliasResourceManager from st2client.models.core import ActionAliasExecutionManager +from st2client.models.core import ActionResourceManager from st2client.models.core import ExecutionResourceManager from st2client.models.core import InquiryResourceManager from st2client.models.core import TriggerInstanceResourceManager @@ -118,7 +119,7 @@ def __init__(self, base_url=None, auth_url=None, api_url=None, stream_url=None, models.Token, self.endpoints['auth'], cacert=self.cacert, debug=self.debug) self.managers['RunnerType'] = ResourceManager( models.RunnerType, self.endpoints['api'], cacert=self.cacert, debug=self.debug) - self.managers['Action'] = ResourceManager( + self.managers['Action'] = ActionResourceManager( models.Action, self.endpoints['api'], cacert=self.cacert, debug=self.debug) self.managers['ActionAlias'] = ActionAliasResourceManager( models.ActionAlias, self.endpoints['api'], cacert=self.cacert, debug=self.debug) diff --git a/st2client/st2client/models/action.py b/st2client/st2client/models/action.py index d931c48427..6432192792 100644 --- a/st2client/st2client/models/action.py +++ b/st2client/st2client/models/action.py @@ -33,6 +33,7 @@ class RunnerType(core.Resource): class Action(core.Resource): _plural = 'Actions' _repr_attributes = ['name', 'pack', 'enabled', 'runner_type'] + _url_path = 'actions' class Execution(core.Resource): diff --git a/st2client/st2client/models/core.py b/st2client/st2client/models/core.py index f9d2a86838..6b70c3ffc0 100644 --- a/st2client/st2client/models/core.py +++ b/st2client/st2client/models/core.py @@ -376,6 +376,18 @@ def match_and_execute(self, instance, **kwargs): return instance +class ActionResourceManager(ResourceManager): + @add_auth_token_to_kwargs_from_env + def get_entrypoint(self, ref_or_id, **kwargs): + url = '/%s/views/entry_point/%s' % (self.resource.get_url_path_name(), ref_or_id) + + response = self.client.get(url, **kwargs) + if response.status_code != http_client.OK: + self.handle_error(response) + + return response.text + + class ExecutionResourceManager(ResourceManager): @add_auth_token_to_kwargs_from_env def re_run(self, execution_id, parameters=None, tasks=None, no_reset=None, user=None, delay=0, From eaa00767fa3d9cf549630ad03a43bb8b808c9702 Mon Sep 17 00:00:00 2001 From: Tristan Struthers Date: Tue, 24 Sep 2019 12:48:09 -0700 Subject: [PATCH 2/5] Update CHANGELOG to reflect new feature --- CHANGELOG.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 1aa027c819..a8e3c5a016 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -11,6 +11,7 @@ Added ``url_hosts_blacklist`` and ``url_hosts_whitelist`` runner attribute. (new feature) #4757 * Add ``user`` parameter to ``re_run`` method of st2client. #4785 +* Add ``get_entrypoint()`` method to ``ActionResourceManager`` attribute of st2client. #4791 Changed ~~~~~~~ From fcf6fe09abcb448ec6071f5a92b1d44621fb2a49 Mon Sep 17 00:00:00 2001 From: Tristan Struthers Date: Tue, 24 Sep 2019 12:48:33 -0700 Subject: [PATCH 3/5] Add unit tests for the new ActionResourceManager methods --- st2client/tests/unit/test_client_actions.py | 88 +++++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 st2client/tests/unit/test_client_actions.py diff --git a/st2client/tests/unit/test_client_actions.py b/st2client/tests/unit/test_client_actions.py new file mode 100644 index 0000000000..b2d1f39d82 --- /dev/null +++ b/st2client/tests/unit/test_client_actions.py @@ -0,0 +1,88 @@ +# 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 logging +import mock +import unittest2 + +from tests import base + +from st2client import client +from st2client.utils import httpclient + + +LOG = logging.getLogger(__name__) + + +EXECUTION = { + "id": 12345, + "action": { + "ref": "mock.foobar" + }, + "status": "failed", + "result": "non-empty" +} + +ENTRYPOINT = ( + "version: 1.0" + + "description: A basic workflow that runs an arbitrary linux command." + + "input:" + " - cmd" + " - timeout" + + "tasks:" + " task1:" + " action: core.local cmd=<% ctx(cmd) %> timeout=<% ctx(timeout) %>" + " next:" + " - when: <% succeeded() %>" + " publish:" + " - stdout: <% result().stdout %>" + " - stderr: <% result().stderr %>" + + "output:" + " - stdout: <% ctx(stdout) %>" +) + + +class TestActionResourceManager(unittest2.TestCase): + + @classmethod + def setUpClass(cls): + super(TestActionResourceManager, cls).setUpClass() + cls.client = client.Client() + + @mock.patch.object( + httpclient.HTTPClient, 'get', + mock.MagicMock(return_value=base.FakeResponse(json.dumps(ENTRYPOINT), 200, 'OK'))) + def test_get_action_entry_point_by_ref(self): + self.client.actions.get_entrypoint(EXECUTION['action']['ref']) + + endpoint = '/actions/views/entry_point/%s' % EXECUTION['action']['ref'] + + httpclient.HTTPClient.get.assert_called_with(endpoint) + + @mock.patch.object( + httpclient.HTTPClient, 'get', + mock.MagicMock(return_value=base.FakeResponse(json.dumps(ENTRYPOINT), 200, 'OK'))) + def test_get_action_entry_point_by_id(self): + self.client.actions.get_entrypoint(EXECUTION['id']) + + endpoint = '/actions/views/entry_point/%s' % EXECUTION['id'] + + httpclient.HTTPClient.get.assert_called_with(endpoint) From 622fbfc49bb235e86acc468283d4de05d279cf4c Mon Sep 17 00:00:00 2001 From: Tristan Struthers Date: Tue, 24 Sep 2019 15:20:13 -0700 Subject: [PATCH 4/5] Assert correctness of return value and add 404 test --- st2client/tests/unit/test_client_actions.py | 22 ++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/st2client/tests/unit/test_client_actions.py b/st2client/tests/unit/test_client_actions.py index b2d1f39d82..ac7c3b191a 100644 --- a/st2client/tests/unit/test_client_actions.py +++ b/st2client/tests/unit/test_client_actions.py @@ -71,18 +71,34 @@ def setUpClass(cls): httpclient.HTTPClient, 'get', mock.MagicMock(return_value=base.FakeResponse(json.dumps(ENTRYPOINT), 200, 'OK'))) def test_get_action_entry_point_by_ref(self): - self.client.actions.get_entrypoint(EXECUTION['action']['ref']) + actual_entrypoint = self.client.actions.get_entrypoint(EXECUTION['action']['ref']) + actual_entrypoint = json.loads(actual_entrypoint) endpoint = '/actions/views/entry_point/%s' % EXECUTION['action']['ref'] - httpclient.HTTPClient.get.assert_called_with(endpoint) + self.assertEqual(ENTRYPOINT, actual_entrypoint) + @mock.patch.object( httpclient.HTTPClient, 'get', mock.MagicMock(return_value=base.FakeResponse(json.dumps(ENTRYPOINT), 200, 'OK'))) def test_get_action_entry_point_by_id(self): - self.client.actions.get_entrypoint(EXECUTION['id']) + actual_entrypoint = self.client.actions.get_entrypoint(EXECUTION['id']) + actual_entrypoint = json.loads(actual_entrypoint) endpoint = '/actions/views/entry_point/%s' % EXECUTION['id'] + httpclient.HTTPClient.get.assert_called_with(endpoint) + self.assertEqual(ENTRYPOINT, actual_entrypoint) + + @mock.patch.object( + httpclient.HTTPClient, 'get', + mock.MagicMock(return_value=base.FakeResponse( + json.dumps({}), 404, '404 Client Error: Not Found' + ))) + def test_get_non_existent_action_entry_point(self): + with self.assertRaises(Exception): + self.client.actions.get_entrypoint('nonexistentpack.nonexistentaction') + + endpoint = '/actions/views/entry_point/%s' % 'nonexistentpack.nonexistentaction' httpclient.HTTPClient.get.assert_called_with(endpoint) From 150aafe3467e89ade52af9b6897f332b8b72cae0 Mon Sep 17 00:00:00 2001 From: Tristan Struthers Date: Tue, 1 Oct 2019 18:50:56 -0700 Subject: [PATCH 5/5] Use assertRaisesRegexp --- st2client/tests/unit/test_client_actions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/st2client/tests/unit/test_client_actions.py b/st2client/tests/unit/test_client_actions.py index ac7c3b191a..5a5c798360 100644 --- a/st2client/tests/unit/test_client_actions.py +++ b/st2client/tests/unit/test_client_actions.py @@ -97,7 +97,7 @@ def test_get_action_entry_point_by_id(self): json.dumps({}), 404, '404 Client Error: Not Found' ))) def test_get_non_existent_action_entry_point(self): - with self.assertRaises(Exception): + with self.assertRaisesRegexp(Exception, '404 Client Error: Not Found'): self.client.actions.get_entrypoint('nonexistentpack.nonexistentaction') endpoint = '/actions/views/entry_point/%s' % 'nonexistentpack.nonexistentaction'