From 673f14d8c6c6c1c0751ca8c38e0f9254f4afdb44 Mon Sep 17 00:00:00 2001 From: Jack Lloyd-Walters Date: Wed, 10 Jul 2024 14:34:05 +0100 Subject: [PATCH 01/24] add refreshing to install --- anvil-python/anvil/commands/haproxy.py | 2 ++ anvil-python/anvil/commands/maas_agent.py | 3 ++- anvil-python/anvil/commands/maas_region.py | 3 ++- anvil-python/anvil/commands/postgresql.py | 19 +++++++++++++++++++ 4 files changed, 25 insertions(+), 2 deletions(-) diff --git a/anvil-python/anvil/commands/haproxy.py b/anvil-python/anvil/commands/haproxy.py index 3268ff6..9d5daea 100644 --- a/anvil-python/anvil/commands/haproxy.py +++ b/anvil-python/anvil/commands/haproxy.py @@ -185,6 +185,7 @@ def haproxy_install_steps( fqdn: str, accept_defaults: bool, preseed: dict[Any, Any], + refresh: bool = False, ) -> List[BaseStep]: return [ TerraformInitStep(manifest.get_tfhelper("haproxy-plan")), @@ -195,6 +196,7 @@ def haproxy_install_steps( model, accept_defaults=accept_defaults, deployment_preseed=preseed, + refresh=refresh, ), AddHAProxyUnitsStep(client, fqdn, jhelper, model), ] diff --git a/anvil-python/anvil/commands/maas_agent.py b/anvil-python/anvil/commands/maas_agent.py index 0b2934d..9c97a51 100644 --- a/anvil-python/anvil/commands/maas_agent.py +++ b/anvil-python/anvil/commands/maas_agent.py @@ -117,9 +117,10 @@ def maas_agent_install_steps( jhelper: JujuHelper, model: str, fqdn: str, + refresh: bool = False, ) -> List[BaseStep]: return [ TerraformInitStep(manifest.get_tfhelper("maas-agent-plan")), - DeployMAASAgentApplicationStep(client, manifest, jhelper, model), + DeployMAASAgentApplicationStep(client, manifest, jhelper, model, refresh=refresh), AddMAASAgentUnitsStep(client, fqdn, jhelper, model), ] diff --git a/anvil-python/anvil/commands/maas_region.py b/anvil-python/anvil/commands/maas_region.py index cc2e9ad..492d6ac 100644 --- a/anvil-python/anvil/commands/maas_region.py +++ b/anvil-python/anvil/commands/maas_region.py @@ -125,9 +125,10 @@ def maas_region_install_steps( jhelper: JujuHelper, model: str, fqdn: str, + refresh: bool = False, ) -> List[BaseStep]: return [ TerraformInitStep(manifest.get_tfhelper("maas-region-plan")), - DeployMAASRegionApplicationStep(client, manifest, jhelper, model), + DeployMAASRegionApplicationStep(client, manifest, jhelper, model, refresh), AddMAASRegionUnitsStep(client, fqdn, jhelper, model), ] diff --git a/anvil-python/anvil/commands/postgresql.py b/anvil-python/anvil/commands/postgresql.py index d447835..80db14f 100644 --- a/anvil-python/anvil/commands/postgresql.py +++ b/anvil-python/anvil/commands/postgresql.py @@ -248,3 +248,22 @@ def __init__( def get_unit_timeout(self) -> int: return POSTGRESQL_UNIT_TIMEOUT + + +def postgresql_install_steps( + client: Client, + manifest: Manifest, + jhelper: JujuHelper, + deployment: LocalDeployment, + fqdn: str, + refresh: bool = False, +) -> List[BaseStep]: + return [ + TerraformInitStep(manifest.get_tfhelper("postgresql-plan")), + DeployPostgreSQLApplicationStep( + client, manifest, jhelper, deployment.infrastructure_model, refresh + ), + AddPostgreSQLUnitsStep( + client, fqdn, jhelper, deployment.infrastructure_model + ), + ] From 0f24911a99087c572e1ab36def807dc2fcf3b76c Mon Sep 17 00:00:00 2001 From: Jack Lloyd-Walters Date: Wed, 10 Jul 2024 14:34:15 +0100 Subject: [PATCH 02/24] add refresh command --- anvil-python/anvil/commands/refresh.py | 105 +++++++++++++++++++++++++ anvil-python/anvil/main.py | 2 + 2 files changed, 107 insertions(+) create mode 100644 anvil-python/anvil/commands/refresh.py diff --git a/anvil-python/anvil/commands/refresh.py b/anvil-python/anvil/commands/refresh.py new file mode 100644 index 0000000..93da94b --- /dev/null +++ b/anvil-python/anvil/commands/refresh.py @@ -0,0 +1,105 @@ +import logging +from pathlib import Path + +import click +from rich.console import Console +from sunbeam import utils +from sunbeam.commands.clusterd import ( + ClusterAddJujuUserStep, + ClusterAddNodeStep, + ClusterInitStep, + ClusterJoinNodeStep, + ClusterListNodeStep, + ClusterRemoveNodeStep, + ClusterUpdateJujuControllerStep, + ClusterUpdateNodeStep, +) +from sunbeam.jobs.checks import ( + SshKeysConnectedCheck, +) +from sunbeam.jobs.common import BaseStep, run_plan, run_preflight_checks +from sunbeam.jobs.juju import JujuHelper + +from anvil.commands.haproxy import ( + haproxy_install_steps, +) +from anvil.commands.maas_agent import ( + maas_agent_install_steps, +) +from anvil.commands.maas_region import ( + maas_region_install_steps, +) +from anvil.commands.postgresql import ( + postgresql_install_steps, +) +from anvil.jobs.checks import VerifyBootstrappedCheck +from anvil.jobs.manifest import Manifest +from anvil.provider.local.deployment import LocalDeployment + +LOG = logging.getLogger(__name__) +console = Console() + + +@click.command() +@click.pass_context +def refresh(ctx: click.Context, manifest: Path | None = None) -> None: + """Refresh anvil cluster.""" + + deployment: LocalDeployment = ctx.obj + client = deployment.get_client() + + manifest_obj = ( + Manifest.load( + deployment, manifest_file=manifest, include_defaults=True + ) + if manifest + else Manifest.get_default_manifest(deployment) + ) + preseed = manifest_obj.deployment_config + + # Don't refresh a cluster that isn't bootstrapped + preflight_checks = [SshKeysConnectedCheck(), VerifyBootstrappedCheck()] + run_preflight_checks(preflight_checks, console) + + jhelper = JujuHelper(deployment.get_connected_controller()) + fqdn = utils.get_fqdn() + + roles = client.cluster.get_node_info(fqdn).get("roles", []) + is_database_node = "database" in roles + is_haproxy_node = "haproxy" in roles + is_region_node = "region" in roles + is_agent_node = "agent" in roles + + plan: list[BaseStep] = [] + if is_database_node: + plan.extend( + postgresql_install_steps( + client, manifest_obj, jhelper, deployment, fqdn, True + ) + ) + if is_haproxy_node: + plan.extend( + haproxy_install_steps( + client, + manifest_obj, + jhelper, + deployment.infrastructure_model, + fqdn, + True, + preseed, + refresh=True, + ) + ) + if is_region_node: + plan.extend( + maas_region_install_steps( + client, manifest_obj, jhelper, deployment, fqdn, refresh=True + ) + ) + if is_agent_node: + plan.extend( + maas_agent_install_steps( + client, manifest_obj, jhelper, deployment, fqdn, refresh=True + ) + ) + run_plan(plan, console) diff --git a/anvil-python/anvil/main.py b/anvil-python/anvil/main.py index 04e65ae..13d5a8f 100644 --- a/anvil-python/anvil/main.py +++ b/anvil-python/anvil/main.py @@ -25,6 +25,7 @@ inspect as inspect_cmds, manifest as manifest_commands, prepare_node as prepare_node_cmds, + refresh as refresh_cmds, ) from anvil.provider.local.commands import LocalProvider from anvil.provider.local.deployment import LocalDeployment @@ -60,6 +61,7 @@ def main() -> None: log.setup_root_logging(logfile) cli.add_command(prepare_node_cmds.prepare_node_script) cli.add_command(inspect_cmds.inspect) + cli.add_command(refresh_cmds.refresh) # Cluster management deployment = LocalDeployment() From 231a4d03ccca276f3881673a6ee0c4898d6dbc2e Mon Sep 17 00:00:00 2001 From: Jack Lloyd-Walters Date: Wed, 10 Jul 2024 14:35:56 +0100 Subject: [PATCH 03/24] add default acceptance to refresh --- anvil-python/anvil/commands/refresh.py | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/anvil-python/anvil/commands/refresh.py b/anvil-python/anvil/commands/refresh.py index 93da94b..ca4deb3 100644 --- a/anvil-python/anvil/commands/refresh.py +++ b/anvil-python/anvil/commands/refresh.py @@ -41,8 +41,21 @@ @click.command() +@click.option( + "-a", "--accept-defaults", help="Accept all defaults.", is_flag=True +) +@click.option( + "-m", + "--manifest", + help="Manifest file.", + type=click.Path(exists=True, dir_okay=False, path_type=Path), +) @click.pass_context -def refresh(ctx: click.Context, manifest: Path | None = None) -> None: +def refresh( + ctx: click.Context, + manifest: Path | None = None, + accept_defaults: bool = False, +) -> None: """Refresh anvil cluster.""" deployment: LocalDeployment = ctx.obj @@ -85,7 +98,7 @@ def refresh(ctx: click.Context, manifest: Path | None = None) -> None: jhelper, deployment.infrastructure_model, fqdn, - True, + accept_defaults, preseed, refresh=True, ) From 3ff6bba7d91e0c133de2babdd17e36b25906ad2c Mon Sep 17 00:00:00 2001 From: Jack Lloyd-Walters Date: Wed, 10 Jul 2024 16:19:00 +0100 Subject: [PATCH 04/24] add charm upgrades --- README.md | 16 +++ anvil-python/anvil/commands/haproxy.py | 27 ++++ anvil-python/anvil/commands/maas_agent.py | 27 ++++ anvil-python/anvil/commands/maas_region.py | 27 ++++ anvil-python/anvil/commands/postgresql.py | 27 ++++ anvil-python/anvil/commands/refresh.py | 152 ++++++++++++++------- 6 files changed, 225 insertions(+), 51 deletions(-) diff --git a/README.md b/README.md index 7a7cf4e..f191a3e 100644 --- a/README.md +++ b/README.md @@ -84,6 +84,22 @@ ubuntu@infra1:~$ maas-anvil cluster list ubuntu@infra1:~$ juju run maas-region/0 create-admin username=admin password=pass email=admin@maas.io ssh-import=lp:maasadmin ``` +## Cluster updates + +You can refresh the cluster by running the `refresh` command: + +```bash +ubuntu@infra1:~$ maas-anvil refresh +``` + +## Cluster updates + +You can refresh the cluster by running the `refresh` command: + +```bash +ubuntu@infra1:~$ maas-anvil refresh +``` + # Managing the cluster after initial deployment ## Juju permission denied diff --git a/anvil-python/anvil/commands/haproxy.py b/anvil-python/anvil/commands/haproxy.py index 9d5daea..c93a846 100644 --- a/anvil-python/anvil/commands/haproxy.py +++ b/anvil-python/anvil/commands/haproxy.py @@ -20,6 +20,7 @@ from rich.console import Console from sunbeam.clusterd.client import Client from sunbeam.commands.terraform import TerraformInitStep +from sunbeam.commands.upgrades.inter_channel import UpgradeMachineCharm from sunbeam.jobs import questions from sunbeam.jobs.common import BaseStep from sunbeam.jobs.juju import JujuHelper @@ -41,6 +42,8 @@ HAPROXY_UNIT_TIMEOUT = ( 1200 # 15 minutes, adding / removing units can take a long time ) +# TODO: Should we determine charms from the tfvars, to prevent duplication? +CHARMS = ["haproxy", "keepalived"] def keepalived_questions() -> dict[str, questions.PromptQuestion]: @@ -177,6 +180,30 @@ def get_unit_timeout(self) -> int: return HAPROXY_UNIT_TIMEOUT +class UpgradeHAProxyCharm(UpgradeMachineCharm): + """Upgrade HAProxy Unit Charms.""" + + def __init__( + self, + client: Client, + jhelper: JujuHelper, + manifest: Manifest, + model: str, + ): + super().__init__( + "Upgrade HAProxy unit charm", + "Upgrading HAProxy unit charm", + client, + jhelper, + manifest, + model, + CHARMS, + "haproxy-plan", + CONFIG_KEY, + HAPROXY_UNIT_TIMEOUT, + ) + + def haproxy_install_steps( client: Client, manifest: Manifest, diff --git a/anvil-python/anvil/commands/maas_agent.py b/anvil-python/anvil/commands/maas_agent.py index 9c97a51..9e86658 100644 --- a/anvil-python/anvil/commands/maas_agent.py +++ b/anvil-python/anvil/commands/maas_agent.py @@ -18,6 +18,7 @@ from sunbeam.clusterd.client import Client from sunbeam.commands.terraform import TerraformInitStep from sunbeam.jobs.common import BaseStep +from sunbeam.commands.upgrades.inter_channel import UpgradeMachineCharm from sunbeam.jobs.juju import JujuHelper from sunbeam.jobs.steps import ( AddMachineUnitsStep, @@ -35,6 +36,8 @@ MAASAGENT_UNIT_TIMEOUT = ( 1200 # 15 minutes, adding / removing units can take a long time ) +# TODO: Should we determine charms from the tfvars, to prevent duplication? +CHARMS = ["maas-agent"] class DeployMAASAgentApplicationStep(DeployMachineApplicationStep): @@ -111,6 +114,30 @@ def get_unit_timeout(self) -> int: return MAASAGENT_UNIT_TIMEOUT +class UpgradeMAASAgentCharm(UpgradeMachineCharm): + """Upgrade MAAS Agent Unit Charms.""" + + def __init__( + self, + client: Client, + jhelper: JujuHelper, + manifest: Manifest, + model: str, + ): + super().__init__( + "Upgrade MAAS Agent unit charm", + "Upgrading MAAS Agent unit charm", + client, + jhelper, + manifest, + model, + CHARMS, + "haproxy-plan", + CONFIG_KEY, + MAASAGENT_UNIT_TIMEOUT, + ) + + def maas_agent_install_steps( client: Client, manifest: Manifest, diff --git a/anvil-python/anvil/commands/maas_region.py b/anvil-python/anvil/commands/maas_region.py index 492d6ac..953eb41 100644 --- a/anvil-python/anvil/commands/maas_region.py +++ b/anvil-python/anvil/commands/maas_region.py @@ -18,6 +18,7 @@ from sunbeam.clusterd.client import Client from sunbeam.commands.terraform import TerraformInitStep from sunbeam.jobs.common import BaseStep +from sunbeam.commands.upgrades.inter_channel import UpgradeMachineCharm from sunbeam.jobs.juju import JujuHelper from sunbeam.jobs.steps import ( AddMachineUnitsStep, @@ -35,6 +36,8 @@ MAASREGION_UNIT_TIMEOUT = ( 1200 # 15 minutes, adding / removing units can take a long time ) +# TODO: Should we determine charms from the tfvars, to prevent duplication? +CHARMS = ["maas-region", "pgbouncer"] class DeployMAASRegionApplicationStep(DeployMachineApplicationStep): @@ -119,6 +122,30 @@ def get_unit_timeout(self) -> int: return MAASREGION_UNIT_TIMEOUT +class UpgradeMAASRegionCharm(UpgradeMachineCharm): + """Upgrade MAAS Region Unit Charms.""" + + def __init__( + self, + client: Client, + jhelper: JujuHelper, + manifest: Manifest, + model: str, + ): + super().__init__( + "Upgrade MAAS Region unit charm", + "Upgrading MAAS Region unit charm", + client, + jhelper, + manifest, + model, + CHARMS, + "haproxy-plan", + CONFIG_KEY, + MAASREGION_UNIT_TIMEOUT, + ) + + def maas_region_install_steps( client: Client, manifest: Manifest, diff --git a/anvil-python/anvil/commands/postgresql.py b/anvil-python/anvil/commands/postgresql.py index 80db14f..71b3605 100644 --- a/anvil-python/anvil/commands/postgresql.py +++ b/anvil-python/anvil/commands/postgresql.py @@ -19,6 +19,7 @@ from rich.status import Status from sunbeam.clusterd.client import Client from sunbeam.commands.terraform import TerraformInitStep +from sunbeam.commands.upgrades.inter_channel import UpgradeMachineCharm from sunbeam.jobs import questions from sunbeam.jobs.common import BaseStep, Result, ResultType from sunbeam.jobs.juju import JujuHelper @@ -87,6 +88,8 @@ def validate_max_connections(value: str) -> str | ValueError: raise ValueError( "Please provide either a number between 100 and 500 or 'default' for system default or 'dynamic' for calculating max_connections relevant to maas regions" ) +# TODO: Should we determine charms from the tfvars, to prevent duplication? +CHARMS = ["postgresql"] class DeployPostgreSQLApplicationStep(DeployMachineApplicationStep): @@ -250,6 +253,30 @@ def get_unit_timeout(self) -> int: return POSTGRESQL_UNIT_TIMEOUT +class UpgradePostgreSQLCharm(UpgradeMachineCharm): + """Upgrade PostgreSQL Unit Charms.""" + + def __init__( + self, + client: Client, + jhelper: JujuHelper, + manifest: Manifest, + model: str, + ): + super().__init__( + "Upgrade PostgreSQL unit charm", + "Upgrading PostgreSQL unit charm", + client, + jhelper, + manifest, + model, + CHARMS, + "postgresql-plan", + CONFIG_KEY, + POSTGRESQL_UNIT_TIMEOUT, + ) + + def postgresql_install_steps( client: Client, manifest: Manifest, diff --git a/anvil-python/anvil/commands/refresh.py b/anvil-python/anvil/commands/refresh.py index ca4deb3..da9f949 100644 --- a/anvil-python/anvil/commands/refresh.py +++ b/anvil-python/anvil/commands/refresh.py @@ -3,16 +3,9 @@ import click from rich.console import Console -from sunbeam import utils +from sunbeam.clusterd.client import Client from sunbeam.commands.clusterd import ( - ClusterAddJujuUserStep, - ClusterAddNodeStep, - ClusterInitStep, - ClusterJoinNodeStep, ClusterListNodeStep, - ClusterRemoveNodeStep, - ClusterUpdateJujuControllerStep, - ClusterUpdateNodeStep, ) from sunbeam.jobs.checks import ( SshKeysConnectedCheck, @@ -20,19 +13,20 @@ from sunbeam.jobs.common import BaseStep, run_plan, run_preflight_checks from sunbeam.jobs.juju import JujuHelper -from anvil.commands.haproxy import ( - haproxy_install_steps, -) +from anvil.commands.haproxy import UpgradeHAProxyCharm, haproxy_install_steps from anvil.commands.maas_agent import ( + UpgradeMAASAgentCharm, maas_agent_install_steps, ) from anvil.commands.maas_region import ( + UpgradeMAASRegionCharm, maas_region_install_steps, ) from anvil.commands.postgresql import ( + UpgradePostgreSQLCharm, postgresql_install_steps, ) -from anvil.jobs.checks import VerifyBootstrappedCheck +from anvil.jobs.checks import DaemonGroupCheck, VerifyBootstrappedCheck from anvil.jobs.manifest import Manifest from anvil.provider.local.deployment import LocalDeployment @@ -40,64 +34,38 @@ console = Console() -@click.command() -@click.option( - "-a", "--accept-defaults", help="Accept all defaults.", is_flag=True -) -@click.option( - "-m", - "--manifest", - help="Manifest file.", - type=click.Path(exists=True, dir_okay=False, path_type=Path), -) -@click.pass_context -def refresh( - ctx: click.Context, - manifest: Path | None = None, +def refresh_node( + client: Client, + name: str, + manifest: Manifest, + deployment: LocalDeployment, + roles: list[str] = [], accept_defaults: bool = False, ) -> None: - """Refresh anvil cluster.""" - - deployment: LocalDeployment = ctx.obj - client = deployment.get_client() - - manifest_obj = ( - Manifest.load( - deployment, manifest_file=manifest, include_defaults=True - ) - if manifest - else Manifest.get_default_manifest(deployment) - ) - preseed = manifest_obj.deployment_config - - # Don't refresh a cluster that isn't bootstrapped - preflight_checks = [SshKeysConnectedCheck(), VerifyBootstrappedCheck()] - run_preflight_checks(preflight_checks, console) - jhelper = JujuHelper(deployment.get_connected_controller()) - fqdn = utils.get_fqdn() - roles = client.cluster.get_node_info(fqdn).get("roles", []) is_database_node = "database" in roles is_haproxy_node = "haproxy" in roles is_region_node = "region" in roles is_agent_node = "agent" in roles + preseed = manifest.deployment_config + plan: list[BaseStep] = [] if is_database_node: plan.extend( postgresql_install_steps( - client, manifest_obj, jhelper, deployment, fqdn, True + client, manifest, jhelper, deployment, name, True ) ) if is_haproxy_node: plan.extend( haproxy_install_steps( client, - manifest_obj, + manifest, jhelper, deployment.infrastructure_model, - fqdn, + name, accept_defaults, preseed, refresh=True, @@ -106,13 +74,95 @@ def refresh( if is_region_node: plan.extend( maas_region_install_steps( - client, manifest_obj, jhelper, deployment, fqdn, refresh=True + client, manifest, jhelper, deployment, name, refresh=True ) ) if is_agent_node: plan.extend( maas_agent_install_steps( - client, manifest_obj, jhelper, deployment, fqdn, refresh=True + client, manifest, jhelper, deployment, name, refresh=True ) ) run_plan(plan, console) + + click.echo(f"Node {name} has been refreshed") + + +@click.command() +@click.option( + "-a", "--accept-defaults", help="Accept all defaults.", is_flag=True +) +@click.option( + "-m", + "--manifest", + help="Manifest file.", + type=click.Path(exists=True, dir_okay=False, path_type=Path), +) +@click.option( + "--upgrade", + is_flag=True, + show_default=True, + default=False, + help="Upgrade release.", +) +@click.pass_context +def refresh( + ctx: click.Context, + manifest: Path | None = None, + accept_defaults: bool = False, + upgrade: bool = False, +) -> None: + """Refresh the anvil cluster.""" + + deployment: LocalDeployment = ctx.obj + client = deployment.get_client() + run_preflight_checks( + [ + SshKeysConnectedCheck(), + VerifyBootstrappedCheck(), + DaemonGroupCheck(), + ], + console, + ) + + manifest_obj = ( + Manifest.load( + deployment, manifest_file=manifest, include_defaults=True + ) + if manifest + else Manifest.get_default_manifest(deployment) + ) + + nodes = ( + run_plan([ClusterListNodeStep(client)], console) + .get("ClusterListNodeStep") + .message + ) + + for name, node in nodes.items(): + refresh_node( + client, + name, + manifest_obj, + deployment, + node.get("roles", []), + accept_defaults=accept_defaults, + ) + + if upgrade: + jhelper = JujuHelper(deployment.get_connected_controller()) + upgrade_plan = [ + UpgradePostgreSQLCharm( + client, jhelper, manifest, deployment.infrastructure_model + ), + UpgradeHAProxyCharm( + client, jhelper, manifest, deployment.infrastructure_model + ), + UpgradeMAASRegionCharm( + client, jhelper, manifest, deployment.infrastructure_model + ), + UpgradeMAASAgentCharm( + client, jhelper, manifest, deployment.infrastructure_model + ), + ] + run_plan(upgrade_plan, console) From 28044d5315ef81f6fb836a2ae9d4ad0df2cb3383 Mon Sep 17 00:00:00 2001 From: Jack Lloyd-Walters Date: Wed, 10 Jul 2024 16:23:21 +0100 Subject: [PATCH 05/24] liniting and formatting --- anvil-python/anvil/commands/refresh.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/anvil-python/anvil/commands/refresh.py b/anvil-python/anvil/commands/refresh.py index da9f949..6d947e6 100644 --- a/anvil-python/anvil/commands/refresh.py +++ b/anvil-python/anvil/commands/refresh.py @@ -153,16 +153,16 @@ def refresh( jhelper = JujuHelper(deployment.get_connected_controller()) upgrade_plan = [ UpgradePostgreSQLCharm( - client, jhelper, manifest, deployment.infrastructure_model + client, jhelper, manifest_obj, deployment.infrastructure_model ), UpgradeHAProxyCharm( - client, jhelper, manifest, deployment.infrastructure_model + client, jhelper, manifest_obj, deployment.infrastructure_model ), UpgradeMAASRegionCharm( - client, jhelper, manifest, deployment.infrastructure_model + client, jhelper, manifest_obj, deployment.infrastructure_model ), UpgradeMAASAgentCharm( - client, jhelper, manifest, deployment.infrastructure_model + client, jhelper, manifest_obj, deployment.infrastructure_model ), ] run_plan(upgrade_plan, console) From 5b1f393b1f456614d7109c73943b7d2774052c7d Mon Sep 17 00:00:00 2001 From: Jack Lloyd-Walters Date: Thu, 11 Jul 2024 09:43:09 +0100 Subject: [PATCH 06/24] renaming --- anvil-python/anvil/commands/haproxy.py | 4 ++-- anvil-python/anvil/commands/maas_agent.py | 4 ++-- anvil-python/anvil/commands/maas_region.py | 4 ++-- anvil-python/anvil/commands/postgresql.py | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/anvil-python/anvil/commands/haproxy.py b/anvil-python/anvil/commands/haproxy.py index c93a846..679a439 100644 --- a/anvil-python/anvil/commands/haproxy.py +++ b/anvil-python/anvil/commands/haproxy.py @@ -191,8 +191,8 @@ def __init__( model: str, ): super().__init__( - "Upgrade HAProxy unit charm", - "Upgrading HAProxy unit charm", + "Upgrade HAProxy unit charms", + "Upgrading HAProxy unit charms", client, jhelper, manifest, diff --git a/anvil-python/anvil/commands/maas_agent.py b/anvil-python/anvil/commands/maas_agent.py index 9e86658..f0d8bfb 100644 --- a/anvil-python/anvil/commands/maas_agent.py +++ b/anvil-python/anvil/commands/maas_agent.py @@ -125,8 +125,8 @@ def __init__( model: str, ): super().__init__( - "Upgrade MAAS Agent unit charm", - "Upgrading MAAS Agent unit charm", + "Upgrade MAAS Agent unit charms", + "Upgrading MAAS Agent unit charms", client, jhelper, manifest, diff --git a/anvil-python/anvil/commands/maas_region.py b/anvil-python/anvil/commands/maas_region.py index 953eb41..b78772d 100644 --- a/anvil-python/anvil/commands/maas_region.py +++ b/anvil-python/anvil/commands/maas_region.py @@ -133,8 +133,8 @@ def __init__( model: str, ): super().__init__( - "Upgrade MAAS Region unit charm", - "Upgrading MAAS Region unit charm", + "Upgrade MAAS Region unit charms", + "Upgrading MAAS Region unit charms", client, jhelper, manifest, diff --git a/anvil-python/anvil/commands/postgresql.py b/anvil-python/anvil/commands/postgresql.py index 71b3605..2d634c1 100644 --- a/anvil-python/anvil/commands/postgresql.py +++ b/anvil-python/anvil/commands/postgresql.py @@ -264,8 +264,8 @@ def __init__( model: str, ): super().__init__( - "Upgrade PostgreSQL unit charm", - "Upgrading PostgreSQL unit charm", + "Upgrade PostgreSQL unit charms", + "Upgrading PostgreSQL unit charms", client, jhelper, manifest, From 4d76e2715d6311637dc9a9fd55359b3886dd0804 Mon Sep 17 00:00:00 2001 From: Jack Lloyd-Walters Date: Thu, 11 Jul 2024 15:22:02 +0100 Subject: [PATCH 07/24] refactor --- anvil-python/anvil/commands/haproxy.py | 46 +++-- anvil-python/anvil/commands/maas_agent.py | 44 ++--- anvil-python/anvil/commands/maas_region.py | 44 ++--- anvil-python/anvil/commands/postgresql.py | 69 +++---- anvil-python/anvil/commands/refresh.py | 211 ++++++++++----------- 5 files changed, 189 insertions(+), 225 deletions(-) diff --git a/anvil-python/anvil/commands/haproxy.py b/anvil-python/anvil/commands/haproxy.py index 679a439..b1b2a98 100644 --- a/anvil-python/anvil/commands/haproxy.py +++ b/anvil-python/anvil/commands/haproxy.py @@ -180,30 +180,6 @@ def get_unit_timeout(self) -> int: return HAPROXY_UNIT_TIMEOUT -class UpgradeHAProxyCharm(UpgradeMachineCharm): - """Upgrade HAProxy Unit Charms.""" - - def __init__( - self, - client: Client, - jhelper: JujuHelper, - manifest: Manifest, - model: str, - ): - super().__init__( - "Upgrade HAProxy unit charms", - "Upgrading HAProxy unit charms", - client, - jhelper, - manifest, - model, - CHARMS, - "haproxy-plan", - CONFIG_KEY, - HAPROXY_UNIT_TIMEOUT, - ) - - def haproxy_install_steps( client: Client, manifest: Manifest, @@ -227,3 +203,25 @@ def haproxy_install_steps( ), AddHAProxyUnitsStep(client, fqdn, jhelper, model), ] + + +def haproxy_upgrade_steps( + client: Client, + manifest: Manifest, + jhelper: JujuHelper, + model: str, + accept_defaults: bool, + preseed: dict[Any, Any], +) -> List[BaseStep]: + return [ + TerraformInitStep(manifest.get_tfhelper("haproxy-plan")), + DeployHAProxyApplicationStep( + client, + manifest, + jhelper, + model, + accept_defaults=accept_defaults, + deployment_preseed=preseed, + refresh=True, + ), + ] diff --git a/anvil-python/anvil/commands/maas_agent.py b/anvil-python/anvil/commands/maas_agent.py index f0d8bfb..24a671b 100644 --- a/anvil-python/anvil/commands/maas_agent.py +++ b/anvil-python/anvil/commands/maas_agent.py @@ -17,8 +17,8 @@ from sunbeam.clusterd.client import Client from sunbeam.commands.terraform import TerraformInitStep -from sunbeam.jobs.common import BaseStep from sunbeam.commands.upgrades.inter_channel import UpgradeMachineCharm +from sunbeam.jobs.common import BaseStep from sunbeam.jobs.juju import JujuHelper from sunbeam.jobs.steps import ( AddMachineUnitsStep, @@ -114,30 +114,6 @@ def get_unit_timeout(self) -> int: return MAASAGENT_UNIT_TIMEOUT -class UpgradeMAASAgentCharm(UpgradeMachineCharm): - """Upgrade MAAS Agent Unit Charms.""" - - def __init__( - self, - client: Client, - jhelper: JujuHelper, - manifest: Manifest, - model: str, - ): - super().__init__( - "Upgrade MAAS Agent unit charms", - "Upgrading MAAS Agent unit charms", - client, - jhelper, - manifest, - model, - CHARMS, - "haproxy-plan", - CONFIG_KEY, - MAASAGENT_UNIT_TIMEOUT, - ) - - def maas_agent_install_steps( client: Client, manifest: Manifest, @@ -148,6 +124,22 @@ def maas_agent_install_steps( ) -> List[BaseStep]: return [ TerraformInitStep(manifest.get_tfhelper("maas-agent-plan")), - DeployMAASAgentApplicationStep(client, manifest, jhelper, model, refresh=refresh), + DeployMAASAgentApplicationStep( + client, manifest, jhelper, model, refresh=refresh + ), AddMAASAgentUnitsStep(client, fqdn, jhelper, model), ] + + +def maas_agent_upgrade_steps( + client: Client, + manifest: Manifest, + jhelper: JujuHelper, + model: str, +) -> List[BaseStep]: + return [ + TerraformInitStep(manifest.get_tfhelper("maas-agent-plan")), + DeployMAASAgentApplicationStep( + client, manifest, jhelper, model, refresh=True + ), + ] diff --git a/anvil-python/anvil/commands/maas_region.py b/anvil-python/anvil/commands/maas_region.py index b78772d..af6d969 100644 --- a/anvil-python/anvil/commands/maas_region.py +++ b/anvil-python/anvil/commands/maas_region.py @@ -17,8 +17,8 @@ from sunbeam.clusterd.client import Client from sunbeam.commands.terraform import TerraformInitStep -from sunbeam.jobs.common import BaseStep from sunbeam.commands.upgrades.inter_channel import UpgradeMachineCharm +from sunbeam.jobs.common import BaseStep from sunbeam.jobs.juju import JujuHelper from sunbeam.jobs.steps import ( AddMachineUnitsStep, @@ -122,30 +122,6 @@ def get_unit_timeout(self) -> int: return MAASREGION_UNIT_TIMEOUT -class UpgradeMAASRegionCharm(UpgradeMachineCharm): - """Upgrade MAAS Region Unit Charms.""" - - def __init__( - self, - client: Client, - jhelper: JujuHelper, - manifest: Manifest, - model: str, - ): - super().__init__( - "Upgrade MAAS Region unit charms", - "Upgrading MAAS Region unit charms", - client, - jhelper, - manifest, - model, - CHARMS, - "haproxy-plan", - CONFIG_KEY, - MAASREGION_UNIT_TIMEOUT, - ) - - def maas_region_install_steps( client: Client, manifest: Manifest, @@ -156,6 +132,22 @@ def maas_region_install_steps( ) -> List[BaseStep]: return [ TerraformInitStep(manifest.get_tfhelper("maas-region-plan")), - DeployMAASRegionApplicationStep(client, manifest, jhelper, model, refresh), + DeployMAASRegionApplicationStep( + client, manifest, jhelper, model, refresh + ), AddMAASRegionUnitsStep(client, fqdn, jhelper, model), ] + + +def maas_region_upgrade_steps( + client: Client, + manifest: Manifest, + jhelper: JujuHelper, + model: str, +) -> List[BaseStep]: + return [ + TerraformInitStep(manifest.get_tfhelper("maas-region-plan")), + DeployMAASRegionApplicationStep( + client, manifest, jhelper, model, refresh=True + ), + ] diff --git a/anvil-python/anvil/commands/postgresql.py b/anvil-python/anvil/commands/postgresql.py index 2d634c1..d083885 100644 --- a/anvil-python/anvil/commands/postgresql.py +++ b/anvil-python/anvil/commands/postgresql.py @@ -51,6 +51,7 @@ def postgresql_install_steps( fqdn: str, accept_defaults: bool, preseed: dict[Any, Any], + refresh: bool = False, ) -> List[BaseStep]: return [ TerraformInitStep(manifest.get_tfhelper("postgresql-plan")), @@ -61,11 +62,34 @@ def postgresql_install_steps( model, accept_defaults=accept_defaults, deployment_preseed=preseed, + refresh=refresh, ), AddPostgreSQLUnitsStep(client, fqdn, jhelper, model), ] +def postgresql_upgrade_steps( + client: Client, + manifest: Manifest, + jhelper: JujuHelper, + model: str, + accept_defaults: bool, + preseed: dict[Any, Any], +) -> List[BaseStep]: + return [ + TerraformInitStep(manifest.get_tfhelper("postgresql-plan")), + DeployPostgreSQLApplicationStep( + client, + manifest, + jhelper, + model, + accept_defaults=accept_defaults, + deployment_preseed=preseed, + refresh=True, + ), + ] + + def postgresql_questions() -> dict[str, questions.PromptQuestion]: return { "max_connections": questions.PromptQuestion( @@ -88,6 +112,8 @@ def validate_max_connections(value: str) -> str | ValueError: raise ValueError( "Please provide either a number between 100 and 500 or 'default' for system default or 'dynamic' for calculating max_connections relevant to maas regions" ) + + # TODO: Should we determine charms from the tfvars, to prevent duplication? CHARMS = ["postgresql"] @@ -251,46 +277,3 @@ def __init__( def get_unit_timeout(self) -> int: return POSTGRESQL_UNIT_TIMEOUT - - -class UpgradePostgreSQLCharm(UpgradeMachineCharm): - """Upgrade PostgreSQL Unit Charms.""" - - def __init__( - self, - client: Client, - jhelper: JujuHelper, - manifest: Manifest, - model: str, - ): - super().__init__( - "Upgrade PostgreSQL unit charms", - "Upgrading PostgreSQL unit charms", - client, - jhelper, - manifest, - model, - CHARMS, - "postgresql-plan", - CONFIG_KEY, - POSTGRESQL_UNIT_TIMEOUT, - ) - - -def postgresql_install_steps( - client: Client, - manifest: Manifest, - jhelper: JujuHelper, - deployment: LocalDeployment, - fqdn: str, - refresh: bool = False, -) -> List[BaseStep]: - return [ - TerraformInitStep(manifest.get_tfhelper("postgresql-plan")), - DeployPostgreSQLApplicationStep( - client, manifest, jhelper, deployment.infrastructure_model, refresh - ), - AddPostgreSQLUnitsStep( - client, fqdn, jhelper, deployment.infrastructure_model - ), - ] diff --git a/anvil-python/anvil/commands/refresh.py b/anvil-python/anvil/commands/refresh.py index 6d947e6..e290ca6 100644 --- a/anvil-python/anvil/commands/refresh.py +++ b/anvil-python/anvil/commands/refresh.py @@ -4,29 +4,23 @@ import click from rich.console import Console from sunbeam.clusterd.client import Client -from sunbeam.commands.clusterd import ( - ClusterListNodeStep, +from sunbeam.commands.upgrades.base import UpgradeCoordinator, UpgradeFeatures +from sunbeam.commands.upgrades.intra_channel import ( + LatestInChannel, ) -from sunbeam.jobs.checks import ( - SshKeysConnectedCheck, +from sunbeam.jobs.common import ( + BaseStep, + run_plan, ) -from sunbeam.jobs.common import BaseStep, run_plan, run_preflight_checks +from sunbeam.jobs.deployment import Deployment +from sunbeam.jobs.deployments import Deployment from sunbeam.jobs.juju import JujuHelper +from sunbeam.jobs.manifest import AddManifestStep, Manifest -from anvil.commands.haproxy import UpgradeHAProxyCharm, haproxy_install_steps -from anvil.commands.maas_agent import ( - UpgradeMAASAgentCharm, - maas_agent_install_steps, -) -from anvil.commands.maas_region import ( - UpgradeMAASRegionCharm, - maas_region_install_steps, -) -from anvil.commands.postgresql import ( - UpgradePostgreSQLCharm, - postgresql_install_steps, -) -from anvil.jobs.checks import DaemonGroupCheck, VerifyBootstrappedCheck +from anvil.commands.haproxy import haproxy_upgrade_steps +from anvil.commands.maas_agent import maas_agent_upgrade_steps +from anvil.commands.maas_region import maas_region_upgrade_steps +from anvil.commands.postgresql import postgresql_upgrade_steps from anvil.jobs.manifest import Manifest from anvil.provider.local.deployment import LocalDeployment @@ -34,135 +28,140 @@ console = Console() -def refresh_node( - client: Client, - name: str, - manifest: Manifest, - deployment: LocalDeployment, - roles: list[str] = [], - accept_defaults: bool = False, -) -> None: - jhelper = JujuHelper(deployment.get_connected_controller()) +class LatestInChannelCoordinator(UpgradeCoordinator): + """Coordinator for refreshing charms in their current channel.""" - is_database_node = "database" in roles - is_haproxy_node = "haproxy" in roles - is_region_node = "region" in roles - is_agent_node = "agent" in roles + def __init__( + self, + deployment: Deployment, + client: Client, + jhelper: JujuHelper, + manifest: Manifest, + accept_defaults: bool = False, + ): + super().__init__(deployment, client, jhelper, manifest) + self.accept_defaults = accept_defaults + self.preseed = self.manifest.deployment_config - preseed = manifest.deployment_config + def get_plan(self) -> list[BaseStep]: + """Return the upgrade plan.""" + plan: list[BaseStep] = [LatestInChannel(self.jhelper, self.manifest)] - plan: list[BaseStep] = [] - if is_database_node: plan.extend( - postgresql_install_steps( - client, manifest, jhelper, deployment, name, True + haproxy_upgrade_steps( + self.client, + self.manifest, + self.jhelper, + self.deployment.infrastructure_model, + self.accept_defaults, + self.preseed, ) ) - if is_haproxy_node: plan.extend( - haproxy_install_steps( - client, - manifest, - jhelper, - deployment.infrastructure_model, - name, - accept_defaults, - preseed, - refresh=True, + postgresql_upgrade_steps( + self.client, + self.manifest, + self.jhelper, + self.deployment.infrastructure_model, + self.accept_defaults, + self.preseed, ) ) - if is_region_node: plan.extend( - maas_region_install_steps( - client, manifest, jhelper, deployment, name, refresh=True + maas_region_upgrade_steps( + self.client, + self.manifest, + self.jhelper, + self.deployment.infrastructure_model, ) ) - if is_agent_node: plan.extend( - maas_agent_install_steps( - client, manifest, jhelper, deployment, name, refresh=True + maas_agent_upgrade_steps( + self.client, + self.manifest, + self.jhelper, + self.deployment.infrastructure_model, ) ) - run_plan(plan, console) - click.echo(f"Node {name} has been refreshed") + plan.extend( + UpgradeFeatures(self.deployment, upgrade_release=False), + ) + + return plan @click.command() @click.option( - "-a", "--accept-defaults", help="Accept all defaults.", is_flag=True + "-c", + "--clear-manifest", + is_flag=True, + default=False, + help="Clear the manifest file.", + type=bool, ) @click.option( "-m", "--manifest", + "manifest_path", help="Manifest file.", type=click.Path(exists=True, dir_okay=False, path_type=Path), ) @click.option( - "--upgrade", + "--upgrade-release", is_flag=True, show_default=True, default=False, - help="Upgrade release.", + help="Upgrade OpenStack release.", +) +@click.option( + "-a", "--accept-defaults", help="Accept all defaults.", is_flag=True ) @click.pass_context def refresh( ctx: click.Context, - manifest: Path | None = None, + upgrade_release: bool, + manifest_path: Path | None = None, + clear_manifest: bool = False, accept_defaults: bool = False, - upgrade: bool = False, ) -> None: - """Refresh the anvil cluster.""" + """Refresh deployment. + + Refresh the deployment. If --upgrade-release is supplied then charms are + upgraded the channels aligned with this snap revision + """ deployment: LocalDeployment = ctx.obj client = deployment.get_client() - run_preflight_checks( - [ - SshKeysConnectedCheck(), - VerifyBootstrappedCheck(), - DaemonGroupCheck(), - ], - console, - ) - - manifest_obj = ( - Manifest.load( - deployment, manifest_file=manifest, include_defaults=True + + manifest = None + if clear_manifest: + raise click.ClickException( + "Anvil does not currently support clear-manifest." ) - if manifest - else Manifest.get_default_manifest(deployment) - ) - - nodes = ( - run_plan([ClusterListNodeStep(client)], console) - .get("ClusterListNodeStep") - .message - ) - - for name, node in nodes.items(): - refresh_node( - client, - name, - manifest_obj, + elif manifest_path: + manifest = deployment.get_manifest(manifest_path) + run_plan([AddManifestStep(client, manifest_path)], console) + + if not manifest: + LOG.debug("Getting latest manifest from cluster db") + manifest = deployment.get_manifest() + + LOG.debug(f"Manifest used for deployment - software: {manifest.software}") + jhelper = JujuHelper(deployment.get_connected_controller()) + + if upgrade_release: + raise click.ClickException( + "Anvil does not current support upgrade-release." + ) + else: + a = LatestInChannelCoordinator( deployment, - node.get("roles", []), + client, + jhelper, + manifest, accept_defaults=accept_defaults, ) + a.run_plan() - if upgrade: - jhelper = JujuHelper(deployment.get_connected_controller()) - upgrade_plan = [ - UpgradePostgreSQLCharm( - client, jhelper, manifest_obj, deployment.infrastructure_model - ), - UpgradeHAProxyCharm( - client, jhelper, manifest_obj, deployment.infrastructure_model - ), - UpgradeMAASRegionCharm( - client, jhelper, manifest_obj, deployment.infrastructure_model - ), - UpgradeMAASAgentCharm( - client, jhelper, manifest_obj, deployment.infrastructure_model - ), - ] - run_plan(upgrade_plan, console) + click.echo("Refresh complete.") From 4dd29b6c766afc49d0a2be1e5c44b1fe40c88dbd Mon Sep 17 00:00:00 2001 From: Jack Lloyd-Walters Date: Thu, 11 Jul 2024 15:29:59 +0100 Subject: [PATCH 08/24] update readme --- README.md | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index f191a3e..ce19977 100644 --- a/README.md +++ b/README.md @@ -84,13 +84,8 @@ ubuntu@infra1:~$ maas-anvil cluster list ubuntu@infra1:~$ juju run maas-region/0 create-admin username=admin password=pass email=admin@maas.io ssh-import=lp:maasadmin ``` -## Cluster updates - -You can refresh the cluster by running the `refresh` command: +# Managing the cluster after initial deployment -```bash -ubuntu@infra1:~$ maas-anvil refresh -``` ## Cluster updates @@ -100,7 +95,7 @@ You can refresh the cluster by running the `refresh` command: ubuntu@infra1:~$ maas-anvil refresh ``` -# Managing the cluster after initial deployment +This allows passing a new manifest file with `--manifest` for updating configuration options. ## Juju permission denied From 14b202fad97eea65f16ffc35b96a9d5839dca400 Mon Sep 17 00:00:00 2001 From: Jack Lloyd-Walters Date: Thu, 11 Jul 2024 17:28:55 +0100 Subject: [PATCH 09/24] rollback features from sunbeam latest to sunbeam anvil --- anvil-python/anvil/commands/refresh.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/anvil-python/anvil/commands/refresh.py b/anvil-python/anvil/commands/refresh.py index e290ca6..4ba5310 100644 --- a/anvil-python/anvil/commands/refresh.py +++ b/anvil-python/anvil/commands/refresh.py @@ -4,7 +4,7 @@ import click from rich.console import Console from sunbeam.clusterd.client import Client -from sunbeam.commands.upgrades.base import UpgradeCoordinator, UpgradeFeatures +from sunbeam.commands.upgrades.base import UpgradeCoordinator, UpgradePlugins #UpgradeFeatures from sunbeam.commands.upgrades.intra_channel import ( LatestInChannel, ) @@ -24,10 +24,10 @@ from anvil.jobs.manifest import Manifest from anvil.provider.local.deployment import LocalDeployment + LOG = logging.getLogger(__name__) console = Console() - class LatestInChannelCoordinator(UpgradeCoordinator): """Coordinator for refreshing charms in their current channel.""" @@ -84,8 +84,12 @@ def get_plan(self) -> list[BaseStep]: ) ) + # TODO: Update MAAS-Anvil sunbeam tag to allow using UpgradeFeatures instead of UpgradePlugins + # plan.extend( + # UpgradeFeatures(self.deployment, upgrade_release=False), + # ) plan.extend( - UpgradeFeatures(self.deployment, upgrade_release=False), + UpgradePlugins(self.deployment, upgrade_release=False) ) return plan From 2800bd618d4554a09b65d00b917f41ed55adf853 Mon Sep 17 00:00:00 2001 From: Jack Lloyd-Walters Date: Thu, 11 Jul 2024 17:29:05 +0100 Subject: [PATCH 10/24] format again --- anvil-python/anvil/commands/refresh.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/anvil-python/anvil/commands/refresh.py b/anvil-python/anvil/commands/refresh.py index 4ba5310..890d247 100644 --- a/anvil-python/anvil/commands/refresh.py +++ b/anvil-python/anvil/commands/refresh.py @@ -4,7 +4,12 @@ import click from rich.console import Console from sunbeam.clusterd.client import Client -from sunbeam.commands.upgrades.base import UpgradeCoordinator, UpgradePlugins #UpgradeFeatures +from sunbeam.commands.upgrades.base import ( + UpgradeCoordinator, + UpgradePlugins, +) + +# UpgradeFeatures from sunbeam.commands.upgrades.intra_channel import ( LatestInChannel, ) @@ -24,10 +29,10 @@ from anvil.jobs.manifest import Manifest from anvil.provider.local.deployment import LocalDeployment - LOG = logging.getLogger(__name__) console = Console() + class LatestInChannelCoordinator(UpgradeCoordinator): """Coordinator for refreshing charms in their current channel.""" @@ -88,9 +93,7 @@ def get_plan(self) -> list[BaseStep]: # plan.extend( # UpgradeFeatures(self.deployment, upgrade_release=False), # ) - plan.extend( - UpgradePlugins(self.deployment, upgrade_release=False) - ) + plan.extend(UpgradePlugins(self.deployment, upgrade_release=False)) return plan From d1138b504507a369b22bdc54f380a7eaa8f8c9f7 Mon Sep 17 00:00:00 2001 From: Jack Lloyd-Walters Date: Thu, 11 Jul 2024 17:29:55 +0100 Subject: [PATCH 11/24] more linting --- anvil-python/anvil/commands/refresh.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/anvil-python/anvil/commands/refresh.py b/anvil-python/anvil/commands/refresh.py index 890d247..6aac012 100644 --- a/anvil-python/anvil/commands/refresh.py +++ b/anvil-python/anvil/commands/refresh.py @@ -8,8 +8,6 @@ UpgradeCoordinator, UpgradePlugins, ) - -# UpgradeFeatures from sunbeam.commands.upgrades.intra_channel import ( LatestInChannel, ) @@ -89,7 +87,9 @@ def get_plan(self) -> list[BaseStep]: ) ) - # TODO: Update MAAS-Anvil sunbeam tag to allow using UpgradeFeatures instead of UpgradePlugins + # TODO: Update MAAS-Anvil sunbeam tag to allow using + # sunbeam.commands.upgrades.base.UpgradeFeatures instead of + # sunbeam.commands.upgrades.base.UpgradePlugins # plan.extend( # UpgradeFeatures(self.deployment, upgrade_release=False), # ) From 4d22ebc0171989284fc7c73a81f46dcecd396c6b Mon Sep 17 00:00:00 2001 From: Jack Lloyd-Walters Date: Thu, 11 Jul 2024 17:32:21 +0100 Subject: [PATCH 12/24] remove unused imports --- anvil-python/anvil/commands/haproxy.py | 3 --- anvil-python/anvil/commands/maas_agent.py | 3 --- anvil-python/anvil/commands/maas_region.py | 3 --- anvil-python/anvil/commands/postgresql.py | 5 ----- 4 files changed, 14 deletions(-) diff --git a/anvil-python/anvil/commands/haproxy.py b/anvil-python/anvil/commands/haproxy.py index b1b2a98..32f8903 100644 --- a/anvil-python/anvil/commands/haproxy.py +++ b/anvil-python/anvil/commands/haproxy.py @@ -20,7 +20,6 @@ from rich.console import Console from sunbeam.clusterd.client import Client from sunbeam.commands.terraform import TerraformInitStep -from sunbeam.commands.upgrades.inter_channel import UpgradeMachineCharm from sunbeam.jobs import questions from sunbeam.jobs.common import BaseStep from sunbeam.jobs.juju import JujuHelper @@ -42,8 +41,6 @@ HAPROXY_UNIT_TIMEOUT = ( 1200 # 15 minutes, adding / removing units can take a long time ) -# TODO: Should we determine charms from the tfvars, to prevent duplication? -CHARMS = ["haproxy", "keepalived"] def keepalived_questions() -> dict[str, questions.PromptQuestion]: diff --git a/anvil-python/anvil/commands/maas_agent.py b/anvil-python/anvil/commands/maas_agent.py index 24a671b..49bbded 100644 --- a/anvil-python/anvil/commands/maas_agent.py +++ b/anvil-python/anvil/commands/maas_agent.py @@ -17,7 +17,6 @@ from sunbeam.clusterd.client import Client from sunbeam.commands.terraform import TerraformInitStep -from sunbeam.commands.upgrades.inter_channel import UpgradeMachineCharm from sunbeam.jobs.common import BaseStep from sunbeam.jobs.juju import JujuHelper from sunbeam.jobs.steps import ( @@ -36,8 +35,6 @@ MAASAGENT_UNIT_TIMEOUT = ( 1200 # 15 minutes, adding / removing units can take a long time ) -# TODO: Should we determine charms from the tfvars, to prevent duplication? -CHARMS = ["maas-agent"] class DeployMAASAgentApplicationStep(DeployMachineApplicationStep): diff --git a/anvil-python/anvil/commands/maas_region.py b/anvil-python/anvil/commands/maas_region.py index af6d969..b261605 100644 --- a/anvil-python/anvil/commands/maas_region.py +++ b/anvil-python/anvil/commands/maas_region.py @@ -17,7 +17,6 @@ from sunbeam.clusterd.client import Client from sunbeam.commands.terraform import TerraformInitStep -from sunbeam.commands.upgrades.inter_channel import UpgradeMachineCharm from sunbeam.jobs.common import BaseStep from sunbeam.jobs.juju import JujuHelper from sunbeam.jobs.steps import ( @@ -36,8 +35,6 @@ MAASREGION_UNIT_TIMEOUT = ( 1200 # 15 minutes, adding / removing units can take a long time ) -# TODO: Should we determine charms from the tfvars, to prevent duplication? -CHARMS = ["maas-region", "pgbouncer"] class DeployMAASRegionApplicationStep(DeployMachineApplicationStep): diff --git a/anvil-python/anvil/commands/postgresql.py b/anvil-python/anvil/commands/postgresql.py index d083885..b7410e0 100644 --- a/anvil-python/anvil/commands/postgresql.py +++ b/anvil-python/anvil/commands/postgresql.py @@ -19,7 +19,6 @@ from rich.status import Status from sunbeam.clusterd.client import Client from sunbeam.commands.terraform import TerraformInitStep -from sunbeam.commands.upgrades.inter_channel import UpgradeMachineCharm from sunbeam.jobs import questions from sunbeam.jobs.common import BaseStep, Result, ResultType from sunbeam.jobs.juju import JujuHelper @@ -114,10 +113,6 @@ def validate_max_connections(value: str) -> str | ValueError: ) -# TODO: Should we determine charms from the tfvars, to prevent duplication? -CHARMS = ["postgresql"] - - class DeployPostgreSQLApplicationStep(DeployMachineApplicationStep): """Deploy PostgreSQL application using Terraform""" From c26cac02828f4cbe0f20f96b78ed7dcbbf95ac2e Mon Sep 17 00:00:00 2001 From: Jack Lloyd-Walters Date: Thu, 11 Jul 2024 17:57:43 +0100 Subject: [PATCH 13/24] include openstack client --- anvil-python/pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/anvil-python/pyproject.toml b/anvil-python/pyproject.toml index 65c150e..42e281d 100644 --- a/anvil-python/pyproject.toml +++ b/anvil-python/pyproject.toml @@ -26,6 +26,7 @@ dynamic = [ ] dependencies = [ "pydantic==1.10.14", + "python-openstackclient===6.6.0", "rich", "snap-helpers@ git+https://github.com/skatsaounis/snap-helpers", "sunbeam@ git+https://github.com/canonical/snap-openstack@anvil-0.1#subdirectory=sunbeam-python", From 109e194510ae5652351559e4681aa2820b4c7971 Mon Sep 17 00:00:00 2001 From: Jack Lloyd-Walters Date: Tue, 16 Jul 2024 13:24:39 +0100 Subject: [PATCH 14/24] fetch manifest correctly --- anvil-python/anvil/commands/refresh.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/anvil-python/anvil/commands/refresh.py b/anvil-python/anvil/commands/refresh.py index 6aac012..e99c2e1 100644 --- a/anvil-python/anvil/commands/refresh.py +++ b/anvil-python/anvil/commands/refresh.py @@ -147,8 +147,11 @@ def refresh( "Anvil does not currently support clear-manifest." ) elif manifest_path: - manifest = deployment.get_manifest(manifest_path) - run_plan([AddManifestStep(client, manifest_path)], console) + manifest = Manifest.load( + deployment, manifest_file=manifest, include_defaults=True + ) + else: + manifest = Manifest.get_default_manifest(deployment) if not manifest: LOG.debug("Getting latest manifest from cluster db") From f13e0ede5d0546fddd21ad2cb936580ab73ca779 Mon Sep 17 00:00:00 2001 From: Jack Lloyd-Walters Date: Tue, 16 Jul 2024 13:29:00 +0100 Subject: [PATCH 15/24] remove clear manifest --- anvil-python/anvil/commands/refresh.py | 46 ++++++-------------------- 1 file changed, 10 insertions(+), 36 deletions(-) diff --git a/anvil-python/anvil/commands/refresh.py b/anvil-python/anvil/commands/refresh.py index e99c2e1..e0a5ff4 100644 --- a/anvil-python/anvil/commands/refresh.py +++ b/anvil-python/anvil/commands/refresh.py @@ -99,14 +99,6 @@ def get_plan(self) -> list[BaseStep]: @click.command() -@click.option( - "-c", - "--clear-manifest", - is_flag=True, - default=False, - help="Clear the manifest file.", - type=bool, -) @click.option( "-m", "--manifest", @@ -114,13 +106,6 @@ def get_plan(self) -> list[BaseStep]: help="Manifest file.", type=click.Path(exists=True, dir_okay=False, path_type=Path), ) -@click.option( - "--upgrade-release", - is_flag=True, - show_default=True, - default=False, - help="Upgrade OpenStack release.", -) @click.option( "-a", "--accept-defaults", help="Accept all defaults.", is_flag=True ) @@ -129,24 +114,18 @@ def refresh( ctx: click.Context, upgrade_release: bool, manifest_path: Path | None = None, - clear_manifest: bool = False, accept_defaults: bool = False, ) -> None: """Refresh deployment. - Refresh the deployment. If --upgrade-release is supplied then charms are - upgraded the channels aligned with this snap revision + Refresh the deployment and allow passing new configuration options. """ deployment: LocalDeployment = ctx.obj client = deployment.get_client() manifest = None - if clear_manifest: - raise click.ClickException( - "Anvil does not currently support clear-manifest." - ) - elif manifest_path: + if manifest_path: manifest = Manifest.load( deployment, manifest_file=manifest, include_defaults=True ) @@ -160,18 +139,13 @@ def refresh( LOG.debug(f"Manifest used for deployment - software: {manifest.software}") jhelper = JujuHelper(deployment.get_connected_controller()) - if upgrade_release: - raise click.ClickException( - "Anvil does not current support upgrade-release." - ) - else: - a = LatestInChannelCoordinator( - deployment, - client, - jhelper, - manifest, - accept_defaults=accept_defaults, - ) - a.run_plan() + a = LatestInChannelCoordinator( + deployment, + client, + jhelper, + manifest, + accept_defaults=accept_defaults, + ) + a.run_plan() click.echo("Refresh complete.") From 4461f6aceca5670286c55f8cdb714daba9f8f480 Mon Sep 17 00:00:00 2001 From: Jack Lloyd-Walters Date: Wed, 17 Jul 2024 15:06:56 +0100 Subject: [PATCH 16/24] Roll our own upgrades to stop sunbeam issues --- anvil-python/anvil/commands/refresh.py | 76 ++++++++++++++++++++------ 1 file changed, 60 insertions(+), 16 deletions(-) diff --git a/anvil-python/anvil/commands/refresh.py b/anvil-python/anvil/commands/refresh.py index e0a5ff4..6c6ae47 100644 --- a/anvil-python/anvil/commands/refresh.py +++ b/anvil-python/anvil/commands/refresh.py @@ -3,22 +3,24 @@ import click from rich.console import Console +from rich.status import Status from sunbeam.clusterd.client import Client from sunbeam.commands.upgrades.base import ( - UpgradeCoordinator, UpgradePlugins, ) from sunbeam.commands.upgrades.intra_channel import ( - LatestInChannel, + LatestInChannel as SunbeamLatestInChannel, ) from sunbeam.jobs.common import ( BaseStep, + Result, + ResultType, run_plan, ) from sunbeam.jobs.deployment import Deployment from sunbeam.jobs.deployments import Deployment from sunbeam.jobs.juju import JujuHelper -from sunbeam.jobs.manifest import AddManifestStep, Manifest +from sunbeam.jobs.manifest import Manifest from anvil.commands.haproxy import haproxy_upgrade_steps from anvil.commands.maas_agent import maas_agent_upgrade_steps @@ -31,7 +33,32 @@ console = Console() -class LatestInChannelCoordinator(UpgradeCoordinator): +# We require a small refactor as compared to sunbeam as we don't have identical charms +class LatestInChannel(SunbeamLatestInChannel): + def run(self, status: Status | None = None) -> Result: + """Refresh all charms identified as needing a refresh. + + If the manifest has charm channel and revision, terraform apply should update + the charms. + If the manifest has only charm, then juju refresh is required if channel is + same as deployed charm, otherwise juju upgrade charm. + """ + deployed_machine_apps = self.get_charm_deployed_versions("controller") + + all_deployed_apps = deployed_machine_apps.copy() + LOG.debug(f"All deployed apps: {all_deployed_apps}") + if self.is_track_changed_for_any_charm(all_deployed_apps): + error_msg = ( + "Manifest has track values that require upgrades, rerun with " + "option --upgrade-release for release upgrades." + ) + return Result(ResultType.FAILED, error_msg) + + self.refresh_apps(deployed_machine_apps, "controller") + return Result(ResultType.COMPLETED) + + +class LatestInChannelCoordinator: """Coordinator for refreshing charms in their current channel.""" def __init__( @@ -42,13 +69,30 @@ def __init__( manifest: Manifest, accept_defaults: bool = False, ): - super().__init__(deployment, client, jhelper, manifest) + """Upgrade coordinator. + + Execute plan for conducting an upgrade. + + :client: Helper for interacting with clusterd + :jhelper: Helper for interacting with pylibjuju + :manifest: Manifest object + """ + self.deployment = deployment + self.client = client + self.jhelper = jhelper + self.manifest = manifest self.accept_defaults = accept_defaults self.preseed = self.manifest.deployment_config + def run_plan(self) -> None: + """Execute the upgrade plan.""" + plan = self.get_plan() + run_plan(plan, console) + def get_plan(self) -> list[BaseStep]: """Return the upgrade plan.""" - plan: list[BaseStep] = [LatestInChannel(self.jhelper, self.manifest)] + plan: list[BaseStep] = [] + plan.append(LatestInChannel(self.jhelper, self.manifest)) plan.extend( haproxy_upgrade_steps( @@ -90,10 +134,10 @@ def get_plan(self) -> list[BaseStep]: # TODO: Update MAAS-Anvil sunbeam tag to allow using # sunbeam.commands.upgrades.base.UpgradeFeatures instead of # sunbeam.commands.upgrades.base.UpgradePlugins - # plan.extend( + # plan.append( # UpgradeFeatures(self.deployment, upgrade_release=False), # ) - plan.extend(UpgradePlugins(self.deployment, upgrade_release=False)) + plan.append(UpgradePlugins(self.deployment, upgrade_release=False)) return plan @@ -112,7 +156,6 @@ def get_plan(self) -> list[BaseStep]: @click.pass_context def refresh( ctx: click.Context, - upgrade_release: bool, manifest_path: Path | None = None, accept_defaults: bool = False, ) -> None: @@ -125,18 +168,19 @@ def refresh( client = deployment.get_client() manifest = None - if manifest_path: + if manifest: manifest = Manifest.load( - deployment, manifest_file=manifest, include_defaults=True + deployment, manifest_file=manifest_path, include_defaults=True ) else: manifest = Manifest.get_default_manifest(deployment) - if not manifest: - LOG.debug("Getting latest manifest from cluster db") - manifest = deployment.get_manifest() - - LOG.debug(f"Manifest used for deployment - software: {manifest.software}") + LOG.debug( + f"Manifest used for refresh - preseed: {manifest.deployment_config}" + ) + LOG.debug( + f"Manifest used for refresh - software: {manifest.software_config}" + ) jhelper = JujuHelper(deployment.get_connected_controller()) a = LatestInChannelCoordinator( From 04505425f6a53a9da93dba0d77faf3ccabd3c65e Mon Sep 17 00:00:00 2001 From: Jack Lloyd-Walters Date: Thu, 18 Jul 2024 12:12:20 +0100 Subject: [PATCH 17/24] subordinate unit --- cloud/etc/deploy-haproxy/main.tf | 1 + 1 file changed, 1 insertion(+) diff --git a/cloud/etc/deploy-haproxy/main.tf b/cloud/etc/deploy-haproxy/main.tf index ad6b2be..24ec9fd 100644 --- a/cloud/etc/deploy-haproxy/main.tf +++ b/cloud/etc/deploy-haproxy/main.tf @@ -53,6 +53,7 @@ resource "juju_application" "keepalived" { count = min(length(var.virtual_ip), 1) name = "keepalived" model = data.juju_model.machine_model.name + units = 0 # subordinate charm charm { name = "keepalived" From 883dbd39e7b15bdae65127648a6f14b062a31c2f Mon Sep 17 00:00:00 2001 From: Jack Lloyd-Walters Date: Thu, 18 Jul 2024 12:47:39 +0100 Subject: [PATCH 18/24] remove openstack --- anvil-python/anvil/commands/refresh.py | 74 +++++++++++++++++++++++--- anvil-python/pyproject.toml | 1 - 2 files changed, 68 insertions(+), 7 deletions(-) diff --git a/anvil-python/anvil/commands/refresh.py b/anvil-python/anvil/commands/refresh.py index 6c6ae47..34f17f4 100644 --- a/anvil-python/anvil/commands/refresh.py +++ b/anvil-python/anvil/commands/refresh.py @@ -1,16 +1,15 @@ import logging from pathlib import Path +from typing import Optional import click from rich.console import Console from rich.status import Status from sunbeam.clusterd.client import Client +from sunbeam.commands.juju import JujuStepHelper from sunbeam.commands.upgrades.base import ( UpgradePlugins, ) -from sunbeam.commands.upgrades.intra_channel import ( - LatestInChannel as SunbeamLatestInChannel, -) from sunbeam.jobs.common import ( BaseStep, Result, @@ -19,7 +18,7 @@ ) from sunbeam.jobs.deployment import Deployment from sunbeam.jobs.deployments import Deployment -from sunbeam.jobs.juju import JujuHelper +from sunbeam.jobs.juju import JujuHelper, run_sync from sunbeam.jobs.manifest import Manifest from anvil.commands.haproxy import haproxy_upgrade_steps @@ -33,8 +32,71 @@ console = Console() -# We require a small refactor as compared to sunbeam as we don't have identical charms -class LatestInChannel(SunbeamLatestInChannel): +# We reimplement from sunbeam to avoid openstack dependencies +class LatestInChannel(BaseStep, JujuStepHelper): + def __init__(self, jhelper: JujuHelper, manifest: Manifest): + """Upgrade all charms to latest in current channel. + + :jhelper: Helper for interacting with pylibjuju + """ + super().__init__( + "In channel upgrade", + "Upgrade charms to latest revision in current channel", + ) + self.jhelper = jhelper + self.manifest = manifest + + def is_skip(self, status: Status | None = None) -> Result: + """Step can be skipped if nothing needs refreshing.""" + return Result(ResultType.COMPLETED) + + def is_track_changed_for_any_charm( + self, deployed_apps: dict[str, tuple[str, str, str]] + ) -> bool: + """Check if chanel track is same in manifest and deployed app.""" + for app_name, (charm, channel, revision) in deployed_apps.items(): + if not self.manifest.software_config.charms.get(charm): + LOG.debug(f"Charm not present in manifest: {charm}") + continue + + channel_from_manifest = ( + self.manifest.software_config.charms.get(charm).channel or "" + ) + track_from_manifest = channel_from_manifest.split("/")[0] + track_from_deployed_app = channel.split("/")[0] + # Compare tracks + if track_from_manifest != track_from_deployed_app: + LOG.debug( + "Channel track for app {app_name} different in manifest " + "and actual deployed" + ) + return True + + return False + + def refresh_apps( + self, apps: dict[str, tuple[str, str, str]], model: str + ) -> None: + """Refresh apps in the model. + + If the charm has no revision in manifest and channel mentioned in manifest + and the deployed app is same, run juju refresh. + Otherwise ignore so that terraform plan apply will take care of charm upgrade. + """ + for app_name, (charm, channel, revision) in apps.items(): + manifest_charm = self.manifest.software_config.charms.get(charm) + if not manifest_charm: + continue + + if ( + not manifest_charm.revision + and manifest_charm.channel == channel + ): + app = run_sync(self.jhelper.get_application(app_name, model)) + LOG.debug(f"Running refresh for app {app_name}") + # refresh() checks for any new revision and updates if available + run_sync(app.refresh()) + def run(self, status: Status | None = None) -> Result: """Refresh all charms identified as needing a refresh. diff --git a/anvil-python/pyproject.toml b/anvil-python/pyproject.toml index 42e281d..65c150e 100644 --- a/anvil-python/pyproject.toml +++ b/anvil-python/pyproject.toml @@ -26,7 +26,6 @@ dynamic = [ ] dependencies = [ "pydantic==1.10.14", - "python-openstackclient===6.6.0", "rich", "snap-helpers@ git+https://github.com/skatsaounis/snap-helpers", "sunbeam@ git+https://github.com/canonical/snap-openstack@anvil-0.1#subdirectory=sunbeam-python", From c8713a770299813ec62a565c6a596a57e5f4c8ca Mon Sep 17 00:00:00 2001 From: Jack Lloyd-Walters Date: Thu, 18 Jul 2024 19:55:47 +0100 Subject: [PATCH 19/24] use manifest path, not manifest --- anvil-python/anvil/commands/refresh.py | 49 +++++++++++--------------- 1 file changed, 21 insertions(+), 28 deletions(-) diff --git a/anvil-python/anvil/commands/refresh.py b/anvil-python/anvil/commands/refresh.py index 34f17f4..a368cf4 100644 --- a/anvil-python/anvil/commands/refresh.py +++ b/anvil-python/anvil/commands/refresh.py @@ -1,6 +1,5 @@ import logging from pathlib import Path -from typing import Optional import click from rich.console import Console @@ -17,9 +16,7 @@ run_plan, ) from sunbeam.jobs.deployment import Deployment -from sunbeam.jobs.deployments import Deployment from sunbeam.jobs.juju import JujuHelper, run_sync -from sunbeam.jobs.manifest import Manifest from anvil.commands.haproxy import haproxy_upgrade_steps from anvil.commands.maas_agent import maas_agent_upgrade_steps @@ -54,21 +51,19 @@ def is_track_changed_for_any_charm( self, deployed_apps: dict[str, tuple[str, str, str]] ) -> bool: """Check if chanel track is same in manifest and deployed app.""" - for app_name, (charm, channel, revision) in deployed_apps.items(): - if not self.manifest.software_config.charms.get(charm): + for name, (charm, channel, revision) in deployed_apps.items(): + charm_manifest = (self.manifest.software_config.charms or {}).get( + charm + ) + if not charm_manifest: LOG.debug(f"Charm not present in manifest: {charm}") continue - channel_from_manifest = ( - self.manifest.software_config.charms.get(charm).channel or "" - ) - track_from_manifest = channel_from_manifest.split("/")[0] - track_from_deployed_app = channel.split("/")[0] - # Compare tracks - if track_from_manifest != track_from_deployed_app: + if (charm_manifest.channel or "").split("/")[0] != channel.split( + "/" + )[0]: LOG.debug( - "Channel track for app {app_name} different in manifest " - "and actual deployed" + f"Channel for {name} in manifest does not match deployed" ) return True @@ -83,18 +78,19 @@ def refresh_apps( and the deployed app is same, run juju refresh. Otherwise ignore so that terraform plan apply will take care of charm upgrade. """ - for app_name, (charm, channel, revision) in apps.items(): - manifest_charm = self.manifest.software_config.charms.get(charm) - if not manifest_charm: + for name, (charm, channel, revision) in apps.items(): + charm_manifest = (self.manifest.software_config.charms or {}).get( + charm + ) + if not charm_manifest: continue if ( - not manifest_charm.revision - and manifest_charm.channel == channel + not charm_manifest.revision + and charm_manifest.channel == channel ): - app = run_sync(self.jhelper.get_application(app_name, model)) - LOG.debug(f"Running refresh for app {app_name}") - # refresh() checks for any new revision and updates if available + app = run_sync(self.jhelper.get_application(name, model)) + LOG.debug(f"Running refresh for app {name}") run_sync(app.refresh()) def run(self, status: Status | None = None) -> Result: @@ -110,10 +106,7 @@ def run(self, status: Status | None = None) -> Result: all_deployed_apps = deployed_machine_apps.copy() LOG.debug(f"All deployed apps: {all_deployed_apps}") if self.is_track_changed_for_any_charm(all_deployed_apps): - error_msg = ( - "Manifest has track values that require upgrades, rerun with " - "option --upgrade-release for release upgrades." - ) + error_msg = "MAAS-Anvil cannot upgrade across tracks! Please modify refresh manifest." return Result(ResultType.FAILED, error_msg) self.refresh_apps(deployed_machine_apps, "controller") @@ -230,7 +223,7 @@ def refresh( client = deployment.get_client() manifest = None - if manifest: + if manifest_path: manifest = Manifest.load( deployment, manifest_file=manifest_path, include_defaults=True ) @@ -238,7 +231,7 @@ def refresh( manifest = Manifest.get_default_manifest(deployment) LOG.debug( - f"Manifest used for refresh - preseed: {manifest.deployment_config}" + f"Manifest used for refresh - deployment preseed: {manifest.deployment_config}" ) LOG.debug( f"Manifest used for refresh - software: {manifest.software_config}" From 09653f4810d8c977389490dfa281d00a831b525e Mon Sep 17 00:00:00 2001 From: Jack Lloyd-Walters Date: Thu, 25 Jul 2024 12:55:29 +0100 Subject: [PATCH 20/24] update job definitions --- anvil-python/anvil/commands/haproxy.py | 13 +++++++++---- anvil-python/anvil/commands/maas_agent.py | 5 +---- anvil-python/anvil/commands/postgresql.py | 7 ------- 3 files changed, 10 insertions(+), 15 deletions(-) diff --git a/anvil-python/anvil/commands/haproxy.py b/anvil-python/anvil/commands/haproxy.py index 32f8903..65fd3d4 100644 --- a/anvil-python/anvil/commands/haproxy.py +++ b/anvil-python/anvil/commands/haproxy.py @@ -97,6 +97,15 @@ def get_application_timeout(self) -> int: return HAPROXY_APP_TIMEOUT def has_prompts(self) -> bool: + """Returns true if the step has prompts that it can ask the user. + + :return: True if the step can ask the user for prompts, + False otherwise + """ + # No need to prompt for questions in case of refresh + if self.refresh: + return False + return True def prompt(self, console: Console | None = None) -> None: @@ -185,7 +194,6 @@ def haproxy_install_steps( fqdn: str, accept_defaults: bool, preseed: dict[Any, Any], - refresh: bool = False, ) -> List[BaseStep]: return [ TerraformInitStep(manifest.get_tfhelper("haproxy-plan")), @@ -196,7 +204,6 @@ def haproxy_install_steps( model, accept_defaults=accept_defaults, deployment_preseed=preseed, - refresh=refresh, ), AddHAProxyUnitsStep(client, fqdn, jhelper, model), ] @@ -207,7 +214,6 @@ def haproxy_upgrade_steps( manifest: Manifest, jhelper: JujuHelper, model: str, - accept_defaults: bool, preseed: dict[Any, Any], ) -> List[BaseStep]: return [ @@ -217,7 +223,6 @@ def haproxy_upgrade_steps( manifest, jhelper, model, - accept_defaults=accept_defaults, deployment_preseed=preseed, refresh=True, ), diff --git a/anvil-python/anvil/commands/maas_agent.py b/anvil-python/anvil/commands/maas_agent.py index 49bbded..d6478b6 100644 --- a/anvil-python/anvil/commands/maas_agent.py +++ b/anvil-python/anvil/commands/maas_agent.py @@ -117,13 +117,10 @@ def maas_agent_install_steps( jhelper: JujuHelper, model: str, fqdn: str, - refresh: bool = False, ) -> List[BaseStep]: return [ TerraformInitStep(manifest.get_tfhelper("maas-agent-plan")), - DeployMAASAgentApplicationStep( - client, manifest, jhelper, model, refresh=refresh - ), + DeployMAASAgentApplicationStep(client, manifest, jhelper, model), AddMAASAgentUnitsStep(client, fqdn, jhelper, model), ] diff --git a/anvil-python/anvil/commands/postgresql.py b/anvil-python/anvil/commands/postgresql.py index b7410e0..f304923 100644 --- a/anvil-python/anvil/commands/postgresql.py +++ b/anvil-python/anvil/commands/postgresql.py @@ -50,7 +50,6 @@ def postgresql_install_steps( fqdn: str, accept_defaults: bool, preseed: dict[Any, Any], - refresh: bool = False, ) -> List[BaseStep]: return [ TerraformInitStep(manifest.get_tfhelper("postgresql-plan")), @@ -61,7 +60,6 @@ def postgresql_install_steps( model, accept_defaults=accept_defaults, deployment_preseed=preseed, - refresh=refresh, ), AddPostgreSQLUnitsStep(client, fqdn, jhelper, model), ] @@ -72,7 +70,6 @@ def postgresql_upgrade_steps( manifest: Manifest, jhelper: JujuHelper, model: str, - accept_defaults: bool, preseed: dict[Any, Any], ) -> List[BaseStep]: return [ @@ -82,7 +79,6 @@ def postgresql_upgrade_steps( manifest, jhelper, model, - accept_defaults=accept_defaults, deployment_preseed=preseed, refresh=True, ), @@ -176,9 +172,6 @@ def extra_tfvars(self) -> dict[str, Any]: ) return variables - def has_prompts(self) -> bool: - return True - class ReapplyPostgreSQLTerraformPlanStep(DeployMachineApplicationStep): """Reapply PostgreSQL Terraform plan""" From 2d79800fc2f850a98a50988aa65f5983f5392c2d Mon Sep 17 00:00:00 2001 From: Jack Lloyd-Walters Date: Thu, 25 Jul 2024 12:55:36 +0100 Subject: [PATCH 21/24] move refresh to correct filepath --- anvil-python/anvil/commands/refresh.py | 200 +----------------- .../anvil/commands/upgrades/__init__.py | 0 .../anvil/commands/upgrades/intra_channel.py | 190 +++++++++++++++++ 3 files changed, 200 insertions(+), 190 deletions(-) create mode 100644 anvil-python/anvil/commands/upgrades/__init__.py create mode 100644 anvil-python/anvil/commands/upgrades/intra_channel.py diff --git a/anvil-python/anvil/commands/refresh.py b/anvil-python/anvil/commands/refresh.py index a368cf4..314df22 100644 --- a/anvil-python/anvil/commands/refresh.py +++ b/anvil-python/anvil/commands/refresh.py @@ -3,25 +3,13 @@ import click from rich.console import Console -from rich.status import Status -from sunbeam.clusterd.client import Client -from sunbeam.commands.juju import JujuStepHelper -from sunbeam.commands.upgrades.base import ( - UpgradePlugins, -) from sunbeam.jobs.common import ( - BaseStep, - Result, - ResultType, run_plan, ) -from sunbeam.jobs.deployment import Deployment -from sunbeam.jobs.juju import JujuHelper, run_sync +from sunbeam.jobs.juju import JujuHelper +from sunbeam.jobs.manifest import AddManifestStep -from anvil.commands.haproxy import haproxy_upgrade_steps -from anvil.commands.maas_agent import maas_agent_upgrade_steps -from anvil.commands.maas_region import maas_region_upgrade_steps -from anvil.commands.postgresql import postgresql_upgrade_steps +from anvil.commands.upgrades.intra_channel import LatestInChannelCoordinator from anvil.jobs.manifest import Manifest from anvil.provider.local.deployment import LocalDeployment @@ -29,174 +17,6 @@ console = Console() -# We reimplement from sunbeam to avoid openstack dependencies -class LatestInChannel(BaseStep, JujuStepHelper): - def __init__(self, jhelper: JujuHelper, manifest: Manifest): - """Upgrade all charms to latest in current channel. - - :jhelper: Helper for interacting with pylibjuju - """ - super().__init__( - "In channel upgrade", - "Upgrade charms to latest revision in current channel", - ) - self.jhelper = jhelper - self.manifest = manifest - - def is_skip(self, status: Status | None = None) -> Result: - """Step can be skipped if nothing needs refreshing.""" - return Result(ResultType.COMPLETED) - - def is_track_changed_for_any_charm( - self, deployed_apps: dict[str, tuple[str, str, str]] - ) -> bool: - """Check if chanel track is same in manifest and deployed app.""" - for name, (charm, channel, revision) in deployed_apps.items(): - charm_manifest = (self.manifest.software_config.charms or {}).get( - charm - ) - if not charm_manifest: - LOG.debug(f"Charm not present in manifest: {charm}") - continue - - if (charm_manifest.channel or "").split("/")[0] != channel.split( - "/" - )[0]: - LOG.debug( - f"Channel for {name} in manifest does not match deployed" - ) - return True - - return False - - def refresh_apps( - self, apps: dict[str, tuple[str, str, str]], model: str - ) -> None: - """Refresh apps in the model. - - If the charm has no revision in manifest and channel mentioned in manifest - and the deployed app is same, run juju refresh. - Otherwise ignore so that terraform plan apply will take care of charm upgrade. - """ - for name, (charm, channel, revision) in apps.items(): - charm_manifest = (self.manifest.software_config.charms or {}).get( - charm - ) - if not charm_manifest: - continue - - if ( - not charm_manifest.revision - and charm_manifest.channel == channel - ): - app = run_sync(self.jhelper.get_application(name, model)) - LOG.debug(f"Running refresh for app {name}") - run_sync(app.refresh()) - - def run(self, status: Status | None = None) -> Result: - """Refresh all charms identified as needing a refresh. - - If the manifest has charm channel and revision, terraform apply should update - the charms. - If the manifest has only charm, then juju refresh is required if channel is - same as deployed charm, otherwise juju upgrade charm. - """ - deployed_machine_apps = self.get_charm_deployed_versions("controller") - - all_deployed_apps = deployed_machine_apps.copy() - LOG.debug(f"All deployed apps: {all_deployed_apps}") - if self.is_track_changed_for_any_charm(all_deployed_apps): - error_msg = "MAAS-Anvil cannot upgrade across tracks! Please modify refresh manifest." - return Result(ResultType.FAILED, error_msg) - - self.refresh_apps(deployed_machine_apps, "controller") - return Result(ResultType.COMPLETED) - - -class LatestInChannelCoordinator: - """Coordinator for refreshing charms in their current channel.""" - - def __init__( - self, - deployment: Deployment, - client: Client, - jhelper: JujuHelper, - manifest: Manifest, - accept_defaults: bool = False, - ): - """Upgrade coordinator. - - Execute plan for conducting an upgrade. - - :client: Helper for interacting with clusterd - :jhelper: Helper for interacting with pylibjuju - :manifest: Manifest object - """ - self.deployment = deployment - self.client = client - self.jhelper = jhelper - self.manifest = manifest - self.accept_defaults = accept_defaults - self.preseed = self.manifest.deployment_config - - def run_plan(self) -> None: - """Execute the upgrade plan.""" - plan = self.get_plan() - run_plan(plan, console) - - def get_plan(self) -> list[BaseStep]: - """Return the upgrade plan.""" - plan: list[BaseStep] = [] - plan.append(LatestInChannel(self.jhelper, self.manifest)) - - plan.extend( - haproxy_upgrade_steps( - self.client, - self.manifest, - self.jhelper, - self.deployment.infrastructure_model, - self.accept_defaults, - self.preseed, - ) - ) - plan.extend( - postgresql_upgrade_steps( - self.client, - self.manifest, - self.jhelper, - self.deployment.infrastructure_model, - self.accept_defaults, - self.preseed, - ) - ) - plan.extend( - maas_region_upgrade_steps( - self.client, - self.manifest, - self.jhelper, - self.deployment.infrastructure_model, - ) - ) - plan.extend( - maas_agent_upgrade_steps( - self.client, - self.manifest, - self.jhelper, - self.deployment.infrastructure_model, - ) - ) - - # TODO: Update MAAS-Anvil sunbeam tag to allow using - # sunbeam.commands.upgrades.base.UpgradeFeatures instead of - # sunbeam.commands.upgrades.base.UpgradePlugins - # plan.append( - # UpgradeFeatures(self.deployment, upgrade_release=False), - # ) - plan.append(UpgradePlugins(self.deployment, upgrade_release=False)) - - return plan - - @click.command() @click.option( "-m", @@ -205,14 +25,10 @@ def get_plan(self) -> list[BaseStep]: help="Manifest file.", type=click.Path(exists=True, dir_okay=False, path_type=Path), ) -@click.option( - "-a", "--accept-defaults", help="Accept all defaults.", is_flag=True -) @click.pass_context def refresh( ctx: click.Context, manifest_path: Path | None = None, - accept_defaults: bool = False, ) -> None: """Refresh deployment. @@ -227,8 +43,13 @@ def refresh( manifest = Manifest.load( deployment, manifest_file=manifest_path, include_defaults=True ) - else: - manifest = Manifest.get_default_manifest(deployment) + run_plan([AddManifestStep(client, manifest)], console) + + if not manifest: + LOG.debug("Getting latest manifest from cluster db") + manifest = Manifest.load_latest_from_clusterdb( + deployment, include_defaults=True + ) LOG.debug( f"Manifest used for refresh - deployment preseed: {manifest.deployment_config}" @@ -243,7 +64,6 @@ def refresh( client, jhelper, manifest, - accept_defaults=accept_defaults, ) a.run_plan() diff --git a/anvil-python/anvil/commands/upgrades/__init__.py b/anvil-python/anvil/commands/upgrades/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/anvil-python/anvil/commands/upgrades/intra_channel.py b/anvil-python/anvil/commands/upgrades/intra_channel.py new file mode 100644 index 0000000..e259e44 --- /dev/null +++ b/anvil-python/anvil/commands/upgrades/intra_channel.py @@ -0,0 +1,190 @@ +import logging + +from rich.console import Console +from rich.status import Status +from sunbeam.clusterd.client import Client +from sunbeam.commands.juju import JujuStepHelper +from sunbeam.commands.upgrades.base import ( + UpgradePlugins, +) +from sunbeam.jobs.common import ( + BaseStep, + Result, + ResultType, + run_plan, +) +from sunbeam.jobs.deployment import Deployment +from sunbeam.jobs.juju import JujuHelper, run_sync + +from anvil.commands.haproxy import haproxy_upgrade_steps +from anvil.commands.maas_agent import maas_agent_upgrade_steps +from anvil.commands.maas_region import maas_region_upgrade_steps +from anvil.commands.postgresql import postgresql_upgrade_steps +from anvil.jobs.manifest import Manifest + +LOG = logging.getLogger(__name__) +console = Console() + + +# We reimplement from sunbeam to avoid openstack dependencies +class LatestInChannel(BaseStep, JujuStepHelper): + def __init__(self, jhelper: JujuHelper, manifest: Manifest): + """Upgrade all charms to latest in current channel. + + :jhelper: Helper for interacting with pylibjuju + """ + super().__init__( + "In channel upgrade", + "Upgrade charms to latest revision in current channel", + ) + self.jhelper = jhelper + self.manifest = manifest + + def is_skip(self, status: Status | None = None) -> Result: + """Step can be skipped if nothing needs refreshing.""" + return Result(ResultType.COMPLETED) + + def is_track_changed_for_any_charm( + self, deployed_apps: dict[str, tuple[str, str, str]] + ) -> bool: + """Check if chanel track is same in manifest and deployed app.""" + for name, (charm, channel, revision) in deployed_apps.items(): + charm_manifest = (self.manifest.software_config.charms or {}).get( + charm + ) + if not charm_manifest: + LOG.debug(f"Charm not present in manifest: {charm}") + continue + + if (charm_manifest.channel or "").split("/")[0] != channel.split( + "/" + )[0]: + LOG.debug( + f"Channel for {name} in manifest does not match deployed" + ) + return True + + return False + + def refresh_apps( + self, apps: dict[str, tuple[str, str, str]], model: str + ) -> None: + """Refresh apps in the model. + + If the charm has no revision in manifest and channel mentioned in manifest + and the deployed app is same, run juju refresh. + Otherwise ignore so that terraform plan apply will take care of charm upgrade. + """ + for name, (charm, channel, revision) in apps.items(): + charm_manifest = (self.manifest.software_config.charms or {}).get( + charm + ) + if not charm_manifest: + continue + + if ( + not charm_manifest.revision + and charm_manifest.channel == channel + ): + app = run_sync(self.jhelper.get_application(name, model)) + LOG.debug(f"Running refresh for app {name}") + run_sync(app.refresh()) + + def run(self, status: Status | None = None) -> Result: + """Refresh all charms identified as needing a refresh. + + If the manifest has charm channel and revision, terraform apply should update + the charms. + If the manifest has only charm, then juju refresh is required if channel is + same as deployed charm, otherwise juju upgrade charm. + """ + deployed_machine_apps = self.get_charm_deployed_versions("controller") + + all_deployed_apps = deployed_machine_apps.copy() + LOG.debug(f"All deployed apps: {all_deployed_apps}") + if self.is_track_changed_for_any_charm(all_deployed_apps): + error_msg = "MAAS-Anvil cannot upgrade across tracks! Please modify refresh manifest." + return Result(ResultType.FAILED, error_msg) + + self.refresh_apps(deployed_machine_apps, "controller") + return Result(ResultType.COMPLETED) + + +class LatestInChannelCoordinator: + """Coordinator for refreshing charms in their current channel.""" + + def __init__( + self, + deployment: Deployment, + client: Client, + jhelper: JujuHelper, + manifest: Manifest, + ): + """Upgrade coordinator. + + Execute plan for conducting an upgrade. + + :client: Helper for interacting with clusterd + :jhelper: Helper for interacting with pylibjuju + :manifest: Manifest object + """ + self.deployment = deployment + self.client = client + self.jhelper = jhelper + self.manifest = manifest + self.preseed = self.manifest.deployment_config + + def run_plan(self) -> None: + """Execute the upgrade plan.""" + plan = self.get_plan() + run_plan(plan, console) + + def get_plan(self) -> list[BaseStep]: + """Return the upgrade plan.""" + plan: list[BaseStep] = [] + plan.append(LatestInChannel(self.jhelper, self.manifest)) + + plan.extend( + haproxy_upgrade_steps( + self.client, + self.manifest, + self.jhelper, + self.deployment.infrastructure_model, + self.preseed, + ) + ) + plan.extend( + postgresql_upgrade_steps( + self.client, + self.manifest, + self.jhelper, + self.deployment.infrastructure_model, + self.preseed, + ) + ) + plan.extend( + maas_region_upgrade_steps( + self.client, + self.manifest, + self.jhelper, + self.deployment.infrastructure_model, + ) + ) + plan.extend( + maas_agent_upgrade_steps( + self.client, + self.manifest, + self.jhelper, + self.deployment.infrastructure_model, + ) + ) + + # TODO: Update MAAS-Anvil sunbeam tag to allow using + # sunbeam.commands.upgrades.base.UpgradeFeatures instead of + # sunbeam.commands.upgrades.base.UpgradePlugins + # plan.append( + # UpgradeFeatures(self.deployment, upgrade_release=False), + # ) + plan.append(UpgradePlugins(self.deployment, upgrade_release=False)) + + return plan From a17e646727eece5a963d3eaa8f5da2c20f00dab1 Mon Sep 17 00:00:00 2001 From: Jack Lloyd-Walters Date: Fri, 26 Jul 2024 09:11:15 +0100 Subject: [PATCH 22/24] add prompts back to postgresql --- anvil-python/anvil/commands/postgresql.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/anvil-python/anvil/commands/postgresql.py b/anvil-python/anvil/commands/postgresql.py index feba171..89eb1b4 100644 --- a/anvil-python/anvil/commands/postgresql.py +++ b/anvil-python/anvil/commands/postgresql.py @@ -172,6 +172,18 @@ def extra_tfvars(self) -> dict[str, Any]: ) return variables + def has_prompts(self) -> bool: + """Returns true if the step has prompts that it can ask the user. + + :return: True if the step can ask the user for prompts, + False otherwise + """ + # No need to prompt for questions in case of refresh + if self.refresh: + return False + + return True + class ReapplyPostgreSQLTerraformPlanStep(DeployMachineApplicationStep): """Reapply PostgreSQL Terraform plan""" From 636b2ce87e65f29e007eb84dd038103afb60cebe Mon Sep 17 00:00:00 2001 From: Jack Lloyd-Walters Date: Fri, 26 Jul 2024 09:14:59 +0100 Subject: [PATCH 23/24] remove extra refresh --- anvil-python/anvil/commands/maas_region.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/anvil-python/anvil/commands/maas_region.py b/anvil-python/anvil/commands/maas_region.py index 37e953a..4f60ef2 100644 --- a/anvil-python/anvil/commands/maas_region.py +++ b/anvil-python/anvil/commands/maas_region.py @@ -125,13 +125,10 @@ def maas_region_install_steps( jhelper: JujuHelper, model: str, fqdn: str, - refresh: bool = False, ) -> List[BaseStep]: return [ TerraformInitStep(manifest.get_tfhelper("maas-region-plan")), - DeployMAASRegionApplicationStep( - client, manifest, jhelper, model, refresh - ), + DeployMAASRegionApplicationStep(client, manifest, jhelper, model), AddMAASRegionUnitsStep(client, fqdn, jhelper, model), ] From c10ece1020c980269e886d2824e16532b9b7da08 Mon Sep 17 00:00:00 2001 From: Jack Lloyd-Walters Date: Fri, 26 Jul 2024 09:44:56 +0100 Subject: [PATCH 24/24] license and moving --- anvil-python/anvil/commands/refresh.py | 15 ++++++ anvil-python/anvil/commands/upgrades/base.py | 54 +++++++++++++++++++ .../anvil/commands/upgrades/intra_channel.py | 30 +++++++---- 3 files changed, 88 insertions(+), 11 deletions(-) create mode 100644 anvil-python/anvil/commands/upgrades/base.py diff --git a/anvil-python/anvil/commands/refresh.py b/anvil-python/anvil/commands/refresh.py index 314df22..a4a311e 100644 --- a/anvil-python/anvil/commands/refresh.py +++ b/anvil-python/anvil/commands/refresh.py @@ -1,3 +1,18 @@ +# Copyright (c) 2024 Canonical Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +# implied. +# See the License for the specific language governing permissions and +# limitations under the License. + import logging from pathlib import Path diff --git a/anvil-python/anvil/commands/upgrades/base.py b/anvil-python/anvil/commands/upgrades/base.py new file mode 100644 index 0000000..4e4747a --- /dev/null +++ b/anvil-python/anvil/commands/upgrades/base.py @@ -0,0 +1,54 @@ +# Copyright (c) 2024 Canonical Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +# implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import logging + +from rich.console import Console +from rich.status import Status +from sunbeam.jobs.common import ( + BaseStep, + Result, + ResultType, +) +from sunbeam.jobs.deployment import Deployment + +from anvil.jobs.plugin import PluginManager + +LOG = logging.getLogger(__name__) +console = Console() + + +class UpgradePlugins(BaseStep): + def __init__( + self, + deployment: Deployment, + upgrade_release: bool = False, + ): + """Upgrade plugins. + + :client: Helper for interacting with clusterd + :upgrade_release: Whether to upgrade channel + """ + super().__init__("Validation", "Running pre-upgrade validation") + self.deployment = deployment + self.upgrade_release = upgrade_release + + def run(self, status: Status | None = None) -> Result: + PluginManager.update_plugins( + self.deployment, + repos=["core"], + upgrade_release=self.upgrade_release, + ) + return Result(ResultType.COMPLETED) diff --git a/anvil-python/anvil/commands/upgrades/intra_channel.py b/anvil-python/anvil/commands/upgrades/intra_channel.py index e259e44..6242391 100644 --- a/anvil-python/anvil/commands/upgrades/intra_channel.py +++ b/anvil-python/anvil/commands/upgrades/intra_channel.py @@ -1,12 +1,24 @@ +# Copyright (c) 2024 Canonical Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +# implied. +# See the License for the specific language governing permissions and +# limitations under the License. + import logging from rich.console import Console from rich.status import Status from sunbeam.clusterd.client import Client from sunbeam.commands.juju import JujuStepHelper -from sunbeam.commands.upgrades.base import ( - UpgradePlugins, -) from sunbeam.jobs.common import ( BaseStep, Result, @@ -20,13 +32,15 @@ from anvil.commands.maas_agent import maas_agent_upgrade_steps from anvil.commands.maas_region import maas_region_upgrade_steps from anvil.commands.postgresql import postgresql_upgrade_steps +from anvil.commands.upgrades.base import ( + UpgradePlugins, +) from anvil.jobs.manifest import Manifest LOG = logging.getLogger(__name__) console = Console() -# We reimplement from sunbeam to avoid openstack dependencies class LatestInChannel(BaseStep, JujuStepHelper): def __init__(self, jhelper: JujuHelper, manifest: Manifest): """Upgrade all charms to latest in current channel. @@ -103,7 +117,7 @@ def run(self, status: Status | None = None) -> Result: all_deployed_apps = deployed_machine_apps.copy() LOG.debug(f"All deployed apps: {all_deployed_apps}") if self.is_track_changed_for_any_charm(all_deployed_apps): - error_msg = "MAAS-Anvil cannot upgrade across tracks! Please modify refresh manifest." + error_msg = "MAAS Anvil cannot upgrade across tracks! Please modify refresh manifest." return Result(ResultType.FAILED, error_msg) self.refresh_apps(deployed_machine_apps, "controller") @@ -179,12 +193,6 @@ def get_plan(self) -> list[BaseStep]: ) ) - # TODO: Update MAAS-Anvil sunbeam tag to allow using - # sunbeam.commands.upgrades.base.UpgradeFeatures instead of - # sunbeam.commands.upgrades.base.UpgradePlugins - # plan.append( - # UpgradeFeatures(self.deployment, upgrade_release=False), - # ) plan.append(UpgradePlugins(self.deployment, upgrade_release=False)) return plan