diff --git a/juju/bundle.py b/juju/bundle.py index f18231a10..7e6083b74 100644 --- a/juju/bundle.py +++ b/juju/bundle.py @@ -1,6 +1,7 @@ import asyncio import logging import os +import zipfile from pathlib import Path import yaml @@ -179,11 +180,16 @@ def get_charm_series(path): Returns None if no series can be determined. """ - md = Path(path) / "metadata.yaml" - if not md.exists(): - return None try: - data = yaml.safe_load(md.open()) + if path.endswith('.charm'): + md = "metadata.yaml in %s" % path + with zipfile.ZipFile(path, 'r') as charm_file: + data = yaml.safe_load(charm_file.read('metadata.yaml')) + else: + md = Path(path) / "metadata.yaml" + if not md.exists(): + return None + data = yaml.safe_load(md.open()) except yaml.YAMLError as exc: if hasattr(exc, "problem_mark"): mark = exc.problem_mark diff --git a/juju/model.py b/juju/model.py index 416ffba77..2fc93dc8f 100644 --- a/juju/model.py +++ b/juju/model.py @@ -637,11 +637,14 @@ async def add_local_charm_dir(self, charm_dir, series): :param series: Charm series """ - fh = tempfile.NamedTemporaryFile() - CharmArchiveGenerator(charm_dir).make_archive(fh.name) - with fh: + if charm_dir.endswith('.charm'): + fn = charm_dir + else: + fn = tempfile.NamedTemporaryFile().name + CharmArchiveGenerator(charm_dir).make_archive(fn) + with open(fn, 'rb') as fh: func = partial( - self.add_local_charm, fh, series, os.stat(fh.name).st_size) + self.add_local_charm, fh, series, os.stat(fn).st_size) charm_url = await self._connector.loop.run_in_executor(None, func) log.debug('Uploaded local charm: %s -> %s', charm_dir, charm_url) @@ -1398,6 +1401,7 @@ async def deploy( if trust and (self.info.agent_version < client.Number.from_json('2.4.0')): raise NotImplementedError("trusted is not supported on model version {}".format(self.info.agent_version)) + entity_url = str(entity_url) # allow for pathlib.Path objects entity_path = Path(entity_url.replace('local:', '')) bundle_path = entity_path / 'bundle.yaml' metadata_path = entity_path / 'metadata.yaml' @@ -1452,7 +1456,11 @@ async def deploy( entity=entity) else: if not application_name: - metadata = yaml.load(metadata_path.read_text(), Loader=yaml.FullLoader) + if str(entity_path).endswith('.charm'): + with zipfile.ZipFile(entity_path, 'r') as charm_file: + metadata = yaml.load(charm_file.read('metadata.yaml'), Loader=yaml.FullLoader) + else: + metadata = yaml.load(metadata_path.read_text(), Loader=yaml.FullLoader) application_name = metadata['name'] # We have a local charm dir that needs to be uploaded charm_dir = os.path.abspath(