|
15 | 15 | import asyncio |
16 | 16 | import json |
17 | 17 | import logging |
| 18 | +import os |
18 | 19 |
|
19 | 20 | from . import model, tag |
20 | 21 | from .status import derive_status |
21 | 22 | from .annotationhelper import _get_annotations, _set_annotations |
22 | 23 | from .client import client |
23 | 24 | from .errors import JujuError |
| 25 | +from .bundle import get_charm_series |
24 | 26 | from .placement import parse as parse_placement |
| 27 | +from .charm import get_local_charm_metadata |
25 | 28 |
|
26 | 29 | log = logging.getLogger(__name__) |
27 | 30 |
|
@@ -578,9 +581,10 @@ async def refresh( |
578 | 581 | :param str switch: Crossgrade charm url |
579 | 582 |
|
580 | 583 | """ |
581 | | - # TODO: Support local upgrades |
582 | 584 | if path is not None: |
583 | | - raise NotImplementedError("path option is not implemented") |
| 585 | + await self.local_refresh(channel, force, force_series, force_units, |
| 586 | + path, resources) |
| 587 | + return |
584 | 588 | if resources is not None: |
585 | 589 | raise NotImplementedError("resources option is not implemented") |
586 | 590 |
|
@@ -684,6 +688,61 @@ async def refresh( |
684 | 688 |
|
685 | 689 | upgrade_charm = refresh |
686 | 690 |
|
| 691 | + async def local_refresh( |
| 692 | + self, channel=None, force=False, force_series=False, force_units=False, |
| 693 | + path=None, resources=None): |
| 694 | + """Refresh the charm for this application with a local charm. |
| 695 | +
|
| 696 | + :param str channel: Channel to use when getting the charm from the |
| 697 | + charm store, e.g. 'development' |
| 698 | + :param bool force_series: Refresh even if series of deployed |
| 699 | + application is not supported by the new charm |
| 700 | + :param bool force_units: Refresh all units immediately, even if in |
| 701 | + error state |
| 702 | + :param str path: Refresh to a charm located at path |
| 703 | + :param dict resources: Dictionary of resource name/filepath pairs |
| 704 | + :param int revision: Explicit refresh revision |
| 705 | + :param str switch: Crossgrade charm url |
| 706 | +
|
| 707 | + """ |
| 708 | + app_facade = self._facade() |
| 709 | + |
| 710 | + charm_dir = os.path.abspath( |
| 711 | + os.path.expanduser(path)) |
| 712 | + model_config = await self.get_config() |
| 713 | + |
| 714 | + series = get_charm_series(charm_dir) |
| 715 | + if not series: |
| 716 | + model_config = await self.get_config() |
| 717 | + default_series = model_config.get("default-series") |
| 718 | + if default_series: |
| 719 | + series = default_series.value |
| 720 | + charm_url = await self.model.add_local_charm_dir(charm_dir, series) |
| 721 | + metadata = get_local_charm_metadata(path) |
| 722 | + if resources is not None: |
| 723 | + resources = await self.model.add_local_resources(self.entity_id, |
| 724 | + charm_url, |
| 725 | + metadata, |
| 726 | + resources=resources) |
| 727 | + |
| 728 | + # Update application |
| 729 | + await app_facade.SetCharm( |
| 730 | + application=self.entity_id, |
| 731 | + channel=channel, |
| 732 | + charm_url=charm_url, |
| 733 | + config_settings=None, |
| 734 | + config_settings_yaml=None, |
| 735 | + force=force, |
| 736 | + force_series=force_series, |
| 737 | + force_units=force_units, |
| 738 | + resource_ids=resources, |
| 739 | + storage_constraints=None, |
| 740 | + ) |
| 741 | + |
| 742 | + await self.model.block_until( |
| 743 | + lambda: self.data['charm-url'] == charm_url |
| 744 | + ) |
| 745 | + |
687 | 746 | async def get_metrics(self): |
688 | 747 | """Get metrics for this application's units. |
689 | 748 |
|
|
0 commit comments