From 841becdf44d881417dd7bf30b5d7d7bd366aa46a Mon Sep 17 00:00:00 2001 From: Arif Ali Date: Fri, 24 Nov 2023 21:56:24 +0000 Subject: [PATCH] [collect] update for strict confinement for juju With juju versions 3 and above, when collecting the tarballs from machines it will grab them into a strictly confined area. This means that we need to be able to access this area via sudo. In order for this now to be fully supported, we need sudo on the host that is running juju, otherwise sos collect on a juju environment will not work. Related: #3399 Signed-off-by: Arif Ali --- sos/collector/transports/juju.py | 23 +++++++++++++++++--- tests/unittests/juju/juju_transports_test.py | 9 +++++++- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/sos/collector/transports/juju.py b/sos/collector/transports/juju.py index bea95fb6f9..13dab704fc 100644 --- a/sos/collector/transports/juju.py +++ b/sos/collector/transports/juju.py @@ -13,7 +13,7 @@ from sos.collector.exceptions import JujuNotInstalledException from sos.collector.transports import RemoteTransport -from sos.utilities import sos_get_command_output +from sos.utilities import sos_get_command_output, parse_version class JujuSSH(RemoteTransport): @@ -72,12 +72,29 @@ def remote_exec(self): option = f"{model_option} {target_option}" return f"juju ssh {option}" + def _get_juju_version(self): + """Grab the version of juju""" + res = sos_get_command_output("juju version") + return res['output'].split("-")[0] + def _retrieve_file(self, fname, dest): self._chmod(fname) # juju scp needs the archive to be world-readable model, unit = self.address.split(":") model_option = f"-m {model}" if model else "" - cmd = f"juju scp {model_option} -- -r {unit}:{fname} {dest}" - res = sos_get_command_output(cmd) + if parse_version(self._get_juju_version()) > parse_version("3"): + # juju version above 3 is strictly confined, and therefore + # the way we grab the data is slightly different + juju_tmpdir = f"/tmp/snap-private-tmp/snap.juju/{self.tmpdir}" + sos_get_command_output(f"sudo mkdir {juju_tmpdir}") + sos_get_command_output(f"sudo chmod o+rwx {juju_tmpdir}") + cmd = f"juju scp {model_option} -- -r {unit}:{fname} {self.tmpdir}" + res = sos_get_command_output(cmd) + cmd2 = f"sudo cp {juju_tmpdir}/{fname.split('/')[-1]} {dest}" + sos_get_command_output(cmd2) + sos_get_command_output(f"sudo chmod 644 {dest}") + else: + cmd = f"juju scp {model_option} -- -r {unit}:{fname} {dest}" + res = sos_get_command_output(cmd) return res["status"] == 0 diff --git a/tests/unittests/juju/juju_transports_test.py b/tests/unittests/juju/juju_transports_test.py index 911a957e43..b600b16259 100644 --- a/tests/unittests/juju/juju_transports_test.py +++ b/tests/unittests/juju/juju_transports_test.py @@ -33,6 +33,9 @@ def setUp(self): address="model_abc:unit_abc", ) + def get_juju_version(): + return "2.9.45" + @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.""" @@ -70,12 +73,16 @@ def test_remote_exec(self): self.juju_ssh.remote_exec == "juju ssh -m model_abc unit_abc" ) + @patch( + "sos.collector.transports.juju.JujuSSH._get_juju_version", + side_effect=get_juju_version, + ) @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): + def test_retrieve_file(self, mock_chmod, mock_sos_get_cmd_output, mock_get_juju_version): 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/"