From 3a121727eedfa68ddee57d6a19a99548d207f637 Mon Sep 17 00:00:00 2001 From: aabhinav Date: Mon, 29 Sep 2025 07:58:41 -0400 Subject: [PATCH] Refactor subcloud rehoming test Reorganized the test_rehome_one_subcloud function to improve code structure and readability by moving rehoming logic into a dedicated function and consolidating related operations. Changes include: - Renamed rehome_subcloud() to perform_rehome_operarion() for clarity - Moved software release verification and asset synchronization logic into the perform_rehome_operarion() function - Reorganized test function to separate validation phases with clear comments (before/after rehome operation) - Consolidated deployment asset configuration retrieval within the rehoming operation function Test Plan: PASS: Verify software load exists PASS: Verify deployment assets are synced PASS: Verify subcloud rehoming operation completes successfully PASS: Verify test structure and validation logic remains intact PASS: Verify no functional changes to rehoming behavior Change-Id: I3c32e4e050363dbbe431dbe7ad2e5aa310767410 Signed-off-by: aabhinav Signed-off-by: Abhishek jaiswal Signed-off-by: aabhinav --- .../dcmanager_subcloud_list_keywords.py | 2 +- .../host_profile_yaml_keywords.py | 36 +++++ .../sync_files/sync_deployment_assets.py | 24 +++ .../dc/rehoming/test_subcloud_rehome.py | 146 ++++++++++++++---- 4 files changed, 174 insertions(+), 34 deletions(-) diff --git a/keywords/cloud_platform/dcmanager/dcmanager_subcloud_list_keywords.py b/keywords/cloud_platform/dcmanager/dcmanager_subcloud_list_keywords.py index 0f753259..ff3f746c 100644 --- a/keywords/cloud_platform/dcmanager/dcmanager_subcloud_list_keywords.py +++ b/keywords/cloud_platform/dcmanager/dcmanager_subcloud_list_keywords.py @@ -71,7 +71,7 @@ class DcManagerSubcloudListKeywords(BaseKeyword): Exception: if the subcloud is in a failed state. """ - failed_status = ["bootstrap-failed", "install-failed", "create-failed", "config-failed", "pre-enroll-failed", "enroll-failed", "pre-init-enroll-failed", "init-enroll-failed"] + failed_status = ["bootstrap-failed", "install-failed", "create-failed", "config-failed", "pre-enroll-failed", "enroll-failed", "pre-init-enroll-failed", "init-enroll-failed", "rehome-failed"] time_out = 4800 polling_sleep_time = 60 end_time = time.time() + time_out diff --git a/keywords/cloud_platform/deployment_assets/host_profile_yaml_keywords.py b/keywords/cloud_platform/deployment_assets/host_profile_yaml_keywords.py index 7395d368..c29e6590 100644 --- a/keywords/cloud_platform/deployment_assets/host_profile_yaml_keywords.py +++ b/keywords/cloud_platform/deployment_assets/host_profile_yaml_keywords.py @@ -77,3 +77,39 @@ class HostProfileYamlKeywords: """ FileKeywords(self.ssh_connection).upload_file(local_file, remote_file) os.remove(local_file) + + def update_yaml_key(self, yaml_file: str, key: str, new_value: str) -> None: + """ + Update a key in a YAML file. + + Args: + yaml_file (str): Path to the YAML file. + key (str): The key to update. + new_value (str): New value to assign to the key. + """ + with open(yaml_file, "r") as f: + data = yaml.safe_load(f) + + if key not in data: + raise KeyError(f"Key '{key}' not found in {yaml_file}") + + data[key] = new_value + + with open(yaml_file, "w") as f: + yaml.safe_dump(data, f, default_flow_style=False) + + def remove_yaml_key(self, yaml_file: str, key: str) -> None: + """ + Remove a key from a YAML file if it exists. + + Args: + yaml_file (str): Path to the YAML file. + key (str): The key to remove. + """ + with open(yaml_file, "r") as f: + data = yaml.safe_load(f) + + data.pop(key, None) + + with open(yaml_file, "w") as f: + yaml.safe_dump(data, f, default_flow_style=False) diff --git a/keywords/cloud_platform/sync_files/sync_deployment_assets.py b/keywords/cloud_platform/sync_files/sync_deployment_assets.py index e9346ed5..22292434 100644 --- a/keywords/cloud_platform/sync_files/sync_deployment_assets.py +++ b/keywords/cloud_platform/sync_files/sync_deployment_assets.py @@ -1,6 +1,7 @@ import os from config.configuration_manager import ConfigurationManager +from framework.ssh.ssh_connection import SSHConnection from keywords.cloud_platform.ssh.lab_connection_keywords import LabConnectionKeywords from keywords.files.file_keywords import FileKeywords @@ -37,3 +38,26 @@ class SyncDeploymentAssets: # rsync files file_kw = FileKeywords(src_controller) file_kw.rsync_to_remote_server(base_file_path, dest_controller.get_name(), user, password, base_file_path, True) + + def sync_subcloud_assets(self, subcloud_name: str, destination_ssh: SSHConnection): + """ + Sync all deployment assets of a given subcloud from the origin controller to the destination system controller. + + Args: + subcloud_name (str): Name of the subcloud to sync. + destination_ssh (SSHConnection): SSH connection object for the destination system controller. + """ + deployment_assets_config = ConfigurationManager.get_deployment_assets_config() + lab_config = ConfigurationManager.get_lab_config() + user = lab_config.get_admin_credentials().get_user_name() + password = lab_config.get_admin_credentials().get_password() + + # Get the subcloud assets folder path on origin + subcloud_assets = deployment_assets_config.get_subcloud_deployment_assets(subcloud_name) + origin_folder = os.path.dirname(subcloud_assets.get_bootstrap_file()) + "/" + + # Ensure the folder exists on the destination + FileKeywords(destination_ssh).create_directory(origin_folder) + + # Rsync the folder recursively from origin to destination + FileKeywords(self.ssh_connection).rsync_to_remote_server(local_dest_path=origin_folder, remote_server=destination_ssh.get_name(), remote_user=user, remote_password=password, remote_path=origin_folder, recursive=True) diff --git a/testcases/cloud_platform/regression/dc/rehoming/test_subcloud_rehome.py b/testcases/cloud_platform/regression/dc/rehoming/test_subcloud_rehome.py index 7e04973b..a4ad05ea 100644 --- a/testcases/cloud_platform/regression/dc/rehoming/test_subcloud_rehome.py +++ b/testcases/cloud_platform/regression/dc/rehoming/test_subcloud_rehome.py @@ -2,14 +2,106 @@ from pytest import mark from config.configuration_manager import ConfigurationManager from framework.logging.automation_logger import get_logger +from framework.ssh.ssh_connection import SSHConnection from framework.validation.validation import validate_equals from keywords.cloud_platform.dcmanager.dcmanager_subcloud_add_keywords import DcManagerSubcloudAddKeywords from keywords.cloud_platform.dcmanager.dcmanager_subcloud_delete_keywords import DcManagerSubcloudDeleteKeywords from keywords.cloud_platform.dcmanager.dcmanager_subcloud_list_keywords import DcManagerSubcloudListKeywords from keywords.cloud_platform.dcmanager.dcmanager_subcloud_manager_keywords import DcManagerSubcloudManagerKeywords +from keywords.cloud_platform.deployment_assets.host_profile_yaml_keywords import HostProfileYamlKeywords from keywords.cloud_platform.ssh.lab_connection_keywords import LabConnectionKeywords +from keywords.cloud_platform.sync_files.sync_deployment_assets import SyncDeploymentAssets from keywords.cloud_platform.system.host.system_host_list_keywords import SystemHostListKeywords from keywords.cloud_platform.system.host.system_host_route_keywords import SystemHostRouteKeywords +from keywords.cloud_platform.version_info.cloud_platform_version_manager import CloudPlatformVersionManagerClass +from keywords.files.file_keywords import FileKeywords + + +def verify_software_release(ssh_connection: SSHConnection): + """ + Verify that the software release image is available on the given system controller. + + Args: + ssh_connection (SSHConnection): SSH connection to the target system controller. + """ + release = CloudPlatformVersionManagerClass().get_sw_version() + path = f"/opt/dc-vault/software/{release}" + file_keywords = FileKeywords(ssh_connection) + is_iso_exist = file_keywords.validate_file_exists_with_sudo(f"{path}/*.iso") + validate_equals(is_iso_exist, True, f"Iso file exists in path {path}.") + + is_sig_exist = file_keywords.validate_file_exists_with_sudo(f"{path}/*.sig") + validate_equals(is_sig_exist, True, f"Sig file exists in path {path}.") + + +def update_subcloud_assets(ssh_connection: SSHConnection, subcloud_bootstrap_values: str, subcloud_install_values: str, systemcontroller_gateway_address: str): + """ + Update the subcloud assets files before rehome. + + Args: + ssh_connection (SSHConnection): SSH connection to the target system controller. + subcloud_bootstrap_values (str): Path to the subcloud bootstrap values file. + subcloud_install_values (str): Path to the subcloud install values file. + systemcontroller_gateway_address (str): Gateway address of the system controller. + """ + yaml_file = HostProfileYamlKeywords(ssh_connection) + file = yaml_file.download_file(subcloud_bootstrap_values) + yaml_file.update_yaml_key(file, "systemcontroller_gateway_address", systemcontroller_gateway_address) + yaml_file.upload_file(file, subcloud_bootstrap_values) + file = yaml_file.download_file(subcloud_install_values) + yaml_file.remove_yaml_key(file, "software_version") + yaml_file.upload_file(file, subcloud_install_values) + + +def sync_deployment_assets_between_system_controllers(origin_ssh_connection: SSHConnection, destination_ssh_connection: SSHConnection, subcloud_name: str, subcloud_bootstrap_values: str, subcloud_install_values: str): + """ + Synchronize deployment assets files for a given subcloud between two system controllers. + + Args: + origin_ssh_connection (SSHConnection): SSH connection to the origin system controller. + destination_ssh_connection (SSHConnection): SSH connection to the destination system controller. + subcloud_name (str): Name of the subcloud whose assets are to be synchronized. + subcloud_bootstrap_values (str): Path to the subcloud bootstrap values file. + subcloud_install_values (str): Path to the subcloud install values file. + """ + SyncDeploymentAssets(origin_ssh_connection).sync_subcloud_assets(subcloud_name, destination_ssh_connection) + host_name = SystemHostListKeywords(destination_ssh_connection).get_active_controller().get_host_name() + system_host_route = SystemHostRouteKeywords(destination_ssh_connection).get_system_host_route_list(host_name) + systemcontroller_gateway_address = system_host_route.get_gateway()[0] + update_subcloud_assets(destination_ssh_connection, subcloud_bootstrap_values, subcloud_install_values, systemcontroller_gateway_address) + + +def perform_rehome_operation(origin_ssh_connection: SSHConnection, destination_ssh_connection: SSHConnection, subcloud_name: str, subcloud_bootstrap_values: str, subcloud_install_values: str): + """ + Rehome a subcloud from the origin system controller to the destination system controller. + + Args: + origin_ssh_connection (SSHConnection): SSH connection to the origin system controller. + destination_ssh_connection (SSHConnection): SSH connection to the destination system controller. + subcloud_name (str): Name of the subcloud to be rehomed. + subcloud_bootstrap_values (str): Path to the subcloud bootstrap values file. + subcloud_install_values (str): Path to the subcloud install values file. + """ + + # Ensure software image load is available on destination system controller. + verify_software_release(destination_ssh_connection) + + # Synchronizes subcloud deployments assets between both source and destination system controllers. + get_logger().log_info(f"Synchronizing subcloud {subcloud_name} deployment assets between source and destination system controllers") + sync_deployment_assets_between_system_controllers(origin_ssh_connection, destination_ssh_connection, subcloud_name, subcloud_bootstrap_values, subcloud_install_values) + + dcm_sc_list_kw_destination = DcManagerSubcloudListKeywords(destination_ssh_connection) + dcm_sc_kw_origin = DcManagerSubcloudManagerKeywords(origin_ssh_connection) + dcm_sc_kw_destination = DcManagerSubcloudManagerKeywords(destination_ssh_connection) + + dcm_sc_kw_origin.get_dcmanager_subcloud_unmanage(subcloud_name, 30) + DcManagerSubcloudAddKeywords(destination_ssh_connection).dcmanager_subcloud_add_migrate(subcloud_name, bootstrap_values=subcloud_bootstrap_values, install_values=subcloud_install_values) + dcm_sc_list_kw_destination.validate_subcloud_status(subcloud_name, status="rehoming") + dcm_sc_list_kw_destination.validate_subcloud_status(subcloud_name, status="complete") + dcm_sc_kw_destination.get_dcmanager_subcloud_manage(subcloud_name, timeout=30) + + get_logger().log_info(f"Deleting subcloud from {origin_ssh_connection}") + DcManagerSubcloudDeleteKeywords(origin_ssh_connection).dcmanager_subcloud_delete(subcloud_name) @mark.p2 @@ -17,49 +109,37 @@ from keywords.cloud_platform.system.host.system_host_route_keywords import Syste @mark.lab_has_secondary_system_controller def test_rehome_one_subcloud(request): """ - Execute a subcloud rehome + Verify rehome one subcloud between two system controllers. Test Steps: - - Ensure both initial and target system controllers have the same date. - - Unmanage the subcloud to be rehomed. - - Shutdown both initial controller and subcloud - - run dcmanager subcloud migration command. - + - Get the lowest subcloud (the subcloud with the lowest id). + - Get the subcloud bootstrap and install values files. + - Synchronize the deployment assets files between both system controllers. + - Rehome subcloud from origin to destination system controller. + - Validate that the system host route list only has one route. """ - - deployment_assets_config = ConfigurationManager.get_deployment_assets_config() - origin_system_controller_ssh = LabConnectionKeywords().get_active_controller_ssh() destination_system_controller_ssh = LabConnectionKeywords().get_secondary_active_controller_ssh() + dcm_sc_list_kw_origin = DcManagerSubcloudListKeywords(origin_system_controller_ssh) # Gets the lowest subcloud (the subcloud with the lowest id). - dcmanager_subcloud_list_keywords = DcManagerSubcloudListKeywords(origin_system_controller_ssh) - lowest_subcloud = dcmanager_subcloud_list_keywords.get_dcmanager_subcloud_list().get_healthy_subcloud_with_lowest_id() + get_logger().log_info("Getting subcloud with the lowest id") + lowest_subcloud = dcm_sc_list_kw_origin.get_dcmanager_subcloud_list().get_healthy_subcloud_with_lowest_id() subcloud_name = lowest_subcloud.get_name() - subcloud_ssh = LabConnectionKeywords().get_subcloud_ssh(subcloud_name) - - subcloud_hostname = SystemHostListKeywords(subcloud_ssh).get_active_controller().get_host_name() + # Gets the subcloud bootstrap and install values files + get_logger().log_info(f"Getting deployment assets for subcloud {subcloud_name}") + deployment_assets_config = ConfigurationManager.get_deployment_assets_config() subcloud_bootstrap_values = deployment_assets_config.get_subcloud_deployment_assets(subcloud_name).get_bootstrap_file() subcloud_install_values = deployment_assets_config.get_subcloud_deployment_assets(subcloud_name).get_install_file() - network_list = SystemHostRouteKeywords(subcloud_ssh).get_system_host_route_list_networks(subcloud_hostname) + # Perform rehome operation + get_logger().log_info(f"Rehoming subcloud {subcloud_name} from {origin_system_controller_ssh} to {destination_system_controller_ssh}") + perform_rehome_operation(origin_system_controller_ssh, destination_system_controller_ssh, subcloud_name, subcloud_bootstrap_values, subcloud_install_values) - get_logger().log_info(f"Running rehome command on {destination_system_controller_ssh}") - DcManagerSubcloudAddKeywords(destination_system_controller_ssh).dcmanager_subcloud_add_migrate(subcloud_name, bootstrap_values=subcloud_bootstrap_values, install_values=subcloud_install_values) - DcManagerSubcloudListKeywords(destination_system_controller_ssh).validate_subcloud_status(subcloud_name=subcloud_name, status="rehoming") - DcManagerSubcloudListKeywords(destination_system_controller_ssh).validate_subcloud_status(subcloud_name=subcloud_name, status="complete") - - get_logger().log_info(f"Deleting subcloud from {origin_system_controller_ssh}") - DcManagerSubcloudManagerKeywords(origin_system_controller_ssh).get_dcmanager_subcloud_unmanage(subcloud_name=subcloud_name, timeout=30) - DcManagerSubcloudDeleteKeywords(origin_system_controller_ssh).dcmanager_subcloud_delete(subcloud_name=subcloud_name) - - get_logger().log_info(f"Running rehome command on {origin_system_controller_ssh}") - DcManagerSubcloudAddKeywords(origin_system_controller_ssh).dcmanager_subcloud_add_migrate(subcloud_name, bootstrap_values=subcloud_bootstrap_values, install_values=subcloud_install_values) - dcmanager_subcloud_list_keywords.validate_subcloud_status(subcloud_name=subcloud_name, status="rehoming") - dcmanager_subcloud_list_keywords.validate_subcloud_status(subcloud_name=subcloud_name, status="complete") - - get_logger().log_info(f"Deleting subcloud from {destination_system_controller_ssh}") - DcManagerSubcloudDeleteKeywords(destination_system_controller_ssh).dcmanager_subcloud_delete(subcloud_name=subcloud_name) - - validate_equals(len(network_list), 1, "Validate system host route list only has one route.") + # Validations after rehome operation + rehomed_subcloud = DcManagerSubcloudListKeywords(destination_system_controller_ssh).get_dcmanager_subcloud_list().get_subcloud_by_name(subcloud_name) + validate_equals(rehomed_subcloud.get_management(), "managed", f"Subcloud {subcloud_name} is managed.") + validate_equals(rehomed_subcloud.get_availability(), "online", f"Subcloud {subcloud_name} is online.") + validate_equals(rehomed_subcloud.get_sync(), "in-sync", f"Subcloud {subcloud_name} is in-sync.") + get_logger().log_info(f"Rehome operation of subcloud {subcloud_name} completed successfully.")