From 88ed98edd7b17ad97d6711f765c3436ba9ea7232 Mon Sep 17 00:00:00 2001 From: Carlos Date: Thu, 4 Apr 2024 19:13:15 +0200 Subject: [PATCH 1/5] Add better error reporting --- README.md | 5 +++++ actions/local.py | 14 +++++++++----- actions/runner.py | 17 ++++++++++++----- actions/salt_bootstrap.py | 5 ++--- 4 files changed, 28 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index e3183b5..80900b4 100644 --- a/README.md +++ b/README.md @@ -66,6 +66,11 @@ One can also use the generic "runner" action to execute arbitrary runners and ex st2 run salt.local module=pillar.items args=thing1,thing2 ``` +Wheel command allows manipulation of keys on the master and requires careful crafting of the runner call. +```bash + st2 run salt.runner module=wheel kwargs='{"client": "wheel", "fun": "key.finger", "match": "*"}' +``` + ### Actions Saltstack runner/execution module function calls are represented as StackStorm actions. Considering Saltstack's [`archive` execution module](http://docs.saltstack.com/en/2014.7/ref/modules/all/salt.modules.archive.html#module-salt.modules.archive), every function would be exposed as an StackStorm action. diff --git a/actions/local.py b/actions/local.py index 0dd9564..3e3e67b 100644 --- a/actions/local.py +++ b/actions/local.py @@ -26,6 +26,7 @@ def run(self, module, target, tgt_type, args, **kwargs): st2 run salt.local module=test.ping matches='web*' st2 run salt.local module=test.ping tgt_type=grain target='os:Ubuntu' """ + self.verify_tls = self.config.get("verify_ssl", True) # ChatOps alias and newer St2 versions set default args=[] which # breaks test.ping & test.version @@ -39,8 +40,11 @@ def run(self, module, target, tgt_type, args, **kwargs): request = self.generate_request() request.prepare_body(json.dumps(self.data), None) resp = Session().send(request, verify=self.verify_tls) - try: - retval = resp.json() - except Exception as exc: - retval = (False, f"Failed to decode json! {str(exc)}") - return retval + + if resp.ok: + try: + return resp.json() + except ValueError as exc: + return resp.text + else: + return (False, f"HTTP error {resp.status_code}\n{resp.text}") diff --git a/actions/runner.py b/actions/runner.py index 7bf15c1..8b0b383 100644 --- a/actions/runner.py +++ b/actions/runner.py @@ -5,7 +5,6 @@ class SaltRunner(SaltAction): - __explicit__ = ["jobs", "manage", "pillar", "mine", "network"] def run(self, module, **kwargs): @@ -15,15 +14,23 @@ def run(self, module, **kwargs): st2 run salt.runner_jobs.active st2 run salt.runner_jobs.list_jobs """ + self.verify_tls = self.config.get("verify_ssl", True) + _cmd = module self.generate_package("runner", cmd=_cmd) + if kwargs.get("kwargs", None) is not None: self.data.update(kwargs["kwargs"]) + request = self.generate_request() - self.logger.info("[salt] Request generated") request.prepare_body(json.dumps(self.data), None) - self.logger.info("[salt] Preparing to send") resp = Session().send(request, verify=self.verify_tls) - self.logger.debug("[salt] Response http code: %s", resp.status_code) - return resp.json() + + if resp.ok: + try: + return resp.json() + except ValueError as exc: + return resp.text + else: + return (False, f"HTTP error {resp.status_code}\n{resp.text}") diff --git a/actions/salt_bootstrap.py b/actions/salt_bootstrap.py index 2e7ada9..a725a3e 100644 --- a/actions/salt_bootstrap.py +++ b/actions/salt_bootstrap.py @@ -5,7 +5,6 @@ class SaltInstaller(Action): def run(self, name, provider, instance_id): - client = salt.cloud.CloudClient('/etc/salt/cloud') - ret = client.create(names=[name], provider=provider, - instance_id=instance_id) + client = salt.cloud.CloudClient("/etc/salt/cloud") + ret = client.create(names=[name], provider=provider, instance_id=instance_id) return ret From c8e563a476d1af95cdb8a072937802f0b3d55194 Mon Sep 17 00:00:00 2001 From: Carlos Date: Sat, 6 Apr 2024 11:23:14 +0200 Subject: [PATCH 2/5] black formatting --- actions/client.py | 4 +--- actions/local.py | 10 ++++---- actions/runner.py | 10 ++++---- tests/test_action_local.py | 49 ++++++++++++++------------------------ 4 files changed, 27 insertions(+), 46 deletions(-) diff --git a/actions/client.py b/actions/client.py index 7113b1c..7bbe9e9 100644 --- a/actions/client.py +++ b/actions/client.py @@ -5,9 +5,7 @@ class SaltClientAction(Action): def run(self, matches, module, args=[], kwargs={}): - """ - CLI Examples: - + """CLI Examples: st2 run salt.client matches='web*' module=test.ping st2 run salt.client module=pkg.install \ kwargs='{"pkgs":["git","httpd"]}' diff --git a/actions/local.py b/actions/local.py index 3e3e67b..5b2f84a 100644 --- a/actions/local.py +++ b/actions/local.py @@ -20,11 +20,9 @@ class SaltLocal(SaltAction): ] def run(self, module, target, tgt_type, args, **kwargs): - """ - CLI Examples: - - st2 run salt.local module=test.ping matches='web*' - st2 run salt.local module=test.ping tgt_type=grain target='os:Ubuntu' + """CLI Examples: + st2 run salt.local module=test.ping matches='web*' + st2 run salt.local module=test.ping tgt_type=grain target='os:Ubuntu' """ self.verify_tls = self.config.get("verify_ssl", True) @@ -44,7 +42,7 @@ def run(self, module, target, tgt_type, args, **kwargs): if resp.ok: try: return resp.json() - except ValueError as exc: + except ValueError: return resp.text else: return (False, f"HTTP error {resp.status_code}\n{resp.text}") diff --git a/actions/runner.py b/actions/runner.py index 8b0b383..5a24c6e 100644 --- a/actions/runner.py +++ b/actions/runner.py @@ -8,11 +8,9 @@ class SaltRunner(SaltAction): __explicit__ = ["jobs", "manage", "pillar", "mine", "network"] def run(self, module, **kwargs): - """ - CLI Examples: - - st2 run salt.runner_jobs.active - st2 run salt.runner_jobs.list_jobs + """CLI Examples: + st2 run salt.runner_jobs.active + st2 run salt.runner_jobs.list_jobs """ self.verify_tls = self.config.get("verify_ssl", True) @@ -30,7 +28,7 @@ def run(self, module, **kwargs): if resp.ok: try: return resp.json() - except ValueError as exc: + except ValueError: return resp.text else: return (False, f"HTTP error {resp.status_code}\n{resp.text}") diff --git a/tests/test_action_local.py b/tests/test_action_local.py index 26027c2..a4bec3a 100644 --- a/tests/test_action_local.py +++ b/tests/test_action_local.py @@ -5,37 +5,26 @@ from requests_mock.contrib import fixture import testtools -__all__ = [ - 'SaltLocalActionTestCase' -] +__all__ = ["SaltLocalActionTestCase"] -no_args = { - 'module': 'this.something', - 'target': '*', - 'tgt_type': 'glob', - 'args': [] -} +no_args = {"module": "this.something", "target": "*", "tgt_type": "glob", "args": []} one_arg = { - 'module': 'this.something', - 'target': '*', - 'tgt_type': 'glob', - 'args': ['os'], + "module": "this.something", + "target": "*", + "tgt_type": "glob", + "args": ["os"], } multiple_args = { - 'module': 'this.something', - 'target': '*', - 'tgt_type': 'glob', - 'args': ['this', 'that', 'home'], + "module": "this.something", + "target": "*", + "tgt_type": "glob", + "args": ["this", "that", "home"], } -CONFIG_DATA = { - 'api_url': 'https://example.com', - 'username': 'this', - 'password': 'that' -} -requests_mock.Mocker.TEST_PREFIX = 'test' +CONFIG_DATA = {"api_url": "https://example.com", "username": "this", "password": "that"} +requests_mock.Mocker.TEST_PREFIX = "test" class SaltLocalActionTestCase(testtools.TestCase, BaseActionTestCase): @@ -45,20 +34,18 @@ def setUp(self): super(SaltLocalActionTestCase, self).setUp() self.m = self.useFixture(fixture.Fixture()) self.action = self.get_action_instance(config=CONFIG_DATA) - self.m.register_uri('POST', - "{}/run".format(CONFIG_DATA['api_url']), - json={}) + self.m.register_uri("POST", "{}/run".format(CONFIG_DATA["api_url"]), json={}) def test_generic_action_no_args(self): self.action.run(**no_args) - self.assertNotIn('arg', self.action.data) + self.assertNotIn("arg", self.action.data) def test_generic_action_one_arg(self): self.action.run(**one_arg) - self.assertIn('arg', self.action.data) - self.assertIsInstance(self.action.data['arg'], list) + self.assertIn("arg", self.action.data) + self.assertIsInstance(self.action.data["arg"], list) def test_generic_action_multiple_args(self): self.action.run(**multiple_args) - self.assertIn('arg', self.action.data) - self.assertIsInstance(self.action.data['arg'], list) + self.assertIn("arg", self.action.data) + self.assertIsInstance(self.action.data["arg"], list) From 3f42bb01f674036c58129fe0e9794abaf886dda2 Mon Sep 17 00:00:00 2001 From: Carlos Date: Sat, 6 Apr 2024 11:24:00 +0200 Subject: [PATCH 3/5] pin salt 3006 and its dependencies --- requirements.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 1fa27ec..961a9c2 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,4 @@ -salt +salt>=3006,<3007 +# dependency of salt 3006 +pyzmq==25.0.2 requests From 78fbd851a0e02b28a1935ec54cd5d73a7e4e6f31 Mon Sep 17 00:00:00 2001 From: Carlos Date: Sun, 7 Apr 2024 01:14:49 +0200 Subject: [PATCH 4/5] Update pack unit tests to use new url paths for login and API calls. --- tests/test_action_local.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/tests/test_action_local.py b/tests/test_action_local.py index a4bec3a..ce89a97 100644 --- a/tests/test_action_local.py +++ b/tests/test_action_local.py @@ -34,7 +34,15 @@ def setUp(self): super(SaltLocalActionTestCase, self).setUp() self.m = self.useFixture(fixture.Fixture()) self.action = self.get_action_instance(config=CONFIG_DATA) - self.m.register_uri("POST", "{}/run".format(CONFIG_DATA["api_url"]), json={}) + # Mock authentication + self.m.register_uri( + "POST", + "{}/login".format(CONFIG_DATA["api_url"]), + json={}, + headers={"X-Auth-Token": "mock-auth-ok-token"}, + ) + # Mock run API + self.m.register_uri("POST", "{}/".format(CONFIG_DATA["api_url"]), json={}) def test_generic_action_no_args(self): self.action.run(**no_args) From 1197c99b54ed0d56ee8e289dcfa7f05d479c6c1e Mon Sep 17 00:00:00 2001 From: Carlos Date: Sun, 7 Apr 2024 01:31:59 +0200 Subject: [PATCH 5/5] Update changelog and bump to 3.0.1 --- CHANGES.md | 14 +++++++++++++- pack.yaml | 2 +- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index a6ea6e2..5a1d376 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,12 @@ # Change Log -## Unreleased; 3.0.0 +## Unreleased; 3.0.2 + +### Add +### Change +### Removed + +## 3.0.1 ### Add - Added TLS connection verification. @@ -9,10 +15,16 @@ ### Change - Formatted Python code with black. - Updated client authentication to work with Salt 3004 to 3006 (maybe higher) +- Improved error reporting when HTTP errors are encountered. +- Fail actions when HTTP return codes >=400 ### Removed - Removed salt-pepper as a python dependency. +## 3.0.0 + +Retracted. + ## 2.0.1 * Drop Python 2.7 support diff --git a/pack.yaml b/pack.yaml index 6708b84..1195110 100644 --- a/pack.yaml +++ b/pack.yaml @@ -6,7 +6,7 @@ keywords: - salt - cfg management - configuration management -version: 3.0.0 +version: 3.0.1 author : jcockhren email : jurnell@sophicware.com python_versions: