aboutsummaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authorjneo8 <james.lin@canonical.com>2023-03-31 19:53:32 +0800
committerJake Hunsaker <jhunsake@redhat.com>2023-04-28 11:25:38 -0400
commit5409ce346e487cad8800a3c072d443b39d1420a8 (patch)
treee59b2e62cd9e1b3101697b59bfb954de54e36b40 /tests
parenta1189b6e28545aac669ef925e6df3fae3caa2f25 (diff)
downloadsos-5409ce346e487cad8800a3c072d443b39d1420a8.tar.gz
[juju] Add juju integration to sos collect.
Add a new cluster profile and transport called "juju" for `sos collect`. Both the profile and transport are intended to be used on juju managed environments which assumes that `juju` is installed on the machine where `sos collect` is called, and that the juju user has superuser privilege to the current controller. When using the "juju" cluster profile, the sos reports will be collected from all the applications within the current model by default. If necessary, one can filter the nodes by models / applications / units / machines with cluster options. For example `-c "juju.models=sos" -c "juju.apps=a,b,c"`. Moreover, transport will also be dynamically changed to "juju" when cluster type is juju. If not using "juju" cluster profile, one can still choose to use the "juju" transport by specifying --transport option. However, not that the --nodes option will be expected to be a comma separated machine IDs , **not** IP addr, since `juju ssh` identifies the ssh target by machine ID. For example, `sos collect --nodes 0,1,2` Closes: #2668 Signed-off-by: Chi Wai Chan <chiwai.chan@canonical.com> Signed-off-by: jneo8 <james.lin@canonical.com> Co-authored-by: Chi Wai Chan <chiwai.chan@canonical.com> Co-authored-by: jneo8 <james.lin@canonical.com>
Diffstat (limited to 'tests')
-rw-r--r--tests/unittests/juju/__init__.py1
-rw-r--r--tests/unittests/juju/data/juju_output_sos.json1
-rw-r--r--tests/unittests/juju/data/juju_output_sos2.json1
-rw-r--r--tests/unittests/juju/juju_cluster_tests.py294
-rw-r--r--tests/unittests/juju/juju_transports_test.py85
5 files changed, 382 insertions, 0 deletions
diff --git a/tests/unittests/juju/__init__.py b/tests/unittests/juju/__init__.py
new file mode 100644
index 00000000..e1758700
--- /dev/null
+++ b/tests/unittests/juju/__init__.py
@@ -0,0 +1 @@
+# vim: set et ts=4 sw=4 :
diff --git a/tests/unittests/juju/data/juju_output_sos.json b/tests/unittests/juju/data/juju_output_sos.json
new file mode 100644
index 00000000..908d049a
--- /dev/null
+++ b/tests/unittests/juju/data/juju_output_sos.json
@@ -0,0 +1 @@
+{"model":{"name":"sos","type":"iaas","controller":"local-lxc","cloud":"localhost","region":"localhost","version":"2.9.42","model-status":{"current":"available","since":"06 Apr 2023 11:31:27+08:00"},"sla":"unsupported"},"machines":{"0":{"juju-status":{"current":"started","since":"06 Apr 2023 11:33:59+08:00","version":"2.9.42"},"hostname":"juju-38ab8b-0","dns-name":"10.224.139.234","ip-addresses":["10.224.139.234"],"instance-id":"juju-38ab8b-0","machine-status":{"current":"running","message":"Running","since":"06 Apr 2023 11:31:58+08:00"},"modification-status":{"current":"applied","since":"06 Apr 2023 11:31:56+08:00"},"series":"focal","network-interfaces":{"eth0":{"ip-addresses":["10.224.139.234"],"mac-address":"00:16:3e:52:05:7f","gateway":"10.224.139.1","space":"alpha","is-up":true}},"constraints":"arch=amd64","hardware":"arch=amd64 cores=0 mem=0M"},"2":{"juju-status":{"current":"started","since":"07 Apr 2023 14:41:09+08:00","version":"2.9.42"},"hostname":"juju-38ab8b-2","dns-name":"10.224.139.188","ip-addresses":["10.224.139.188"],"instance-id":"juju-38ab8b-2","machine-status":{"current":"running","message":"Running","since":"07 Apr 2023 14:39:09+08:00"},"modification-status":{"current":"applied","since":"07 Apr 2023 14:39:06+08:00"},"series":"focal","network-interfaces":{"eth0":{"ip-addresses":["10.224.139.188"],"mac-address":"00:16:3e:44:31:2d","gateway":"10.224.139.1","space":"alpha","is-up":true}},"constraints":"arch=amd64","hardware":"arch=amd64 cores=0 mem=0M"},"3":{"juju-status":{"current":"started","since":"07 Apr 2023 14:41:08+08:00","version":"2.9.42"},"hostname":"juju-38ab8b-3","dns-name":"10.224.139.181","ip-addresses":["10.224.139.181"],"instance-id":"juju-38ab8b-3","machine-status":{"current":"running","message":"Running","since":"07 Apr 2023 14:39:09+08:00"},"modification-status":{"current":"applied","since":"07 Apr 2023 14:39:06+08:00"},"series":"focal","network-interfaces":{"eth0":{"ip-addresses":["10.224.139.181"],"mac-address":"00:16:3e:44:80:a9","gateway":"10.224.139.1","space":"alpha","is-up":true}},"constraints":"arch=amd64","hardware":"arch=amd64 cores=0 mem=0M"},"4":{"juju-status":{"current":"started","since":"07 Apr 2023 17:01:12+08:00","version":"2.9.42"},"hostname":"juju-38ab8b-4","dns-name":"10.224.139.114","ip-addresses":["10.224.139.114"],"instance-id":"juju-38ab8b-4","machine-status":{"current":"running","message":"Running","since":"07 Apr 2023 16:59:27+08:00"},"modification-status":{"current":"applied","since":"07 Apr 2023 16:59:26+08:00"},"series":"jammy","network-interfaces":{"eth0":{"ip-addresses":["10.224.139.114"],"mac-address":"00:16:3e:0f:84:45","gateway":"10.224.139.1","space":"alpha","is-up":true}},"constraints":"arch=amd64","hardware":"arch=amd64 cores=0 mem=0M"}},"applications":{"nginx":{"charm":"nginx","series":"jammy","os":"ubuntu","charm-origin":"charmhub","charm-name":"nginx","charm-rev":6,"charm-channel":"stable","exposed":false,"application-status":{"current":"unknown","since":"07 Apr 2023 16:59:17+08:00"},"units":{"nginx/1":{"workload-status":{"current":"unknown","since":"07 Apr 2023 17:01:28+08:00"},"juju-status":{"current":"idle","since":"07 Apr 2023 17:01:28+08:00","version":"2.9.42"},"leader":true,"machine":"4","public-address":"10.224.139.114"}},"endpoint-bindings":{"":"alpha","publish":"alpha"}},"nrpe":{"charm":"nrpe","series":"jammy","os":"ubuntu","charm-origin":"charmhub","charm-name":"nrpe","charm-rev":97,"charm-channel":"stable","exposed":false,"application-status":{"current":"active","message":"Ready","since":"06 Apr 2023 11:38:44+08:00"},"relations":{"general-info":["ubuntu"]},"subordinate-to":["ubuntu"],"endpoint-bindings":{"":"alpha","general-info":"alpha","local-monitors":"alpha","monitors":"alpha","nrpe":"alpha","nrpe-external-master":"alpha"}},"ubuntu":{"charm":"ubuntu","series":"focal","os":"ubuntu","charm-origin":"charmhub","charm-name":"ubuntu","charm-rev":22,"charm-channel":"stable","exposed":false,"application-status":{"current":"active","since":"06 Apr 2023 11:34:02+08:00"},"relations":{"juju-info":["nrpe"]},"units":{"ubuntu/0":{"workload-status":{"current":"active","since":"06 Apr 2023 11:34:02+08:00"},"juju-status":{"current":"idle","since":"06 Apr 2023 11:34:04+08:00","version":"2.9.42"},"leader":true,"machine":"0","public-address":"10.224.139.234","subordinates":{"nrpe/0":{"workload-status":{"current":"active","message":"Ready","since":"06 Apr 2023 11:38:44+08:00"},"juju-status":{"current":"idle","since":"06 Apr 2023 11:34:30+08:00","version":"2.9.42"},"leader":true,"open-ports":["icmp","5666/tcp"],"public-address":"10.224.139.234"}}},"ubuntu/1":{"workload-status":{"current":"active","since":"07 Apr 2023 14:41:13+08:00"},"juju-status":{"current":"idle","since":"07 Apr 2023 14:41:15+08:00","version":"2.9.42"},"machine":"2","public-address":"10.224.139.188","subordinates":{"nrpe/2":{"workload-status":{"current":"active","message":"Ready","since":"07 Apr 2023 14:45:38+08:00"},"juju-status":{"current":"idle","since":"07 Apr 2023 14:41:41+08:00","version":"2.9.42"},"open-ports":["icmp","5666/tcp"],"public-address":"10.224.139.188"}}},"ubuntu/2":{"workload-status":{"current":"active","since":"07 Apr 2023 14:41:11+08:00"},"juju-status":{"current":"idle","since":"07 Apr 2023 14:41:13+08:00","version":"2.9.42"},"machine":"3","public-address":"10.224.139.181","subordinates":{"nrpe/1":{"workload-status":{"current":"active","message":"Ready","since":"07 Apr 2023 14:46:56+08:00"},"juju-status":{"current":"idle","since":"07 Apr 2023 14:41:41+08:00","version":"2.9.42"},"open-ports":["icmp","5666/tcp"],"public-address":"10.224.139.181"}}}}}},"storage":{"storage":{"files/0":{"kind":"filesystem","life":"alive","status":{"current":"attached","since":"06 Apr 2023 11:34:01+08:00"},"persistent":false,"attachments":{"units":{"ubuntu/0":{"machine":"0","location":"/srv/data","life":"alive"}}}},"files/1":{"kind":"filesystem","life":"alive","status":{"current":"attached","since":"07 Apr 2023 14:41:11+08:00"},"persistent":false,"attachments":{"units":{"ubuntu/1":{"machine":"2","location":"/srv/data","life":"alive"}}}},"files/2":{"kind":"filesystem","life":"alive","status":{"current":"attached","since":"07 Apr 2023 14:41:10+08:00"},"persistent":false,"attachments":{"units":{"ubuntu/2":{"machine":"3","location":"/srv/data","life":"alive"}}}}},"filesystems":{"0/0":{"provider-id":"0/0","storage":"files/0","Attachments":{"machines":{"0":{"mount-point":"/srv/data","read-only":false,"life":"alive"}},"units":{"ubuntu/0":{"machine":"0","location":"/srv/data","life":"alive"}}},"pool":"rootfs","size":12464,"life":"alive","status":{"current":"attached","since":"06 Apr 2023 11:34:01+08:00"}},"2/1":{"provider-id":"2/1","storage":"files/1","Attachments":{"machines":{"2":{"mount-point":"/srv/data","read-only":false,"life":"alive"}},"units":{"ubuntu/1":{"machine":"2","location":"/srv/data","life":"alive"}}},"pool":"rootfs","size":10062,"life":"alive","status":{"current":"attached","since":"07 Apr 2023 14:41:11+08:00"}},"3/2":{"provider-id":"3/2","storage":"files/2","Attachments":{"machines":{"3":{"mount-point":"/srv/data","read-only":false,"life":"alive"}},"units":{"ubuntu/2":{"machine":"3","location":"/srv/data","life":"alive"}}},"pool":"rootfs","size":10113,"life":"alive","status":{"current":"attached","since":"07 Apr 2023 14:41:10+08:00"}}}},"controller":{"timestamp":"17:04:14+08:00"}}
diff --git a/tests/unittests/juju/data/juju_output_sos2.json b/tests/unittests/juju/data/juju_output_sos2.json
new file mode 100644
index 00000000..4a41bba1
--- /dev/null
+++ b/tests/unittests/juju/data/juju_output_sos2.json
@@ -0,0 +1 @@
+{"model":{"name":"sos2","type":"iaas","controller":"local-lxc","cloud":"localhost","region":"localhost","version":"2.9.42","model-status":{"current":"available","since":"07 Apr 2023 12:54:21+08:00"},"sla":"unsupported"},"machines":{"0":{"juju-status":{"current":"started","since":"07 Apr 2023 12:57:16+08:00","version":"2.9.42"},"hostname":"juju-1cba19-0","dns-name":"10.224.139.132","ip-addresses":["10.224.139.132"],"instance-id":"juju-1cba19-0","machine-status":{"current":"running","message":"Running","since":"07 Apr 2023 12:55:16+08:00"},"modification-status":{"current":"applied","since":"07 Apr 2023 12:55:13+08:00"},"series":"focal","network-interfaces":{"eth0":{"ip-addresses":["10.224.139.132"],"mac-address":"00:16:3e:55:4b:a9","gateway":"10.224.139.1","space":"alpha","is-up":true}},"constraints":"arch=amd64","hardware":"arch=amd64 cores=0 mem=0M"},"1":{"juju-status":{"current":"started","since":"07 Apr 2023 12:57:17+08:00","version":"2.9.42"},"hostname":"juju-1cba19-1","dns-name":"10.224.139.94","ip-addresses":["10.224.139.94"],"instance-id":"juju-1cba19-1","machine-status":{"current":"running","message":"Running","since":"07 Apr 2023 12:55:16+08:00"},"modification-status":{"current":"applied","since":"07 Apr 2023 12:55:15+08:00"},"series":"focal","network-interfaces":{"eth0":{"ip-addresses":["10.224.139.94"],"mac-address":"00:16:3e:5d:d8:08","gateway":"10.224.139.1","space":"alpha","is-up":true}},"constraints":"arch=amd64","hardware":"arch=amd64 cores=0 mem=0M"}},"applications":{"ubuntu":{"charm":"ubuntu","series":"focal","os":"ubuntu","charm-origin":"charmhub","charm-name":"ubuntu","charm-rev":22,"charm-channel":"stable","exposed":false,"application-status":{"current":"active","since":"07 Apr 2023 12:57:19+08:00"},"units":{"ubuntu/0":{"workload-status":{"current":"active","since":"07 Apr 2023 12:57:19+08:00"},"juju-status":{"current":"idle","since":"07 Apr 2023 12:57:21+08:00","version":"2.9.42"},"leader":true,"machine":"0","public-address":"10.224.139.132"},"ubuntu/1":{"workload-status":{"current":"active","since":"07 Apr 2023 12:57:20+08:00"},"juju-status":{"current":"idle","since":"07 Apr 2023 12:57:22+08:00","version":"2.9.42"},"machine":"1","public-address":"10.224.139.94"}},"version":"20.04"}},"storage":{"storage":{"files/0":{"kind":"filesystem","life":"alive","status":{"current":"attached","since":"07 Apr 2023 12:57:18+08:00"},"persistent":false,"attachments":{"units":{"ubuntu/0":{"machine":"0","location":"/srv/data","life":"alive"}}}},"files/1":{"kind":"filesystem","life":"alive","status":{"current":"attached","since":"07 Apr 2023 12:57:19+08:00"},"persistent":false,"attachments":{"units":{"ubuntu/1":{"machine":"1","location":"/srv/data","life":"alive"}}}}},"filesystems":{"0/0":{"provider-id":"0/0","storage":"files/0","Attachments":{"machines":{"0":{"mount-point":"/srv/data","read-only":false,"life":"alive"}},"units":{"ubuntu/0":{"machine":"0","location":"/srv/data","life":"alive"}}},"pool":"rootfs","size":11131,"life":"alive","status":{"current":"attached","since":"07 Apr 2023 12:57:18+08:00"}},"1/1":{"provider-id":"1/1","storage":"files/1","Attachments":{"machines":{"1":{"mount-point":"/srv/data","read-only":false,"life":"alive"}},"units":{"ubuntu/1":{"machine":"1","location":"/srv/data","life":"alive"}}},"pool":"rootfs","size":11094,"life":"alive","status":{"current":"attached","since":"07 Apr 2023 12:57:19+08:00"}}}},"controller":{"timestamp":"14:16:44+08:00"}}
diff --git a/tests/unittests/juju/juju_cluster_tests.py b/tests/unittests/juju/juju_cluster_tests.py
new file mode 100644
index 00000000..136dc49f
--- /dev/null
+++ b/tests/unittests/juju/juju_cluster_tests.py
@@ -0,0 +1,294 @@
+# Copyright (c) 2023 Canonical Ltd., Chi Wai Chan <chiwai.chan@canonical.com>
+
+# This file is part of the sos project: https://github.com/sosreport/sos
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions of
+# version 2 of the GNU General Public License.
+#
+# See the LICENSE file in the source distribution for further information.
+import pathlib
+import unittest
+from unittest.mock import call, patch
+
+from sos.collector.clusters.juju import _parse_option_string, juju
+from sos.options import ClusterOption
+
+
+class MockOptions:
+
+ def __init__(self):
+ self.cluster_options = []
+
+
+def get_juju_output(model):
+ dir = pathlib.Path(__file__).parent.resolve()
+ with open(dir / "data" / f"juju_output_{model}.json") as f:
+ return f.read()
+
+
+def get_juju_status(cmd):
+ if "-m" in cmd:
+ model = cmd.split()[3]
+ else:
+ model = "sos"
+
+ return {
+ "status": 0,
+ "output": get_juju_output(model),
+ }
+
+
+def test_parse_option_string():
+ result = _parse_option_string(" a,b,c")
+ assert result == ["a", "b", "c"]
+
+ result = _parse_option_string()
+ assert result == []
+
+
+class JujuTest(unittest.TestCase):
+ """Test for juju cluster."""
+
+ @patch(
+ "sos.collector.clusters.juju.juju.exec_primary_cmd",
+ side_effect=get_juju_status,
+ )
+ def test_get_nodes_no_filter(self, mock_exec_primary_cmd):
+ """No filter."""
+ mock_opts = MockOptions()
+ cluster = juju(
+ commons={
+ "tmpdir": "/tmp",
+ "cmdlineopts": mock_opts,
+ }
+ )
+ nodes = cluster.get_nodes()
+ assert nodes == []
+
+ @patch(
+ "sos.collector.clusters.juju.juju.exec_primary_cmd",
+ side_effect=get_juju_status,
+ )
+ def test_get_nodes_app_filter(self, mock_exec_primary_cmd):
+ """Application filter."""
+ mock_opts = MockOptions()
+ mock_opts.cluster_options.append(
+ ClusterOption(
+ name="apps",
+ opt_type=str,
+ value="ubuntu",
+ cluster=juju.__name__,
+ )
+ )
+ cluster = juju(
+ commons={
+ "tmpdir": "/tmp",
+ "cmdlineopts": mock_opts,
+ }
+ )
+ nodes = cluster.get_nodes()
+ nodes.sort()
+ assert nodes == [":0", ":2", ":3"]
+ mock_exec_primary_cmd.assert_called_once_with(
+ "juju status --format json"
+ )
+
+ @patch(
+ "sos.collector.clusters.juju.juju.exec_primary_cmd",
+ side_effect=get_juju_status,
+ )
+ def test_get_nodes_app_regex_filter(self, mock_exec_primary_cmd):
+ """Application filter."""
+ mock_opts = MockOptions()
+ mock_opts.cluster_options.append(
+ ClusterOption(
+ name="apps",
+ opt_type=str,
+ value="ubuntu|nginx",
+ cluster=juju.__name__,
+ )
+ )
+ cluster = juju(
+ commons={
+ "tmpdir": "/tmp",
+ "cmdlineopts": mock_opts,
+ }
+ )
+ nodes = cluster.get_nodes()
+ nodes.sort()
+ assert nodes == [":0", ":2", ":3", ":4"]
+ mock_exec_primary_cmd.assert_called_once_with(
+ "juju status --format json"
+ )
+
+ @patch(
+ "sos.collector.clusters.juju.juju.exec_primary_cmd",
+ side_effect=get_juju_status,
+ )
+ def test_get_nodes_model_filter_multiple_models(
+ self, mock_exec_primary_cmd
+ ):
+ """Multiple model filter."""
+ mock_opts = MockOptions()
+ mock_opts.cluster_options.append(
+ ClusterOption(
+ name="models",
+ opt_type=str,
+ value="sos,sos2",
+ cluster=juju.__name__,
+ ),
+ )
+ mock_opts.cluster_options.append(
+ ClusterOption(
+ name="apps",
+ opt_type=str,
+ value="ubuntu",
+ cluster=juju.__name__,
+ ),
+ )
+ cluster = juju(
+ commons={
+ "tmpdir": "/tmp",
+ "cmdlineopts": mock_opts,
+ }
+ )
+ nodes = cluster.get_nodes()
+ nodes.sort()
+ assert nodes == [
+ "sos2:0",
+ "sos2:1",
+ "sos:0",
+ "sos:2",
+ "sos:3",
+ ]
+ mock_exec_primary_cmd.assert_has_calls(
+ [
+ call("juju status -m sos --format json"),
+ call("juju status -m sos2 --format json"),
+ ]
+ )
+
+ @patch(
+ "sos.collector.clusters.juju.juju.exec_primary_cmd",
+ side_effect=get_juju_status,
+ )
+ def test_get_nodes_model_filter(self, mock_exec_primary_cmd):
+ """Model filter."""
+ mock_opts = MockOptions()
+ mock_opts.cluster_options.append(
+ ClusterOption(
+ name="models",
+ opt_type=str,
+ value="sos",
+ cluster=juju.__name__,
+ )
+ )
+ mock_opts.cluster_options.append(
+ ClusterOption(
+ name="apps",
+ opt_type=str,
+ value="ubuntu",
+ cluster=juju.__name__,
+ ),
+ )
+ cluster = juju(
+ commons={
+ "tmpdir": "/tmp",
+ "cmdlineopts": mock_opts,
+ }
+ )
+ nodes = cluster.get_nodes()
+ nodes.sort()
+ assert nodes == [
+ "sos:0",
+ "sos:2",
+ "sos:3",
+ ]
+ mock_exec_primary_cmd.assert_has_calls(
+ [
+ call("juju status -m sos --format json"),
+ ]
+ )
+
+ @patch(
+ "sos.collector.clusters.juju.juju.exec_primary_cmd",
+ side_effect=get_juju_status,
+ )
+ def test_get_nodes_unit_filter(self, mock_exec_primary_cmd):
+ """Node filter."""
+ mock_opts = MockOptions()
+ mock_opts.cluster_options.append(
+ ClusterOption(
+ name="units",
+ opt_type=str,
+ value="ubuntu/0,ubuntu/1",
+ cluster=juju.__name__,
+ )
+ )
+ cluster = juju(
+ commons={
+ "tmpdir": "/tmp",
+ "cmdlineopts": mock_opts,
+ }
+ )
+ nodes = cluster.get_nodes()
+ nodes.sort()
+ assert nodes == [":0", ":2"]
+
+ @patch(
+ "sos.collector.clusters.juju.juju.exec_primary_cmd",
+ side_effect=get_juju_status,
+ )
+ def test_get_nodes_machine_filter(self, mock_exec_primary_cmd):
+ """Machine filter."""
+ mock_opts = MockOptions()
+ mock_opts.cluster_options.append(
+ ClusterOption(
+ name="machines",
+ opt_type=str,
+ value="0,2",
+ cluster=juju.__name__,
+ )
+ )
+ cluster = juju(
+ commons={
+ "tmpdir": "/tmp",
+ "cmdlineopts": mock_opts,
+ }
+ )
+ nodes = cluster.get_nodes()
+ nodes.sort()
+ print(nodes)
+ assert nodes == [":0", ":2"]
+
+ @patch(
+ "sos.collector.clusters.juju.juju.exec_primary_cmd",
+ side_effect=get_juju_status,
+ )
+ def test_subordinates(self, mock_exec_primary_cmd):
+ """Subordinate filter."""
+ mock_opts = MockOptions()
+ mock_opts.cluster_options.append(
+ ClusterOption(
+ name="apps",
+ opt_type=str,
+ value="nrpe",
+ cluster=juju.__name__,
+ )
+ )
+ cluster = juju(
+ commons={
+ "tmpdir": "/tmp",
+ "cmdlineopts": mock_opts,
+ }
+ )
+ nodes = cluster.get_nodes()
+ nodes.sort()
+ assert nodes == [":0", ":2", ":3"]
+ mock_exec_primary_cmd.assert_called_once_with(
+ "juju status --format json"
+ )
+
+
+# vim: set et ts=4 sw=4 :
diff --git a/tests/unittests/juju/juju_transports_test.py b/tests/unittests/juju/juju_transports_test.py
new file mode 100644
index 00000000..911a957e
--- /dev/null
+++ b/tests/unittests/juju/juju_transports_test.py
@@ -0,0 +1,85 @@
+# Copyright (c) 2023 Canonical Ltd., Chi Wai Chan <chiwai.chan@canonical.com>
+
+# This file is part of the sos project: https://github.com/sosreport/sos
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions of
+# version 2 of the GNU General Public License.
+#
+# See the LICENSE file in the source distribution for further information.
+
+import subprocess
+import unittest
+from unittest.mock import patch
+
+from sos.collector.exceptions import JujuNotInstalledException
+from sos.collector.transports.juju import JujuSSH
+
+
+class MockCmdLineOpts(object):
+ ssh_user = "user_abc"
+ sudo_pw = "pw_abc"
+ root_password = "root_pw_abc"
+
+
+class JujuSSHTest(unittest.TestCase):
+ def setUp(self):
+ self.juju_ssh = JujuSSH(
+ commons={
+ "cmdlineopts": MockCmdLineOpts,
+ "tmpdir": "/tmp/sos-juju/",
+ "need_sudo": False,
+ },
+ address="model_abc:unit_abc",
+ )
+
+ @patch("sos.collector.transports.juju.subprocess.check_output")
+ def test_check_juju_installed_err(self, mock_subprocess_check_output):
+ """Raise error if juju is not installed."""
+ mock_subprocess_check_output.side_effect = (
+ subprocess.CalledProcessError(returncode="127", cmd="cmd_abc")
+ )
+ with self.assertRaises(JujuNotInstalledException):
+ self.juju_ssh._check_juju_installed()
+
+ @patch("sos.collector.transports.juju.subprocess.check_output")
+ def test_check_juju_installed_true(self, mock_subprocess_check_output):
+ """Return True if juju is installed."""
+ result = self.juju_ssh._check_juju_installed()
+ assert result
+
+ @patch("sos.collector.transports.juju.subprocess.check_output")
+ def test_chmod(self, mock_subprocess_check_output):
+ self.juju_ssh._chmod(fname="file_abc")
+ mock_subprocess_check_output.assert_called_with(
+ f"{self.juju_ssh.remote_exec} sudo chmod o+r file_abc",
+ stderr=subprocess.STDOUT,
+ shell=True,
+ )
+
+ @patch(
+ "sos.collector.transports.juju.JujuSSH._check_juju_installed",
+ return_value=True,
+ )
+ def test_connect(self, mock_result):
+ self.juju_ssh.connect(password=None)
+ assert self.juju_ssh.connected
+
+ def test_remote_exec(self):
+ assert (
+ self.juju_ssh.remote_exec == "juju ssh -m model_abc unit_abc"
+ )
+
+ @patch(
+ "sos.collector.transports.juju.sos_get_command_output",
+ return_value={"status": 0},
+ )
+ @patch("sos.collector.transports.juju.JujuSSH._chmod", return_value=True)
+ def test_retrieve_file(self, mock_chmod, mock_sos_get_cmd_output):
+ self.juju_ssh._retrieve_file(fname="file_abc", dest="/tmp/sos-juju/")
+ mock_sos_get_cmd_output.assert_called_with(
+ "juju scp -m model_abc -- -r unit_abc:file_abc /tmp/sos-juju/"
+ )
+
+
+# vim: set et ts=4 sw=4 :