From 88aabe7e0a3df6e6f6a2075dab748a91122571e1 Mon Sep 17 00:00:00 2001 From: Guillaume Boutry Date: Fri, 23 Aug 2024 11:06:26 +0200 Subject: [PATCH 1/2] Refactor package structure Changes: - `jobs` -> `core`: this package outgrown its initial purpose and is the package where we put important classes to manage the deployment - `commands` -> `steps`: Lots of the modules in the `commands` package held no commands but where a registry of steps to use to deploy the different parts. The long term goal is to create import rules, for example: - core is forbidden to import from steps and commands Signed-off-by: Guillaume Boutry --- sunbeam-python/sunbeam/commands/configure.py | 72 +++++----- .../sunbeam/commands/dashboard_url.py | 8 +- .../sunbeam/commands/generate_cloud_config.py | 16 +-- sunbeam-python/sunbeam/commands/inspect.py | 10 +- sunbeam-python/sunbeam/commands/juju_utils.py | 6 +- sunbeam-python/sunbeam/commands/launch.py | 8 +- sunbeam-python/sunbeam/commands/manifest.py | 6 +- sunbeam-python/sunbeam/commands/openrc.py | 8 +- sunbeam-python/sunbeam/commands/proxy.py | 20 +-- sunbeam-python/sunbeam/commands/refresh.py | 14 +- sunbeam-python/sunbeam/commands/resize.py | 12 +- sunbeam-python/sunbeam/commands/utils.py | 8 +- .../{commands/upgrades => core}/__init__.py | 0 .../sunbeam/{jobs => core}/checks.py | 2 +- .../sunbeam/{jobs => core}/common.py | 0 .../sunbeam/{jobs => core}/deployment.py | 12 +- .../sunbeam/{jobs => core}/deployments.py | 4 +- .../sunbeam/{jobs => core}/feature.py | 6 +- sunbeam-python/sunbeam/{jobs => core}/juju.py | 2 +- sunbeam-python/sunbeam/{jobs => core}/k8s.py | 2 +- .../sunbeam/{jobs => core}/manifest.py | 2 +- sunbeam-python/sunbeam/core/openstack.py | 16 +++ .../{commands => core}/openstack_api.py | 4 +- .../sunbeam/{jobs => core}/questions.py | 0 .../sunbeam/{jobs => core}/steps.py | 12 +- .../sunbeam/{commands => core}/terraform.py | 4 +- sunbeam-python/sunbeam/features/ca/feature.py | 40 +++--- .../sunbeam/features/caas/feature.py | 22 +-- .../sunbeam/features/dns/feature.py | 14 +- .../sunbeam/features/images_sync/feature.py | 4 +- .../sunbeam/features/interface/v1/base.py | 8 +- .../features/interface/v1/openstack.py | 27 ++-- .../sunbeam/features/interface/v1/tls.py | 18 +-- .../sunbeam/features/ldap/feature.py | 22 +-- .../sunbeam/features/loadbalancer/feature.py | 4 +- .../sunbeam/features/observability/feature.py | 44 +++--- .../sunbeam/features/orchestration/feature.py | 4 +- .../sunbeam/features/pro/feature.py | 12 +- .../sunbeam/features/secrets/feature.py | 4 +- .../sunbeam/features/telemetry/feature.py | 12 +- .../sunbeam/features/validation/feature.py | 30 ++-- .../sunbeam/features/vault/feature.py | 4 +- sunbeam-python/sunbeam/main.py | 4 +- sunbeam-python/sunbeam/provider/base.py | 2 +- sunbeam-python/sunbeam/provider/commands.py | 8 +- .../sunbeam/provider/local/commands.py | 128 +++++++++--------- .../sunbeam/provider/local/deployment.py | 36 ++--- .../sunbeam/provider/local/steps.py | 18 +-- .../sunbeam/provider/maas/client.py | 4 +- .../sunbeam/provider/maas/commands.py | 98 +++++++------- .../sunbeam/provider/maas/deployment.py | 8 +- sunbeam-python/sunbeam/provider/maas/steps.py | 52 +++---- .../sunbeam/{jobs => steps}/__init__.py | 0 .../{commands => steps}/bootstrap_state.py | 2 +- .../{commands => steps}/certificates.py | 6 +- .../{commands => steps}/cluster_status.py | 10 +- .../sunbeam/{commands => steps}/clusterd.py | 10 +- .../sunbeam/{commands => steps}/hypervisor.py | 18 +-- .../sunbeam/{commands => steps}/juju.py | 6 +- .../sunbeam/{commands => steps}/k8s.py | 18 +-- .../sunbeam/{commands => steps}/microceph.py | 17 ++- .../sunbeam/{commands => steps}/microk8s.py | 20 +-- .../sunbeam/{commands => steps}/mysql.py | 6 +- .../sunbeam/{commands => steps}/openstack.py | 22 +-- .../{commands => steps}/sunbeam_machine.py | 10 +- .../steps/upgrades}/__init__.py | 0 .../{commands => steps}/upgrades/base.py | 10 +- .../upgrades/inter_channel.py | 30 ++-- .../upgrades/intra_channel.py | 24 ++-- sunbeam-python/sunbeam/utils.py | 2 +- .../unit/sunbeam/commands/test_configure.py | 12 +- .../commands/test_generate_cloud_config.py | 6 +- .../tests/unit/sunbeam/commands/test_proxy.py | 2 +- .../sunbeam/{jobs => core}/test_checks.py | 22 +-- .../sunbeam/{jobs => core}/test_common.py | 8 +- .../sunbeam/{jobs => core}/test_deployment.py | 10 +- .../unit/sunbeam/{jobs => core}/test_juju.py | 2 +- .../sunbeam/{jobs => core}/test_manifest.py | 4 +- .../{commands => core}/test_openstack_api.py | 26 ++-- .../unit/sunbeam/{jobs => core}/test_steps.py | 12 +- .../{commands => core}/test_terraform.py | 12 +- .../tests/unit/sunbeam/features/__init__.py | 0 .../{plugins => features}/test_base.py | 4 +- .../{plugins => features}/test_ldap.py | 6 +- .../test_observability.py | 8 +- .../{plugins => features}/test_openstack.py | 6 +- .../sunbeam/{plugins => features}/test_pro.py | 6 +- .../sunbeam/{plugins => features}/test_tls.py | 12 +- .../{plugins => features}/test_validation.py | 0 .../unit/sunbeam/provider/local/test_steps.py | 8 +- .../unit/sunbeam/provider/maas/test_maas.py | 12 +- .../tests/unit/sunbeam/steps/__init__.py | 0 .../{commands => steps}/test_hypervisor.py | 34 ++--- .../sunbeam/{commands => steps}/test_juju.py | 20 +-- .../sunbeam/{commands => steps}/test_k8s.py | 22 +-- .../{commands => steps}/test_microceph.py | 8 +- .../{commands => steps}/test_microk8s.py | 20 +-- .../sunbeam/{commands => steps}/test_mysql.py | 18 +-- .../{commands => steps}/test_openstack.py | 54 ++++---- .../{commands => steps}/upgrades/test_base.py | 8 +- .../tests/unit/sunbeam/test_clusterd.py | 6 +- 101 files changed, 734 insertions(+), 726 deletions(-) rename sunbeam-python/sunbeam/{commands/upgrades => core}/__init__.py (100%) rename sunbeam-python/sunbeam/{jobs => core}/checks.py (99%) rename sunbeam-python/sunbeam/{jobs => core}/common.py (100%) rename sunbeam-python/sunbeam/{jobs => core}/deployment.py (97%) rename sunbeam-python/sunbeam/{jobs => core}/deployments.py (98%) rename sunbeam-python/sunbeam/{jobs => core}/feature.py (98%) rename sunbeam-python/sunbeam/{jobs => core}/juju.py (99%) rename sunbeam-python/sunbeam/{jobs => core}/k8s.py (98%) rename sunbeam-python/sunbeam/{jobs => core}/manifest.py (99%) create mode 100644 sunbeam-python/sunbeam/core/openstack.py rename sunbeam-python/sunbeam/{commands => core}/openstack_api.py (97%) rename sunbeam-python/sunbeam/{jobs => core}/questions.py (100%) rename sunbeam-python/sunbeam/{jobs => core}/steps.py (98%) rename sunbeam-python/sunbeam/{commands => core}/terraform.py (99%) rename sunbeam-python/sunbeam/{jobs => steps}/__init__.py (100%) rename sunbeam-python/sunbeam/{commands => steps}/bootstrap_state.py (95%) rename sunbeam-python/sunbeam/{commands => steps}/certificates.py (95%) rename sunbeam-python/sunbeam/{commands => steps}/cluster_status.py (97%) rename sunbeam-python/sunbeam/{commands => steps}/clusterd.py (98%) rename sunbeam-python/sunbeam/{commands => steps}/hypervisor.py (95%) rename sunbeam-python/sunbeam/{commands => steps}/juju.py (99%) rename sunbeam-python/sunbeam/{commands => steps}/k8s.py (97%) rename sunbeam-python/sunbeam/{commands => steps}/microceph.py (97%) rename sunbeam-python/sunbeam/{commands => steps}/microk8s.py (95%) rename sunbeam-python/sunbeam/{commands => steps}/mysql.py (96%) rename sunbeam-python/sunbeam/{commands => steps}/openstack.py (96%) rename sunbeam-python/sunbeam/{commands => steps}/sunbeam_machine.py (94%) rename sunbeam-python/{tests/unit/sunbeam/plugins => sunbeam/steps/upgrades}/__init__.py (100%) rename sunbeam-python/sunbeam/{commands => steps}/upgrades/base.py (90%) rename sunbeam-python/sunbeam/{commands => steps}/upgrades/inter_channel.py (94%) rename sunbeam-python/sunbeam/{commands => steps}/upgrades/intra_channel.py (90%) rename sunbeam-python/tests/unit/sunbeam/{jobs => core}/test_checks.py (91%) rename sunbeam-python/tests/unit/sunbeam/{jobs => core}/test_common.py (96%) rename sunbeam-python/tests/unit/sunbeam/{jobs => core}/test_deployment.py (96%) rename sunbeam-python/tests/unit/sunbeam/{jobs => core}/test_juju.py (99%) rename sunbeam-python/tests/unit/sunbeam/{jobs => core}/test_manifest.py (99%) rename sunbeam-python/tests/unit/sunbeam/{commands => core}/test_openstack_api.py (77%) rename sunbeam-python/tests/unit/sunbeam/{jobs => core}/test_steps.py (97%) rename sunbeam-python/tests/unit/sunbeam/{commands => core}/test_terraform.py (93%) create mode 100644 sunbeam-python/tests/unit/sunbeam/features/__init__.py rename sunbeam-python/tests/unit/sunbeam/{plugins => features}/test_base.py (99%) rename sunbeam-python/tests/unit/sunbeam/{plugins => features}/test_ldap.py (98%) rename sunbeam-python/tests/unit/sunbeam/{plugins => features}/test_observability.py (98%) rename sunbeam-python/tests/unit/sunbeam/{plugins => features}/test_openstack.py (97%) rename sunbeam-python/tests/unit/sunbeam/{plugins => features}/test_pro.py (96%) rename sunbeam-python/tests/unit/sunbeam/{plugins => features}/test_tls.py (98%) rename sunbeam-python/tests/unit/sunbeam/{plugins => features}/test_validation.py (100%) create mode 100644 sunbeam-python/tests/unit/sunbeam/steps/__init__.py rename sunbeam-python/tests/unit/sunbeam/{commands => steps}/test_hypervisor.py (89%) rename sunbeam-python/tests/unit/sunbeam/{commands => steps}/test_juju.py (97%) rename sunbeam-python/tests/unit/sunbeam/{commands => steps}/test_k8s.py (94%) rename sunbeam-python/tests/unit/sunbeam/{commands => steps}/test_microceph.py (94%) rename sunbeam-python/tests/unit/sunbeam/{commands => steps}/test_microk8s.py (94%) rename sunbeam-python/tests/unit/sunbeam/{commands => steps}/test_mysql.py (85%) rename sunbeam-python/tests/unit/sunbeam/{commands => steps}/test_openstack.py (92%) rename sunbeam-python/tests/unit/sunbeam/{commands => steps}/upgrades/test_base.py (94%) diff --git a/sunbeam-python/sunbeam/commands/configure.py b/sunbeam-python/sunbeam/commands/configure.py index b03dda67..74b7effb 100644 --- a/sunbeam-python/sunbeam/commands/configure.py +++ b/sunbeam-python/sunbeam/commands/configure.py @@ -21,21 +21,21 @@ import click from rich.console import Console -import sunbeam.jobs.questions +import sunbeam.core.questions from sunbeam import utils from sunbeam.clusterd.client import Client -from sunbeam.commands.terraform import ( - TerraformException, - TerraformHelper, - TerraformInitStep, -) -from sunbeam.jobs.common import BaseStep, Result, ResultType, Status -from sunbeam.jobs.juju import ( +from sunbeam.core.common import BaseStep, Result, ResultType, Status +from sunbeam.core.juju import ( ActionFailedException, JujuHelper, LeaderNotFoundException, run_sync, ) +from sunbeam.core.terraform import ( + TerraformException, + TerraformHelper, + TerraformInitStep, +) CLOUD_CONFIG_SECTION = "CloudConfig" LOG = logging.getLogger(__name__) @@ -44,31 +44,31 @@ def user_questions(): return { - "run_demo_setup": sunbeam.jobs.questions.ConfirmQuestion( + "run_demo_setup": sunbeam.core.questions.ConfirmQuestion( "Populate OpenStack cloud with demo user, default images, flavors etc", default_value=True, ), - "username": sunbeam.jobs.questions.PromptQuestion( + "username": sunbeam.core.questions.PromptQuestion( "Username to use for access to OpenStack", default_value="demo" ), - "password": sunbeam.jobs.questions.PasswordPromptQuestion( + "password": sunbeam.core.questions.PasswordPromptQuestion( "Password to use for access to OpenStack", default_function=utils.generate_password, password=True, ), - "cidr": sunbeam.jobs.questions.PromptQuestion( + "cidr": sunbeam.core.questions.PromptQuestion( "Network range to use for project network", default_value="192.168.122.0/24", validation_function=ipaddress.ip_network, ), - "nameservers": sunbeam.jobs.questions.PromptQuestion( + "nameservers": sunbeam.core.questions.PromptQuestion( "List of nameservers guests should use for DNS resolution", default_function=lambda: " ".join(utils.get_nameservers()), ), - "security_group_rules": sunbeam.jobs.questions.ConfirmQuestion( + "security_group_rules": sunbeam.core.questions.ConfirmQuestion( "Enable ping and SSH access to instances?", default_value=True ), - "remote_access_location": sunbeam.jobs.questions.PromptQuestion( + "remote_access_location": sunbeam.core.questions.PromptQuestion( "Local or remote access to VMs", choices=[utils.LOCAL_ACCESS, utils.REMOTE_ACCESS], default_value=utils.LOCAL_ACCESS, @@ -78,32 +78,32 @@ def user_questions(): def ext_net_questions(): return { - "cidr": sunbeam.jobs.questions.PromptQuestion( + "cidr": sunbeam.core.questions.PromptQuestion( "CIDR of network to use for external networking", default_value="10.20.20.0/24", validation_function=ipaddress.ip_network, ), - "gateway": sunbeam.jobs.questions.PromptQuestion( + "gateway": sunbeam.core.questions.PromptQuestion( "IP address of default gateway for external network", default_value=None, validation_function=ipaddress.ip_address, ), - "start": sunbeam.jobs.questions.PromptQuestion( + "start": sunbeam.core.questions.PromptQuestion( "Start of IP allocation range for external network", default_value=None, validation_function=ipaddress.ip_address, ), - "end": sunbeam.jobs.questions.PromptQuestion( + "end": sunbeam.core.questions.PromptQuestion( "End of IP allocation range for external network", default_value=None, validation_function=ipaddress.ip_address, ), - "network_type": sunbeam.jobs.questions.PromptQuestion( + "network_type": sunbeam.core.questions.PromptQuestion( "Network type for access to external network", choices=["flat", "vlan"], default_value="flat", ), - "segmentation_id": sunbeam.jobs.questions.PromptQuestion( + "segmentation_id": sunbeam.core.questions.PromptQuestion( "VLAN ID to use for external network", default_value=0 ), } @@ -111,7 +111,7 @@ def ext_net_questions(): def ext_net_questions_local_only(): return { - "cidr": sunbeam.jobs.questions.PromptQuestion( + "cidr": sunbeam.core.questions.PromptQuestion( ( "CIDR of OpenStack external network - arbitrary but must not " "be in use" @@ -119,22 +119,22 @@ def ext_net_questions_local_only(): default_value="10.20.20.0/24", validation_function=ipaddress.ip_network, ), - "start": sunbeam.jobs.questions.PromptQuestion( + "start": sunbeam.core.questions.PromptQuestion( "Start of IP allocation range for external network", default_value=None, validation_function=ipaddress.ip_address, ), - "end": sunbeam.jobs.questions.PromptQuestion( + "end": sunbeam.core.questions.PromptQuestion( "End of IP allocation range for external network", default_value=None, validation_function=ipaddress.ip_address, ), - "network_type": sunbeam.jobs.questions.PromptQuestion( + "network_type": sunbeam.core.questions.PromptQuestion( "Network type for access to external network", choices=["flat", "vlan"], default_value="flat", ), - "segmentation_id": sunbeam.jobs.questions.PromptQuestion( + "segmentation_id": sunbeam.core.questions.PromptQuestion( "VLAN ID to use for external network", default_value=0 ), } @@ -268,7 +268,7 @@ def run(self, status: Status | None = None) -> Result: :return: """ - self.variables = sunbeam.jobs.questions.load_answers( + self.variables = sunbeam.core.questions.load_answers( self.client, CLOUD_CONFIG_SECTION ) self.ext_network = self.variables.get("external_network", {}) @@ -333,7 +333,7 @@ def is_skip(self, status: Status | None = None) -> Result: :return: ResultType.SKIPPED if the Step should be skipped, ResultType.COMPLETED or ResultType.FAILED otherwise """ - self.variables = sunbeam.jobs.questions.load_answers( + self.variables = sunbeam.core.questions.load_answers( self.client, CLOUD_CONFIG_SECTION ) if "user" not in self.variables: @@ -409,14 +409,14 @@ def prompt(self, console: Console | None = None) -> None: :param console: the console to prompt on :type console: rich.console.Console (Optional) """ - self.variables = sunbeam.jobs.questions.load_answers( + self.variables = sunbeam.core.questions.load_answers( self.client, CLOUD_CONFIG_SECTION ) for section in ["user", "external_network"]: if not self.variables.get(section): self.variables[section] = {} - user_bank = sunbeam.jobs.questions.QuestionBank( + user_bank = sunbeam.core.questions.QuestionBank( questions=user_questions(), console=console, preseed=self.preseed.get("user"), @@ -428,7 +428,7 @@ def prompt(self, console: Console | None = None) -> None: ) # External Network Configuration if self.variables["user"]["remote_access_location"] == utils.LOCAL_ACCESS: - ext_net_bank = sunbeam.jobs.questions.QuestionBank( + ext_net_bank = sunbeam.core.questions.QuestionBank( questions=ext_net_questions_local_only(), console=console, preseed=self.preseed.get("external_network"), @@ -436,7 +436,7 @@ def prompt(self, console: Console | None = None) -> None: accept_defaults=self.accept_defaults, ) else: - ext_net_bank = sunbeam.jobs.questions.QuestionBank( + ext_net_bank = sunbeam.core.questions.QuestionBank( questions=ext_net_questions(), console=console, preseed=self.preseed.get("external_network"), @@ -499,7 +499,7 @@ def prompt(self, console: Console | None = None) -> None: user_bank.security_group_rules.ask() ) - sunbeam.jobs.questions.write_answers( + sunbeam.core.questions.write_answers( self.client, CLOUD_CONFIG_SECTION, self.variables ) @@ -531,7 +531,7 @@ def is_skip(self, status: Status | None = None) -> Result: :return: ResultType.SKIPPED if the Step should be skipped, ResultType.COMPLETED or ResultType.FAILED otherwise """ - self.variables = sunbeam.jobs.questions.load_answers( + self.variables = sunbeam.core.questions.load_answers( self.client, CLOUD_CONFIG_SECTION ) if self.variables["user"]["run_demo_setup"]: @@ -541,7 +541,7 @@ def is_skip(self, status: Status | None = None) -> Result: def run(self, status: Status | None = None) -> Result: """Execute configuration using terraform.""" - self.variables = sunbeam.jobs.questions.load_answers( + self.variables = sunbeam.core.questions.load_answers( self.client, CLOUD_CONFIG_SECTION ) self.tfhelper.write_tfvars(self.variables, self.answer_file) @@ -569,7 +569,7 @@ def is_skip(self, status: Status | None = None) -> Result: :return: ResultType.SKIPPED if the Step should be skipped, ResultType.COMPLETED or ResultType.FAILED otherwise """ - self.variables = sunbeam.jobs.questions.load_answers( + self.variables = sunbeam.core.questions.load_answers( self.client, CLOUD_CONFIG_SECTION ) if self.variables["user"]["run_demo_setup"]: diff --git a/sunbeam-python/sunbeam/commands/dashboard_url.py b/sunbeam-python/sunbeam/commands/dashboard_url.py index 4964f794..b395787a 100644 --- a/sunbeam-python/sunbeam/commands/dashboard_url.py +++ b/sunbeam-python/sunbeam/commands/dashboard_url.py @@ -18,10 +18,10 @@ import click from rich.console import Console -from sunbeam.commands.openstack import OPENSTACK_MODEL -from sunbeam.jobs import juju -from sunbeam.jobs.checks import VerifyBootstrappedCheck, run_preflight_checks -from sunbeam.jobs.deployment import Deployment +from sunbeam.core import juju +from sunbeam.core.checks import VerifyBootstrappedCheck, run_preflight_checks +from sunbeam.core.deployment import Deployment +from sunbeam.core.openstack import OPENSTACK_MODEL LOG = logging.getLogger(__name__) console = Console() diff --git a/sunbeam-python/sunbeam/commands/generate_cloud_config.py b/sunbeam-python/sunbeam/commands/generate_cloud_config.py index 5df019d0..16341f17 100644 --- a/sunbeam-python/sunbeam/commands/generate_cloud_config.py +++ b/sunbeam-python/sunbeam/commands/generate_cloud_config.py @@ -26,21 +26,21 @@ import yaml from rich.console import Console -import sunbeam.jobs.questions +import sunbeam.core.questions from sunbeam.clusterd.client import Client from sunbeam.commands.configure import CLOUD_CONFIG_SECTION, retrieve_admin_credentials -from sunbeam.commands.openstack import OPENSTACK_MODEL -from sunbeam.commands.terraform import TerraformHelper -from sunbeam.jobs.checks import VerifyBootstrappedCheck, run_preflight_checks -from sunbeam.jobs.common import ( +from sunbeam.core.checks import VerifyBootstrappedCheck, run_preflight_checks +from sunbeam.core.common import ( BaseStep, Result, ResultType, Status, run_plan, ) -from sunbeam.jobs.deployment import Deployment -from sunbeam.jobs.juju import JujuHelper, ModelNotFoundException, run_sync +from sunbeam.core.deployment import Deployment +from sunbeam.core.juju import JujuHelper, ModelNotFoundException, run_sync +from sunbeam.core.openstack import OPENSTACK_MODEL +from sunbeam.core.terraform import TerraformHelper LOG = logging.getLogger(__name__) console = Console() @@ -83,7 +83,7 @@ def is_skip(self, status: Status | None = None) -> Result: return Result(ResultType.COMPLETED) # Check if run_demo_setup is done to get demo user information - self.variables = sunbeam.jobs.questions.load_answers( + self.variables = sunbeam.core.questions.load_answers( self.client, CLOUD_CONFIG_SECTION ) if "user" not in self.variables: diff --git a/sunbeam-python/sunbeam/commands/inspect.py b/sunbeam-python/sunbeam/commands/inspect.py index 012ed3ba..30ccb523 100644 --- a/sunbeam-python/sunbeam/commands/inspect.py +++ b/sunbeam-python/sunbeam/commands/inspect.py @@ -27,15 +27,15 @@ from snaphelpers import Snap from sunbeam.clusterd.service import ConfigItemNotFoundException -from sunbeam.commands.juju import WriteCharmLogStep, WriteJujuStatusStep -from sunbeam.commands.openstack import OPENSTACK_MODEL -from sunbeam.jobs.common import ( +from sunbeam.core.common import ( FORMAT_TABLE, FORMAT_YAML, run_plan, ) -from sunbeam.jobs.deployment import Deployment -from sunbeam.jobs.juju import JujuHelper +from sunbeam.core.deployment import Deployment +from sunbeam.core.juju import JujuHelper +from sunbeam.core.openstack import OPENSTACK_MODEL +from sunbeam.steps.juju import WriteCharmLogStep, WriteJujuStatusStep from sunbeam.utils import argument_with_deprecated_option LOG = logging.getLogger(__name__) diff --git a/sunbeam-python/sunbeam/commands/juju_utils.py b/sunbeam-python/sunbeam/commands/juju_utils.py index 1796b35f..6ff48c02 100644 --- a/sunbeam-python/sunbeam/commands/juju_utils.py +++ b/sunbeam-python/sunbeam/commands/juju_utils.py @@ -19,13 +19,13 @@ from rich.console import Console from snaphelpers import Snap -from sunbeam.commands.juju import ( +from sunbeam.core.common import BaseStep, run_plan +from sunbeam.core.deployment import Deployment +from sunbeam.steps.juju import ( RegisterRemoteJujuUserStep, SwitchToController, UnregisterJujuController, ) -from sunbeam.jobs.common import BaseStep, run_plan -from sunbeam.jobs.deployment import Deployment LOG = logging.getLogger(__name__) console = Console() diff --git a/sunbeam-python/sunbeam/commands/launch.py b/sunbeam-python/sunbeam/commands/launch.py index 9895d0e3..a82a6aa5 100644 --- a/sunbeam-python/sunbeam/commands/launch.py +++ b/sunbeam-python/sunbeam/commands/launch.py @@ -23,10 +23,10 @@ from snaphelpers import Snap from sunbeam.commands.configure import retrieve_admin_credentials -from sunbeam.commands.openstack import OPENSTACK_MODEL -from sunbeam.commands.terraform import TerraformException -from sunbeam.jobs.deployment import Deployment -from sunbeam.jobs.juju import JujuHelper, ModelNotFoundException, run_sync +from sunbeam.core.deployment import Deployment +from sunbeam.core.juju import JujuHelper, ModelNotFoundException, run_sync +from sunbeam.core.openstack import OPENSTACK_MODEL +from sunbeam.core.terraform import TerraformException LOG = logging.getLogger(__name__) console = Console() diff --git a/sunbeam-python/sunbeam/commands/manifest.py b/sunbeam-python/sunbeam/commands/manifest.py index 5e2b738f..2f947a8a 100644 --- a/sunbeam-python/sunbeam/commands/manifest.py +++ b/sunbeam-python/sunbeam/commands/manifest.py @@ -27,9 +27,9 @@ ClusterServiceUnavailableException, ManifestItemNotFoundException, ) -from sunbeam.jobs.common import FORMAT_TABLE, FORMAT_YAML -from sunbeam.jobs.deployment import Deployment -from sunbeam.jobs.manifest import Manifest +from sunbeam.core.common import FORMAT_TABLE, FORMAT_YAML +from sunbeam.core.deployment import Deployment +from sunbeam.core.manifest import Manifest from sunbeam.utils import argument_with_deprecated_option LOG = logging.getLogger(__name__) diff --git a/sunbeam-python/sunbeam/commands/openrc.py b/sunbeam-python/sunbeam/commands/openrc.py index e9385f63..77258720 100644 --- a/sunbeam-python/sunbeam/commands/openrc.py +++ b/sunbeam-python/sunbeam/commands/openrc.py @@ -19,10 +19,10 @@ from rich.console import Console from sunbeam.commands.configure import retrieve_admin_credentials -from sunbeam.commands.openstack import OPENSTACK_MODEL -from sunbeam.jobs import juju -from sunbeam.jobs.checks import VerifyBootstrappedCheck, run_preflight_checks -from sunbeam.jobs.deployment import Deployment +from sunbeam.core import juju +from sunbeam.core.checks import VerifyBootstrappedCheck, run_preflight_checks +from sunbeam.core.deployment import Deployment +from sunbeam.core.openstack import OPENSTACK_MODEL LOG = logging.getLogger(__name__) console = Console() diff --git a/sunbeam-python/sunbeam/commands/proxy.py b/sunbeam-python/sunbeam/commands/proxy.py index 748a69b4..5753ea60 100644 --- a/sunbeam-python/sunbeam/commands/proxy.py +++ b/sunbeam-python/sunbeam/commands/proxy.py @@ -26,12 +26,8 @@ ClusterServiceUnavailableException, ConfigItemNotFoundException, ) -from sunbeam.commands.juju import UpdateJujuModelConfigStep -from sunbeam.commands.openstack import UpdateOpenStackModelConfigStep -from sunbeam.commands.sunbeam_machine import DeploySunbeamMachineApplicationStep -from sunbeam.commands.terraform import TerraformInitStep -from sunbeam.jobs.checks import VerifyBootstrappedCheck, run_preflight_checks -from sunbeam.jobs.common import ( +from sunbeam.core.checks import VerifyBootstrappedCheck, run_preflight_checks +from sunbeam.core.common import ( FORMAT_TABLE, FORMAT_YAML, BaseStep, @@ -42,16 +38,20 @@ run_plan, update_config, ) -from sunbeam.jobs.deployment import PROXY_CONFIG_KEY, Deployment -from sunbeam.jobs.feature import FeatureManager -from sunbeam.jobs.juju import CONTROLLER_MODEL, JujuHelper -from sunbeam.jobs.questions import ( +from sunbeam.core.deployment import PROXY_CONFIG_KEY, Deployment +from sunbeam.core.feature import FeatureManager +from sunbeam.core.juju import CONTROLLER_MODEL, JujuHelper +from sunbeam.core.questions import ( ConfirmQuestion, PromptQuestion, QuestionBank, load_answers, write_answers, ) +from sunbeam.core.terraform import TerraformInitStep +from sunbeam.steps.juju import UpdateJujuModelConfigStep +from sunbeam.steps.openstack import UpdateOpenStackModelConfigStep +from sunbeam.steps.sunbeam_machine import DeploySunbeamMachineApplicationStep LOG = logging.getLogger(__name__) console = Console() diff --git a/sunbeam-python/sunbeam/commands/refresh.py b/sunbeam-python/sunbeam/commands/refresh.py index 11cf79e3..0be0438c 100644 --- a/sunbeam-python/sunbeam/commands/refresh.py +++ b/sunbeam-python/sunbeam/commands/refresh.py @@ -18,13 +18,13 @@ import click from rich.console import Console -from sunbeam.commands.upgrades.base import UpgradeCoordinator -from sunbeam.commands.upgrades.inter_channel import ChannelUpgradeCoordinator -from sunbeam.commands.upgrades.intra_channel import LatestInChannelCoordinator -from sunbeam.jobs.common import run_plan -from sunbeam.jobs.deployment import Deployment -from sunbeam.jobs.juju import JujuHelper -from sunbeam.jobs.manifest import AddManifestStep +from sunbeam.core.common import run_plan +from sunbeam.core.deployment import Deployment +from sunbeam.core.juju import JujuHelper +from sunbeam.core.manifest import AddManifestStep +from sunbeam.steps.upgrades.base import UpgradeCoordinator +from sunbeam.steps.upgrades.inter_channel import ChannelUpgradeCoordinator +from sunbeam.steps.upgrades.intra_channel import LatestInChannelCoordinator LOG = logging.getLogger(__name__) console = Console() diff --git a/sunbeam-python/sunbeam/commands/resize.py b/sunbeam-python/sunbeam/commands/resize.py index 5f11e570..c45e2d01 100644 --- a/sunbeam-python/sunbeam/commands/resize.py +++ b/sunbeam-python/sunbeam/commands/resize.py @@ -18,15 +18,15 @@ from rich.console import Console from sunbeam.clusterd.client import Client -from sunbeam.commands.microceph import ( +from sunbeam.core.common import click_option_topology, run_plan +from sunbeam.core.deployment import Deployment +from sunbeam.core.juju import JujuHelper +from sunbeam.core.terraform import TerraformInitStep +from sunbeam.steps.microceph import ( DeployMicrocephApplicationStep, SetCephMgrPoolSizeStep, ) -from sunbeam.commands.openstack import DeployControlPlaneStep -from sunbeam.commands.terraform import TerraformInitStep -from sunbeam.jobs.common import click_option_topology, run_plan -from sunbeam.jobs.deployment import Deployment -from sunbeam.jobs.juju import JujuHelper +from sunbeam.steps.openstack import DeployControlPlaneStep LOG = logging.getLogger(__name__) console = Console() diff --git a/sunbeam-python/sunbeam/commands/utils.py b/sunbeam-python/sunbeam/commands/utils.py index d1f128b2..dd533738 100644 --- a/sunbeam-python/sunbeam/commands/utils.py +++ b/sunbeam-python/sunbeam/commands/utils.py @@ -18,10 +18,10 @@ import click from rich.console import Console -from sunbeam.commands.juju import JujuLoginStep -from sunbeam.jobs.checks import VerifyBootstrappedCheck, run_preflight_checks -from sunbeam.jobs.common import run_plan -from sunbeam.jobs.deployment import Deployment +from sunbeam.core.checks import VerifyBootstrappedCheck, run_preflight_checks +from sunbeam.core.common import run_plan +from sunbeam.core.deployment import Deployment +from sunbeam.steps.juju import JujuLoginStep LOG = logging.getLogger(__name__) console = Console() diff --git a/sunbeam-python/sunbeam/commands/upgrades/__init__.py b/sunbeam-python/sunbeam/core/__init__.py similarity index 100% rename from sunbeam-python/sunbeam/commands/upgrades/__init__.py rename to sunbeam-python/sunbeam/core/__init__.py diff --git a/sunbeam-python/sunbeam/jobs/checks.py b/sunbeam-python/sunbeam/core/checks.py similarity index 99% rename from sunbeam-python/sunbeam/jobs/checks.py rename to sunbeam-python/sunbeam/core/checks.py index d1acdd52..da858b7f 100644 --- a/sunbeam-python/sunbeam/jobs/checks.py +++ b/sunbeam-python/sunbeam/core/checks.py @@ -28,7 +28,7 @@ from sunbeam.clusterd.client import Client from sunbeam.clusterd.service import ClusterServiceUnavailableException -from sunbeam.jobs.common import ( +from sunbeam.core.common import ( RAM_16_GB_IN_KB, get_host_total_cores, get_host_total_ram, diff --git a/sunbeam-python/sunbeam/jobs/common.py b/sunbeam-python/sunbeam/core/common.py similarity index 100% rename from sunbeam-python/sunbeam/jobs/common.py rename to sunbeam-python/sunbeam/core/common.py diff --git a/sunbeam-python/sunbeam/jobs/deployment.py b/sunbeam-python/sunbeam/core/deployment.py similarity index 97% rename from sunbeam-python/sunbeam/jobs/deployment.py rename to sunbeam-python/sunbeam/core/deployment.py index 8e80ce7c..ca7dc1cc 100644 --- a/sunbeam-python/sunbeam/jobs/deployment.py +++ b/sunbeam-python/sunbeam/core/deployment.py @@ -31,19 +31,19 @@ ClusterServiceUnavailableException, ConfigItemNotFoundException, ) -from sunbeam.commands.terraform import TerraformHelper -from sunbeam.jobs.common import ( +from sunbeam.core.common import ( RiskLevel, _get_default_no_proxy_settings, infer_risk, read_config, ) -from sunbeam.jobs.juju import JujuAccount, JujuController -from sunbeam.jobs.manifest import Manifest, embedded_manifest_path +from sunbeam.core.juju import JujuAccount, JujuController +from sunbeam.core.manifest import Manifest, embedded_manifest_path +from sunbeam.core.terraform import TerraformHelper from sunbeam.versions import MANIFEST_ATTRIBUTES_TFVAR_MAP, TERRAFORM_DIR_NAMES if TYPE_CHECKING: - from sunbeam.jobs.feature import FeatureManager + from sunbeam.core.feature import FeatureManager LOG = logging.getLogger(__name__) PROXY_CONFIG_KEY = "ProxySettings" @@ -157,7 +157,7 @@ def get_default_proxy_settings(self) -> dict: def get_feature_manager(self) -> "FeatureManager": """Return the feature manager for the deployment.""" - from sunbeam.jobs.feature import FeatureManager + from sunbeam.core.feature import FeatureManager feature_manager = FeatureManager() return feature_manager diff --git a/sunbeam-python/sunbeam/jobs/deployments.py b/sunbeam-python/sunbeam/core/deployments.py similarity index 98% rename from sunbeam-python/sunbeam/jobs/deployments.py rename to sunbeam-python/sunbeam/core/deployments.py index c067c7e2..98e6a0d5 100644 --- a/sunbeam-python/sunbeam/jobs/deployments.py +++ b/sunbeam-python/sunbeam/core/deployments.py @@ -24,8 +24,8 @@ import yaml from snaphelpers import Snap -from sunbeam.jobs.common import SHARE_PATH, str_presenter -from sunbeam.jobs.deployment import Deployment +from sunbeam.core.common import SHARE_PATH, str_presenter +from sunbeam.core.deployment import Deployment LOG = logging.getLogger(__name__) DEPLOYMENTS_CONFIG = SHARE_PATH / "deployments.yaml" diff --git a/sunbeam-python/sunbeam/jobs/feature.py b/sunbeam-python/sunbeam/core/feature.py similarity index 98% rename from sunbeam-python/sunbeam/jobs/feature.py rename to sunbeam-python/sunbeam/core/feature.py index 4e373a03..19d76413 100644 --- a/sunbeam-python/sunbeam/jobs/feature.py +++ b/sunbeam-python/sunbeam/core/feature.py @@ -21,9 +21,9 @@ import yaml from sunbeam import utils -from sunbeam.jobs.common import SunbeamException -from sunbeam.jobs.deployment import Deployment -from sunbeam.jobs.manifest import SoftwareConfig +from sunbeam.core.common import SunbeamException +from sunbeam.core.deployment import Deployment +from sunbeam.core.manifest import SoftwareConfig LOG = logging.getLogger(__name__) FEATURES_YAML = "features.yaml" diff --git a/sunbeam-python/sunbeam/jobs/juju.py b/sunbeam-python/sunbeam/core/juju.py similarity index 99% rename from sunbeam-python/sunbeam/jobs/juju.py rename to sunbeam-python/sunbeam/core/juju.py index df4e749f..60de166c 100644 --- a/sunbeam-python/sunbeam/jobs/juju.py +++ b/sunbeam-python/sunbeam/core/juju.py @@ -49,7 +49,7 @@ from juju.unit import Unit from sunbeam.clusterd.client import Client -from sunbeam.jobs.common import SunbeamException +from sunbeam.core.common import SunbeamException from sunbeam.versions import JUJU_BASE LOG = logging.getLogger(__name__) diff --git a/sunbeam-python/sunbeam/jobs/k8s.py b/sunbeam-python/sunbeam/core/k8s.py similarity index 98% rename from sunbeam-python/sunbeam/jobs/k8s.py rename to sunbeam-python/sunbeam/core/k8s.py index 00da22d8..72b74e60 100644 --- a/sunbeam-python/sunbeam/jobs/k8s.py +++ b/sunbeam-python/sunbeam/core/k8s.py @@ -17,7 +17,7 @@ from snaphelpers import Snap -from sunbeam.jobs.common import SunbeamException +from sunbeam.core.common import SunbeamException LOG = logging.getLogger(__name__) diff --git a/sunbeam-python/sunbeam/jobs/manifest.py b/sunbeam-python/sunbeam/core/manifest.py similarity index 99% rename from sunbeam-python/sunbeam/jobs/manifest.py rename to sunbeam-python/sunbeam/core/manifest.py index 4a05d6cf..116ab1f7 100644 --- a/sunbeam-python/sunbeam/jobs/manifest.py +++ b/sunbeam-python/sunbeam/core/manifest.py @@ -29,7 +29,7 @@ ClusterServiceUnavailableException, ManifestItemNotFoundException, ) -from sunbeam.jobs.common import ( +from sunbeam.core.common import ( BaseStep, Result, ResultType, diff --git a/sunbeam-python/sunbeam/core/openstack.py b/sunbeam-python/sunbeam/core/openstack.py new file mode 100644 index 00000000..6822cd07 --- /dev/null +++ b/sunbeam-python/sunbeam/core/openstack.py @@ -0,0 +1,16 @@ +# 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. + +OPENSTACK_MODEL = "openstack" diff --git a/sunbeam-python/sunbeam/commands/openstack_api.py b/sunbeam-python/sunbeam/core/openstack_api.py similarity index 97% rename from sunbeam-python/sunbeam/commands/openstack_api.py rename to sunbeam-python/sunbeam/core/openstack_api.py index 30fa40d1..f42db3ca 100644 --- a/sunbeam-python/sunbeam/commands/openstack_api.py +++ b/sunbeam-python/sunbeam/core/openstack_api.py @@ -18,8 +18,8 @@ import openstack from sunbeam.commands.configure import retrieve_admin_credentials -from sunbeam.commands.openstack import OPENSTACK_MODEL -from sunbeam.jobs.juju import JujuHelper +from sunbeam.core.juju import JujuHelper +from sunbeam.core.openstack import OPENSTACK_MODEL LOG = logging.getLogger(__name__) diff --git a/sunbeam-python/sunbeam/jobs/questions.py b/sunbeam-python/sunbeam/core/questions.py similarity index 100% rename from sunbeam-python/sunbeam/jobs/questions.py rename to sunbeam-python/sunbeam/core/questions.py diff --git a/sunbeam-python/sunbeam/jobs/steps.py b/sunbeam-python/sunbeam/core/steps.py similarity index 98% rename from sunbeam-python/sunbeam/jobs/steps.py rename to sunbeam-python/sunbeam/core/steps.py index 8d0cfb43..597696af 100644 --- a/sunbeam-python/sunbeam/jobs/steps.py +++ b/sunbeam-python/sunbeam/core/steps.py @@ -27,17 +27,17 @@ from sunbeam.clusterd.service import ( ConfigItemNotFoundException, ) -from sunbeam.commands.terraform import TerraformException, TerraformHelper -from sunbeam.jobs.common import BaseStep, Result, ResultType, read_config, update_config -from sunbeam.jobs.deployment import Deployment -from sunbeam.jobs.juju import ( +from sunbeam.core.common import BaseStep, Result, ResultType, read_config, update_config +from sunbeam.core.deployment import Deployment +from sunbeam.core.juju import ( ApplicationNotFoundException, JujuHelper, TimeoutException, run_sync, ) -from sunbeam.jobs.k8s import K8SHelper -from sunbeam.jobs.manifest import Manifest +from sunbeam.core.k8s import K8SHelper +from sunbeam.core.manifest import Manifest +from sunbeam.core.terraform import TerraformException, TerraformHelper LOG = logging.getLogger(__name__) diff --git a/sunbeam-python/sunbeam/commands/terraform.py b/sunbeam-python/sunbeam/core/terraform.py similarity index 99% rename from sunbeam-python/sunbeam/commands/terraform.py rename to sunbeam-python/sunbeam/core/terraform.py index e957a3a3..6d996b02 100644 --- a/sunbeam-python/sunbeam/commands/terraform.py +++ b/sunbeam-python/sunbeam/core/terraform.py @@ -26,8 +26,8 @@ from sunbeam.clusterd.client import Client from sunbeam.clusterd.service import ConfigItemNotFoundException -from sunbeam.jobs.common import BaseStep, Result, ResultType, read_config, update_config -from sunbeam.jobs.manifest import Manifest +from sunbeam.core.common import BaseStep, Result, ResultType, read_config, update_config +from sunbeam.core.manifest import Manifest LOG = logging.getLogger(__name__) diff --git a/sunbeam-python/sunbeam/features/ca/feature.py b/sunbeam-python/sunbeam/features/ca/feature.py index 2a91329e..3bde7792 100644 --- a/sunbeam-python/sunbeam/features/ca/feature.py +++ b/sunbeam-python/sunbeam/features/ca/feature.py @@ -29,7 +29,26 @@ ClusterServiceUnavailableException, ConfigItemNotFoundException, ) -from sunbeam.commands.openstack import OPENSTACK_MODEL +from sunbeam.core import questions +from sunbeam.core.common import ( + FORMAT_TABLE, + FORMAT_YAML, + BaseStep, + Result, + ResultType, + read_config, + run_plan, + str_presenter, +) +from sunbeam.core.deployment import Deployment +from sunbeam.core.juju import ( + ActionFailedException, + JujuHelper, + LeaderNotFoundException, + run_sync, +) +from sunbeam.core.manifest import AddManifestStep, CharmManifest, SoftwareConfig +from sunbeam.core.openstack import OPENSTACK_MODEL from sunbeam.features.interface.utils import ( encode_base64_as_string, get_subject_from_csr, @@ -45,25 +64,6 @@ INGRESS_CHANGE_APPLICATION_TIMEOUT, TlsFeatureGroup, ) -from sunbeam.jobs import questions -from sunbeam.jobs.common import ( - FORMAT_TABLE, - FORMAT_YAML, - BaseStep, - Result, - ResultType, - read_config, - run_plan, - str_presenter, -) -from sunbeam.jobs.deployment import Deployment -from sunbeam.jobs.juju import ( - ActionFailedException, - JujuHelper, - LeaderNotFoundException, - run_sync, -) -from sunbeam.jobs.manifest import AddManifestStep, CharmManifest, SoftwareConfig CERTIFICATE_FEATURE_KEY = "TlsProvider" CA_APP_NAME = "manual-tls-certificates" diff --git a/sunbeam-python/sunbeam/features/caas/feature.py b/sunbeam-python/sunbeam/features/caas/feature.py index a8dc4a18..ed48899b 100644 --- a/sunbeam-python/sunbeam/features/caas/feature.py +++ b/sunbeam-python/sunbeam/features/caas/feature.py @@ -26,8 +26,17 @@ from sunbeam.clusterd.client import Client from sunbeam.clusterd.service import ClusterServiceUnavailableException from sunbeam.commands.configure import retrieve_admin_credentials -from sunbeam.commands.openstack import OPENSTACK_MODEL -from sunbeam.commands.terraform import ( +from sunbeam.core.common import BaseStep, Result, ResultType, run_plan +from sunbeam.core.deployment import Deployment +from sunbeam.core.juju import JujuHelper +from sunbeam.core.manifest import ( + CharmManifest, + Manifest, + SoftwareConfig, + TerraformManifest, +) +from sunbeam.core.openstack import OPENSTACK_MODEL +from sunbeam.core.terraform import ( TerraformException, TerraformHelper, TerraformInitStep, @@ -37,15 +46,6 @@ OpenStackControlPlaneFeature, TerraformPlanLocation, ) -from sunbeam.jobs.common import BaseStep, Result, ResultType, run_plan -from sunbeam.jobs.deployment import Deployment -from sunbeam.jobs.juju import JujuHelper -from sunbeam.jobs.manifest import ( - CharmManifest, - Manifest, - SoftwareConfig, - TerraformManifest, -) from sunbeam.versions import OPENSTACK_CHANNEL LOG = logging.getLogger(__name__) diff --git a/sunbeam-python/sunbeam/features/dns/feature.py b/sunbeam-python/sunbeam/features/dns/feature.py index ec670b0c..235d8c0b 100644 --- a/sunbeam-python/sunbeam/features/dns/feature.py +++ b/sunbeam-python/sunbeam/features/dns/feature.py @@ -20,19 +20,19 @@ from rich.console import Console from sunbeam.clusterd.service import ClusterServiceUnavailableException -from sunbeam.commands.openstack import OPENSTACK_MODEL -from sunbeam.commands.terraform import TerraformInitStep +from sunbeam.core.common import BaseStep, run_plan +from sunbeam.core.deployment import Deployment +from sunbeam.core.juju import JujuHelper, run_sync +from sunbeam.core.manifest import AddManifestStep, CharmManifest, SoftwareConfig +from sunbeam.core.openstack import OPENSTACK_MODEL +from sunbeam.core.steps import PatchLoadBalancerServicesStep +from sunbeam.core.terraform import TerraformInitStep from sunbeam.features.interface.v1.openstack import ( ApplicationChannelData, EnableOpenStackApplicationStep, OpenStackControlPlaneFeature, TerraformPlanLocation, ) -from sunbeam.jobs.common import BaseStep, run_plan -from sunbeam.jobs.deployment import Deployment -from sunbeam.jobs.juju import JujuHelper, run_sync -from sunbeam.jobs.manifest import AddManifestStep, CharmManifest, SoftwareConfig -from sunbeam.jobs.steps import PatchLoadBalancerServicesStep from sunbeam.utils import argument_with_deprecated_option from sunbeam.versions import BIND_CHANNEL, OPENSTACK_CHANNEL diff --git a/sunbeam-python/sunbeam/features/images_sync/feature.py b/sunbeam-python/sunbeam/features/images_sync/feature.py index 0ff57a62..453fda33 100644 --- a/sunbeam-python/sunbeam/features/images_sync/feature.py +++ b/sunbeam-python/sunbeam/features/images_sync/feature.py @@ -19,13 +19,13 @@ from packaging.version import Version from rich.console import Console +from sunbeam.core.deployment import Deployment +from sunbeam.core.manifest import CharmManifest, SoftwareConfig from sunbeam.features.interface.v1.openstack import ( ApplicationChannelData, OpenStackControlPlaneFeature, TerraformPlanLocation, ) -from sunbeam.jobs.deployment import Deployment -from sunbeam.jobs.manifest import CharmManifest, SoftwareConfig from sunbeam.versions import OPENSTACK_CHANNEL LOG = logging.getLogger(__name__) diff --git a/sunbeam-python/sunbeam/features/interface/v1/base.py b/sunbeam-python/sunbeam/features/interface/v1/base.py index ec6b5260..90ac067e 100644 --- a/sunbeam-python/sunbeam/features/interface/v1/base.py +++ b/sunbeam-python/sunbeam/features/interface/v1/base.py @@ -27,11 +27,11 @@ from snaphelpers import Snap from sunbeam.clusterd.service import ConfigItemNotFoundException +from sunbeam.core.common import SunbeamException, read_config, update_config +from sunbeam.core.deployment import Deployment +from sunbeam.core.feature import FeatureManager +from sunbeam.core.manifest import SoftwareConfig from sunbeam.features.interface import utils -from sunbeam.jobs.common import SunbeamException, read_config, update_config -from sunbeam.jobs.deployment import Deployment -from sunbeam.jobs.feature import FeatureManager -from sunbeam.jobs.manifest import SoftwareConfig LOG = logging.getLogger(__name__) diff --git a/sunbeam-python/sunbeam/features/interface/v1/openstack.py b/sunbeam-python/sunbeam/features/interface/v1/openstack.py index c0850186..df324133 100644 --- a/sunbeam-python/sunbeam/features/interface/v1/openstack.py +++ b/sunbeam-python/sunbeam/features/interface/v1/openstack.py @@ -28,16 +28,8 @@ from snaphelpers import Snap from sunbeam.clusterd.service import ConfigItemNotFoundException -from sunbeam.commands.juju import JujuStepHelper -from sunbeam.commands.openstack import OPENSTACK_MODEL, TOPOLOGY_KEY -from sunbeam.commands.terraform import ( - TerraformException, - TerraformHelper, - TerraformInitStep, -) -from sunbeam.features.interface.v1.base import EnableDisableFeature -from sunbeam.jobs.checks import VerifyBootstrappedCheck, run_preflight_checks -from sunbeam.jobs.common import ( +from sunbeam.core.checks import VerifyBootstrappedCheck, run_preflight_checks +from sunbeam.core.common import ( BaseStep, Result, ResultType, @@ -46,15 +38,24 @@ run_plan, update_status_background, ) -from sunbeam.jobs.deployment import Deployment -from sunbeam.jobs.juju import ( +from sunbeam.core.deployment import Deployment +from sunbeam.core.juju import ( ApplicationNotFoundException, JujuHelper, JujuWaitException, TimeoutException, run_sync, ) -from sunbeam.jobs.manifest import AddManifestStep, Manifest +from sunbeam.core.manifest import AddManifestStep, Manifest +from sunbeam.core.openstack import OPENSTACK_MODEL +from sunbeam.core.terraform import ( + TerraformException, + TerraformHelper, + TerraformInitStep, +) +from sunbeam.features.interface.v1.base import EnableDisableFeature +from sunbeam.steps.juju import JujuStepHelper +from sunbeam.steps.openstack import TOPOLOGY_KEY LOG = logging.getLogger(__name__) console = Console() diff --git a/sunbeam-python/sunbeam/features/interface/v1/tls.py b/sunbeam-python/sunbeam/features/interface/v1/tls.py index dc063b18..6ef54988 100644 --- a/sunbeam-python/sunbeam/features/interface/v1/tls.py +++ b/sunbeam-python/sunbeam/features/interface/v1/tls.py @@ -21,13 +21,7 @@ from rich.status import Status from sunbeam.clusterd.service import ConfigItemNotFoundException -from sunbeam.commands.openstack import OPENSTACK_MODEL -from sunbeam.features.interface.v1.openstack import ( - OpenStackControlPlaneFeature, - TerraformPlanLocation, - WaitForApplicationsStep, -) -from sunbeam.jobs.common import ( +from sunbeam.core.common import ( BaseStep, Result, ResultType, @@ -35,13 +29,19 @@ run_plan, update_config, ) -from sunbeam.jobs.deployment import Deployment -from sunbeam.jobs.juju import ( +from sunbeam.core.deployment import Deployment +from sunbeam.core.juju import ( ActionFailedException, JujuHelper, LeaderNotFoundException, run_sync, ) +from sunbeam.core.openstack import OPENSTACK_MODEL +from sunbeam.features.interface.v1.openstack import ( + OpenStackControlPlaneFeature, + TerraformPlanLocation, + WaitForApplicationsStep, +) CERTIFICATE_FEATURE_KEY = "TlsProvider" # Time out for keystone to settle once ingress change relation data diff --git a/sunbeam-python/sunbeam/features/ldap/feature.py b/sunbeam-python/sunbeam/features/ldap/feature.py index 7f725f87..afa2d933 100644 --- a/sunbeam-python/sunbeam/features/ldap/feature.py +++ b/sunbeam-python/sunbeam/features/ldap/feature.py @@ -28,14 +28,7 @@ ClusterServiceUnavailableException, ConfigItemNotFoundException, ) -from sunbeam.commands.juju import JujuStepHelper -from sunbeam.commands.openstack import OPENSTACK_MODEL -from sunbeam.commands.terraform import TerraformException, TerraformInitStep -from sunbeam.features.interface.v1.openstack import ( - OpenStackControlPlaneFeature, - TerraformPlanLocation, -) -from sunbeam.jobs.common import ( +from sunbeam.core.common import ( BaseStep, Result, ResultType, @@ -44,9 +37,16 @@ update_config, update_status_background, ) -from sunbeam.jobs.deployment import Deployment -from sunbeam.jobs.juju import JujuHelper, JujuWaitException, TimeoutException, run_sync -from sunbeam.jobs.manifest import CharmManifest, SoftwareConfig +from sunbeam.core.deployment import Deployment +from sunbeam.core.juju import JujuHelper, JujuWaitException, TimeoutException, run_sync +from sunbeam.core.manifest import CharmManifest, SoftwareConfig +from sunbeam.core.openstack import OPENSTACK_MODEL +from sunbeam.core.terraform import TerraformException, TerraformInitStep +from sunbeam.features.interface.v1.openstack import ( + OpenStackControlPlaneFeature, + TerraformPlanLocation, +) +from sunbeam.steps.juju import JujuStepHelper from sunbeam.versions import OPENSTACK_CHANNEL LOG = logging.getLogger(__name__) diff --git a/sunbeam-python/sunbeam/features/loadbalancer/feature.py b/sunbeam-python/sunbeam/features/loadbalancer/feature.py index a3e9d832..f1dddceb 100644 --- a/sunbeam-python/sunbeam/features/loadbalancer/feature.py +++ b/sunbeam-python/sunbeam/features/loadbalancer/feature.py @@ -18,12 +18,12 @@ import click from packaging.version import Version +from sunbeam.core.deployment import Deployment +from sunbeam.core.manifest import CharmManifest, SoftwareConfig from sunbeam.features.interface.v1.openstack import ( OpenStackControlPlaneFeature, TerraformPlanLocation, ) -from sunbeam.jobs.deployment import Deployment -from sunbeam.jobs.manifest import CharmManifest, SoftwareConfig from sunbeam.versions import OPENSTACK_CHANNEL LOG = logging.getLogger(__name__) diff --git a/sunbeam-python/sunbeam/features/observability/feature.py b/sunbeam-python/sunbeam/features/observability/feature.py index be0b654a..7bedafe9 100644 --- a/sunbeam-python/sunbeam/features/observability/feature.py +++ b/sunbeam-python/sunbeam/features/observability/feature.py @@ -34,27 +34,12 @@ ClusterServiceUnavailableException, ConfigItemNotFoundException, ) -from sunbeam.commands.juju import JujuStepHelper -from sunbeam.commands.k8s import CREDENTIAL_SUFFIX -from sunbeam.commands.openstack import OPENSTACK_MODEL -from sunbeam.commands.terraform import ( - TerraformException, - TerraformHelper, - TerraformInitStep, -) -from sunbeam.features.interface.v1.base import FeatureRequirement -from sunbeam.features.interface.v1.openstack import ( - DisableOpenStackApplicationStep, - EnableOpenStackApplicationStep, - OpenStackControlPlaneFeature, - TerraformPlanLocation, -) -from sunbeam.jobs.checks import ( +from sunbeam.core.checks import ( Check, JujuControllerRegistrationCheck, run_preflight_checks, ) -from sunbeam.jobs.common import ( +from sunbeam.core.common import ( BaseStep, Result, ResultType, @@ -64,17 +49,32 @@ update_config, update_status_background, ) -from sunbeam.jobs.deployment import Deployment -from sunbeam.jobs.juju import JujuHelper, JujuWaitException, TimeoutException, run_sync -from sunbeam.jobs.k8s import K8SHelper -from sunbeam.jobs.manifest import ( +from sunbeam.core.deployment import Deployment +from sunbeam.core.juju import JujuHelper, JujuWaitException, TimeoutException, run_sync +from sunbeam.core.k8s import K8SHelper +from sunbeam.core.manifest import ( AddManifestStep, CharmManifest, Manifest, SoftwareConfig, TerraformManifest, ) -from sunbeam.jobs.steps import PatchLoadBalancerServicesStep +from sunbeam.core.openstack import OPENSTACK_MODEL +from sunbeam.core.steps import PatchLoadBalancerServicesStep +from sunbeam.core.terraform import ( + TerraformException, + TerraformHelper, + TerraformInitStep, +) +from sunbeam.features.interface.v1.base import FeatureRequirement +from sunbeam.features.interface.v1.openstack import ( + DisableOpenStackApplicationStep, + EnableOpenStackApplicationStep, + OpenStackControlPlaneFeature, + TerraformPlanLocation, +) +from sunbeam.steps.juju import JujuStepHelper +from sunbeam.steps.k8s import CREDENTIAL_SUFFIX LOG = logging.getLogger(__name__) console = Console() diff --git a/sunbeam-python/sunbeam/features/orchestration/feature.py b/sunbeam-python/sunbeam/features/orchestration/feature.py index 14650746..f1995513 100644 --- a/sunbeam-python/sunbeam/features/orchestration/feature.py +++ b/sunbeam-python/sunbeam/features/orchestration/feature.py @@ -18,12 +18,12 @@ import click from packaging.version import Version +from sunbeam.core.deployment import Deployment +from sunbeam.core.manifest import CharmManifest, SoftwareConfig from sunbeam.features.interface.v1.openstack import ( OpenStackControlPlaneFeature, TerraformPlanLocation, ) -from sunbeam.jobs.deployment import Deployment -from sunbeam.jobs.manifest import CharmManifest, SoftwareConfig from sunbeam.versions import OPENSTACK_CHANNEL LOG = logging.getLogger(__name__) diff --git a/sunbeam-python/sunbeam/features/pro/feature.py b/sunbeam-python/sunbeam/features/pro/feature.py index 3f6e24ee..11c012b4 100644 --- a/sunbeam-python/sunbeam/features/pro/feature.py +++ b/sunbeam-python/sunbeam/features/pro/feature.py @@ -25,17 +25,17 @@ from snaphelpers import Snap from sunbeam.clusterd.client import Client -from sunbeam.commands.juju import JujuStepHelper -from sunbeam.commands.terraform import ( +from sunbeam.core.common import BaseStep, Result, ResultType, run_plan +from sunbeam.core.deployment import Deployment +from sunbeam.core.juju import JujuHelper, TimeoutException, run_sync +from sunbeam.core.manifest import Manifest, SoftwareConfig, TerraformManifest +from sunbeam.core.terraform import ( TerraformException, TerraformHelper, TerraformInitStep, ) from sunbeam.features.interface.v1.base import EnableDisableFeature -from sunbeam.jobs.common import BaseStep, Result, ResultType, run_plan -from sunbeam.jobs.deployment import Deployment -from sunbeam.jobs.juju import JujuHelper, TimeoutException, run_sync -from sunbeam.jobs.manifest import Manifest, SoftwareConfig, TerraformManifest +from sunbeam.steps.juju import JujuStepHelper from sunbeam.utils import argument_with_deprecated_option LOG = logging.getLogger(__name__) diff --git a/sunbeam-python/sunbeam/features/secrets/feature.py b/sunbeam-python/sunbeam/features/secrets/feature.py index a2b6b252..27133a4c 100644 --- a/sunbeam-python/sunbeam/features/secrets/feature.py +++ b/sunbeam-python/sunbeam/features/secrets/feature.py @@ -16,13 +16,13 @@ import click from packaging.version import Version +from sunbeam.core.deployment import Deployment +from sunbeam.core.manifest import CharmManifest, SoftwareConfig from sunbeam.features.interface.v1.base import FeatureRequirement from sunbeam.features.interface.v1.openstack import ( OpenStackControlPlaneFeature, TerraformPlanLocation, ) -from sunbeam.jobs.deployment import Deployment -from sunbeam.jobs.manifest import CharmManifest, SoftwareConfig from sunbeam.versions import OPENSTACK_CHANNEL diff --git a/sunbeam-python/sunbeam/features/telemetry/feature.py b/sunbeam-python/sunbeam/features/telemetry/feature.py index 0b50b7ee..c66d1aa1 100644 --- a/sunbeam-python/sunbeam/features/telemetry/feature.py +++ b/sunbeam-python/sunbeam/features/telemetry/feature.py @@ -19,18 +19,18 @@ from packaging.version import Version from rich.console import Console -from sunbeam.commands.hypervisor import ReapplyHypervisorTerraformPlanStep -from sunbeam.commands.terraform import TerraformInitStep +from sunbeam.core.common import BaseStep, run_plan +from sunbeam.core.deployment import Deployment +from sunbeam.core.juju import JujuHelper +from sunbeam.core.manifest import AddManifestStep, CharmManifest, SoftwareConfig +from sunbeam.core.terraform import TerraformInitStep from sunbeam.features.interface.v1.openstack import ( DisableOpenStackApplicationStep, EnableOpenStackApplicationStep, OpenStackControlPlaneFeature, TerraformPlanLocation, ) -from sunbeam.jobs.common import BaseStep, run_plan -from sunbeam.jobs.deployment import Deployment -from sunbeam.jobs.juju import JujuHelper -from sunbeam.jobs.manifest import AddManifestStep, CharmManifest, SoftwareConfig +from sunbeam.steps.hypervisor import ReapplyHypervisorTerraformPlanStep from sunbeam.versions import OPENSTACK_CHANNEL LOG = logging.getLogger(__name__) diff --git a/sunbeam-python/sunbeam/features/validation/feature.py b/sunbeam-python/sunbeam/features/validation/feature.py index 0a39b905..4df32aab 100644 --- a/sunbeam-python/sunbeam/features/validation/feature.py +++ b/sunbeam-python/sunbeam/features/validation/feature.py @@ -30,9 +30,20 @@ from sunbeam.clusterd.client import Client from sunbeam.clusterd.service import ClusterServiceUnavailableException -from sunbeam.commands.juju import JujuLoginStep -from sunbeam.commands.openstack import OPENSTACK_MODEL -from sunbeam.commands.terraform import ( +from sunbeam.core.common import BaseStep, Result, ResultType, run_plan +from sunbeam.core.deployment import Deployment +from sunbeam.core.feature import FeatureManager +from sunbeam.core.juju import ( + ActionFailedException, + ApplicationNotFoundException, + JujuHelper, + LeaderNotFoundException, + UnitNotFoundException, + run_sync, +) +from sunbeam.core.manifest import CharmManifest, Manifest, SoftwareConfig +from sunbeam.core.openstack import OPENSTACK_MODEL +from sunbeam.core.terraform import ( TerraformException, TerraformHelper, TerraformInitStep, @@ -41,18 +52,7 @@ OpenStackControlPlaneFeature, TerraformPlanLocation, ) -from sunbeam.jobs.common import BaseStep, Result, ResultType, run_plan -from sunbeam.jobs.deployment import Deployment -from sunbeam.jobs.feature import FeatureManager -from sunbeam.jobs.juju import ( - ActionFailedException, - ApplicationNotFoundException, - JujuHelper, - LeaderNotFoundException, - UnitNotFoundException, - run_sync, -) -from sunbeam.jobs.manifest import CharmManifest, Manifest, SoftwareConfig +from sunbeam.steps.juju import JujuLoginStep from sunbeam.versions import TEMPEST_CHANNEL LOG = logging.getLogger(__name__) diff --git a/sunbeam-python/sunbeam/features/vault/feature.py b/sunbeam-python/sunbeam/features/vault/feature.py index 501de883..6ecbd091 100644 --- a/sunbeam-python/sunbeam/features/vault/feature.py +++ b/sunbeam-python/sunbeam/features/vault/feature.py @@ -24,12 +24,12 @@ import click from packaging.version import Version +from sunbeam.core.deployment import Deployment +from sunbeam.core.manifest import CharmManifest, SoftwareConfig from sunbeam.features.interface.v1.openstack import ( OpenStackControlPlaneFeature, TerraformPlanLocation, ) -from sunbeam.jobs.deployment import Deployment -from sunbeam.jobs.manifest import CharmManifest, SoftwareConfig from sunbeam.versions import VAULT_CHANNEL LOG = logging.getLogger(__name__) diff --git a/sunbeam-python/sunbeam/main.py b/sunbeam-python/sunbeam/main.py index 82fda072..a63d6e2a 100644 --- a/sunbeam-python/sunbeam/main.py +++ b/sunbeam-python/sunbeam/main.py @@ -32,8 +32,8 @@ from sunbeam.commands import prepare_node as prepare_node_cmds from sunbeam.commands import proxy as proxy_cmds from sunbeam.commands import utils as utils_cmds -from sunbeam.jobs import deployments as deployments_jobs -from sunbeam.jobs.feature import FeatureManager +from sunbeam.core import deployments as deployments_jobs +from sunbeam.core.feature import FeatureManager from sunbeam.provider import commands as provider_cmds from sunbeam.utils import CatchGroup diff --git a/sunbeam-python/sunbeam/provider/base.py b/sunbeam-python/sunbeam/provider/base.py index 4300b85b..dbee4280 100644 --- a/sunbeam-python/sunbeam/provider/base.py +++ b/sunbeam-python/sunbeam/provider/base.py @@ -19,7 +19,7 @@ import click from rich.console import Console -from sunbeam.jobs.deployment import Deployment +from sunbeam.core.deployment import Deployment console = Console() diff --git a/sunbeam-python/sunbeam/provider/commands.py b/sunbeam-python/sunbeam/provider/commands.py index 6f7a2f29..6a0b6620 100644 --- a/sunbeam-python/sunbeam/provider/commands.py +++ b/sunbeam-python/sunbeam/provider/commands.py @@ -25,15 +25,15 @@ from rich.table import Table from snaphelpers import Snap -from sunbeam.jobs.checks import LocalShareCheck, run_preflight_checks -from sunbeam.jobs.common import ( +from sunbeam.core.checks import LocalShareCheck, run_preflight_checks +from sunbeam.core.common import ( CONTEXT_SETTINGS, FORMAT_TABLE, FORMAT_YAML, run_plan, ) -from sunbeam.jobs.deployment import Deployment, register_deployment_type -from sunbeam.jobs.deployments import ( +from sunbeam.core.deployment import Deployment, register_deployment_type +from sunbeam.core.deployments import ( DeploymentsConfig, deployment_path, list_deployments, diff --git a/sunbeam-python/sunbeam/provider/local/commands.py b/sunbeam-python/sunbeam/provider/local/commands.py index 35092cb5..ebb39599 100644 --- a/sunbeam-python/sunbeam/provider/local/commands.py +++ b/sunbeam-python/sunbeam/provider/local/commands.py @@ -27,11 +27,64 @@ ClusterServiceUnavailableException, ConfigItemNotFoundException, ) -from sunbeam.commands import cluster_status from sunbeam.commands import refresh as refresh_cmds from sunbeam.commands import resize as resize_cmds -from sunbeam.commands.bootstrap_state import SetBootstrapped -from sunbeam.commands.clusterd import ( +from sunbeam.commands.configure import ( + DemoSetup, + SetHypervisorCharmConfigStep, + TerraformDemoInitStep, + UserOpenRCStep, + UserQuestions, + retrieve_admin_credentials, +) +from sunbeam.commands.proxy import PromptForProxyStep +from sunbeam.core.checks import ( + Check, + DaemonGroupCheck, + JujuControllerRegistrationCheck, + JujuSnapCheck, + LocalShareCheck, + SshKeysConnectedCheck, + SystemRequirementsCheck, + TokenCheck, + VerifyBootstrappedCheck, + VerifyFQDNCheck, + VerifyHypervisorHostnameCheck, + run_preflight_checks, +) +from sunbeam.core.common import ( + CONTEXT_SETTINGS, + FORMAT_DEFAULT, + FORMAT_TABLE, + FORMAT_VALUE, + FORMAT_YAML, + BaseStep, + ResultType, + Role, + click_option_topology, + get_step_message, + get_step_result, + read_config, + roles_to_str_list, + run_plan, + update_config, + validate_roles, +) +from sunbeam.core.deployment import Deployment, Networks +from sunbeam.core.deployments import DeploymentsConfig, deployment_path +from sunbeam.core.juju import JujuHelper, ModelNotFoundException, run_sync +from sunbeam.core.manifest import AddManifestStep +from sunbeam.core.openstack import OPENSTACK_MODEL +from sunbeam.core.terraform import TerraformInitStep +from sunbeam.provider.base import ProviderBase +from sunbeam.provider.local.deployment import LOCAL_TYPE, LocalDeployment +from sunbeam.provider.local.steps import ( + LocalClusterStatusStep, + LocalSetHypervisorUnitsOptionsStep, +) +from sunbeam.steps import cluster_status +from sunbeam.steps.bootstrap_state import SetBootstrapped +from sunbeam.steps.clusterd import ( AskManagementCidrStep, ClusterAddJujuUserStep, ClusterAddNodeStep, @@ -42,20 +95,12 @@ ClusterUpdateNodeStep, SaveManagementCidrStep, ) -from sunbeam.commands.configure import ( - DemoSetup, - SetHypervisorCharmConfigStep, - TerraformDemoInitStep, - UserOpenRCStep, - UserQuestions, - retrieve_admin_credentials, -) -from sunbeam.commands.hypervisor import ( +from sunbeam.steps.hypervisor import ( AddHypervisorUnitsStep, DeployHypervisorApplicationStep, RemoveHypervisorUnitStep, ) -from sunbeam.commands.juju import ( +from sunbeam.steps.juju import ( AddCloudJujuStep, AddJujuMachineStep, AddJujuModelStep, @@ -74,7 +119,7 @@ SaveJujuUserLocallyStep, UpdateJujuModelConfigStep, ) -from sunbeam.commands.k8s import ( +from sunbeam.steps.k8s import ( AddK8SCloudStep, AddK8SCredentialStep, AddK8SUnitsStep, @@ -83,13 +128,13 @@ RemoveK8SUnitsStep, StoreK8SKubeConfigStep, ) -from sunbeam.commands.microceph import ( +from sunbeam.steps.microceph import ( AddMicrocephUnitsStep, ConfigureMicrocephOSDStep, DeployMicrocephApplicationStep, RemoveMicrocephUnitsStep, ) -from sunbeam.commands.microk8s import ( +from sunbeam.steps.microk8s import ( AddMicrok8sCloudStep, AddMicrok8sCredentialStep, AddMicrok8sUnitsStep, @@ -97,62 +142,17 @@ RemoveMicrok8sUnitsStep, StoreMicrok8sConfigStep, ) -from sunbeam.commands.mysql import ConfigureMySQLStep -from sunbeam.commands.openstack import ( - OPENSTACK_MODEL, +from sunbeam.steps.mysql import ConfigureMySQLStep +from sunbeam.steps.openstack import ( DeployControlPlaneStep, OpenStackPatchLoadBalancerServicesStep, PromptRegionStep, ) -from sunbeam.commands.proxy import PromptForProxyStep -from sunbeam.commands.sunbeam_machine import ( +from sunbeam.steps.sunbeam_machine import ( AddSunbeamMachineUnitsStep, DeploySunbeamMachineApplicationStep, RemoveSunbeamMachineUnitsStep, ) -from sunbeam.commands.terraform import TerraformInitStep -from sunbeam.jobs.checks import ( - Check, - DaemonGroupCheck, - JujuControllerRegistrationCheck, - JujuSnapCheck, - LocalShareCheck, - SshKeysConnectedCheck, - SystemRequirementsCheck, - TokenCheck, - VerifyBootstrappedCheck, - VerifyFQDNCheck, - VerifyHypervisorHostnameCheck, - run_preflight_checks, -) -from sunbeam.jobs.common import ( - CONTEXT_SETTINGS, - FORMAT_DEFAULT, - FORMAT_TABLE, - FORMAT_VALUE, - FORMAT_YAML, - BaseStep, - ResultType, - Role, - click_option_topology, - get_step_message, - get_step_result, - read_config, - roles_to_str_list, - run_plan, - update_config, - validate_roles, -) -from sunbeam.jobs.deployment import Deployment, Networks -from sunbeam.jobs.deployments import DeploymentsConfig, deployment_path -from sunbeam.jobs.juju import JujuHelper, ModelNotFoundException, run_sync -from sunbeam.jobs.manifest import AddManifestStep -from sunbeam.provider.base import ProviderBase -from sunbeam.provider.local.deployment import LOCAL_TYPE, LocalDeployment -from sunbeam.provider.local.steps import ( - LocalClusterStatusStep, - LocalSetHypervisorUnitsOptionsStep, -) from sunbeam.utils import CatchGroup, argument_with_deprecated_option LOG = logging.getLogger(__name__) diff --git a/sunbeam-python/sunbeam/provider/local/deployment.py b/sunbeam-python/sunbeam/provider/local/deployment.py index ebd84134..b240ff00 100644 --- a/sunbeam-python/sunbeam/provider/local/deployment.py +++ b/sunbeam-python/sunbeam/provider/local/deployment.py @@ -26,36 +26,36 @@ ClusterServiceUnavailableException, ConfigItemNotFoundException, ) -from sunbeam.commands.clusterd import ( - BOOTSTRAP_CONFIG_KEY, - CLUSTERD_PORT, - bootstrap_questions, -) from sunbeam.commands.configure import ( CLOUD_CONFIG_SECTION, ext_net_questions, ext_net_questions_local_only, user_questions, ) -from sunbeam.commands.k8s import K8S_ADDONS_CONFIG_KEY, k8s_addons_questions -from sunbeam.commands.microceph import CONFIG_DISKS_KEY, microceph_questions -from sunbeam.commands.microk8s import ( - MICROK8S_ADDONS_CONFIG_KEY, - microk8s_addons_questions, -) -from sunbeam.commands.openstack import REGION_CONFIG_KEY, region_questions from sunbeam.commands.proxy import proxy_questions -from sunbeam.jobs.checks import DaemonGroupCheck -from sunbeam.jobs.common import SunbeamException -from sunbeam.jobs.deployment import PROXY_CONFIG_KEY, CertPair, Deployment, Networks -from sunbeam.jobs.feature import FeatureManager -from sunbeam.jobs.juju import ( +from sunbeam.core.checks import DaemonGroupCheck +from sunbeam.core.common import SunbeamException +from sunbeam.core.deployment import PROXY_CONFIG_KEY, CertPair, Deployment, Networks +from sunbeam.core.feature import FeatureManager +from sunbeam.core.juju import ( CONTROLLER, JujuAccount, JujuAccountNotFound, JujuController, ) -from sunbeam.jobs.questions import QuestionBank, load_answers, show_questions +from sunbeam.core.questions import QuestionBank, load_answers, show_questions +from sunbeam.steps.clusterd import ( + BOOTSTRAP_CONFIG_KEY, + CLUSTERD_PORT, + bootstrap_questions, +) +from sunbeam.steps.k8s import K8S_ADDONS_CONFIG_KEY, k8s_addons_questions +from sunbeam.steps.microceph import CONFIG_DISKS_KEY, microceph_questions +from sunbeam.steps.microk8s import ( + MICROK8S_ADDONS_CONFIG_KEY, + microk8s_addons_questions, +) +from sunbeam.steps.openstack import REGION_CONFIG_KEY, region_questions LOG = logging.getLogger(__name__) LOCAL_TYPE = "local" diff --git a/sunbeam-python/sunbeam/provider/local/steps.py b/sunbeam-python/sunbeam/provider/local/steps.py index 0f1bcef8..bb82a31c 100644 --- a/sunbeam-python/sunbeam/provider/local/steps.py +++ b/sunbeam-python/sunbeam/provider/local/steps.py @@ -21,16 +21,16 @@ from rich.console import Console from rich.prompt import InvalidResponse, PromptBase -import sunbeam.jobs.questions +import sunbeam.core.questions from sunbeam import utils from sunbeam.clusterd.client import Client -from sunbeam.commands import hypervisor -from sunbeam.commands.cluster_status import ClusterStatusStep from sunbeam.commands.configure import ( CLOUD_CONFIG_SECTION, SetHypervisorUnitsOptionsStep, ) -from sunbeam.jobs.juju import JujuHelper +from sunbeam.core.juju import JujuHelper +from sunbeam.steps import hypervisor +from sunbeam.steps.cluster_status import ClusterStatusStep LOG = logging.getLogger(__name__) console = Console() @@ -99,7 +99,7 @@ def __call__(self, *, default: Any = ..., stream: TextIO | None = None) -> Any: return return_value -class NicQuestion(sunbeam.jobs.questions.Question[str]): +class NicQuestion(sunbeam.core.questions.Question[str]): """Ask the user a simple yes / no question.""" @property @@ -143,7 +143,7 @@ def has_prompts(self) -> bool: def prompt_for_nic(self) -> str | None: """Prompt user for nic to use and do some validation.""" - local_hypervisor_bank = sunbeam.jobs.questions.QuestionBank( + local_hypervisor_bank = sunbeam.core.questions.QuestionBank( questions=local_hypervisor_questions(), console=console, accept_defaults=False, @@ -154,7 +154,7 @@ def prompt_for_nic(self) -> str | None: if not nic: continue if utils.is_configured(nic): - agree_nic_up = sunbeam.jobs.questions.ConfirmQuestion( + agree_nic_up = sunbeam.core.questions.ConfirmQuestion( f"WARNING: Interface {nic} is configured. Any " "configuration will be lost, are you sure you want to " "continue?" @@ -162,7 +162,7 @@ def prompt_for_nic(self) -> str | None: if not agree_nic_up: continue if utils.is_nic_up(nic) and not utils.is_nic_connected(nic): - agree_nic_no_link = sunbeam.jobs.questions.ConfirmQuestion( + agree_nic_no_link = sunbeam.core.questions.ConfirmQuestion( f"WARNING: Interface {nic} is not connected. Are " "you sure you want to continue?" ).ask() @@ -175,7 +175,7 @@ def prompt(self, console: Console | None = None) -> None: """Determines if the step can take input from the user.""" # If adding a node before configure step has run then answers will # not be populated yet. - self.variables = sunbeam.jobs.questions.load_answers( + self.variables = sunbeam.core.questions.load_answers( self.client, CLOUD_CONFIG_SECTION ) remote_access_location = self.variables.get("user", {}).get( diff --git a/sunbeam-python/sunbeam/provider/maas/client.py b/sunbeam-python/sunbeam/provider/maas/client.py index 28717b59..6ee48aed 100644 --- a/sunbeam-python/sunbeam/provider/maas/client.py +++ b/sunbeam-python/sunbeam/provider/maas/client.py @@ -22,8 +22,8 @@ from maas.client import bones, connect # type: ignore [import-untyped] from rich.console import Console -from sunbeam.jobs.deployment import Deployment, Networks -from sunbeam.jobs.deployments import DeploymentsConfig +from sunbeam.core.deployment import Deployment, Networks +from sunbeam.core.deployments import DeploymentsConfig from sunbeam.provider.maas.deployment import ( MaasDeployment, RoleTags, diff --git a/sunbeam-python/sunbeam/provider/maas/commands.py b/sunbeam-python/sunbeam/provider/maas/commands.py index 52bfc436..9245f265 100644 --- a/sunbeam-python/sunbeam/provider/maas/commands.py +++ b/sunbeam-python/sunbeam/provider/maas/commands.py @@ -28,13 +28,7 @@ from rich.table import Table from snaphelpers import Snap -from sunbeam.commands import cluster_status from sunbeam.commands import resize as resize_cmds -from sunbeam.commands.bootstrap_state import SetBootstrapped -from sunbeam.commands.certificates import APPLICATION as CERTIFICATES_APPLICATION -from sunbeam.commands.certificates import DeployCertificatesProviderApplicationStep -from sunbeam.commands.clusterd import APPLICATION as CLUSTERD_APPLICATION -from sunbeam.commands.clusterd import DeploySunbeamClusterdApplicationStep from sunbeam.commands.configure import ( DemoSetup, SetHypervisorCharmConfigStep, @@ -42,47 +36,8 @@ UserOpenRCStep, retrieve_admin_credentials, ) -from sunbeam.commands.hypervisor import ( - AddHypervisorUnitsStep, - DeployHypervisorApplicationStep, -) -from sunbeam.commands.juju import ( - AddCloudJujuStep, - AddCredentialsJujuStep, - AddJujuModelStep, - DownloadJujuControllerCharmStep, - IntegrateJujuApplicationsStep, - JujuLoginStep, - UpdateJujuMachineIDStep, -) -from sunbeam.commands.k8s import ( - AddK8SCloudStep, - AddK8SUnitsStep, - StoreK8SKubeConfigStep, -) -from sunbeam.commands.microceph import ( - AddMicrocephUnitsStep, - DeployMicrocephApplicationStep, -) -from sunbeam.commands.microk8s import ( - AddMicrok8sCloudStep, - AddMicrok8sUnitsStep, - StoreMicrok8sConfigStep, -) -from sunbeam.commands.mysql import ConfigureMySQLStep -from sunbeam.commands.openstack import ( - OPENSTACK_MODEL, - DeployControlPlaneStep, - OpenStackPatchLoadBalancerServicesStep, - PromptRegionStep, -) from sunbeam.commands.proxy import PromptForProxyStep -from sunbeam.commands.sunbeam_machine import ( - AddSunbeamMachineUnitsStep, - DeploySunbeamMachineApplicationStep, -) -from sunbeam.commands.terraform import TerraformInitStep -from sunbeam.jobs.checks import ( +from sunbeam.core.checks import ( Check, DiagnosticResultType, DiagnosticsCheck, @@ -93,7 +48,7 @@ VerifyClusterdNotBootstrappedCheck, run_preflight_checks, ) -from sunbeam.jobs.common import ( +from sunbeam.core.common import ( CLICK_FAIL, CLICK_OK, CLICK_WARN, @@ -105,16 +60,18 @@ run_plan, str_presenter, ) -from sunbeam.jobs.deployment import PROXY_CONFIG_KEY, Deployment, Networks -from sunbeam.jobs.deployments import DeploymentsConfig, deployment_path -from sunbeam.jobs.juju import ( +from sunbeam.core.deployment import PROXY_CONFIG_KEY, Deployment, Networks +from sunbeam.core.deployments import DeploymentsConfig, deployment_path +from sunbeam.core.juju import ( CONTROLLER_APPLICATION, CONTROLLER_MODEL, JujuHelper, ModelNotFoundException, run_sync, ) -from sunbeam.jobs.manifest import AddManifestStep +from sunbeam.core.manifest import AddManifestStep +from sunbeam.core.openstack import OPENSTACK_MODEL +from sunbeam.core.terraform import TerraformInitStep from sunbeam.provider.base import ProviderBase from sunbeam.provider.maas.client import ( MaasClient, @@ -158,6 +115,45 @@ MachineStorageCheck, NetworkMappingCompleteCheck, ) +from sunbeam.steps import cluster_status +from sunbeam.steps.bootstrap_state import SetBootstrapped +from sunbeam.steps.certificates import APPLICATION as CERTIFICATES_APPLICATION +from sunbeam.steps.certificates import DeployCertificatesProviderApplicationStep +from sunbeam.steps.clusterd import APPLICATION as CLUSTERD_APPLICATION +from sunbeam.steps.clusterd import DeploySunbeamClusterdApplicationStep +from sunbeam.steps.hypervisor import ( + AddHypervisorUnitsStep, + DeployHypervisorApplicationStep, +) +from sunbeam.steps.juju import ( + AddCloudJujuStep, + AddCredentialsJujuStep, + AddJujuModelStep, + DownloadJujuControllerCharmStep, + IntegrateJujuApplicationsStep, + JujuLoginStep, + UpdateJujuMachineIDStep, +) +from sunbeam.steps.k8s import AddK8SCloudStep, AddK8SUnitsStep, StoreK8SKubeConfigStep +from sunbeam.steps.microceph import ( + AddMicrocephUnitsStep, + DeployMicrocephApplicationStep, +) +from sunbeam.steps.microk8s import ( + AddMicrok8sCloudStep, + AddMicrok8sUnitsStep, + StoreMicrok8sConfigStep, +) +from sunbeam.steps.mysql import ConfigureMySQLStep +from sunbeam.steps.openstack import ( + DeployControlPlaneStep, + OpenStackPatchLoadBalancerServicesStep, + PromptRegionStep, +) +from sunbeam.steps.sunbeam_machine import ( + AddSunbeamMachineUnitsStep, + DeploySunbeamMachineApplicationStep, +) from sunbeam.utils import CatchGroup, argument_with_deprecated_option LOG = logging.getLogger(__name__) diff --git a/sunbeam-python/sunbeam/provider/maas/deployment.py b/sunbeam-python/sunbeam/provider/maas/deployment.py index a5e37845..fe2471cd 100644 --- a/sunbeam-python/sunbeam/provider/maas/deployment.py +++ b/sunbeam-python/sunbeam/provider/maas/deployment.py @@ -25,11 +25,11 @@ ext_net_questions, user_questions, ) -from sunbeam.commands.openstack import REGION_CONFIG_KEY, region_questions from sunbeam.commands.proxy import proxy_questions -from sunbeam.jobs.deployment import PROXY_CONFIG_KEY, Deployment, Networks -from sunbeam.jobs.feature import FeatureManager -from sunbeam.jobs.questions import Question, QuestionBank, load_answers, show_questions +from sunbeam.core.deployment import PROXY_CONFIG_KEY, Deployment, Networks +from sunbeam.core.feature import FeatureManager +from sunbeam.core.questions import Question, QuestionBank, load_answers, show_questions +from sunbeam.steps.openstack import REGION_CONFIG_KEY, region_questions if TYPE_CHECKING: from sunbeam.provider.maas.client import MaasClient diff --git a/sunbeam-python/sunbeam/provider/maas/steps.py b/sunbeam-python/sunbeam/provider/maas/steps.py index e2fc2bd6..d8c2cfe9 100644 --- a/sunbeam-python/sunbeam/provider/maas/steps.py +++ b/sunbeam-python/sunbeam/provider/maas/steps.py @@ -29,43 +29,31 @@ from rich.status import Status from snaphelpers import Snap -import sunbeam.commands.k8s as k8s -import sunbeam.commands.microceph as microceph -import sunbeam.commands.microk8s as microk8s -import sunbeam.jobs.questions +import sunbeam.core.questions import sunbeam.provider.maas.client as maas_client import sunbeam.provider.maas.deployment as maas_deployment +import sunbeam.steps.k8s as k8s +import sunbeam.steps.microceph as microceph +import sunbeam.steps.microk8s as microk8s import sunbeam.utils as sunbeam_utils from sunbeam.clusterd.client import Client -from sunbeam.commands import clusterd -from sunbeam.commands.cluster_status import ClusterStatusStep -from sunbeam.commands.clusterd import APPLICATION as CLUSTERD_APPLICATION from sunbeam.commands.configure import ( CLOUD_CONFIG_SECTION, VARIABLE_DEFAULTS, SetHypervisorUnitsOptionsStep, ext_net_questions, ) -from sunbeam.commands.juju import ( - JUJU_CONTROLLER_CHARM, - BootstrapJujuStep, - ControllerNotFoundException, - JujuStepHelper, - SaveControllerStep, - ScaleJujuStep, -) -from sunbeam.commands.terraform import TerraformHelper -from sunbeam.jobs.checks import Check, DiagnosticsCheck, DiagnosticsResult -from sunbeam.jobs.common import ( +from sunbeam.core.checks import Check, DiagnosticsCheck, DiagnosticsResult +from sunbeam.core.common import ( RAM_4_GB_IN_MB, RAM_32_GB_IN_MB, BaseStep, Result, ResultType, ) -from sunbeam.jobs.deployment import CertPair, Networks -from sunbeam.jobs.deployments import DeploymentsConfig -from sunbeam.jobs.juju import ( +from sunbeam.core.deployment import CertPair, Networks +from sunbeam.core.deployments import DeploymentsConfig +from sunbeam.core.juju import ( ActionFailedException, JujuHelper, JujuSecretNotFound, @@ -74,7 +62,19 @@ UnitNotFoundException, run_sync, ) -from sunbeam.jobs.manifest import Manifest +from sunbeam.core.manifest import Manifest +from sunbeam.core.terraform import TerraformHelper +from sunbeam.steps import clusterd +from sunbeam.steps.cluster_status import ClusterStatusStep +from sunbeam.steps.clusterd import APPLICATION as CLUSTERD_APPLICATION +from sunbeam.steps.juju import ( + JUJU_CONTROLLER_CHARM, + BootstrapJujuStep, + ControllerNotFoundException, + JujuStepHelper, + SaveControllerStep, + ScaleJujuStep, +) from sunbeam.versions import JUJU_BASE LOG = logging.getLogger(__name__) @@ -2098,14 +2098,14 @@ def prompt(self, console: Console | None = None) -> None: :param console: the console to prompt on :type console: rich.console.Console (Optional) """ - self.variables = sunbeam.jobs.questions.load_answers( + self.variables = sunbeam.core.questions.load_answers( self.client, CLOUD_CONFIG_SECTION ) for section in ["user", "external_network"]: if not self.variables.get(section): self.variables[section] = {} - user_bank = sunbeam.jobs.questions.QuestionBank( + user_bank = sunbeam.core.questions.QuestionBank( questions=maas_deployment.maas_user_questions(self.maas_client), console=console, preseed=self.preseed.get("user"), @@ -2114,7 +2114,7 @@ def prompt(self, console: Console | None = None) -> None: ) self.variables["user"]["remote_access_location"] = sunbeam_utils.REMOTE_ACCESS # External Network Configuration - ext_net_bank = sunbeam.jobs.questions.QuestionBank( + ext_net_bank = sunbeam.core.questions.QuestionBank( questions=ext_net_questions(), console=console, preseed=self.preseed.get("external_network"), @@ -2174,7 +2174,7 @@ def prompt(self, console: Console | None = None) -> None: user_bank.security_group_rules.ask() ) - sunbeam.jobs.questions.write_answers( + sunbeam.core.questions.write_answers( self.client, CLOUD_CONFIG_SECTION, self.variables ) diff --git a/sunbeam-python/sunbeam/jobs/__init__.py b/sunbeam-python/sunbeam/steps/__init__.py similarity index 100% rename from sunbeam-python/sunbeam/jobs/__init__.py rename to sunbeam-python/sunbeam/steps/__init__.py diff --git a/sunbeam-python/sunbeam/commands/bootstrap_state.py b/sunbeam-python/sunbeam/steps/bootstrap_state.py similarity index 95% rename from sunbeam-python/sunbeam/commands/bootstrap_state.py rename to sunbeam-python/sunbeam/steps/bootstrap_state.py index b0daf717..938e4b57 100644 --- a/sunbeam-python/sunbeam/commands/bootstrap_state.py +++ b/sunbeam-python/sunbeam/steps/bootstrap_state.py @@ -17,7 +17,7 @@ from rich.status import Status from sunbeam.clusterd.client import Client -from sunbeam.jobs.common import BaseStep, Result, ResultType +from sunbeam.core.common import BaseStep, Result, ResultType LOG = logging.getLogger(__name__) diff --git a/sunbeam-python/sunbeam/commands/certificates.py b/sunbeam-python/sunbeam/steps/certificates.py similarity index 95% rename from sunbeam-python/sunbeam/commands/certificates.py rename to sunbeam-python/sunbeam/steps/certificates.py index be4b18a1..fbd0e924 100644 --- a/sunbeam-python/sunbeam/commands/certificates.py +++ b/sunbeam-python/sunbeam/steps/certificates.py @@ -15,15 +15,15 @@ import logging -from sunbeam.jobs.common import BaseStep, Result, ResultType, Status -from sunbeam.jobs.juju import ( +from sunbeam.core.common import BaseStep, Result, ResultType, Status +from sunbeam.core.juju import ( ApplicationNotFoundException, JujuHelper, JujuWaitException, TimeoutException, run_sync, ) -from sunbeam.jobs.manifest import CharmManifest, Manifest +from sunbeam.core.manifest import CharmManifest, Manifest LOG = logging.getLogger(__name__) APPLICATION = "tls-operator" diff --git a/sunbeam-python/sunbeam/commands/cluster_status.py b/sunbeam-python/sunbeam/steps/cluster_status.py similarity index 97% rename from sunbeam-python/sunbeam/commands/cluster_status.py rename to sunbeam-python/sunbeam/steps/cluster_status.py index 0db0e6e1..1ce45484 100644 --- a/sunbeam-python/sunbeam/commands/cluster_status.py +++ b/sunbeam-python/sunbeam/steps/cluster_status.py @@ -25,17 +25,17 @@ from rich.status import Status from sunbeam.clusterd.service import ClusterServiceUnavailableException -from sunbeam.commands import clusterd, hypervisor, k8s, microceph, microk8s -from sunbeam.jobs.common import ( +from sunbeam.core.common import ( FORMAT_TABLE, FORMAT_YAML, Result, ResultType, SunbeamException, ) -from sunbeam.jobs.deployment import Deployment -from sunbeam.jobs.juju import JujuHelper, ModelNotFoundException, run_sync -from sunbeam.jobs.steps import BaseStep +from sunbeam.core.deployment import Deployment +from sunbeam.core.juju import JujuHelper, ModelNotFoundException, run_sync +from sunbeam.core.steps import BaseStep +from sunbeam.steps import clusterd, hypervisor, k8s, microceph, microk8s from sunbeam.utils import merge_dict LOG = logging.getLogger(__name__) diff --git a/sunbeam-python/sunbeam/commands/clusterd.py b/sunbeam-python/sunbeam/steps/clusterd.py similarity index 98% rename from sunbeam-python/sunbeam/commands/clusterd.py rename to sunbeam-python/sunbeam/steps/clusterd.py index 458af350..2d089693 100644 --- a/sunbeam-python/sunbeam/commands/clusterd.py +++ b/sunbeam-python/sunbeam/steps/clusterd.py @@ -34,10 +34,9 @@ TokenAlreadyGeneratedException, TokenNotFoundException, ) -from sunbeam.commands.juju import BOOTSTRAP_CONFIG_KEY, JujuStepHelper -from sunbeam.jobs import questions -from sunbeam.jobs.common import BaseStep, Result, ResultType, Status -from sunbeam.jobs.juju import ( +from sunbeam.core import questions +from sunbeam.core.common import BaseStep, Result, ResultType, Status +from sunbeam.core.juju import ( ApplicationNotFoundException, JujuController, JujuHelper, @@ -45,7 +44,8 @@ TimeoutException, run_sync, ) -from sunbeam.jobs.manifest import CharmManifest, Manifest +from sunbeam.core.manifest import CharmManifest, Manifest +from sunbeam.steps.juju import BOOTSTRAP_CONFIG_KEY, JujuStepHelper LOG = logging.getLogger(__name__) APPLICATION = "sunbeam-clusterd" diff --git a/sunbeam-python/sunbeam/commands/hypervisor.py b/sunbeam-python/sunbeam/steps/hypervisor.py similarity index 95% rename from sunbeam-python/sunbeam/commands/hypervisor.py rename to sunbeam-python/sunbeam/steps/hypervisor.py index 957ca4fc..5b9f7e49 100644 --- a/sunbeam-python/sunbeam/commands/hypervisor.py +++ b/sunbeam-python/sunbeam/steps/hypervisor.py @@ -24,20 +24,20 @@ ConfigItemNotFoundException, NodeNotExistInClusterException, ) -from sunbeam.commands.juju import JujuStepHelper -from sunbeam.commands.openstack import OPENSTACK_MODEL -from sunbeam.commands.openstack_api import guests_on_hypervisor, remove_hypervisor -from sunbeam.commands.terraform import TerraformException, TerraformHelper -from sunbeam.jobs.common import BaseStep, Result, ResultType, read_config, update_config -from sunbeam.jobs.deployment import Deployment, Networks -from sunbeam.jobs.juju import ( +from sunbeam.core.common import BaseStep, Result, ResultType, read_config, update_config +from sunbeam.core.deployment import Deployment, Networks +from sunbeam.core.juju import ( ApplicationNotFoundException, JujuHelper, TimeoutException, run_sync, ) -from sunbeam.jobs.manifest import Manifest -from sunbeam.jobs.steps import AddMachineUnitsStep, DeployMachineApplicationStep +from sunbeam.core.manifest import Manifest +from sunbeam.core.openstack import OPENSTACK_MODEL +from sunbeam.core.openstack_api import guests_on_hypervisor, remove_hypervisor +from sunbeam.core.steps import AddMachineUnitsStep, DeployMachineApplicationStep +from sunbeam.core.terraform import TerraformException, TerraformHelper +from sunbeam.steps.juju import JujuStepHelper LOG = logging.getLogger(__name__) CONFIG_KEY = "TerraformVarsHypervisor" diff --git a/sunbeam-python/sunbeam/commands/juju.py b/sunbeam-python/sunbeam/steps/juju.py similarity index 99% rename from sunbeam-python/sunbeam/commands/juju.py rename to sunbeam-python/sunbeam/steps/juju.py index ae96b75b..aa2d6403 100644 --- a/sunbeam-python/sunbeam/commands/juju.py +++ b/sunbeam-python/sunbeam/steps/juju.py @@ -38,14 +38,14 @@ JujuUserNotFoundException, NodeNotExistInClusterException, ) -from sunbeam.jobs.common import ( +from sunbeam.core.common import ( BaseStep, Result, ResultType, convert_proxy_to_model_configs, ) -from sunbeam.jobs.deployments import DeploymentsConfig -from sunbeam.jobs.juju import ( +from sunbeam.core.deployments import DeploymentsConfig +from sunbeam.core.juju import ( CONTROLLER_MODEL, ApplicationNotFoundException, ControllerNotFoundException, diff --git a/sunbeam-python/sunbeam/commands/k8s.py b/sunbeam-python/sunbeam/steps/k8s.py similarity index 97% rename from sunbeam-python/sunbeam/commands/k8s.py rename to sunbeam-python/sunbeam/steps/k8s.py index 5249bf85..3df309e9 100644 --- a/sunbeam-python/sunbeam/commands/k8s.py +++ b/sunbeam-python/sunbeam/steps/k8s.py @@ -22,9 +22,7 @@ from sunbeam.clusterd.client import Client from sunbeam.clusterd.service import ConfigItemNotFoundException -from sunbeam.commands.juju import JujuStepHelper -from sunbeam.commands.terraform import TerraformHelper -from sunbeam.jobs.common import ( +from sunbeam.core.common import ( BaseStep, Result, ResultType, @@ -32,8 +30,8 @@ read_config, update_config, ) -from sunbeam.jobs.deployment import Deployment, Networks -from sunbeam.jobs.juju import ( +from sunbeam.core.deployment import Deployment, Networks +from sunbeam.core.juju import ( ActionFailedException, ApplicationNotFoundException, JujuException, @@ -42,24 +40,26 @@ UnsupportedKubeconfigException, run_sync, ) -from sunbeam.jobs.k8s import ( +from sunbeam.core.k8s import ( CREDENTIAL_SUFFIX, K8S_CLOUD_SUFFIX, K8S_KUBECONFIG_KEY, validate_cidr_or_ip_range, ) -from sunbeam.jobs.manifest import Manifest -from sunbeam.jobs.questions import ( +from sunbeam.core.manifest import Manifest +from sunbeam.core.questions import ( PromptQuestion, QuestionBank, load_answers, write_answers, ) -from sunbeam.jobs.steps import ( +from sunbeam.core.steps import ( AddMachineUnitsStep, DeployMachineApplicationStep, RemoveMachineUnitsStep, ) +from sunbeam.core.terraform import TerraformHelper +from sunbeam.steps.juju import JujuStepHelper LOG = logging.getLogger(__name__) K8S_CONFIG_KEY = "TerraformVarsK8S" diff --git a/sunbeam-python/sunbeam/commands/microceph.py b/sunbeam-python/sunbeam/steps/microceph.py similarity index 97% rename from sunbeam-python/sunbeam/commands/microceph.py rename to sunbeam-python/sunbeam/steps/microceph.py index 3c333f82..905de9c6 100644 --- a/sunbeam-python/sunbeam/commands/microceph.py +++ b/sunbeam-python/sunbeam/steps/microceph.py @@ -17,16 +17,14 @@ import logging from typing import Any -import click from rich.console import Console from rich.status import Status from sunbeam.clusterd.client import Client -from sunbeam.commands.terraform import TerraformHelper -from sunbeam.jobs import questions -from sunbeam.jobs.common import BaseStep, Result, ResultType -from sunbeam.jobs.deployment import Deployment, Networks -from sunbeam.jobs.juju import ( +from sunbeam.core import questions +from sunbeam.core.common import BaseStep, Result, ResultType, SunbeamException +from sunbeam.core.deployment import Deployment, Networks +from sunbeam.core.juju import ( ActionFailedException, ApplicationNotFoundException, JujuHelper, @@ -34,12 +32,13 @@ UnitNotFoundException, run_sync, ) -from sunbeam.jobs.manifest import Manifest -from sunbeam.jobs.steps import ( +from sunbeam.core.manifest import Manifest +from sunbeam.core.steps import ( AddMachineUnitsStep, DeployMachineApplicationStep, RemoveMachineUnitsStep, ) +from sunbeam.core.terraform import TerraformHelper LOG = logging.getLogger(__name__) CONFIG_KEY = "TerraformVarsMicrocephPlan" @@ -300,7 +299,7 @@ def get_all_disks(self) -> None: except (UnitNotFoundException, ActionFailedException) as e: LOG.debug(str(e)) - raise click.ClickException("Unable to list disks") + raise SunbeamException("Unable to list disks") def prompt(self, console: Console | None = None) -> None: """Determines if the step can take input from the user. diff --git a/sunbeam-python/sunbeam/commands/microk8s.py b/sunbeam-python/sunbeam/steps/microk8s.py similarity index 95% rename from sunbeam-python/sunbeam/commands/microk8s.py rename to sunbeam-python/sunbeam/steps/microk8s.py index 73754e29..b4668cf5 100644 --- a/sunbeam-python/sunbeam/commands/microk8s.py +++ b/sunbeam-python/sunbeam/steps/microk8s.py @@ -21,13 +21,10 @@ from sunbeam.clusterd.client import Client from sunbeam.clusterd.service import ConfigItemNotFoundException -from sunbeam.commands.juju import JujuStepHelper -from sunbeam.commands.k8s import AddK8SCredentialStep -from sunbeam.commands.terraform import TerraformHelper -from sunbeam.jobs import questions -from sunbeam.jobs.common import BaseStep, Result, ResultType, read_config, update_config -from sunbeam.jobs.deployment import Deployment, Networks -from sunbeam.jobs.juju import ( +from sunbeam.core import questions +from sunbeam.core.common import BaseStep, Result, ResultType, read_config, update_config +from sunbeam.core.deployment import Deployment, Networks +from sunbeam.core.juju import ( ActionFailedException, ApplicationNotFoundException, JujuHelper, @@ -35,18 +32,21 @@ UnsupportedKubeconfigException, run_sync, ) -from sunbeam.jobs.k8s import ( +from sunbeam.core.k8s import ( CREDENTIAL_SUFFIX, K8S_CLOUD_SUFFIX, MICROK8S_KUBECONFIG_KEY, validate_cidr_or_ip_range, ) -from sunbeam.jobs.manifest import Manifest -from sunbeam.jobs.steps import ( +from sunbeam.core.manifest import Manifest +from sunbeam.core.steps import ( AddMachineUnitsStep, DeployMachineApplicationStep, RemoveMachineUnitsStep, ) +from sunbeam.core.terraform import TerraformHelper +from sunbeam.steps.juju import JujuStepHelper +from sunbeam.steps.k8s import AddK8SCredentialStep LOG = logging.getLogger(__name__) APPLICATION = "microk8s" diff --git a/sunbeam-python/sunbeam/commands/mysql.py b/sunbeam-python/sunbeam/steps/mysql.py similarity index 96% rename from sunbeam-python/sunbeam/commands/mysql.py rename to sunbeam-python/sunbeam/steps/mysql.py index 6d2b833d..c096ea03 100644 --- a/sunbeam-python/sunbeam/commands/mysql.py +++ b/sunbeam-python/sunbeam/steps/mysql.py @@ -16,15 +16,15 @@ from rich.status import Status -from sunbeam.commands.openstack import OPENSTACK_MODEL -from sunbeam.jobs.common import BaseStep, Result, ResultType -from sunbeam.jobs.juju import ( +from sunbeam.core.common import BaseStep, Result, ResultType +from sunbeam.core.juju import ( JujuException, JujuHelper, ModelNotFoundException, TimeoutException, run_sync, ) +from sunbeam.core.openstack import OPENSTACK_MODEL MAX_CONNECTIONS = 500 SET_MAX_CONNECTIONS_TIMEOUT = 300 diff --git a/sunbeam-python/sunbeam/commands/openstack.py b/sunbeam-python/sunbeam/steps/openstack.py similarity index 96% rename from sunbeam-python/sunbeam/commands/openstack.py rename to sunbeam-python/sunbeam/steps/openstack.py index e13494b7..edc203e8 100644 --- a/sunbeam-python/sunbeam/commands/openstack.py +++ b/sunbeam-python/sunbeam/steps/openstack.py @@ -19,12 +19,10 @@ from rich.console import Console from rich.status import Status -import sunbeam.commands.microceph as microceph +import sunbeam.steps.microceph as microceph from sunbeam.clusterd.client import Client from sunbeam.clusterd.service import ConfigItemNotFoundException -from sunbeam.commands.juju import JujuStepHelper -from sunbeam.commands.terraform import TerraformException, TerraformHelper -from sunbeam.jobs.common import ( +from sunbeam.core.common import ( RAM_32_GB_IN_KB, BaseStep, Result, @@ -35,20 +33,22 @@ update_config, update_status_background, ) -from sunbeam.jobs.deployment import Deployment -from sunbeam.jobs.juju import JujuHelper, JujuWaitException, TimeoutException, run_sync -from sunbeam.jobs.k8s import CREDENTIAL_SUFFIX, K8SHelper -from sunbeam.jobs.manifest import Manifest -from sunbeam.jobs.questions import ( +from sunbeam.core.deployment import Deployment +from sunbeam.core.juju import JujuHelper, JujuWaitException, TimeoutException, run_sync +from sunbeam.core.k8s import CREDENTIAL_SUFFIX, K8SHelper +from sunbeam.core.manifest import Manifest +from sunbeam.core.openstack import OPENSTACK_MODEL +from sunbeam.core.questions import ( PromptQuestion, QuestionBank, load_answers, write_answers, ) -from sunbeam.jobs.steps import PatchLoadBalancerServicesStep +from sunbeam.core.steps import PatchLoadBalancerServicesStep +from sunbeam.core.terraform import TerraformException, TerraformHelper +from sunbeam.steps.juju import JujuStepHelper LOG = logging.getLogger(__name__) -OPENSTACK_MODEL = "openstack" OPENSTACK_DEPLOY_TIMEOUT = 5400 # 90 minutes CONFIG_KEY = "TerraformVarsOpenstack" diff --git a/sunbeam-python/sunbeam/commands/sunbeam_machine.py b/sunbeam-python/sunbeam/steps/sunbeam_machine.py similarity index 94% rename from sunbeam-python/sunbeam/commands/sunbeam_machine.py rename to sunbeam-python/sunbeam/steps/sunbeam_machine.py index aa768278..fd925904 100644 --- a/sunbeam-python/sunbeam/commands/sunbeam_machine.py +++ b/sunbeam-python/sunbeam/steps/sunbeam_machine.py @@ -16,15 +16,15 @@ import logging from sunbeam.clusterd.client import Client -from sunbeam.commands.terraform import TerraformHelper -from sunbeam.jobs.deployment import Deployment, Networks -from sunbeam.jobs.juju import JujuHelper -from sunbeam.jobs.manifest import Manifest -from sunbeam.jobs.steps import ( +from sunbeam.core.deployment import Deployment, Networks +from sunbeam.core.juju import JujuHelper +from sunbeam.core.manifest import Manifest +from sunbeam.core.steps import ( AddMachineUnitsStep, DeployMachineApplicationStep, RemoveMachineUnitsStep, ) +from sunbeam.core.terraform import TerraformHelper LOG = logging.getLogger(__name__) CONFIG_KEY = "TerraformVarsSunbeamMachine" diff --git a/sunbeam-python/tests/unit/sunbeam/plugins/__init__.py b/sunbeam-python/sunbeam/steps/upgrades/__init__.py similarity index 100% rename from sunbeam-python/tests/unit/sunbeam/plugins/__init__.py rename to sunbeam-python/sunbeam/steps/upgrades/__init__.py diff --git a/sunbeam-python/sunbeam/commands/upgrades/base.py b/sunbeam-python/sunbeam/steps/upgrades/base.py similarity index 90% rename from sunbeam-python/sunbeam/commands/upgrades/base.py rename to sunbeam-python/sunbeam/steps/upgrades/base.py index 21d187e3..b4023857 100644 --- a/sunbeam-python/sunbeam/commands/upgrades/base.py +++ b/sunbeam-python/sunbeam/steps/upgrades/base.py @@ -20,11 +20,11 @@ from snaphelpers import Snap from sunbeam.clusterd.client import Client -from sunbeam.jobs.common import BaseStep, Result, ResultType, run_plan -from sunbeam.jobs.deployments import Deployment -from sunbeam.jobs.feature import FeatureManager -from sunbeam.jobs.juju import JujuHelper -from sunbeam.jobs.manifest import Manifest +from sunbeam.core.common import BaseStep, Result, ResultType, run_plan +from sunbeam.core.deployments import Deployment +from sunbeam.core.feature import FeatureManager +from sunbeam.core.juju import JujuHelper +from sunbeam.core.manifest import Manifest LOG = logging.getLogger(__name__) console = Console() diff --git a/sunbeam-python/sunbeam/commands/upgrades/inter_channel.py b/sunbeam-python/sunbeam/steps/upgrades/inter_channel.py similarity index 94% rename from sunbeam-python/sunbeam/commands/upgrades/inter_channel.py rename to sunbeam-python/sunbeam/steps/upgrades/inter_channel.py index e7b6bd12..aecd2e78 100644 --- a/sunbeam-python/sunbeam/commands/upgrades/inter_channel.py +++ b/sunbeam-python/sunbeam/steps/upgrades/inter_channel.py @@ -20,27 +20,27 @@ from rich.status import Status from sunbeam.clusterd.client import Client -from sunbeam.commands.hypervisor import CONFIG_KEY as HYPERVISOR_CONFIG_KEY -from sunbeam.commands.juju import JujuStepHelper -from sunbeam.commands.k8s import K8S_CONFIG_KEY -from sunbeam.commands.microceph import CONFIG_KEY as MICROCEPH_CONFIG_KEY -from sunbeam.commands.microk8s import MICROK8S_CONFIG_KEY -from sunbeam.commands.openstack import CONFIG_KEY as OPENSTACK_CONFIG_KEY -from sunbeam.commands.openstack import OPENSTACK_DEPLOY_TIMEOUT -from sunbeam.commands.sunbeam_machine import CONFIG_KEY as SUNBEAM_MACHINE_CONFIG_KEY -from sunbeam.commands.terraform import TerraformException, TerraformHelper -from sunbeam.commands.upgrades.base import UpgradeCoordinator, UpgradeFeatures -from sunbeam.jobs.common import ( +from sunbeam.core.common import ( BaseStep, Result, ResultType, run_plan, update_status_background, ) -from sunbeam.jobs.deployment import Deployment -from sunbeam.jobs.feature import FeatureManager -from sunbeam.jobs.juju import JujuHelper, JujuWaitException, TimeoutException, run_sync -from sunbeam.jobs.manifest import Manifest +from sunbeam.core.deployment import Deployment +from sunbeam.core.feature import FeatureManager +from sunbeam.core.juju import JujuHelper, JujuWaitException, TimeoutException, run_sync +from sunbeam.core.manifest import Manifest +from sunbeam.core.terraform import TerraformException, TerraformHelper +from sunbeam.steps.hypervisor import CONFIG_KEY as HYPERVISOR_CONFIG_KEY +from sunbeam.steps.juju import JujuStepHelper +from sunbeam.steps.k8s import K8S_CONFIG_KEY +from sunbeam.steps.microceph import CONFIG_KEY as MICROCEPH_CONFIG_KEY +from sunbeam.steps.microk8s import MICROK8S_CONFIG_KEY +from sunbeam.steps.openstack import CONFIG_KEY as OPENSTACK_CONFIG_KEY +from sunbeam.steps.openstack import OPENSTACK_DEPLOY_TIMEOUT +from sunbeam.steps.sunbeam_machine import CONFIG_KEY as SUNBEAM_MACHINE_CONFIG_KEY +from sunbeam.steps.upgrades.base import UpgradeCoordinator, UpgradeFeatures from sunbeam.versions import ( MISC_CHARMS_K8S, MYSQL_CHARMS_K8S, diff --git a/sunbeam-python/sunbeam/commands/upgrades/intra_channel.py b/sunbeam-python/sunbeam/steps/upgrades/intra_channel.py similarity index 90% rename from sunbeam-python/sunbeam/commands/upgrades/intra_channel.py rename to sunbeam-python/sunbeam/steps/upgrades/intra_channel.py index 05e7f057..84967a35 100644 --- a/sunbeam-python/sunbeam/commands/upgrades/intra_channel.py +++ b/sunbeam-python/sunbeam/steps/upgrades/intra_channel.py @@ -18,18 +18,18 @@ from rich.console import Console from rich.status import Status -from sunbeam.commands.hypervisor import ReapplyHypervisorTerraformPlanStep -from sunbeam.commands.juju import JujuStepHelper -from sunbeam.commands.k8s import DeployK8SApplicationStep -from sunbeam.commands.microceph import DeployMicrocephApplicationStep -from sunbeam.commands.microk8s import DeployMicrok8sApplicationStep -from sunbeam.commands.openstack import ReapplyOpenStackTerraformPlanStep -from sunbeam.commands.sunbeam_machine import DeploySunbeamMachineApplicationStep -from sunbeam.commands.terraform import TerraformInitStep -from sunbeam.commands.upgrades.base import UpgradeCoordinator, UpgradeFeatures -from sunbeam.jobs.common import BaseStep, Result, ResultType -from sunbeam.jobs.juju import JujuHelper, run_sync -from sunbeam.jobs.manifest import Manifest +from sunbeam.core.common import BaseStep, Result, ResultType +from sunbeam.core.juju import JujuHelper, run_sync +from sunbeam.core.manifest import Manifest +from sunbeam.core.terraform import TerraformInitStep +from sunbeam.steps.hypervisor import ReapplyHypervisorTerraformPlanStep +from sunbeam.steps.juju import JujuStepHelper +from sunbeam.steps.k8s import DeployK8SApplicationStep +from sunbeam.steps.microceph import DeployMicrocephApplicationStep +from sunbeam.steps.microk8s import DeployMicrok8sApplicationStep +from sunbeam.steps.openstack import ReapplyOpenStackTerraformPlanStep +from sunbeam.steps.sunbeam_machine import DeploySunbeamMachineApplicationStep +from sunbeam.steps.upgrades.base import UpgradeCoordinator, UpgradeFeatures LOG = logging.getLogger(__name__) console = Console() diff --git a/sunbeam-python/sunbeam/utils.py b/sunbeam-python/sunbeam/utils.py index 085f0e0e..ae32db4e 100644 --- a/sunbeam-python/sunbeam/utils.py +++ b/sunbeam-python/sunbeam/utils.py @@ -31,7 +31,7 @@ import netifaces # type: ignore [import-not-found] from pyroute2 import IPDB, NDB # type: ignore [import-untyped] -from sunbeam.jobs.common import SunbeamException +from sunbeam.core.common import SunbeamException LOG = logging.getLogger(__name__) LOCAL_ACCESS = "local" diff --git a/sunbeam-python/tests/unit/sunbeam/commands/test_configure.py b/sunbeam-python/tests/unit/sunbeam/commands/test_configure.py index fecdf3f1..4ee852d0 100644 --- a/sunbeam-python/tests/unit/sunbeam/commands/test_configure.py +++ b/sunbeam-python/tests/unit/sunbeam/commands/test_configure.py @@ -19,10 +19,10 @@ import pytest import sunbeam.commands.configure as configure -import sunbeam.jobs.questions +import sunbeam.core.questions import sunbeam.utils -from sunbeam.commands.terraform import TerraformException -from sunbeam.jobs.common import ResultType +from sunbeam.core.common import ResultType +from sunbeam.core.terraform import TerraformException @pytest.fixture(autouse=True) @@ -47,19 +47,19 @@ def cclient(): @pytest.fixture() def load_answers(): - with patch.object(sunbeam.jobs.questions, "load_answers") as p: + with patch.object(sunbeam.core.questions, "load_answers") as p: yield p @pytest.fixture() def write_answers(): - with patch.object(sunbeam.jobs.questions, "write_answers") as p: + with patch.object(sunbeam.core.questions, "write_answers") as p: yield p @pytest.fixture() def question_bank(): - with patch.object(sunbeam.jobs.questions, "QuestionBank") as p: + with patch.object(sunbeam.core.questions, "QuestionBank") as p: yield p diff --git a/sunbeam-python/tests/unit/sunbeam/commands/test_generate_cloud_config.py b/sunbeam-python/tests/unit/sunbeam/commands/test_generate_cloud_config.py index 8c41278d..433420db 100644 --- a/sunbeam-python/tests/unit/sunbeam/commands/test_generate_cloud_config.py +++ b/sunbeam-python/tests/unit/sunbeam/commands/test_generate_cloud_config.py @@ -18,8 +18,8 @@ import pytest import sunbeam.commands.generate_cloud_config as generate -import sunbeam.jobs.questions -from sunbeam.jobs.common import ResultType +import sunbeam.core.questions +from sunbeam.core.common import ResultType @pytest.fixture(autouse=True) @@ -49,7 +49,7 @@ def tfhelper(): @pytest.fixture() def load_answers(): - with patch.object(sunbeam.jobs.questions, "load_answers") as p: + with patch.object(sunbeam.core.questions, "load_answers") as p: yield p diff --git a/sunbeam-python/tests/unit/sunbeam/commands/test_proxy.py b/sunbeam-python/tests/unit/sunbeam/commands/test_proxy.py index c58aedc1..015fb96b 100644 --- a/sunbeam-python/tests/unit/sunbeam/commands/test_proxy.py +++ b/sunbeam-python/tests/unit/sunbeam/commands/test_proxy.py @@ -19,7 +19,7 @@ import pytest from sunbeam.commands.proxy import PromptForProxyStep -from sunbeam.jobs.deployment import PROXY_CONFIG_KEY +from sunbeam.core.deployment import PROXY_CONFIG_KEY @pytest.fixture() diff --git a/sunbeam-python/tests/unit/sunbeam/jobs/test_checks.py b/sunbeam-python/tests/unit/sunbeam/core/test_checks.py similarity index 91% rename from sunbeam-python/tests/unit/sunbeam/jobs/test_checks.py rename to sunbeam-python/tests/unit/sunbeam/core/test_checks.py index 6382e3ff..7a188095 100644 --- a/sunbeam-python/tests/unit/sunbeam/jobs/test_checks.py +++ b/sunbeam-python/tests/unit/sunbeam/core/test_checks.py @@ -18,7 +18,7 @@ import os from unittest.mock import Mock -from sunbeam.jobs import checks +from sunbeam.core import checks class TestSshKeysConnectedCheck: @@ -159,9 +159,9 @@ class TestSystemRequirementsCheck: def test_run(self, mocker): mocker.patch( - "sunbeam.jobs.checks.get_host_total_ram", return_value=16 * 1024 * 1024 + "sunbeam.core.checks.get_host_total_ram", return_value=16 * 1024 * 1024 ) - mocker.patch("sunbeam.jobs.checks.get_host_total_cores", return_value=4) + mocker.patch("sunbeam.core.checks.get_host_total_cores", return_value=4) check = checks.SystemRequirementsCheck() result = check.run() @@ -170,9 +170,9 @@ def test_run(self, mocker): def test_run_less_than_16GB_RAM(self, mocker): mocker.patch( - "sunbeam.jobs.checks.get_host_total_ram", return_value=8 * 1024 * 1024 + "sunbeam.core.checks.get_host_total_ram", return_value=8 * 1024 * 1024 ) - mocker.patch("sunbeam.jobs.checks.get_host_total_cores", return_value=4) + mocker.patch("sunbeam.core.checks.get_host_total_cores", return_value=4) check = checks.SystemRequirementsCheck() result = check.run() @@ -182,9 +182,9 @@ def test_run_less_than_16GB_RAM(self, mocker): def test_run_less_than_4_cores(self, mocker): mocker.patch( - "sunbeam.jobs.checks.get_host_total_ram", return_value=16 * 1024 * 1024 + "sunbeam.core.checks.get_host_total_ram", return_value=16 * 1024 * 1024 ) - mocker.patch("sunbeam.jobs.checks.get_host_total_cores", return_value=2) + mocker.patch("sunbeam.core.checks.get_host_total_cores", return_value=2) check = checks.SystemRequirementsCheck() result = check.run() @@ -194,9 +194,9 @@ def test_run_less_than_4_cores(self, mocker): def test_run_more_than_16GB_RAM(self, mocker): mocker.patch( - "sunbeam.jobs.checks.get_host_total_ram", return_value=32 * 1024 * 1024 + "sunbeam.core.checks.get_host_total_ram", return_value=32 * 1024 * 1024 ) - mocker.patch("sunbeam.jobs.checks.get_host_total_cores", return_value=4) + mocker.patch("sunbeam.core.checks.get_host_total_cores", return_value=4) check = checks.SystemRequirementsCheck() result = check.run() @@ -205,9 +205,9 @@ def test_run_more_than_16GB_RAM(self, mocker): def test_run_more_than_4_cores(self, mocker): mocker.patch( - "sunbeam.jobs.checks.get_host_total_ram", return_value=16 * 1024 * 1024 + "sunbeam.core.checks.get_host_total_ram", return_value=16 * 1024 * 1024 ) - mocker.patch("sunbeam.jobs.checks.get_host_total_cores", return_value=8) + mocker.patch("sunbeam.core.checks.get_host_total_cores", return_value=8) check = checks.SystemRequirementsCheck() result = check.run() diff --git a/sunbeam-python/tests/unit/sunbeam/jobs/test_common.py b/sunbeam-python/tests/unit/sunbeam/core/test_common.py similarity index 96% rename from sunbeam-python/tests/unit/sunbeam/jobs/test_common.py rename to sunbeam-python/tests/unit/sunbeam/core/test_common.py index 5cb1bbd7..ce5b6ee0 100644 --- a/sunbeam-python/tests/unit/sunbeam/jobs/test_common.py +++ b/sunbeam-python/tests/unit/sunbeam/core/test_common.py @@ -20,19 +20,19 @@ import pytest from sunbeam.clusterd.service import ClusterServiceUnavailableException -from sunbeam.jobs.common import Role, validate_roles -from sunbeam.jobs.deployment import Deployment +from sunbeam.core.common import Role, validate_roles +from sunbeam.core.deployment import Deployment @pytest.fixture() def read_config(): - with patch("sunbeam.jobs.deployment.read_config") as p: + with patch("sunbeam.core.deployment.read_config") as p: yield p @pytest.fixture() def deployment(): - with patch("sunbeam.jobs.deployment.Deployment") as p: + with patch("sunbeam.core.deployment.Deployment") as p: dep = p(name="", url="", type="") dep.get_proxy_settings.side_effect = functools.partial( Deployment.get_proxy_settings, dep diff --git a/sunbeam-python/tests/unit/sunbeam/jobs/test_deployment.py b/sunbeam-python/tests/unit/sunbeam/core/test_deployment.py similarity index 96% rename from sunbeam-python/tests/unit/sunbeam/jobs/test_deployment.py rename to sunbeam-python/tests/unit/sunbeam/core/test_deployment.py index 2cb1a76d..86734bd1 100644 --- a/sunbeam-python/tests/unit/sunbeam/jobs/test_deployment.py +++ b/sunbeam-python/tests/unit/sunbeam/core/test_deployment.py @@ -18,10 +18,10 @@ import pytest import yaml -import sunbeam.commands.terraform as terraform_mod -import sunbeam.jobs.deployment as deployment_mod -import sunbeam.jobs.manifest as manifest_mod -from sunbeam.jobs.deployment import Deployment +import sunbeam.core.deployment as deployment_mod +import sunbeam.core.manifest as manifest_mod +import sunbeam.core.terraform as terraform_mod +from sunbeam.core.deployment import Deployment from sunbeam.versions import ( MANIFEST_CHARM_VERSIONS, OPENSTACK_CHANNEL, @@ -56,7 +56,7 @@ def deployment(mocker, snap): mocker.patch.object(deployment_mod, "Snap", return_value=snap) snap_config = {"deployment.risk": "stable"} snap.config.get.side_effect = snap_config.__getitem__ - with patch("sunbeam.jobs.deployment.Deployment") as p: + with patch("sunbeam.core.deployment.Deployment") as p: dep = p(name="", url="", type="") dep.get_manifest.side_effect = functools.partial(Deployment.get_manifest, dep) dep.get_tfhelper.side_effect = functools.partial(Deployment.get_tfhelper, dep) diff --git a/sunbeam-python/tests/unit/sunbeam/jobs/test_juju.py b/sunbeam-python/tests/unit/sunbeam/core/test_juju.py similarity index 99% rename from sunbeam-python/tests/unit/sunbeam/jobs/test_juju.py rename to sunbeam-python/tests/unit/sunbeam/core/test_juju.py index 72b875eb..1b60ca7a 100644 --- a/sunbeam-python/tests/unit/sunbeam/jobs/test_juju.py +++ b/sunbeam-python/tests/unit/sunbeam/core/test_juju.py @@ -22,7 +22,7 @@ from juju.model import Model from juju.unit import Unit -import sunbeam.jobs.juju as juju +import sunbeam.core.juju as juju kubeconfig_yaml = """ apiVersion: v1 diff --git a/sunbeam-python/tests/unit/sunbeam/jobs/test_manifest.py b/sunbeam-python/tests/unit/sunbeam/core/test_manifest.py similarity index 99% rename from sunbeam-python/tests/unit/sunbeam/jobs/test_manifest.py rename to sunbeam-python/tests/unit/sunbeam/core/test_manifest.py index 8a916ddf..20b25aca 100644 --- a/sunbeam-python/tests/unit/sunbeam/jobs/test_manifest.py +++ b/sunbeam-python/tests/unit/sunbeam/core/test_manifest.py @@ -21,12 +21,12 @@ import yaml.scanner from pydantic import ValidationError -import sunbeam.jobs.manifest as manifest_mod +import sunbeam.core.manifest as manifest_mod from sunbeam.clusterd.service import ( ClusterServiceUnavailableException, ManifestItemNotFoundException, ) -from sunbeam.jobs.common import ResultType +from sunbeam.core.common import ResultType test_manifest = """ software: diff --git a/sunbeam-python/tests/unit/sunbeam/commands/test_openstack_api.py b/sunbeam-python/tests/unit/sunbeam/core/test_openstack_api.py similarity index 77% rename from sunbeam-python/tests/unit/sunbeam/commands/test_openstack_api.py rename to sunbeam-python/tests/unit/sunbeam/core/test_openstack_api.py index 37da88cf..20dd2e37 100644 --- a/sunbeam-python/tests/unit/sunbeam/commands/test_openstack_api.py +++ b/sunbeam-python/tests/unit/sunbeam/core/test_openstack_api.py @@ -18,7 +18,7 @@ import pytest import sunbeam.commands.configure -import sunbeam.commands.openstack_api +import sunbeam.core.openstack_api FAKE_CREDS = { "OS_AUTH_URL": "http://10.20.21.12:80/openstack-keystone", @@ -34,40 +34,38 @@ @pytest.fixture() def retrieve_admin_credentials(): - with patch.object( - sunbeam.commands.openstack_api, "retrieve_admin_credentials" - ) as p: + with patch.object(sunbeam.core.openstack_api, "retrieve_admin_credentials") as p: p.return_value = FAKE_CREDS yield p @pytest.fixture() def os_connect(): - with patch.object(sunbeam.commands.openstack_api.openstack, "connect") as p: + with patch.object(sunbeam.core.openstack_api.openstack, "connect") as p: yield p @pytest.fixture() def get_admin_connection(): - with patch.object(sunbeam.commands.openstack_api, "get_admin_connection") as p: + with patch.object(sunbeam.core.openstack_api, "get_admin_connection") as p: yield p @pytest.fixture() def remove_compute_service(): - with patch.object(sunbeam.commands.openstack_api, "remove_compute_service") as p: + with patch.object(sunbeam.core.openstack_api, "remove_compute_service") as p: yield p @pytest.fixture() def remove_network_service(): - with patch.object(sunbeam.commands.openstack_api, "remove_network_service") as p: + with patch.object(sunbeam.core.openstack_api, "remove_network_service") as p: yield p class TestOpenStackAPI: def test_get_admin_connection(self, retrieve_admin_credentials, os_connect): - sunbeam.commands.openstack_api.get_admin_connection(None) + sunbeam.core.openstack_api.get_admin_connection(None) os_connect.assert_called_once_with( auth_url=FAKE_CREDS.get("OS_AUTH_URL"), username=FAKE_CREDS.get("OS_USERNAME"), @@ -81,16 +79,14 @@ def test_guests_on_hypervisor(self, get_admin_connection): conn = Mock() get_admin_connection.return_value = conn conn.compute.servers.return_value = [1] - assert sunbeam.commands.openstack_api.guests_on_hypervisor("hyper1", None) == [ - 1 - ] + assert sunbeam.core.openstack_api.guests_on_hypervisor("hyper1", None) == [1] conn.compute.servers.assert_called_once_with(all_projects=True, host="hyper1") def test_remove_compute_service(self): service1 = Mock(binary="nova-compute", host="hyper1") conn = Mock() conn.compute.services.return_value = [service1] - sunbeam.commands.openstack_api.remove_compute_service("hyper1", conn) + sunbeam.core.openstack_api.remove_compute_service("hyper1", conn) conn.compute.disable_service.assert_called_once_with(service1) conn.compute.delete_service.assert_called_once_with(service1) @@ -98,7 +94,7 @@ def test_remove_network_service(self): service1 = Mock(binary="ovn-controller", host="hyper1") conn = Mock() conn.network.agents.return_value = [service1] - sunbeam.commands.openstack_api.remove_network_service("hyper1", conn) + sunbeam.core.openstack_api.remove_network_service("hyper1", conn) conn.network.delete_agent.assert_called_once_with(service1) def test_remove_hypervisor( @@ -106,7 +102,7 @@ def test_remove_hypervisor( ): conn = Mock() get_admin_connection.return_value = conn - sunbeam.commands.openstack_api.remove_hypervisor("hyper1", None) + sunbeam.core.openstack_api.remove_hypervisor("hyper1", None) get_admin_connection.assert_called_once_with(None) remove_compute_service.assert_called_once_with("hyper1", conn) remove_network_service.assert_called_once_with("hyper1", conn) diff --git a/sunbeam-python/tests/unit/sunbeam/jobs/test_steps.py b/sunbeam-python/tests/unit/sunbeam/core/test_steps.py similarity index 97% rename from sunbeam-python/tests/unit/sunbeam/jobs/test_steps.py rename to sunbeam-python/tests/unit/sunbeam/core/test_steps.py index 1203aa6d..17321427 100644 --- a/sunbeam-python/tests/unit/sunbeam/jobs/test_steps.py +++ b/sunbeam-python/tests/unit/sunbeam/core/test_steps.py @@ -18,14 +18,14 @@ import pytest -from sunbeam.commands.terraform import TerraformException -from sunbeam.jobs.common import ResultType -from sunbeam.jobs.juju import ApplicationNotFoundException, TimeoutException -from sunbeam.jobs.steps import ( +from sunbeam.core.common import ResultType +from sunbeam.core.juju import ApplicationNotFoundException, TimeoutException +from sunbeam.core.steps import ( AddMachineUnitsStep, DeployMachineApplicationStep, RemoveMachineUnitsStep, ) +from sunbeam.core.terraform import TerraformException @pytest.fixture(autouse=True) @@ -38,7 +38,7 @@ def mock_run_sync(mocker): def run_sync(coro): return loop.run_until_complete(coro) - mocker.patch("sunbeam.jobs.steps.run_sync", run_sync) + mocker.patch("sunbeam.core.steps.run_sync", run_sync) yield loop.close() @@ -65,7 +65,7 @@ def jhelper(): @pytest.fixture() def read_config(): - with patch("sunbeam.jobs.steps.read_config", return_value={}) as p: + with patch("sunbeam.core.steps.read_config", return_value={}) as p: yield p diff --git a/sunbeam-python/tests/unit/sunbeam/commands/test_terraform.py b/sunbeam-python/tests/unit/sunbeam/core/test_terraform.py similarity index 93% rename from sunbeam-python/tests/unit/sunbeam/commands/test_terraform.py rename to sunbeam-python/tests/unit/sunbeam/core/test_terraform.py index cb8e74a9..118cdae4 100644 --- a/sunbeam-python/tests/unit/sunbeam/commands/test_terraform.py +++ b/sunbeam-python/tests/unit/sunbeam/core/test_terraform.py @@ -16,10 +16,10 @@ import pytest -import sunbeam.commands.terraform as terraform_mod -import sunbeam.jobs.deployment as deployment_mod -import sunbeam.jobs.manifest as manifest_mod -from sunbeam.jobs.deployment import Deployment +import sunbeam.core.deployment as deployment_mod +import sunbeam.core.manifest as manifest_mod +import sunbeam.core.terraform as terraform_mod +from sunbeam.core.deployment import Deployment from sunbeam.versions import OPENSTACK_CHANNEL test_manifest = """ @@ -48,7 +48,7 @@ @pytest.fixture() def deployment(): - with patch("sunbeam.jobs.deployment.Deployment") as p: + with patch("sunbeam.core.deployment.Deployment") as p: dep = p(name="", url="", type="") dep.get_manifest.side_effect = functools.partial(Deployment.get_manifest, dep) dep.get_tfhelper.side_effect = functools.partial(Deployment.get_tfhelper, dep) @@ -63,7 +63,7 @@ def deployment(): @pytest.fixture() def read_config(): - with patch("sunbeam.commands.terraform.read_config") as p: + with patch("sunbeam.core.terraform.read_config") as p: yield p diff --git a/sunbeam-python/tests/unit/sunbeam/features/__init__.py b/sunbeam-python/tests/unit/sunbeam/features/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/sunbeam-python/tests/unit/sunbeam/plugins/test_base.py b/sunbeam-python/tests/unit/sunbeam/features/test_base.py similarity index 99% rename from sunbeam-python/tests/unit/sunbeam/plugins/test_base.py rename to sunbeam-python/tests/unit/sunbeam/features/test_base.py index 9205c538..05c92fe1 100644 --- a/sunbeam-python/tests/unit/sunbeam/plugins/test_base.py +++ b/sunbeam-python/tests/unit/sunbeam/features/test_base.py @@ -19,6 +19,8 @@ from packaging.version import Version from sunbeam.clusterd.service import ConfigItemNotFoundException +from sunbeam.core.deployment import Deployment +from sunbeam.core.feature import FEATURES_YAML, FeatureManager from sunbeam.features.interface.v1.base import ( BaseFeature, EnableDisableFeature, @@ -29,8 +31,6 @@ MissingVersionInfoError, NotAutomaticFeatureError, ) -from sunbeam.jobs.deployment import Deployment -from sunbeam.jobs.feature import FEATURES_YAML, FeatureManager @pytest.fixture() diff --git a/sunbeam-python/tests/unit/sunbeam/plugins/test_ldap.py b/sunbeam-python/tests/unit/sunbeam/features/test_ldap.py similarity index 98% rename from sunbeam-python/tests/unit/sunbeam/plugins/test_ldap.py rename to sunbeam-python/tests/unit/sunbeam/features/test_ldap.py index 64adae3b..3bf3b49e 100644 --- a/sunbeam-python/tests/unit/sunbeam/plugins/test_ldap.py +++ b/sunbeam-python/tests/unit/sunbeam/features/test_ldap.py @@ -17,15 +17,15 @@ import pytest -from sunbeam.commands.terraform import TerraformException +from sunbeam.core.common import ResultType +from sunbeam.core.juju import TimeoutException +from sunbeam.core.terraform import TerraformException from sunbeam.features.ldap.feature import ( AddLDAPDomainStep, DisableLDAPDomainStep, LDAPFeature, UpdateLDAPDomainStep, ) -from sunbeam.jobs.common import ResultType -from sunbeam.jobs.juju import TimeoutException @pytest.fixture() diff --git a/sunbeam-python/tests/unit/sunbeam/plugins/test_observability.py b/sunbeam-python/tests/unit/sunbeam/features/test_observability.py similarity index 98% rename from sunbeam-python/tests/unit/sunbeam/plugins/test_observability.py rename to sunbeam-python/tests/unit/sunbeam/features/test_observability.py index a08fa296..7f8c99da 100644 --- a/sunbeam-python/tests/unit/sunbeam/plugins/test_observability.py +++ b/sunbeam-python/tests/unit/sunbeam/features/test_observability.py @@ -17,10 +17,10 @@ import pytest -from sunbeam.commands.terraform import TerraformException +from sunbeam.core.common import ResultType +from sunbeam.core.juju import TimeoutException +from sunbeam.core.terraform import TerraformException from sunbeam.features.observability import feature as observability_feature -from sunbeam.jobs.common import ResultType -from sunbeam.jobs.juju import TimeoutException @pytest.fixture(autouse=True) @@ -56,7 +56,7 @@ def observabilityfeature(): @pytest.fixture() def ssnap(): - with patch("sunbeam.jobs.k8s.Snap") as p: + with patch("sunbeam.core.k8s.Snap") as p: yield p diff --git a/sunbeam-python/tests/unit/sunbeam/plugins/test_openstack.py b/sunbeam-python/tests/unit/sunbeam/features/test_openstack.py similarity index 97% rename from sunbeam-python/tests/unit/sunbeam/plugins/test_openstack.py rename to sunbeam-python/tests/unit/sunbeam/features/test_openstack.py index 0dfa841f..e0e969ed 100644 --- a/sunbeam-python/tests/unit/sunbeam/plugins/test_openstack.py +++ b/sunbeam-python/tests/unit/sunbeam/features/test_openstack.py @@ -19,9 +19,9 @@ import pytest import sunbeam.features.interface.v1.openstack as openstack -from sunbeam.commands.terraform import TerraformException -from sunbeam.jobs.common import ResultType -from sunbeam.jobs.juju import TimeoutException +from sunbeam.core.common import ResultType +from sunbeam.core.juju import TimeoutException +from sunbeam.core.terraform import TerraformException @pytest.fixture(autouse=True) diff --git a/sunbeam-python/tests/unit/sunbeam/plugins/test_pro.py b/sunbeam-python/tests/unit/sunbeam/features/test_pro.py similarity index 96% rename from sunbeam-python/tests/unit/sunbeam/plugins/test_pro.py rename to sunbeam-python/tests/unit/sunbeam/features/test_pro.py index 1630968a..4945f538 100644 --- a/sunbeam-python/tests/unit/sunbeam/plugins/test_pro.py +++ b/sunbeam-python/tests/unit/sunbeam/features/test_pro.py @@ -18,13 +18,13 @@ import pytest -from sunbeam.commands.terraform import TerraformException +from sunbeam.core.common import ResultType +from sunbeam.core.juju import TimeoutException +from sunbeam.core.terraform import TerraformException from sunbeam.features.pro.feature import ( DisableUbuntuProApplicationStep, EnableUbuntuProApplicationStep, ) -from sunbeam.jobs.common import ResultType -from sunbeam.jobs.juju import TimeoutException @pytest.fixture(autouse=True) diff --git a/sunbeam-python/tests/unit/sunbeam/plugins/test_tls.py b/sunbeam-python/tests/unit/sunbeam/features/test_tls.py similarity index 98% rename from sunbeam-python/tests/unit/sunbeam/plugins/test_tls.py rename to sunbeam-python/tests/unit/sunbeam/features/test_tls.py index c877aef9..0ff962c3 100644 --- a/sunbeam-python/tests/unit/sunbeam/plugins/test_tls.py +++ b/sunbeam-python/tests/unit/sunbeam/features/test_tls.py @@ -18,12 +18,12 @@ import click import pytest +import sunbeam.core.questions import sunbeam.features.ca.feature as ca import sunbeam.features.interface.utils import sunbeam.features.interface.v1.tls as tls -import sunbeam.jobs.questions -from sunbeam.jobs.common import ResultType -from sunbeam.jobs.juju import ActionFailedException, LeaderNotFoundException +from sunbeam.core.common import ResultType +from sunbeam.core.juju import ActionFailedException, LeaderNotFoundException @pytest.fixture() @@ -38,19 +38,19 @@ def jhelper(): @pytest.fixture() def load_answers(): - with patch.object(sunbeam.jobs.questions, "load_answers") as p: + with patch.object(sunbeam.core.questions, "load_answers") as p: yield p @pytest.fixture() def write_answers(): - with patch.object(sunbeam.jobs.questions, "write_answers") as p: + with patch.object(sunbeam.core.questions, "write_answers") as p: yield p @pytest.fixture() def question_bank(): - with patch.object(sunbeam.jobs.questions, "QuestionBank") as p: + with patch.object(sunbeam.core.questions, "QuestionBank") as p: yield p diff --git a/sunbeam-python/tests/unit/sunbeam/plugins/test_validation.py b/sunbeam-python/tests/unit/sunbeam/features/test_validation.py similarity index 100% rename from sunbeam-python/tests/unit/sunbeam/plugins/test_validation.py rename to sunbeam-python/tests/unit/sunbeam/features/test_validation.py diff --git a/sunbeam-python/tests/unit/sunbeam/provider/local/test_steps.py b/sunbeam-python/tests/unit/sunbeam/provider/local/test_steps.py index 2bcf3186..bbc3db23 100644 --- a/sunbeam-python/tests/unit/sunbeam/provider/local/test_steps.py +++ b/sunbeam-python/tests/unit/sunbeam/provider/local/test_steps.py @@ -19,7 +19,7 @@ import pytest from rich.console import Console -import sunbeam.jobs.questions +import sunbeam.core.questions import sunbeam.provider.local.steps as local_steps import sunbeam.utils @@ -46,19 +46,19 @@ def cclient(): @pytest.fixture() def load_answers(): - with patch.object(sunbeam.jobs.questions, "load_answers") as p: + with patch.object(sunbeam.core.questions, "load_answers") as p: yield p @pytest.fixture() def write_answers(): - with patch.object(sunbeam.jobs.questions, "write_answers") as p: + with patch.object(sunbeam.core.questions, "write_answers") as p: yield p @pytest.fixture() def question_bank(): - with patch.object(sunbeam.jobs.questions, "QuestionBank") as p: + with patch.object(sunbeam.core.questions, "QuestionBank") as p: yield p diff --git a/sunbeam-python/tests/unit/sunbeam/provider/maas/test_maas.py b/sunbeam-python/tests/unit/sunbeam/provider/maas/test_maas.py index f49a74d3..cd6c2b9f 100644 --- a/sunbeam-python/tests/unit/sunbeam/provider/maas/test_maas.py +++ b/sunbeam-python/tests/unit/sunbeam/provider/maas/test_maas.py @@ -20,10 +20,10 @@ from maas.client.bones import CallError import sunbeam.provider.maas.steps as maas_steps -from sunbeam.jobs.checks import DiagnosticResultType -from sunbeam.jobs.deployment import Networks -from sunbeam.jobs.deployments import DeploymentsConfig -from sunbeam.jobs.juju import ControllerNotFoundException +from sunbeam.core.checks import DiagnosticResultType +from sunbeam.core.deployment import Networks +from sunbeam.core.deployments import DeploymentsConfig +from sunbeam.core.juju import ControllerNotFoundException from sunbeam.provider.maas.deployment import ( MaasDeployment, NicTags, @@ -692,7 +692,7 @@ def test_is_skip_with_multiple_machines(self, snap, mocker): ], ) mocker.patch( - "sunbeam.commands.juju.BootstrapJujuStep.is_skip", + "sunbeam.steps.juju.BootstrapJujuStep.is_skip", return_value=Result(ResultType.COMPLETED), ) mocker.patch.object(maas_steps, "Snap", return_value=snap) @@ -717,7 +717,7 @@ def test_is_skip_with_single_machine(self, snap, mocker): ], ) mocker.patch( - "sunbeam.commands.juju.BootstrapJujuStep.is_skip", + "sunbeam.steps.juju.BootstrapJujuStep.is_skip", return_value=Result(ResultType.COMPLETED), ) mocker.patch.object(maas_steps, "Snap", return_value=snap) diff --git a/sunbeam-python/tests/unit/sunbeam/steps/__init__.py b/sunbeam-python/tests/unit/sunbeam/steps/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/sunbeam-python/tests/unit/sunbeam/commands/test_hypervisor.py b/sunbeam-python/tests/unit/sunbeam/steps/test_hypervisor.py similarity index 89% rename from sunbeam-python/tests/unit/sunbeam/commands/test_hypervisor.py rename to sunbeam-python/tests/unit/sunbeam/steps/test_hypervisor.py index dadaf3dc..dc18c062 100644 --- a/sunbeam-python/tests/unit/sunbeam/commands/test_hypervisor.py +++ b/sunbeam-python/tests/unit/sunbeam/steps/test_hypervisor.py @@ -19,13 +19,13 @@ import pytest from sunbeam.clusterd.service import NodeNotExistInClusterException -from sunbeam.commands.hypervisor import ( +from sunbeam.core.common import ResultType +from sunbeam.core.juju import ApplicationNotFoundException, TimeoutException +from sunbeam.core.terraform import TerraformException +from sunbeam.steps.hypervisor import ( ReapplyHypervisorTerraformPlanStep, RemoveHypervisorUnitStep, ) -from sunbeam.commands.terraform import TerraformException -from sunbeam.jobs.common import ResultType -from sunbeam.jobs.juju import ApplicationNotFoundException, TimeoutException @pytest.fixture(autouse=True) @@ -38,7 +38,7 @@ def mock_run_sync(mocker): def run_sync(coro): return loop.run_until_complete(coro) - mocker.patch("sunbeam.commands.hypervisor.run_sync", run_sync) + mocker.patch("sunbeam.steps.hypervisor.run_sync", run_sync) yield loop.close() @@ -47,7 +47,7 @@ class TestRemoveHypervisorUnitStep(unittest.TestCase): def __init__(self, methodName: str = "runTest") -> None: super().__init__(methodName) self.read_config = patch( - "sunbeam.commands.hypervisor.read_config", + "sunbeam.steps.hypervisor.read_config", Mock( return_value={ "openstack_model": "openstack", @@ -122,8 +122,8 @@ def test_is_skip_unit_missing(self): self.jhelper.get_application.assert_called_once() assert result.result_type == ResultType.SKIPPED - @patch("sunbeam.commands.hypervisor.remove_hypervisor") - @patch("sunbeam.commands.hypervisor.guests_on_hypervisor") + @patch("sunbeam.steps.hypervisor.remove_hypervisor") + @patch("sunbeam.steps.hypervisor.guests_on_hypervisor") def test_run(self, guests_on_hypervisor, remove_hypervisor): guests_on_hypervisor.return_value = [] step = RemoveHypervisorUnitStep( @@ -133,8 +133,8 @@ def test_run(self, guests_on_hypervisor, remove_hypervisor): assert result.result_type == ResultType.COMPLETED remove_hypervisor.assert_called_once_with("test-0", self.jhelper) - @patch("sunbeam.commands.hypervisor.remove_hypervisor") - @patch("sunbeam.commands.hypervisor.guests_on_hypervisor") + @patch("sunbeam.steps.hypervisor.remove_hypervisor") + @patch("sunbeam.steps.hypervisor.guests_on_hypervisor") def test_run_guests(self, guests_on_hypervisor, remove_hypervisor): guests_on_hypervisor.return_value = self.guests step = RemoveHypervisorUnitStep( @@ -144,8 +144,8 @@ def test_run_guests(self, guests_on_hypervisor, remove_hypervisor): assert result.result_type == ResultType.FAILED assert not remove_hypervisor.called - @patch("sunbeam.commands.hypervisor.remove_hypervisor") - @patch("sunbeam.commands.hypervisor.guests_on_hypervisor") + @patch("sunbeam.steps.hypervisor.remove_hypervisor") + @patch("sunbeam.steps.hypervisor.guests_on_hypervisor") def test_run_guests_force(self, guests_on_hypervisor, remove_hypervisor): guests_on_hypervisor.return_value = self.guests step = RemoveHypervisorUnitStep( @@ -155,8 +155,8 @@ def test_run_guests_force(self, guests_on_hypervisor, remove_hypervisor): assert result.result_type == ResultType.COMPLETED remove_hypervisor.assert_called_once_with("test-0", self.jhelper) - @patch("sunbeam.commands.hypervisor.remove_hypervisor") - @patch("sunbeam.commands.hypervisor.guests_on_hypervisor") + @patch("sunbeam.steps.hypervisor.remove_hypervisor") + @patch("sunbeam.steps.hypervisor.guests_on_hypervisor") def test_run_application_not_found(self, guests_on_hypervisor, remove_hypervisor): guests_on_hypervisor.return_value = [] self.jhelper.remove_unit.side_effect = ApplicationNotFoundException( @@ -172,8 +172,8 @@ def test_run_application_not_found(self, guests_on_hypervisor, remove_hypervisor assert result.result_type == ResultType.FAILED assert result.message == "Application missing..." - @patch("sunbeam.commands.hypervisor.remove_hypervisor") - @patch("sunbeam.commands.hypervisor.guests_on_hypervisor") + @patch("sunbeam.steps.hypervisor.remove_hypervisor") + @patch("sunbeam.steps.hypervisor.guests_on_hypervisor") def test_run_timeout(self, guests_on_hypervisor, remove_hypervisor): guests_on_hypervisor.return_value = [] self.jhelper.wait_application_ready.side_effect = TimeoutException("timed out") @@ -192,7 +192,7 @@ class TestReapplyHypervisorTerraformPlanStep(unittest.TestCase): def __init__(self, methodName: str = "runTest") -> None: super().__init__(methodName) self.read_config = patch( - "sunbeam.commands.hypervisor.read_config", + "sunbeam.steps.hypervisor.read_config", Mock( return_value={ "openstack_model": "openstack", diff --git a/sunbeam-python/tests/unit/sunbeam/commands/test_juju.py b/sunbeam-python/tests/unit/sunbeam/steps/test_juju.py similarity index 97% rename from sunbeam-python/tests/unit/sunbeam/commands/test_juju.py rename to sunbeam-python/tests/unit/sunbeam/steps/test_juju.py index 09f06b72..d7ee37f0 100644 --- a/sunbeam-python/tests/unit/sunbeam/commands/test_juju.py +++ b/sunbeam-python/tests/unit/sunbeam/steps/test_juju.py @@ -21,9 +21,9 @@ import pexpect import pytest -import sunbeam.commands.juju as juju -from sunbeam.jobs.common import ResultType -from sunbeam.jobs.juju import ModelNotFoundException +import sunbeam.steps.juju as juju +from sunbeam.core.common import ResultType +from sunbeam.core.juju import ModelNotFoundException @pytest.fixture(autouse=True) @@ -36,7 +36,7 @@ def mock_run_sync(mocker): def run_sync(coro): return loop.run_until_complete(coro) - mocker.patch("sunbeam.commands.juju.run_sync", run_sync) + mocker.patch("sunbeam.steps.juju.run_sync", run_sync) yield loop.close() @@ -190,7 +190,7 @@ def test_is_skip_when_juju_account_not_present(self): def test_run(self): with patch( - "sunbeam.commands.juju.pexpect.spawn", + "sunbeam.steps.juju.pexpect.spawn", Mock( return_value=Mock( __enter__=Mock(return_value=Mock(exitstatus=0)), __exit__=Mock() @@ -202,14 +202,14 @@ def test_run(self): assert step.is_skip().result_type == ResultType.COMPLETED with patch( - "sunbeam.commands.juju.pexpect.spawn", Mock(return_value=Mock(exitstatus=0)) + "sunbeam.steps.juju.pexpect.spawn", Mock(return_value=Mock(exitstatus=0)) ): result = step.run() assert result.result_type == ResultType.COMPLETED def test_run_pexpect_timeout(self): with patch( - "sunbeam.commands.juju.pexpect.spawn", + "sunbeam.steps.juju.pexpect.spawn", Mock( return_value=Mock( __enter__=Mock(return_value=Mock(exitstatus=0)), __exit__=Mock() @@ -221,7 +221,7 @@ def test_run_pexpect_timeout(self): assert step.is_skip().result_type == ResultType.COMPLETED with patch( - "sunbeam.commands.juju.pexpect.spawn", + "sunbeam.steps.juju.pexpect.spawn", Mock( return_value=Mock( exitstatus=0, expect=Mock(side_effect=pexpect.TIMEOUT("timeout")) @@ -233,7 +233,7 @@ def test_run_pexpect_timeout(self): def test_run_pexpect_failed_exitcode(self): with patch( - "sunbeam.commands.juju.pexpect.spawn", + "sunbeam.steps.juju.pexpect.spawn", Mock( return_value=Mock( __enter__=Mock(return_value=Mock(exitstatus=0)), __exit__=Mock() @@ -245,7 +245,7 @@ def test_run_pexpect_failed_exitcode(self): assert step.is_skip().result_type == ResultType.COMPLETED with patch( - "sunbeam.commands.juju.pexpect.spawn", Mock(return_value=Mock(exitstatus=1)) + "sunbeam.steps.juju.pexpect.spawn", Mock(return_value=Mock(exitstatus=1)) ): result = step.run() assert result.result_type == ResultType.FAILED diff --git a/sunbeam-python/tests/unit/sunbeam/commands/test_k8s.py b/sunbeam-python/tests/unit/sunbeam/steps/test_k8s.py similarity index 94% rename from sunbeam-python/tests/unit/sunbeam/commands/test_k8s.py rename to sunbeam-python/tests/unit/sunbeam/steps/test_k8s.py index 598203af..2a76a344 100644 --- a/sunbeam-python/tests/unit/sunbeam/commands/test_k8s.py +++ b/sunbeam-python/tests/unit/sunbeam/steps/test_k8s.py @@ -19,19 +19,19 @@ import pytest from sunbeam.clusterd.service import ConfigItemNotFoundException -from sunbeam.commands.k8s import ( +from sunbeam.core.common import ResultType +from sunbeam.core.juju import ( + ActionFailedException, + ApplicationNotFoundException, + LeaderNotFoundException, +) +from sunbeam.steps.k8s import ( CREDENTIAL_SUFFIX, K8S_CLOUD_SUFFIX, AddK8SCloudStep, AddK8SCredentialStep, StoreK8SKubeConfigStep, ) -from sunbeam.jobs.common import ResultType -from sunbeam.jobs.juju import ( - ActionFailedException, - ApplicationNotFoundException, - LeaderNotFoundException, -) @pytest.fixture(autouse=True) @@ -44,7 +44,7 @@ def mock_run_sync(mocker): def run_sync(coro): return loop.run_until_complete(coro) - mocker.patch("sunbeam.commands.k8s.run_sync", run_sync) + mocker.patch("sunbeam.steps.k8s.run_sync", run_sync) yield loop.close() @@ -78,7 +78,7 @@ def test_is_skip_cloud_already_deployed(self): assert result.result_type == ResultType.SKIPPED def test_run(self): - with patch("sunbeam.commands.k8s.read_config", Mock(return_value={})): + with patch("sunbeam.steps.k8s.read_config", Mock(return_value={})): step = AddK8SCloudStep(self.deployment, self.jhelper) result = step.run() @@ -123,7 +123,7 @@ def test_is_skip_credential_exists(self): assert result.result_type == ResultType.SKIPPED def test_run(self): - with patch("sunbeam.commands.k8s.read_config", Mock(return_value={})): + with patch("sunbeam.steps.k8s.read_config", Mock(return_value={})): step = AddK8SCredentialStep(self.deployment, self.jhelper) result = step.run() @@ -151,7 +151,7 @@ def test_is_skip(self): def test_is_skip_config_missing(self): with patch( - "sunbeam.commands.k8s.read_config", + "sunbeam.steps.k8s.read_config", Mock(side_effect=ConfigItemNotFoundException), ): step = StoreK8SKubeConfigStep(self.client, self.jhelper, "test-model") diff --git a/sunbeam-python/tests/unit/sunbeam/commands/test_microceph.py b/sunbeam-python/tests/unit/sunbeam/steps/test_microceph.py similarity index 94% rename from sunbeam-python/tests/unit/sunbeam/commands/test_microceph.py rename to sunbeam-python/tests/unit/sunbeam/steps/test_microceph.py index abdc665f..0e85ae7a 100644 --- a/sunbeam-python/tests/unit/sunbeam/commands/test_microceph.py +++ b/sunbeam-python/tests/unit/sunbeam/steps/test_microceph.py @@ -17,9 +17,9 @@ import pytest -from sunbeam.commands.microceph import ConfigureMicrocephOSDStep, SetCephMgrPoolSizeStep -from sunbeam.jobs.common import ResultType -from sunbeam.jobs.juju import ActionFailedException +from sunbeam.core.common import ResultType +from sunbeam.core.juju import ActionFailedException +from sunbeam.steps.microceph import ConfigureMicrocephOSDStep, SetCephMgrPoolSizeStep @pytest.fixture(autouse=True) @@ -32,7 +32,7 @@ def mock_run_sync(mocker): def run_sync(coro): return loop.run_until_complete(coro) - mocker.patch("sunbeam.commands.microceph.run_sync", run_sync) + mocker.patch("sunbeam.steps.microceph.run_sync", run_sync) yield loop.close() diff --git a/sunbeam-python/tests/unit/sunbeam/commands/test_microk8s.py b/sunbeam-python/tests/unit/sunbeam/steps/test_microk8s.py similarity index 94% rename from sunbeam-python/tests/unit/sunbeam/commands/test_microk8s.py rename to sunbeam-python/tests/unit/sunbeam/steps/test_microk8s.py index 2276f31f..a624b65f 100644 --- a/sunbeam-python/tests/unit/sunbeam/commands/test_microk8s.py +++ b/sunbeam-python/tests/unit/sunbeam/steps/test_microk8s.py @@ -19,18 +19,18 @@ import pytest from sunbeam.clusterd.service import ConfigItemNotFoundException -from sunbeam.commands.microk8s import ( +from sunbeam.core.common import ResultType +from sunbeam.core.juju import ( + ActionFailedException, + ApplicationNotFoundException, + LeaderNotFoundException, +) +from sunbeam.steps.microk8s import ( CREDENTIAL_SUFFIX, K8S_CLOUD_SUFFIX, AddMicrok8sCloudStep, StoreMicrok8sConfigStep, ) -from sunbeam.jobs.common import ResultType -from sunbeam.jobs.juju import ( - ActionFailedException, - ApplicationNotFoundException, - LeaderNotFoundException, -) @pytest.fixture(autouse=True) @@ -43,7 +43,7 @@ def mock_run_sync(mocker): def run_sync(coro): return loop.run_until_complete(coro) - mocker.patch("sunbeam.commands.microk8s.run_sync", run_sync) + mocker.patch("sunbeam.steps.microk8s.run_sync", run_sync) yield loop.close() @@ -77,7 +77,7 @@ def test_is_skip_cloud_already_deployed(self): assert result.result_type == ResultType.SKIPPED def test_run(self): - with patch("sunbeam.commands.microk8s.read_config", Mock(return_value={})): + with patch("sunbeam.steps.microk8s.read_config", Mock(return_value={})): step = AddMicrok8sCloudStep(self.deployment, self.jhelper) result = step.run() @@ -105,7 +105,7 @@ def test_is_skip(self): def test_is_skip_config_missing(self): with patch( - "sunbeam.commands.microk8s.read_config", + "sunbeam.steps.microk8s.read_config", Mock(side_effect=ConfigItemNotFoundException), ): step = StoreMicrok8sConfigStep(self.client, self.jhelper, "test-model") diff --git a/sunbeam-python/tests/unit/sunbeam/commands/test_mysql.py b/sunbeam-python/tests/unit/sunbeam/steps/test_mysql.py similarity index 85% rename from sunbeam-python/tests/unit/sunbeam/commands/test_mysql.py rename to sunbeam-python/tests/unit/sunbeam/steps/test_mysql.py index 54714a13..d38bb6c0 100644 --- a/sunbeam-python/tests/unit/sunbeam/commands/test_mysql.py +++ b/sunbeam-python/tests/unit/sunbeam/steps/test_mysql.py @@ -17,9 +17,9 @@ import pytest -from sunbeam.commands.mysql import ConfigureMySQLStep -from sunbeam.jobs.common import ResultType -from sunbeam.jobs.juju import JujuException +from sunbeam.core.common import ResultType +from sunbeam.core.juju import JujuException +from sunbeam.steps.mysql import ConfigureMySQLStep @pytest.fixture(autouse=True) @@ -32,7 +32,7 @@ def mock_run_sync(mocker): def run_sync(coro): return loop.run_until_complete(coro) - mocker.patch("sunbeam.commands.mysql.run_sync", run_sync) + mocker.patch("sunbeam.steps.mysql.run_sync", run_sync) yield loop.close() @@ -43,7 +43,7 @@ def setUp(self): def test_run_pristine_installation(self): with patch( - "sunbeam.commands.mysql.get_mysqls", + "sunbeam.steps.mysql.get_mysqls", Mock(return_value=["mysql"]), ): step = ConfigureMySQLStep(self.jhelper) @@ -53,7 +53,7 @@ def test_run_pristine_installation(self): def test_run_no_mysql(self): with patch( - "sunbeam.commands.mysql.get_mysqls", + "sunbeam.steps.mysql.get_mysqls", Mock(side_effect=JujuException("No MySQL applications found")), ): step = ConfigureMySQLStep(self.jhelper) @@ -64,7 +64,7 @@ def test_run_no_mysql(self): def test_run_failed_to_get_leader(self): self.jhelper.get_leader_unit.side_effect = JujuException("failed to get leader") with patch( - "sunbeam.commands.mysql.get_mysqls", + "sunbeam.steps.mysql.get_mysqls", Mock(return_value=["mysql"]), ): step = ConfigureMySQLStep(self.jhelper) @@ -75,7 +75,7 @@ def test_run_failed_to_get_leader(self): def test_run_failed_to_get_password(self): self.jhelper.run_action.side_effect = JujuException("failed to get password") with patch( - "sunbeam.commands.mysql.get_mysqls", + "sunbeam.steps.mysql.get_mysqls", Mock(return_value=["mysql"]), ): step = ConfigureMySQLStep(self.jhelper) @@ -88,7 +88,7 @@ def test_run_failed_to_set_config(self): "failed to run cmd" ) with patch( - "sunbeam.commands.mysql.get_mysqls", + "sunbeam.steps.mysql.get_mysqls", Mock(return_value=["mysql"]), ): step = ConfigureMySQLStep(self.jhelper) diff --git a/sunbeam-python/tests/unit/sunbeam/commands/test_openstack.py b/sunbeam-python/tests/unit/sunbeam/steps/test_openstack.py similarity index 92% rename from sunbeam-python/tests/unit/sunbeam/commands/test_openstack.py rename to sunbeam-python/tests/unit/sunbeam/steps/test_openstack.py index 19da9331..4c779c6c 100644 --- a/sunbeam-python/tests/unit/sunbeam/commands/test_openstack.py +++ b/sunbeam-python/tests/unit/sunbeam/steps/test_openstack.py @@ -19,7 +19,15 @@ import pytest from sunbeam.clusterd.service import ConfigItemNotFoundException -from sunbeam.commands.openstack import ( +from sunbeam.core.common import ResultType +from sunbeam.core.juju import ( + ApplicationNotFoundException, + JujuWaitException, + TimeoutException, +) +from sunbeam.core.k8s import SERVICE_LB_ANNOTATION +from sunbeam.core.terraform import TerraformException +from sunbeam.steps.openstack import ( DeployControlPlaneStep, OpenStackPatchLoadBalancerServicesStep, ReapplyOpenStackTerraformPlanStep, @@ -27,14 +35,6 @@ compute_ingress_scale, compute_os_api_scale, ) -from sunbeam.commands.terraform import TerraformException -from sunbeam.jobs.common import ResultType -from sunbeam.jobs.juju import ( - ApplicationNotFoundException, - JujuWaitException, - TimeoutException, -) -from sunbeam.jobs.k8s import SERVICE_LB_ANNOTATION TOPOLOGY = "single" DATABASE = "single" @@ -51,7 +51,7 @@ def mock_run_sync(mocker): def run_sync(coro): return loop.run_until_complete(coro) - mocker.patch("sunbeam.commands.openstack.run_sync", run_sync) + mocker.patch("sunbeam.steps.openstack.run_sync", run_sync) yield loop.close() @@ -60,7 +60,7 @@ class TestDeployControlPlaneStep(unittest.TestCase): def __init__(self, methodName: str = "runTest") -> None: super().__init__(methodName) self.snap_mock = Mock() - self.snap = patch("sunbeam.jobs.k8s.Snap", self.snap_mock) + self.snap = patch("sunbeam.core.k8s.Snap", self.snap_mock) def setUp(self): self.jhelper = AsyncMock() @@ -93,7 +93,7 @@ def test_run_pristine_installation(self): MODEL, ) with patch( - "sunbeam.commands.openstack.read_config", + "sunbeam.steps.openstack.read_config", Mock(return_value={"region": "TestOne"}), ): result = step.run() @@ -117,7 +117,7 @@ def test_run_tf_apply_failed(self): MODEL, ) with patch( - "sunbeam.commands.openstack.read_config", + "sunbeam.steps.openstack.read_config", Mock(return_value={"region": "TestOne"}), ): result = step.run() @@ -140,7 +140,7 @@ def test_run_waiting_timed_out(self): MODEL, ) with patch( - "sunbeam.commands.openstack.read_config", + "sunbeam.steps.openstack.read_config", Mock(return_value={"region": "TestOne"}), ): result = step.run() @@ -165,7 +165,7 @@ def test_run_unit_in_error_state(self): MODEL, ) with patch( - "sunbeam.commands.openstack.read_config", + "sunbeam.steps.openstack.read_config", Mock(return_value={"region": "TestOne"}), ): result = step.run() @@ -186,7 +186,7 @@ def test_is_skip_pristine(self): MODEL, ) with patch( - "sunbeam.commands.openstack.read_config", + "sunbeam.steps.openstack.read_config", Mock(side_effect=ConfigItemNotFoundException("not found")), ): result = step.is_skip() @@ -205,7 +205,7 @@ def test_is_skip_subsequent_run(self): MODEL, ) with patch( - "sunbeam.commands.openstack.read_config", + "sunbeam.steps.openstack.read_config", Mock(return_value={"topology": "single", "database": "single"}), ): result = step.is_skip() @@ -224,7 +224,7 @@ def test_is_skip_database_changed(self): MODEL, ) with patch( - "sunbeam.commands.openstack.read_config", + "sunbeam.steps.openstack.read_config", Mock(return_value={"topology": "single", "database": "multi"}), ): result = step.is_skip() @@ -244,7 +244,7 @@ def test_is_skip_incompatible_topology(self): force=False, ) with patch( - "sunbeam.commands.openstack.read_config", + "sunbeam.steps.openstack.read_config", Mock(return_value={"topology": "single", "database": "single"}), ): result = step.is_skip() @@ -266,7 +266,7 @@ def test_is_skip_force_incompatible_topology(self): force=True, ) with patch( - "sunbeam.commands.openstack.read_config", + "sunbeam.steps.openstack.read_config", Mock(return_value={"topology": "single", "database": "single"}), ): result = step.is_skip() @@ -278,7 +278,7 @@ class PatchLoadBalancerServicesStepTest(unittest.TestCase): def __init__(self, methodName: str = "runTest") -> None: super().__init__(methodName) self.read_config = patch( - "sunbeam.jobs.steps.read_config", + "sunbeam.core.steps.read_config", Mock( return_value={ "apiVersion": "v1", @@ -304,7 +304,7 @@ def __init__(self, methodName: str = "runTest") -> None: ), ) self.snap_mock = Mock() - self.snap = patch("sunbeam.jobs.k8s.Snap", self.snap_mock) + self.snap = patch("sunbeam.core.k8s.Snap", self.snap_mock) def setUp(self): self.client = Mock() @@ -319,7 +319,7 @@ def tearDown(self): def test_is_skip(self): self.snap_mock().config.get.return_value = "k8s" with patch( - "sunbeam.jobs.steps.KubeClient", + "sunbeam.core.steps.KubeClient", new=Mock( return_value=Mock( get=Mock( @@ -339,7 +339,7 @@ def test_is_skip(self): def test_is_skip_missing_annotation(self): self.snap_mock().config.get.return_value = "k8s" with patch( - "sunbeam.jobs.steps.KubeClient", + "sunbeam.core.steps.KubeClient", new=Mock( return_value=Mock( get=Mock(return_value=Mock(metadata=Mock(annotations={}))) @@ -353,7 +353,7 @@ def test_is_skip_missing_annotation(self): def test_is_skip_missing_config(self): self.snap_mock().config.get.return_value = "k8s" with patch( - "sunbeam.jobs.steps.read_config", + "sunbeam.core.steps.read_config", new=Mock(side_effect=ConfigItemNotFoundException), ): step = OpenStackPatchLoadBalancerServicesStep(self.client) @@ -363,7 +363,7 @@ def test_is_skip_missing_config(self): def test_run(self): self.snap_mock().config.get.return_value = "k8s" with patch( - "sunbeam.jobs.steps.KubeClient", + "sunbeam.core.steps.KubeClient", new=Mock( return_value=Mock( get=Mock( @@ -435,7 +435,7 @@ class TestReapplyOpenStackTerraformPlanStep(unittest.TestCase): def __init__(self, methodName: str = "runTest") -> None: super().__init__(methodName) self.read_config = patch( - "sunbeam.commands.openstack.read_config", + "sunbeam.steps.openstack.read_config", Mock(return_value={"topology": "single", "database": "single"}), ) diff --git a/sunbeam-python/tests/unit/sunbeam/commands/upgrades/test_base.py b/sunbeam-python/tests/unit/sunbeam/steps/upgrades/test_base.py similarity index 94% rename from sunbeam-python/tests/unit/sunbeam/commands/upgrades/test_base.py rename to sunbeam-python/tests/unit/sunbeam/steps/upgrades/test_base.py index 29d95d28..78ced9bd 100644 --- a/sunbeam-python/tests/unit/sunbeam/commands/upgrades/test_base.py +++ b/sunbeam-python/tests/unit/sunbeam/steps/upgrades/test_base.py @@ -14,10 +14,10 @@ from unittest.mock import AsyncMock, Mock -from sunbeam.commands.terraform import TerraformException -from sunbeam.commands.upgrades.inter_channel import BaseUpgrade -from sunbeam.jobs.common import ResultType -from sunbeam.jobs.juju import TimeoutException +from sunbeam.core.common import ResultType +from sunbeam.core.juju import TimeoutException +from sunbeam.core.terraform import TerraformException +from sunbeam.steps.upgrades.inter_channel import BaseUpgrade class TestBaseUpgrade: diff --git a/sunbeam-python/tests/unit/sunbeam/test_clusterd.py b/sunbeam-python/tests/unit/sunbeam/test_clusterd.py index 8aea7ebb..c8f6cb3d 100644 --- a/sunbeam-python/tests/unit/sunbeam/test_clusterd.py +++ b/sunbeam-python/tests/unit/sunbeam/test_clusterd.py @@ -20,7 +20,9 @@ import sunbeam.clusterd.service as service from sunbeam.clusterd.cluster import ClusterService -from sunbeam.commands.clusterd import ( +from sunbeam.core.common import ResultType +from sunbeam.core.juju import ApplicationNotFoundException +from sunbeam.steps.clusterd import ( ClusterAddJujuUserStep, ClusterAddNodeStep, ClusterInitStep, @@ -32,8 +34,6 @@ DeploySunbeamClusterdApplicationStep, SaveManagementCidrStep, ) -from sunbeam.jobs.common import ResultType -from sunbeam.jobs.juju import ApplicationNotFoundException @pytest.fixture() From 371bac0502f58a76705cd21f0e952a152824a7c8 Mon Sep 17 00:00:00 2001 From: Guillaume Boutry Date: Tue, 27 Aug 2024 09:48:05 +0200 Subject: [PATCH 2/2] Move JujuStepHelper to core JujuStepHelper's main goal is to fill in where pylibjuju is lacking by using the juju cli. Signed-off-by: Guillaume Boutry --- sunbeam-python/sunbeam/core/juju.py | 343 ++++++++++++++++++ .../features/interface/v1/openstack.py | 2 +- .../sunbeam/features/ldap/feature.py | 9 +- .../sunbeam/features/observability/feature.py | 9 +- .../sunbeam/features/pro/feature.py | 3 +- .../sunbeam/provider/local/commands.py | 8 +- sunbeam-python/sunbeam/provider/maas/steps.py | 2 +- sunbeam-python/sunbeam/steps/clusterd.py | 3 +- sunbeam-python/sunbeam/steps/hypervisor.py | 2 +- sunbeam-python/sunbeam/steps/juju.py | 342 +---------------- sunbeam-python/sunbeam/steps/k8s.py | 2 +- sunbeam-python/sunbeam/steps/microk8s.py | 2 +- sunbeam-python/sunbeam/steps/openstack.py | 9 +- .../sunbeam/steps/upgrades/inter_channel.py | 9 +- .../sunbeam/steps/upgrades/intra_channel.py | 3 +- .../tests/unit/sunbeam/core/test_juju.py | 55 +++ .../tests/unit/sunbeam/steps/test_juju.py | 54 --- 17 files changed, 442 insertions(+), 415 deletions(-) diff --git a/sunbeam-python/sunbeam/core/juju.py b/sunbeam-python/sunbeam/core/juju.py index 60de166c..aa5e14e4 100644 --- a/sunbeam-python/sunbeam/core/juju.py +++ b/sunbeam-python/sunbeam/core/juju.py @@ -19,6 +19,8 @@ import json import logging import os +import subprocess +import tempfile import typing from datetime import datetime from pathlib import Path @@ -47,6 +49,8 @@ from juju.machine import Machine from juju.model import Model from juju.unit import Unit +from packaging import version +from snaphelpers import Snap from sunbeam.clusterd.client import Client from sunbeam.core.common import SunbeamException @@ -1268,3 +1272,342 @@ async def merge_bindings( await facade.MergeBindings(request) except JujuError as e: raise JujuException(f"Failed to merge bindings: {str(e)}") from e + + +class JujuStepHelper: + jhelper: JujuHelper + + def _get_juju_binary(self) -> str: + """Get juju binary path.""" + snap = Snap() + juju_binary = snap.paths.snap / "juju" / "bin" / "juju" + return str(juju_binary) + + def _juju_cmd(self, *args): + """Runs the specified juju command line command. + + The command will be run using the json formatter. Invoking functions + do not need to worry about the format or the juju command that should + be used. + + For example, to run the juju bootstrap k8s, this method should + be invoked as: + + self._juju_cmd('bootstrap', 'k8s') + + Any results from running with json are returned after being parsed. + Subprocess execution errors are raised to the calling code. + + :param args: command to run + :return: + """ + cmd = [self._get_juju_binary()] + cmd.extend(args) + cmd.extend(["--format", "json"]) + + LOG.debug(f'Running command {" ".join(cmd)}') + process = subprocess.run(cmd, capture_output=True, text=True, check=True) + LOG.debug(f"Command finished. stdout={process.stdout}, stderr={process.stderr}") + + return json.loads(process.stdout.strip()) + + def check_model_present(self, model_name) -> bool: + """Determines if the step should be skipped or not. + + :return: True if the Step should be skipped, False otherwise + """ + try: + run_sync(self.jhelper.get_model(model_name)) + return True + except ModelNotFoundException: + LOG.debug(f"Model {model_name} not found") + return False + + def get_clouds( + self, cloud_type: str, local: bool = False, controller: str | None = None + ) -> list: + """Get clouds based on cloud type. + + If local is True, return clouds registered in client. + If local is False, return clouds registered in client and controller. + If local is False and controller specified, return clouds registered + in controller. + """ + clouds = [] + cmd = ["clouds"] + if local: + cmd.append("--client") + else: + if controller: + cmd.extend(["--controller", controller]) + clouds_from_juju_cmd = self._juju_cmd(*cmd) + LOG.debug(f"Available clouds in juju are {clouds_from_juju_cmd.keys()}") + + for name, details in clouds_from_juju_cmd.items(): + if details["type"] == cloud_type: + clouds.append(name) + + LOG.debug(f"There are {len(clouds)} {cloud_type} clouds available: {clouds}") + + return clouds + + def get_credentials( + self, cloud: str | None = None, local: bool = False + ) -> dict[str, dict]: + """Get credentials.""" + cmd = ["credentials"] + if local: + cmd.append("--client") + if cloud: + cmd.append(cloud) + return self._juju_cmd(*cmd) + + def get_controllers(self, clouds: list | None = None) -> list: + """Get controllers hosted on given clouds. + + if clouds is None, return all the controllers. + """ + controllers = self._juju_cmd("controllers") + controllers = controllers.get("controllers", {}) or {} + if clouds is None: + return list(controllers.keys()) + + existing_controllers = [ + name for name, details in controllers.items() if details["cloud"] in clouds + ] + LOG.debug( + f"There are {len(existing_controllers)} existing {clouds} " + f"controllers running: {existing_controllers}" + ) + return existing_controllers + + def get_external_controllers(self) -> list: + """Get all external controllers registered.""" + snap = Snap() + data_location = snap.paths.user_data + external_controllers = [] + + controllers = self.get_controllers() + for controller in controllers: + account_file = data_location / f"{controller}.yaml" + if account_file.exists(): + external_controllers.append(controller) + + return external_controllers + + def get_controller(self, controller: str) -> dict: + """Get controller definition.""" + try: + return self._juju_cmd("show-controller", controller)[controller] + except subprocess.CalledProcessError as e: + LOG.debug(e) + raise ControllerNotFoundException() from e + + def add_cloud(self, name: str, cloud: dict, controller: str | None) -> bool: + """Add cloud to client clouds. + + If controller is specified, add cloud to both client + and given controller. + """ + if cloud["clouds"][name]["type"] not in ("manual", "maas"): + return False + + with tempfile.NamedTemporaryFile() as temp: + temp.write(yaml.dump(cloud).encode("utf-8")) + temp.flush() + cmd = [ + self._get_juju_binary(), + "add-cloud", + name, + "--file", + temp.name, + "--client", + ] + if controller: + cmd.extend(["--controller", controller, "--force"]) + LOG.debug(f'Running command {" ".join(cmd)}') + process = subprocess.run(cmd, capture_output=True, text=True, check=True) + LOG.debug( + f"Command finished. stdout={process.stdout}, stderr={process.stderr}" + ) + + return True + + def add_credential(self, cloud: str, credential: dict, controller: str | None): + """Add credential to client credentials.""" + with tempfile.NamedTemporaryFile() as temp: + temp.write(yaml.dump(credential).encode("utf-8")) + temp.flush() + cmd = [ + self._get_juju_binary(), + "add-credential", + cloud, + "--file", + temp.name, + "--client", + ] + if controller: + cmd.extend(["--controller", controller]) + LOG.debug(f'Running command {" ".join(cmd)}') + process = subprocess.run(cmd, capture_output=True, text=True, check=True) + LOG.debug( + f"Command finished. stdout={process.stdout}, stderr={process.stderr}" + ) + + def integrate( + self, + model: str, + provider: str, + requirer: str, + ignore_error_if_exists: bool = True, + ): + """Juju integrate applications.""" + cmd = [ + self._get_juju_binary(), + "integrate", + "-m", + model, + provider, + requirer, + ] + try: + LOG.debug(f'Running command {" ".join(cmd)}') + process = subprocess.run(cmd, capture_output=True, text=True, check=True) + LOG.debug( + f"Command finished. stdout={process.stdout}, stderr={process.stderr}" + ) + except subprocess.CalledProcessError as e: + LOG.debug(e.stderr) + if ignore_error_if_exists and "already exists" not in e.stderr: + raise e + + def remove_relation(self, model: str, provider: str, requirer: str): + """Juju remove relation.""" + cmd = [ + self._get_juju_binary(), + "remove-relation", + "-m", + model, + provider, + requirer, + ] + LOG.debug(f'Running command {" ".join(cmd)}') + process = subprocess.run(cmd, capture_output=True, text=True, check=True) + LOG.debug(f"Command finished. stdout={process.stdout}, stderr={process.stderr}") + + def revision_update_needed( + self, application_name: str, model: str, status: dict | None = None + ) -> bool: + """Check if a revision update is available for an applicaton. + + :param application_name: Name of application to check for updates for + :param model: Model application is in + :param status: Dictionay of model status + """ + if not status: + status = run_sync(self.jhelper.get_model_status_full(model)) + app_status = status["applications"].get(application_name, {}) + if not app_status: + LOG.debug(f"{application_name} not present in model") + return False + deployed_revision = int(self._extract_charm_revision(app_status["charm"])) + charm_name = self._extract_charm_name(app_status["charm"]) + deployed_channel = self.normalise_channel(app_status["charm-channel"]) + if len(deployed_channel.split("/")) > 2: + LOG.debug(f"Cannot calculate upgrade for {application_name}, branch in use") + return False + available_revision = run_sync( + self.jhelper.get_available_charm_revision( + model, charm_name, deployed_channel + ) + ) + return bool(available_revision > deployed_revision) + + def get_charm_deployed_versions(self, model: str) -> dict: + """Return charm deployed info for all the applications in model. + + For each application, return a tuple of charm name, channel and revision. + Example output: + {"keystone": ("keystone-k8s", "2023.2/stable", 234)} + """ + status = run_sync(self.jhelper.get_model_status_full(model)) + + apps = {} + for app_name, app_status in status.get("applications", {}).items(): + charm_name = self._extract_charm_name(app_status["charm"]) + deployed_channel = self.normalise_channel(app_status["charm-channel"]) + deployed_revision = int(self._extract_charm_revision(app_status["charm"])) + apps[app_name] = (charm_name, deployed_channel, deployed_revision) + + return apps + + def get_apps_filter_by_charms(self, model: str, charms: list) -> list: + """Return apps filtered by given charms. + + Get all apps from the model and return only the apps deployed with + charms in the provided list. + """ + deployed_all_apps = self.get_charm_deployed_versions(model) + return [ + app_name + for app_name, (charm, channel, revision) in deployed_all_apps.items() + if charm in charms + ] + + def normalise_channel(self, channel: str) -> str: + """Expand channel if it is using abbreviation. + + Juju supports abbreviating latest/{risk} to {risk}. This expands it. + + :param channel: Channel string to normalise + """ + if channel in ["stable", "candidate", "beta", "edge"]: + channel = f"latest/{channel}" + return channel + + def _extract_charm_name(self, charm_url: str) -> str: + """Extract charm name from charm url. + + :param charm_url: Url to examine + """ + # XXX There must be a better way. ch:amd64/jammy/cinder-k8s-50 -> cinder-k8s + return charm_url.split("/")[-1].rsplit("-", maxsplit=1)[0] + + def _extract_charm_revision(self, charm_url: str) -> str: + """Extract charm revision from charm url. + + :param charm_url: Url to examine + """ + return charm_url.split("-")[-1] + + def channel_update_needed(self, channel: str, new_channel: str) -> bool: + """Compare two channels and see if the second is 'newer'. + + :param current_channel: Current channel + :param new_channel: Proposed new channel + """ + risks = ["stable", "candidate", "beta", "edge"] + current_channel = self.normalise_channel(channel) + current_track, current_risk = current_channel.split("/") + new_track, new_risk = new_channel.split("/") + if current_track != new_track: + try: + return version.parse(current_track) < version.parse(new_track) + except version.InvalidVersion: + LOG.error("Error: Could not compare tracks") + return False + if risks.index(current_risk) < risks.index(new_risk): + return True + else: + return False + + def get_model_name_with_owner(self, model: str) -> str: + """Return model name with owner name. + + :param model: Model name + + Raises ModelNotFoundException if model does not exist. + """ + model_with_owner = run_sync(self.jhelper.get_model_name_with_owner(model)) + + return model_with_owner diff --git a/sunbeam-python/sunbeam/features/interface/v1/openstack.py b/sunbeam-python/sunbeam/features/interface/v1/openstack.py index df324133..ee852b20 100644 --- a/sunbeam-python/sunbeam/features/interface/v1/openstack.py +++ b/sunbeam-python/sunbeam/features/interface/v1/openstack.py @@ -42,6 +42,7 @@ from sunbeam.core.juju import ( ApplicationNotFoundException, JujuHelper, + JujuStepHelper, JujuWaitException, TimeoutException, run_sync, @@ -54,7 +55,6 @@ TerraformInitStep, ) from sunbeam.features.interface.v1.base import EnableDisableFeature -from sunbeam.steps.juju import JujuStepHelper from sunbeam.steps.openstack import TOPOLOGY_KEY LOG = logging.getLogger(__name__) diff --git a/sunbeam-python/sunbeam/features/ldap/feature.py b/sunbeam-python/sunbeam/features/ldap/feature.py index afa2d933..db420ff7 100644 --- a/sunbeam-python/sunbeam/features/ldap/feature.py +++ b/sunbeam-python/sunbeam/features/ldap/feature.py @@ -38,7 +38,13 @@ update_status_background, ) from sunbeam.core.deployment import Deployment -from sunbeam.core.juju import JujuHelper, JujuWaitException, TimeoutException, run_sync +from sunbeam.core.juju import ( + JujuHelper, + JujuStepHelper, + JujuWaitException, + TimeoutException, + run_sync, +) from sunbeam.core.manifest import CharmManifest, SoftwareConfig from sunbeam.core.openstack import OPENSTACK_MODEL from sunbeam.core.terraform import TerraformException, TerraformInitStep @@ -46,7 +52,6 @@ OpenStackControlPlaneFeature, TerraformPlanLocation, ) -from sunbeam.steps.juju import JujuStepHelper from sunbeam.versions import OPENSTACK_CHANNEL LOG = logging.getLogger(__name__) diff --git a/sunbeam-python/sunbeam/features/observability/feature.py b/sunbeam-python/sunbeam/features/observability/feature.py index 7bedafe9..b6fd9781 100644 --- a/sunbeam-python/sunbeam/features/observability/feature.py +++ b/sunbeam-python/sunbeam/features/observability/feature.py @@ -50,7 +50,13 @@ update_status_background, ) from sunbeam.core.deployment import Deployment -from sunbeam.core.juju import JujuHelper, JujuWaitException, TimeoutException, run_sync +from sunbeam.core.juju import ( + JujuHelper, + JujuStepHelper, + JujuWaitException, + TimeoutException, + run_sync, +) from sunbeam.core.k8s import K8SHelper from sunbeam.core.manifest import ( AddManifestStep, @@ -73,7 +79,6 @@ OpenStackControlPlaneFeature, TerraformPlanLocation, ) -from sunbeam.steps.juju import JujuStepHelper from sunbeam.steps.k8s import CREDENTIAL_SUFFIX LOG = logging.getLogger(__name__) diff --git a/sunbeam-python/sunbeam/features/pro/feature.py b/sunbeam-python/sunbeam/features/pro/feature.py index 11c012b4..2f69fd92 100644 --- a/sunbeam-python/sunbeam/features/pro/feature.py +++ b/sunbeam-python/sunbeam/features/pro/feature.py @@ -27,7 +27,7 @@ from sunbeam.clusterd.client import Client from sunbeam.core.common import BaseStep, Result, ResultType, run_plan from sunbeam.core.deployment import Deployment -from sunbeam.core.juju import JujuHelper, TimeoutException, run_sync +from sunbeam.core.juju import JujuHelper, JujuStepHelper, TimeoutException, run_sync from sunbeam.core.manifest import Manifest, SoftwareConfig, TerraformManifest from sunbeam.core.terraform import ( TerraformException, @@ -35,7 +35,6 @@ TerraformInitStep, ) from sunbeam.features.interface.v1.base import EnableDisableFeature -from sunbeam.steps.juju import JujuStepHelper from sunbeam.utils import argument_with_deprecated_option LOG = logging.getLogger(__name__) diff --git a/sunbeam-python/sunbeam/provider/local/commands.py b/sunbeam-python/sunbeam/provider/local/commands.py index ebb39599..770bfb31 100644 --- a/sunbeam-python/sunbeam/provider/local/commands.py +++ b/sunbeam-python/sunbeam/provider/local/commands.py @@ -72,7 +72,12 @@ ) from sunbeam.core.deployment import Deployment, Networks from sunbeam.core.deployments import DeploymentsConfig, deployment_path -from sunbeam.core.juju import JujuHelper, ModelNotFoundException, run_sync +from sunbeam.core.juju import ( + JujuHelper, + JujuStepHelper, + ModelNotFoundException, + run_sync, +) from sunbeam.core.manifest import AddManifestStep from sunbeam.core.openstack import OPENSTACK_MODEL from sunbeam.core.terraform import TerraformInitStep @@ -111,7 +116,6 @@ CreateJujuUserStep, JujuGrantModelAccessStep, JujuLoginStep, - JujuStepHelper, RegisterJujuUserStep, RemoveJujuMachineStep, SaveControllerStep, diff --git a/sunbeam-python/sunbeam/provider/maas/steps.py b/sunbeam-python/sunbeam/provider/maas/steps.py index d8c2cfe9..1c3360f2 100644 --- a/sunbeam-python/sunbeam/provider/maas/steps.py +++ b/sunbeam-python/sunbeam/provider/maas/steps.py @@ -57,6 +57,7 @@ ActionFailedException, JujuHelper, JujuSecretNotFound, + JujuStepHelper, LeaderNotFoundException, TimeoutException, UnitNotFoundException, @@ -71,7 +72,6 @@ JUJU_CONTROLLER_CHARM, BootstrapJujuStep, ControllerNotFoundException, - JujuStepHelper, SaveControllerStep, ScaleJujuStep, ) diff --git a/sunbeam-python/sunbeam/steps/clusterd.py b/sunbeam-python/sunbeam/steps/clusterd.py index 2d089693..00d2a6c3 100644 --- a/sunbeam-python/sunbeam/steps/clusterd.py +++ b/sunbeam-python/sunbeam/steps/clusterd.py @@ -40,12 +40,13 @@ ApplicationNotFoundException, JujuController, JujuHelper, + JujuStepHelper, JujuWaitException, TimeoutException, run_sync, ) from sunbeam.core.manifest import CharmManifest, Manifest -from sunbeam.steps.juju import BOOTSTRAP_CONFIG_KEY, JujuStepHelper +from sunbeam.steps.juju import BOOTSTRAP_CONFIG_KEY LOG = logging.getLogger(__name__) APPLICATION = "sunbeam-clusterd" diff --git a/sunbeam-python/sunbeam/steps/hypervisor.py b/sunbeam-python/sunbeam/steps/hypervisor.py index 5b9f7e49..acf00fe6 100644 --- a/sunbeam-python/sunbeam/steps/hypervisor.py +++ b/sunbeam-python/sunbeam/steps/hypervisor.py @@ -29,6 +29,7 @@ from sunbeam.core.juju import ( ApplicationNotFoundException, JujuHelper, + JujuStepHelper, TimeoutException, run_sync, ) @@ -37,7 +38,6 @@ from sunbeam.core.openstack_api import guests_on_hypervisor, remove_hypervisor from sunbeam.core.steps import AddMachineUnitsStep, DeployMachineApplicationStep from sunbeam.core.terraform import TerraformException, TerraformHelper -from sunbeam.steps.juju import JujuStepHelper LOG = logging.getLogger(__name__) CONFIG_KEY = "TerraformVarsHypervisor" diff --git a/sunbeam-python/sunbeam/steps/juju.py b/sunbeam-python/sunbeam/steps/juju.py index aa2d6403..777d366a 100644 --- a/sunbeam-python/sunbeam/steps/juju.py +++ b/sunbeam-python/sunbeam/steps/juju.py @@ -21,7 +21,6 @@ import re import shutil import subprocess -import tempfile import time import typing from pathlib import Path @@ -29,7 +28,6 @@ import pexpect # type: ignore [import-untyped] import tenacity import yaml -from packaging import version from rich.status import Status from snaphelpers import Snap @@ -54,6 +52,7 @@ JujuController, JujuException, JujuHelper, + JujuStepHelper, JujuWaitException, ModelNotFoundException, TimeoutException, @@ -68,345 +67,6 @@ JUJU_CONTROLLER_CHARM = "juju-controller.charm" -class JujuStepHelper: - jhelper: JujuHelper - - def _get_juju_binary(self) -> str: - """Get juju binary path.""" - snap = Snap() - juju_binary = snap.paths.snap / "juju" / "bin" / "juju" - return str(juju_binary) - - def _juju_cmd(self, *args): - """Runs the specified juju command line command. - - The command will be run using the json formatter. Invoking functions - do not need to worry about the format or the juju command that should - be used. - - For example, to run the juju bootstrap k8s, this method should - be invoked as: - - self._juju_cmd('bootstrap', 'k8s') - - Any results from running with json are returned after being parsed. - Subprocess execution errors are raised to the calling code. - - :param args: command to run - :return: - """ - cmd = [self._get_juju_binary()] - cmd.extend(args) - cmd.extend(["--format", "json"]) - - LOG.debug(f'Running command {" ".join(cmd)}') - process = subprocess.run(cmd, capture_output=True, text=True, check=True) - LOG.debug(f"Command finished. stdout={process.stdout}, stderr={process.stderr}") - - return json.loads(process.stdout.strip()) - - def check_model_present(self, model_name) -> bool: - """Determines if the step should be skipped or not. - - :return: True if the Step should be skipped, False otherwise - """ - try: - run_sync(self.jhelper.get_model(model_name)) - return True - except ModelNotFoundException: - LOG.debug(f"Model {model_name} not found") - return False - - def get_clouds( - self, cloud_type: str, local: bool = False, controller: str | None = None - ) -> list: - """Get clouds based on cloud type. - - If local is True, return clouds registered in client. - If local is False, return clouds registered in client and controller. - If local is False and controller specified, return clouds registered - in controller. - """ - clouds = [] - cmd = ["clouds"] - if local: - cmd.append("--client") - else: - if controller: - cmd.extend(["--controller", controller]) - clouds_from_juju_cmd = self._juju_cmd(*cmd) - LOG.debug(f"Available clouds in juju are {clouds_from_juju_cmd.keys()}") - - for name, details in clouds_from_juju_cmd.items(): - if details["type"] == cloud_type: - clouds.append(name) - - LOG.debug(f"There are {len(clouds)} {cloud_type} clouds available: {clouds}") - - return clouds - - def get_credentials( - self, cloud: str | None = None, local: bool = False - ) -> dict[str, dict]: - """Get credentials.""" - cmd = ["credentials"] - if local: - cmd.append("--client") - if cloud: - cmd.append(cloud) - return self._juju_cmd(*cmd) - - def get_controllers(self, clouds: list | None = None) -> list: - """Get controllers hosted on given clouds. - - if clouds is None, return all the controllers. - """ - controllers = self._juju_cmd("controllers") - controllers = controllers.get("controllers", {}) or {} - if clouds is None: - return list(controllers.keys()) - - existing_controllers = [ - name for name, details in controllers.items() if details["cloud"] in clouds - ] - LOG.debug( - f"There are {len(existing_controllers)} existing {clouds} " - f"controllers running: {existing_controllers}" - ) - return existing_controllers - - def get_external_controllers(self) -> list: - """Get all external controllers registered.""" - snap = Snap() - data_location = snap.paths.user_data - external_controllers = [] - - controllers = self.get_controllers() - for controller in controllers: - account_file = data_location / f"{controller}.yaml" - if account_file.exists(): - external_controllers.append(controller) - - return external_controllers - - def get_controller(self, controller: str) -> dict: - """Get controller definition.""" - try: - return self._juju_cmd("show-controller", controller)[controller] - except subprocess.CalledProcessError as e: - LOG.debug(e) - raise ControllerNotFoundException() from e - - def add_cloud(self, name: str, cloud: dict, controller: str | None) -> bool: - """Add cloud to client clouds. - - If controller is specified, add cloud to both client - and given controller. - """ - if cloud["clouds"][name]["type"] not in ("manual", "maas"): - return False - - with tempfile.NamedTemporaryFile() as temp: - temp.write(yaml.dump(cloud).encode("utf-8")) - temp.flush() - cmd = [ - self._get_juju_binary(), - "add-cloud", - name, - "--file", - temp.name, - "--client", - ] - if controller: - cmd.extend(["--controller", controller, "--force"]) - LOG.debug(f'Running command {" ".join(cmd)}') - process = subprocess.run(cmd, capture_output=True, text=True, check=True) - LOG.debug( - f"Command finished. stdout={process.stdout}, stderr={process.stderr}" - ) - - return True - - def add_credential(self, cloud: str, credential: dict, controller: str | None): - """Add credential to client credentials.""" - with tempfile.NamedTemporaryFile() as temp: - temp.write(yaml.dump(credential).encode("utf-8")) - temp.flush() - cmd = [ - self._get_juju_binary(), - "add-credential", - cloud, - "--file", - temp.name, - "--client", - ] - if controller: - cmd.extend(["--controller", controller]) - LOG.debug(f'Running command {" ".join(cmd)}') - process = subprocess.run(cmd, capture_output=True, text=True, check=True) - LOG.debug( - f"Command finished. stdout={process.stdout}, stderr={process.stderr}" - ) - - def integrate( - self, - model: str, - provider: str, - requirer: str, - ignore_error_if_exists: bool = True, - ): - """Juju integrate applications.""" - cmd = [ - self._get_juju_binary(), - "integrate", - "-m", - model, - provider, - requirer, - ] - try: - LOG.debug(f'Running command {" ".join(cmd)}') - process = subprocess.run(cmd, capture_output=True, text=True, check=True) - LOG.debug( - f"Command finished. stdout={process.stdout}, stderr={process.stderr}" - ) - except subprocess.CalledProcessError as e: - LOG.debug(e.stderr) - if ignore_error_if_exists and "already exists" not in e.stderr: - raise e - - def remove_relation(self, model: str, provider: str, requirer: str): - """Juju remove relation.""" - cmd = [ - self._get_juju_binary(), - "remove-relation", - "-m", - model, - provider, - requirer, - ] - LOG.debug(f'Running command {" ".join(cmd)}') - process = subprocess.run(cmd, capture_output=True, text=True, check=True) - LOG.debug(f"Command finished. stdout={process.stdout}, stderr={process.stderr}") - - def revision_update_needed( - self, application_name: str, model: str, status: dict | None = None - ) -> bool: - """Check if a revision update is available for an applicaton. - - :param application_name: Name of application to check for updates for - :param model: Model application is in - :param status: Dictionay of model status - """ - if not status: - status = run_sync(self.jhelper.get_model_status_full(model)) - app_status = status["applications"].get(application_name, {}) - if not app_status: - LOG.debug(f"{application_name} not present in model") - return False - deployed_revision = int(self._extract_charm_revision(app_status["charm"])) - charm_name = self._extract_charm_name(app_status["charm"]) - deployed_channel = self.normalise_channel(app_status["charm-channel"]) - if len(deployed_channel.split("/")) > 2: - LOG.debug(f"Cannot calculate upgrade for {application_name}, branch in use") - return False - available_revision = run_sync( - self.jhelper.get_available_charm_revision( - model, charm_name, deployed_channel - ) - ) - return bool(available_revision > deployed_revision) - - def get_charm_deployed_versions(self, model: str) -> dict: - """Return charm deployed info for all the applications in model. - - For each application, return a tuple of charm name, channel and revision. - Example output: - {"keystone": ("keystone-k8s", "2023.2/stable", 234)} - """ - status = run_sync(self.jhelper.get_model_status_full(model)) - - apps = {} - for app_name, app_status in status.get("applications", {}).items(): - charm_name = self._extract_charm_name(app_status["charm"]) - deployed_channel = self.normalise_channel(app_status["charm-channel"]) - deployed_revision = int(self._extract_charm_revision(app_status["charm"])) - apps[app_name] = (charm_name, deployed_channel, deployed_revision) - - return apps - - def get_apps_filter_by_charms(self, model: str, charms: list) -> list: - """Return apps filtered by given charms. - - Get all apps from the model and return only the apps deployed with - charms in the provided list. - """ - deployed_all_apps = self.get_charm_deployed_versions(model) - return [ - app_name - for app_name, (charm, channel, revision) in deployed_all_apps.items() - if charm in charms - ] - - def normalise_channel(self, channel: str) -> str: - """Expand channel if it is using abbreviation. - - Juju supports abbreviating latest/{risk} to {risk}. This expands it. - - :param channel: Channel string to normalise - """ - if channel in ["stable", "candidate", "beta", "edge"]: - channel = f"latest/{channel}" - return channel - - def _extract_charm_name(self, charm_url: str) -> str: - """Extract charm name from charm url. - - :param charm_url: Url to examine - """ - # XXX There must be a better way. ch:amd64/jammy/cinder-k8s-50 -> cinder-k8s - return charm_url.split("/")[-1].rsplit("-", maxsplit=1)[0] - - def _extract_charm_revision(self, charm_url: str) -> str: - """Extract charm revision from charm url. - - :param charm_url: Url to examine - """ - return charm_url.split("-")[-1] - - def channel_update_needed(self, channel: str, new_channel: str) -> bool: - """Compare two channels and see if the second is 'newer'. - - :param current_channel: Current channel - :param new_channel: Proposed new channel - """ - risks = ["stable", "candidate", "beta", "edge"] - current_channel = self.normalise_channel(channel) - current_track, current_risk = current_channel.split("/") - new_track, new_risk = new_channel.split("/") - if current_track != new_track: - try: - return version.parse(current_track) < version.parse(new_track) - except version.InvalidVersion: - LOG.error("Error: Could not compare tracks") - return False - if risks.index(current_risk) < risks.index(new_risk): - return True - else: - return False - - def get_model_name_with_owner(self, model: str) -> str: - """Return model name with owner name. - - :param model: Model name - - Raises ModelNotFoundException if model does not exist. - """ - model_with_owner = run_sync(self.jhelper.get_model_name_with_owner(model)) - - return model_with_owner - - class AddCloudJujuStep(BaseStep, JujuStepHelper): """Add cloud definition to juju client.""" diff --git a/sunbeam-python/sunbeam/steps/k8s.py b/sunbeam-python/sunbeam/steps/k8s.py index 3df309e9..3aa3632e 100644 --- a/sunbeam-python/sunbeam/steps/k8s.py +++ b/sunbeam-python/sunbeam/steps/k8s.py @@ -36,6 +36,7 @@ ApplicationNotFoundException, JujuException, JujuHelper, + JujuStepHelper, LeaderNotFoundException, UnsupportedKubeconfigException, run_sync, @@ -59,7 +60,6 @@ RemoveMachineUnitsStep, ) from sunbeam.core.terraform import TerraformHelper -from sunbeam.steps.juju import JujuStepHelper LOG = logging.getLogger(__name__) K8S_CONFIG_KEY = "TerraformVarsK8S" diff --git a/sunbeam-python/sunbeam/steps/microk8s.py b/sunbeam-python/sunbeam/steps/microk8s.py index b4668cf5..ae30c4d6 100644 --- a/sunbeam-python/sunbeam/steps/microk8s.py +++ b/sunbeam-python/sunbeam/steps/microk8s.py @@ -28,6 +28,7 @@ ActionFailedException, ApplicationNotFoundException, JujuHelper, + JujuStepHelper, LeaderNotFoundException, UnsupportedKubeconfigException, run_sync, @@ -45,7 +46,6 @@ RemoveMachineUnitsStep, ) from sunbeam.core.terraform import TerraformHelper -from sunbeam.steps.juju import JujuStepHelper from sunbeam.steps.k8s import AddK8SCredentialStep LOG = logging.getLogger(__name__) diff --git a/sunbeam-python/sunbeam/steps/openstack.py b/sunbeam-python/sunbeam/steps/openstack.py index edc203e8..73aa4270 100644 --- a/sunbeam-python/sunbeam/steps/openstack.py +++ b/sunbeam-python/sunbeam/steps/openstack.py @@ -34,7 +34,13 @@ update_status_background, ) from sunbeam.core.deployment import Deployment -from sunbeam.core.juju import JujuHelper, JujuWaitException, TimeoutException, run_sync +from sunbeam.core.juju import ( + JujuHelper, + JujuStepHelper, + JujuWaitException, + TimeoutException, + run_sync, +) from sunbeam.core.k8s import CREDENTIAL_SUFFIX, K8SHelper from sunbeam.core.manifest import Manifest from sunbeam.core.openstack import OPENSTACK_MODEL @@ -46,7 +52,6 @@ ) from sunbeam.core.steps import PatchLoadBalancerServicesStep from sunbeam.core.terraform import TerraformException, TerraformHelper -from sunbeam.steps.juju import JujuStepHelper LOG = logging.getLogger(__name__) OPENSTACK_DEPLOY_TIMEOUT = 5400 # 90 minutes diff --git a/sunbeam-python/sunbeam/steps/upgrades/inter_channel.py b/sunbeam-python/sunbeam/steps/upgrades/inter_channel.py index aecd2e78..bc16464a 100644 --- a/sunbeam-python/sunbeam/steps/upgrades/inter_channel.py +++ b/sunbeam-python/sunbeam/steps/upgrades/inter_channel.py @@ -29,11 +29,16 @@ ) from sunbeam.core.deployment import Deployment from sunbeam.core.feature import FeatureManager -from sunbeam.core.juju import JujuHelper, JujuWaitException, TimeoutException, run_sync +from sunbeam.core.juju import ( + JujuHelper, + JujuStepHelper, + JujuWaitException, + TimeoutException, + run_sync, +) from sunbeam.core.manifest import Manifest from sunbeam.core.terraform import TerraformException, TerraformHelper from sunbeam.steps.hypervisor import CONFIG_KEY as HYPERVISOR_CONFIG_KEY -from sunbeam.steps.juju import JujuStepHelper from sunbeam.steps.k8s import K8S_CONFIG_KEY from sunbeam.steps.microceph import CONFIG_KEY as MICROCEPH_CONFIG_KEY from sunbeam.steps.microk8s import MICROK8S_CONFIG_KEY diff --git a/sunbeam-python/sunbeam/steps/upgrades/intra_channel.py b/sunbeam-python/sunbeam/steps/upgrades/intra_channel.py index 84967a35..6adcd3dc 100644 --- a/sunbeam-python/sunbeam/steps/upgrades/intra_channel.py +++ b/sunbeam-python/sunbeam/steps/upgrades/intra_channel.py @@ -19,11 +19,10 @@ from rich.status import Status from sunbeam.core.common import BaseStep, Result, ResultType -from sunbeam.core.juju import JujuHelper, run_sync +from sunbeam.core.juju import JujuHelper, JujuStepHelper, run_sync from sunbeam.core.manifest import Manifest from sunbeam.core.terraform import TerraformInitStep from sunbeam.steps.hypervisor import ReapplyHypervisorTerraformPlanStep -from sunbeam.steps.juju import JujuStepHelper from sunbeam.steps.k8s import DeployK8SApplicationStep from sunbeam.steps.microceph import DeployMicrocephApplicationStep from sunbeam.steps.microk8s import DeployMicrok8sApplicationStep diff --git a/sunbeam-python/tests/unit/sunbeam/core/test_juju.py b/sunbeam-python/tests/unit/sunbeam/core/test_juju.py index 1b60ca7a..5e8339a7 100644 --- a/sunbeam-python/tests/unit/sunbeam/core/test_juju.py +++ b/sunbeam-python/tests/unit/sunbeam/core/test_juju.py @@ -589,3 +589,58 @@ async def test_get_available_charm_revision(jhelper: juju.JujuHelper, model): "openstack", "k8s", "legacy/edge" ) assert revno == 121 + + +class TestJujuStepHelper: + def test_revision_update_needed(self, jhelper): + jsh = juju.JujuStepHelper() + jsh.jhelper = jhelper + CHARMREV = {"nova-k8s": 31, "cinder-k8s": 51, "another-k8s": 70} + + def _get_available_charm_revision(model, charm_name, deployed_channel): + return CHARMREV[charm_name] + + _status = { + "applications": { + "nova": { + "charm": "ch:amd64/jammy/nova-k8s-30", + "charm-channel": "2023.2/edge/gnuoy", + }, + "cinder": { + "charm": "ch:amd64/jammy/cinder-k8s-50", + "charm-channel": "2023.2/edge", + }, + "another": { + "charm": "ch:amd64/jammy/another-k8s-70", + "charm-channel": "edge", + }, + } + } + jhelper.get_available_charm_revision = AsyncMock() + jhelper.get_available_charm_revision.side_effect = _get_available_charm_revision + assert jsh.revision_update_needed("cinder", "openstack", _status) + assert not jsh.revision_update_needed("nova", "openstack", _status) + assert not jsh.revision_update_needed("another", "openstack", _status) + + def test_normalise_channel(self): + jsh = juju.JujuStepHelper() + assert jsh.normalise_channel("2023.2/edge") == "2023.2/edge" + assert jsh.normalise_channel("edge") == "latest/edge" + + def test_extract_charm_name(self): + jsh = juju.JujuStepHelper() + assert jsh._extract_charm_name("ch:amd64/jammy/cinder-k8s-50") == "cinder-k8s" + + def test_extract_charm_revision(self): + jsh = juju.JujuStepHelper() + assert jsh._extract_charm_revision("ch:amd64/jammy/cinder-k8s-50") == "50" + + def test_channel_update_needed(self): + jsh = juju.JujuStepHelper() + assert jsh.channel_update_needed("2023.1/stable", "2023.2/stable") + assert jsh.channel_update_needed("2023.1/stable", "2023.1/edge") + assert jsh.channel_update_needed("latest/stable", "latest/edge") + assert not jsh.channel_update_needed("2023.1/stable", "2023.1/stable") + assert not jsh.channel_update_needed("2023.2/stable", "2023.1/stable") + assert not jsh.channel_update_needed("latest/stable", "latest/stable") + assert not jsh.channel_update_needed("foo/stable", "ba/stable") diff --git a/sunbeam-python/tests/unit/sunbeam/steps/test_juju.py b/sunbeam-python/tests/unit/sunbeam/steps/test_juju.py index d7ee37f0..1ce5bf4e 100644 --- a/sunbeam-python/tests/unit/sunbeam/steps/test_juju.py +++ b/sunbeam-python/tests/unit/sunbeam/steps/test_juju.py @@ -52,60 +52,6 @@ def mock_open(): yield p -class TestJujuStepHelper: - def test_revision_update_needed(self, jhelper): - jsh = juju.JujuStepHelper() - jsh.jhelper = jhelper - CHARMREV = {"nova-k8s": 31, "cinder-k8s": 51, "another-k8s": 70} - - def _get_available_charm_revision(model, charm_name, deployed_channel): - return CHARMREV[charm_name] - - _status = { - "applications": { - "nova": { - "charm": "ch:amd64/jammy/nova-k8s-30", - "charm-channel": "2023.2/edge/gnuoy", - }, - "cinder": { - "charm": "ch:amd64/jammy/cinder-k8s-50", - "charm-channel": "2023.2/edge", - }, - "another": { - "charm": "ch:amd64/jammy/another-k8s-70", - "charm-channel": "edge", - }, - } - } - jhelper.get_available_charm_revision.side_effect = _get_available_charm_revision - assert jsh.revision_update_needed("cinder", "openstack", _status) - assert not jsh.revision_update_needed("nova", "openstack", _status) - assert not jsh.revision_update_needed("another", "openstack", _status) - - def test_normalise_channel(self): - jsh = juju.JujuStepHelper() - assert jsh.normalise_channel("2023.2/edge") == "2023.2/edge" - assert jsh.normalise_channel("edge") == "latest/edge" - - def test_extract_charm_name(self): - jsh = juju.JujuStepHelper() - assert jsh._extract_charm_name("ch:amd64/jammy/cinder-k8s-50") == "cinder-k8s" - - def test_extract_charm_revision(self): - jsh = juju.JujuStepHelper() - assert jsh._extract_charm_revision("ch:amd64/jammy/cinder-k8s-50") == "50" - - def test_channel_update_needed(self): - jsh = juju.JujuStepHelper() - assert jsh.channel_update_needed("2023.1/stable", "2023.2/stable") - assert jsh.channel_update_needed("2023.1/stable", "2023.1/edge") - assert jsh.channel_update_needed("latest/stable", "latest/edge") - assert not jsh.channel_update_needed("2023.1/stable", "2023.1/stable") - assert not jsh.channel_update_needed("2023.2/stable", "2023.1/stable") - assert not jsh.channel_update_needed("latest/stable", "latest/stable") - assert not jsh.channel_update_needed("foo/stable", "ba/stable") - - class TestWriteJujuStatusStep: def test_is_skip(self, jhelper): with tempfile.NamedTemporaryFile() as tmpfile: