Allign DC tests for sanity

- align DC sanity tests.
- add function to get controllers.
- update IPMI keywords to select controllers by BMC IP.
- fix central controller selection bug in ipmi and power keyword.
- update DcManagerSubcloudManagerKeywords to use IPMI for subcloud power off.

Change-Id: I2679f04510823d4f9949c3cdac206cbc7fd4f2bb
Signed-off-by: Abhishek jaiswal <abhishek.jaiswal@windriver.com>
This commit is contained in:
Abhishek jaiswal
2025-04-11 13:14:25 -04:00
parent 20c8586a9f
commit d20ab276fd
5 changed files with 132 additions and 97 deletions

View File

@@ -459,3 +459,14 @@ class LabConfig:
log_strings.append(f" {log_string}")
return log_strings
def get_controllers(self) -> List[Node]:
"""
Getter for controller nodes.
Returns:
List[Node]: List of controller nodes
"""
nodes = self.get_nodes()
controllers = [node for node in nodes if node.node_type == "controller"]
return controllers

View File

@@ -13,23 +13,39 @@ class IPMIToolChassisPowerKeywords(BaseKeyword):
lab_config = ConfigurationManager.get_lab_config()
self.bm_password = lab_config.get_bm_password()
if host_name:
node = lab_config.get_node(host_name)
self.bm_ip = node.get_bm_ip()
self.bm_username = node.get_bm_username()
node = lab_config.get_node(host_name)
self.bm_ip = node.get_bm_ip()
self.bm_username = node.get_bm_username()
def _power_off(self, bm_ip: str, bm_username: str, bm_password: str):
"""Powers off the host using IPMI tool
Args:
bm_ip (str): IP address of the BMC
bm_username (str): Username for BMC
bm_password (str): Password for BMC
"""
self.ssh_connection.send(f"ipmitool -I lanplus -H {bm_ip} -U {bm_username} -P {bm_password} chassis power off")
def power_on(self):
"""
Powers on the host
Returns:
"""
"""Powers on the host"""
self.ssh_connection.send(f"ipmitool -I lanplus -H {self.bm_ip} -U {self.bm_username} -P {self.bm_password} chassis power on")
def power_off(self):
"""
Powers off the host
Returns:
"""Powers off the host"""
self._power_off(self.bm_ip, self.bm_username, self.bm_password)
def power_off_subcloud(self, subcloud_name: str):
"""Powers off the host
Args:
subcloud_name (str): name of the subcloud to be powered off
"""
self.ssh_connection.send(f"ipmitool -I lanplus -H {self.bm_ip} -U {self.bm_username} -P {self.bm_password} chassis power off")
sc_config = ConfigurationManager.get_lab_config().get_subcloud(subcloud_name)
controllers = sc_config.get_controllers()
bm_password = sc_config.get_bm_password()
for controller in controllers:
self._power_off(controller.get_bm_ip(), controller.get_bm_username(), bm_password)
self.bm_ip = controller.get_bm_ip()

View File

@@ -3,29 +3,27 @@ import time
from framework.logging.automation_logger import get_logger
from framework.ssh.ssh_connection import SSHConnection
from keywords.base_keyword import BaseKeyword
from keywords.bmc.ipmitool.chassis.power.ipmitool_chassis_power_keywords import IPMIToolChassisPowerKeywords
from keywords.cloud_platform.command_wrappers import source_openrc
from keywords.cloud_platform.dcmanager.dcmanager_subcloud_list_keywords import DcManagerSubcloudListKeywords
from keywords.cloud_platform.dcmanager.objects.dcmanager_subcloud_list_object_filter import DcManagerSubcloudListObjectFilter
from keywords.cloud_platform.dcmanager.objects.dcmanager_subcloud_manage_output import DcManagerSubcloudManageOutput
from keywords.cloud_platform.ssh.lab_connection_keywords import LabConnectionKeywords
class DcManagerSubcloudManagerKeywords(BaseKeyword):
"""
This class contains all the keywords related to the 'dcmanager subcloud <manage/unmanage> <subcloud name>' and
command.
"""
"""This class contains all the keywords related to the 'dcmanager subcloud <manage/unmanage> <subcloud name>' and command."""
def __init__(self, ssh_connection: SSHConnection):
"""
Constructor
"""Constructor
Args:
ssh_connection (SSHConnection): The SSH connection to the central subcloud.
"""
self.ssh_connection = ssh_connection
def get_dcmanager_subcloud_manage(self, subcloud_name: str, timeout: int) -> DcManagerSubcloudManageOutput:
"""
"""Dcmanager subcloud manage
Gets the output of 'dcmanager subcloud manage <subcloud_name>' as an instance of DcManagerSubcloudManageOutput
if the subcloud is successfully set to 'managed' (its 'management' attribute updated to 'managed') within the
specified 'timeout' period. Otherwise, this method returns None.
@@ -42,7 +40,8 @@ class DcManagerSubcloudManagerKeywords(BaseKeyword):
return self._get_dcmanager_subcloud_operation(subcloud_name, timeout, "manage")
def get_dcmanager_subcloud_unmanage(self, subcloud_name: str, timeout: int) -> DcManagerSubcloudManageOutput:
"""
"""Dcmanager subcloud unmanage
Gets the output of 'dcmanager subcloud unmanage <subcloud_name>' as an instance of DcManagerSubcloudManageOutput
if the subcloud is successfully set to 'unmanaged' (its 'management' attribute updated to 'unmanaged') within
the specified 'timeout' period. Otherwise, this method returns None.
@@ -59,7 +58,8 @@ class DcManagerSubcloudManagerKeywords(BaseKeyword):
return self._get_dcmanager_subcloud_operation(subcloud_name, timeout, "unmanage")
def _get_dcmanager_subcloud_operation(self, subcloud_name: str, end_time: int, operation: str) -> DcManagerSubcloudManageOutput:
"""
"""Dcmanager subcloud manage/unmanage
Gets the output of 'dcmanager subcloud <operation> <subcloud_name>' as an instance of DcManagerSubcloudManageOutput
if the subcloud is successfully set to 'managed' or 'unmanaged' (its 'management' attribute updated to 'managed'
or to 'unmanaged', depending on 'operation') within the specified 'timeout' period. Otherwise, this method
@@ -68,11 +68,15 @@ class DcManagerSubcloudManagerKeywords(BaseKeyword):
Args:
subcloud_name (str): The name of the subcloud that must be set to the 'managed' state.
end_time (int): The maximum time, in seconds, to wait for the subcloud to enter the 'managed' state.
operation (str): The operation to be performed on the subcloud ('manage' or 'unmanage').
Returns:
DcManagerSubcloudManageOutput: An instance representing the output of the command
'dcmanager subcloud <operation> <subcloud_name>' if successful, or None otherwise.
Raises:
TimeoutError: If the subcloud does not enter the 'managed' or 'unmanaged' state within the specified timeout.
"""
target_state = "managed"
if operation == "unmanage":
@@ -112,24 +116,17 @@ class DcManagerSubcloudManagerKeywords(BaseKeyword):
Raises: TimeoutError
"""
# get SSH connection to subcloud
subcloud_ssh = LabConnectionKeywords().get_subcloud_ssh(subcloud_name)
# power off the subcloud
# TODO find a better way to do it. as DC libvirt has no IPMI , To make work for both
# labs and virtual labs we need to find a way to power off the subcloud
subcloud_ssh.send_as_sudo("shutdown -h now")
self.validate_success_return_code(subcloud_ssh)
# power off all the controllers in the subcloud
IPMIToolChassisPowerKeywords(self.ssh_connection, None).power_off_subcloud(subcloud_name)
# This section is responsible for verifying whether the state has changed within a defined timeout.
target_state = "offline"
end_time = time.time() + timeout
while time.time() < end_time:
dcm_sc_list_kw = DcManagerSubcloudListKeywords(self.ssh_connection)
subclouds_list = dcm_sc_list_kw.get_dcmanager_subcloud_list()
subclouds = subclouds_list.get_dcmanager_subcloud_list_objects()
for sc in subclouds:
if sc.get_name() == subcloud_name and sc.get_availability() == target_state:
return True
# If the subcloud is not in the list or its availability is not 'offline', wait and check again
subcloud = dcm_sc_list_kw.get_dcmanager_subcloud_list().get_subcloud_by_name(subcloud_name)
if subcloud.get_availability() == target_state:
return True
# If the subcloud is not 'offline', wait and check again
time.sleep(5)
error_message = f"Failed to change the state of subcloud '{subcloud_name}' to '{target_state}'."
get_logger().log_error(error_message)

View File

@@ -6,6 +6,8 @@ from config.configuration_manager import ConfigurationManager
from framework.logging.automation_logger import get_logger
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.ssh.lab_connection_keywords import LabConnectionKeywords
from keywords.cloud_platform.system.host.system_host_list_keywords import SystemHostListKeywords
@@ -58,6 +60,41 @@ def subcloud_add(subcloud_name: str):
get_logger().log_info(f"The management state of the subcloud {subcloud_name} {manage_status}")
def subcloud_delete(subcloud_name: str):
"""Delete a subcloud from the system.
Args:
subcloud_name (str): name of the subcloud to be deleted
"""
# Gets the SSH connection to the active controller of the central cloud.
ssh_connection = LabConnectionKeywords().get_active_controller_ssh()
dcm_sc_list_kw = DcManagerSubcloudListKeywords(ssh_connection)
subcloud = dcm_sc_list_kw.get_dcmanager_subcloud_list().get_subcloud_by_name(subcloud_name)
sc_name = subcloud.get_name()
msg = (f"Subcloud selected for deletion ID={subcloud.get_id()} ", f" Name={sc_name}, ", f" Management state={subcloud.get_management()} ")
get_logger().log_info(msg)
dcm_sc_manager_kw = DcManagerSubcloudManagerKeywords(ssh_connection)
# poweroff the subcloud.
get_logger().log_test_case_step(f"Poweroff subcloud={sc_name}.")
dcm_sc_manager_kw.set_subcloud_poweroff(sc_name)
# Unmanage the subcloud.
if subcloud.get_management() == "managed":
dcm_sc_manager_kw = DcManagerSubcloudManagerKeywords(ssh_connection)
get_logger().log_test_case_step(f"Unmanage subcloud={sc_name}.")
dcm_sc_manage_output = dcm_sc_manager_kw.get_dcmanager_subcloud_unmanage(sc_name, timeout=10)
get_logger().log_info(f"The management state of the subcloud {sc_name} was changed to {dcm_sc_manage_output.get_dcmanager_subcloud_manage_object().get_management()}.")
# delete the subcloud
get_logger().log_test_case_step(f"Delete subcloud={sc_name}.")
dcm_sc_del_kw = DcManagerSubcloudDeleteKeywords(ssh_connection)
dcm_sc_del_kw.dcmanager_subcloud_delete(sc_name)
# validate that the subcloud is deleted
subclouds_list = dcm_sc_list_kw.get_dcmanager_subcloud_list()
get_logger().log_test_case_step(f"Validate that subcloud={sc_name} is deleted.")
validate_equals(subclouds_list.is_subcloud_in_output(sc_name), False, f"{sc_name} is no longer in the subcloud list.")
@mark.p0
@mark.lab_has_min_2_subclouds
def test_dc_subcloud_add_simplex():
@@ -116,3 +153,39 @@ def test_dc_subcloud_add_duplex():
# read the config file for subcloud
subcloud_name = "subcloud2"
subcloud_add(subcloud_name)
@mark.p0
@mark.lab_has_min_2_subclouds
def test_dc_subcloud_delete_simplex():
"""
Verify subcloud deletion works as expected
Test Steps:
- log onto system controller
- list all subclouds and get the lowest id subcloud
- unmanage the subcloud
- power off the subcloud
- delete the subcloud
- validate that the subcloud is deleted
"""
subcloud_name = "subcloud1"
subcloud_delete(subcloud_name)
@mark.p0
@mark.lab_has_min_2_subclouds
def test_dc_subcloud_delete_duplex():
"""
Verify subcloud deletion works as expected
Test Steps:
- log onto system controller
- list all subclouds and get the lowest id subcloud
- unmanage the subcloud
- power off the subcloud
- delete the subcloud
- validate that the subcloud is deleted
"""
subcloud_name = "subcloud2"
subcloud_delete(subcloud_name)

View File

@@ -14,7 +14,6 @@ from framework.ssh.ssh_connection import SSHConnection
from framework.validation.validation import validate_equals, validate_equals_with_retry
from framework.web.webdriver_core import WebDriverCore
from keywords.cloud_platform.dcmanager.dcmanager_alarm_summary_keywords import DcManagerAlarmSummaryKeywords
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.dcmanager.dcmanager_subcloud_show_keywords import DcManagerSubcloudShowKeywords
@@ -1400,64 +1399,3 @@ def deploy_images_to_local_registry(ssh_connection: SSHConnection):
docker_load_image_keywords.load_docker_image_to_host("node-hello-alpine.tar")
docker_load_image_keywords.tag_docker_image_for_registry("node-hello:alpine", "node-hello", local_registry)
docker_load_image_keywords.push_docker_image_to_registry("node-hello", local_registry)
@mark.p0
@mark.lab_has_min_2_subclouds
def test_dc_subcloud_delete(request):
"""
Verify subcloud deletion works as expected
Test Steps:
- log onto system controller
- list all subclouds and get the lowest id subcloud
- unmanage the subcloud
- power off the subcloud
- delete the subcloud
- validate that the subcloud is deleted
"""
get_logger().log_info("Starting 'test_dc_subcloud_delete' test case.")
# Gets the SSH connection to the active controller of the central cloud.
ssh_connection = LabConnectionKeywords().get_active_controller_ssh()
# check if subclouds has added in config
subclouds = ConfigurationManager.get_lab_config().get_subclouds()
if not subclouds:
raise ValueError("Failed. No subclouds were found in lab config")
# List all subclouds and get the lowest id subcloud.
dcm_sc_list_kw = DcManagerSubcloudListKeywords(ssh_connection)
subclouds_list = dcm_sc_list_kw.get_dcmanager_subcloud_list()
# Retrieves subclouds before deletion.
orig_subclouds = subclouds_list.get_dcmanager_subcloud_list_objects()
total_subclouds = len(orig_subclouds)
lowest_subcloud = subclouds_list.get_healthy_subcloud_with_lowest_id()
sc_name = lowest_subcloud.get_name()
get_logger().log_info(f"Total subclouds Before deletion: {total_subclouds}")
msg = (f"Subcloud selected for deletion ID={lowest_subcloud.get_id()} ", f" Name={sc_name}, ", f" Management state={lowest_subcloud.get_management()} ")
get_logger().log_info(msg)
dcm_sc_manager_kw = DcManagerSubcloudManagerKeywords(ssh_connection)
# Unmanage the subcloud.
get_logger().log_test_case_step(f"Unmanage subcloud={sc_name}.")
dcm_sc_manage_output = dcm_sc_manager_kw.get_dcmanager_subcloud_unmanage(sc_name, timeout=10)
get_logger().log_info(f"The management state of the subcloud {sc_name} was changed to {dcm_sc_manage_output.get_dcmanager_subcloud_manage_object().get_management()}.")
# poweroff the subcloud.
get_logger().log_test_case_step(f"Poweroff subcloud={sc_name}.")
dcm_sc_manager_kw.set_subcloud_poweroff(sc_name)
# delete the subcloud
get_logger().log_test_case_step(f"Delete subcloud={sc_name}.")
dcm_sc_del_kw = DcManagerSubcloudDeleteKeywords(ssh_connection)
dcm_sc_del_kw.dcmanager_subcloud_delete(sc_name)
# Retrieves subclouds after deletion.
subclouds_list = dcm_sc_list_kw.get_dcmanager_subcloud_list()
subclouds_after_deletion = subclouds_list.get_dcmanager_subcloud_list_objects()
# assert len(subclouds_after_deletion) == total_subclouds - 1, "Subcloud was not deleted successfully"
validate_equals(len(subclouds_after_deletion), total_subclouds - 1, "Subcloud deleted successfully")
validate_equals(subclouds_list.is_subcloud_in_output(sc_name), False, f"{sc_name} is no longer in the subcloud list.")