diff --git a/Makefile b/Makefile index df5f479..ed84e3a 100644 --- a/Makefile +++ b/Makefile @@ -6,6 +6,7 @@ help: @echo "" @echo " make help - show this text" @echo " make lint - run flake8" + @echo " make unittests - run the tests defined in the unittest subdirectory" @echo " make test - run the functests and lint" @echo " make functional - run the tests defined in the functional subdirectory" @echo " make release - build the charm" @@ -16,6 +17,9 @@ lint: @echo "Running flake8" @-tox -e lint +unittests: + @echo "No unit tests available at the moment" + test: lint functional functional: build diff --git a/lib/lib_charm_juju_local.py b/lib/lib_charm_juju_local.py index 39fc880..ba18467 100644 --- a/lib/lib_charm_juju_local.py +++ b/lib/lib_charm_juju_local.py @@ -4,6 +4,7 @@ from charmhelpers.core import hookenv, host, templating from charmhelpers.fetch.ubuntu import apt_cache +from charms.layer import snap LXD_BRIDGE_TMPL = "lxd-bridge.ini.j2" @@ -46,6 +47,9 @@ def lxd_migrate(self): subprocess.call("sudo lxd.migrate -yes", shell=True) def lxd_init(self): + # Refresh lxd snap to "latest/stable" channel for Juju 3.x support. + snap.refresh("lxd", channel="latest/stable") + install_sh = textwrap.dedent( """ lxd init --auto --storage-backend dir @@ -64,6 +68,14 @@ def setup_juju(self): shell=True, ) series = host.lsb_release()["DISTRIB_CODENAME"] + + # Create juju's local user directory if missing + # This is a workaround for LP #1988355 + subprocess.call( + "sudo -u ubuntu mkdir -p /home/ubuntu/.local/share/juju", + shell=True, + ) + subprocess.call( textwrap.dedent( f""" diff --git a/tests/bundles/focal-juju3.yaml b/tests/bundles/focal-juju3.yaml new file mode 120000 index 0000000..f81f6ff --- /dev/null +++ b/tests/bundles/focal-juju3.yaml @@ -0,0 +1 @@ +base.yaml \ No newline at end of file diff --git a/tests/bundles/jammy-juju3.yaml b/tests/bundles/jammy-juju3.yaml new file mode 120000 index 0000000..f81f6ff --- /dev/null +++ b/tests/bundles/jammy-juju3.yaml @@ -0,0 +1 @@ +base.yaml \ No newline at end of file diff --git a/tests/bundles/overlays/focal-juju3.yaml.j2 b/tests/bundles/overlays/focal-juju3.yaml.j2 new file mode 100644 index 0000000..e0bb1d4 --- /dev/null +++ b/tests/bundles/overlays/focal-juju3.yaml.j2 @@ -0,0 +1,5 @@ +series: focal +applications: + {{ charm_name }}: + options: + juju-channel: "3.1/stable" diff --git a/tests/bundles/overlays/jammy-juju3.yaml.j2 b/tests/bundles/overlays/jammy-juju3.yaml.j2 new file mode 100644 index 0000000..6dac327 --- /dev/null +++ b/tests/bundles/overlays/jammy-juju3.yaml.j2 @@ -0,0 +1,5 @@ +series: jammy +applications: + {{ charm_name }}: + options: + juju-channel: "3.1/stable" diff --git a/tests/tests.yaml b/tests/tests.yaml index 4476d69..c0f919c 100644 --- a/tests/tests.yaml +++ b/tests/tests.yaml @@ -2,12 +2,16 @@ charm_name: juju-local tests: - tests.tests_juju_local.CharmJujuLocalTest gate_bundles: + - jammy-juju3 + - focal-juju3 - jammy - focal - bionic dev_bundles: + - jammy-juju3 - jammy smoke_bundles: + - focal-juju3 - focal target_deploy_status: juju-local: diff --git a/tests/tests_juju_local.py b/tests/tests_juju_local.py index b3f8a09..d34cf34 100644 --- a/tests/tests_juju_local.py +++ b/tests/tests_juju_local.py @@ -13,8 +13,13 @@ def setUpClass(cls): cls.model_name = model.get_juju_model() cls.test_config = lifecycle_utils.get_charm_config() model.block_until_all_units_idle() + # Add a test model in the remote Juju cloud + # This is needed becuase in Juju 3.x there's no default model created + # after bootstrapping the controller + cls.remote_juju(["add-model", "test"], None) - def remote_juju(self, args, format="json"): + @classmethod + def remote_juju(cls, args, format="json"): if format: fmt = "--format={}".format(format) else: @@ -22,11 +27,18 @@ def remote_juju(self, args, format="json"): cmd = """sudo -u ubuntu bash -c '/snap/bin/juju {} {}'""".format( " ".join(args), fmt ) - res = model.run_on_unit(self.jlocal_unit, cmd) - return res.get("Stdout"), res.get("Stderr") + res = model.run_on_unit(cls.jlocal_unit, cmd) + return_code = int(res["Code"]) + if return_code != 0: + raise RuntimeError( + "Failed to execute command in juju-local unit.\nStderr: {}".format( + res.get("Stderr") + ) + ) + return res.get("Stdout") def juju_status(self): - stdout, _ = self.remote_juju(["status"]) + stdout = self.remote_juju(["status"]) return json.loads(stdout) def test_juju_status(self): @@ -34,7 +46,7 @@ def test_juju_status(self): self.assertEqual(jstatus["model"]["controller"], "lxd") def test_juju_users(self): - stdout, _ = self.remote_juju(["users"]) + stdout = self.remote_juju(["users"]) userobjects = json.loads(stdout) usernames = set(u["user-name"] for u in userobjects) self.assertTrue("admin" in usernames) diff --git a/wheelhouse.txt b/wheelhouse.txt index 02a822a..65c7e41 100644 --- a/wheelhouse.txt +++ b/wheelhouse.txt @@ -1 +1,2 @@ Markupsafe<2.0.0 # for xenial support +tenacity<5.0.4 # workaround for LP#2031582