diff --git a/keywords/cloud_platform/system/ptp/ptp_setup_executor_keywords.py b/keywords/cloud_platform/system/ptp/ptp_setup_executor_keywords.py index f1247827..19f379b6 100644 --- a/keywords/cloud_platform/system/ptp/ptp_setup_executor_keywords.py +++ b/keywords/cloud_platform/system/ptp/ptp_setup_executor_keywords.py @@ -1,4 +1,4 @@ -from typing import Any +from typing import Any, List, Tuple from framework.logging.automation_logger import get_logger from framework.validation.validation import validate_equals, validate_equals_with_retry, validate_str_contains @@ -10,9 +10,10 @@ from keywords.cloud_platform.system.ptp.system_host_ptp_instance_keywords import from keywords.cloud_platform.system.ptp.system_ptp_instance_keywords import SystemPTPInstanceKeywords from keywords.cloud_platform.system.ptp.system_ptp_instance_parameter_keywords import SystemPTPInstanceParameterKeywords from keywords.cloud_platform.system.ptp.system_ptp_interface_keywords import SystemPTPInterfaceKeywords +from keywords.linux.systemctl.systemctl_status_keywords import SystemCTLStatusKeywords +from keywords.ptp.gnss_keywords import GnssKeywords from keywords.ptp.setup.object.ptp_setup import PTPSetup from keywords.ptp.setup.ptp_setup_reader import PTPSetupKeywords -from starlingx.keywords.linux.systemctl.systemctl_status_keywords import SystemCTLStatusKeywords class PTPSetupExecutorKeywords(BaseKeyword): @@ -57,24 +58,7 @@ class PTPSetupExecutorKeywords(BaseKeyword): system_ptp_instance_apply_output = system_ptp_instance_keywords.system_ptp_instance_apply() validate_equals(system_ptp_instance_apply_output, "Applying the PTP Instance configuration", "apply PTP instance configuration") - # After applying the instance configuration, it needs to check whether the services are available or not. - def check_ptp4l_status() -> bool: - """ - Checks if the PTP4L service is active and running. - - Returns: - bool: True if the service is active and running, False otherwise. - """ - ptp4l_status_output = SystemCTLStatusKeywords(self.ssh_connection).get_status("ptp4l@*") - if not ptp4l_status_output: - return False # Handle the case of an empty list - - for line in ptp4l_status_output: - if "Active: active (running)" in line: - return True - return False - - validate_equals_with_retry(check_ptp4l_status, True, 600) + self.wait_for_ptp_configuration_to_update_after_applying() def add_all_ptp_configurations_for_ptp4l_service(self): """ @@ -219,3 +203,60 @@ class PTPSetupExecutorKeywords(BaseKeyword): Exception: raised when validate fails """ validate_equals(set(observed_value.split()), set(expected_value.split()), validation_description) + + def wait_for_ptp_configuration_to_update_after_applying(self) -> None: + """ + Wait for the PTP configuration to update after applying + + Returns: None + + Raises: + TimeoutError: raised when validate does not equal in the required time + """ + gnss_keywords = GnssKeywords() + + # wait for systemctl status + def check_ptp4l_status() -> bool: + """ + Checks if the PTP4L service is active and running. + + Returns: + bool: True if the service is active and running, False otherwise. + """ + ptp4l_status_output = SystemCTLStatusKeywords(self.ssh_connection).get_status("ptp4l@*") + return any("Active: active (running)" in line for line in ptp4l_status_output or []) + + validate_equals_with_retry(check_ptp4l_status, True, "systemctl status for ptp4l", 120, 30) + + # wait for SMA status + check_sma_status = False + for clock_instance_obj in self.clock_setup_list: + + ifaces_to_check = [(host, iface) for host in clock_instance_obj.get_instance_hostnames() for ptp_host_if in clock_instance_obj.get_ptp_interfaces() if "input" in ptp_host_if.get_ptp_interface_parameter() for iface in filter(None, ptp_host_if.get_interfaces_for_hostname(host))] + + for host, interface in ifaces_to_check: + pci_address = gnss_keywords.get_pci_slot_name(host, interface) + cgu_location = f"/sys/kernel/debug/ice/{pci_address}/cgu" + gnss_keywords.validate_gnss_1pps_state_and_pps_dpll_status(host, cgu_location, "SMA1", "valid", ["locked_ho_acq"], 120, 30) + check_sma_status = True + break + + if check_sma_status: + break + + # wait for GNSS status + check_gnss_status = False + for ts2phc_instance_obj in self.ts2phc_setup_list: + expected_gnss_port = gnss_keywords.extract_gnss_port(ts2phc_instance_obj.get_instance_parameters()) + if not expected_gnss_port: + continue + ifaces_to_check = [(host, iface) for host in ts2phc_instance_obj.get_instance_hostnames() for ptp_host_if in ts2phc_instance_obj.get_ptp_interfaces() for iface in filter(None, ptp_host_if.get_interfaces_for_hostname(host)) if gnss_keywords.get_gnss_serial_port_from_gnss_directory(host, iface) == expected_gnss_port] + for host, interface in ifaces_to_check: + pci_address = gnss_keywords.get_pci_slot_name(host, interface) + cgu_location = f"/sys/kernel/debug/ice/{pci_address}/cgu" + gnss_keywords.validate_gnss_1pps_state_and_pps_dpll_status(host, cgu_location, "GNSS-1PPS", "valid", ["locked_ho_acq"], 120, 30) + check_gnss_status = True + break + + if check_gnss_status: + break diff --git a/keywords/cloud_platform/system/ptp/ptp_verify_config_keywords.py b/keywords/cloud_platform/system/ptp/ptp_verify_config_keywords.py index 1f895f76..d54700f3 100644 --- a/keywords/cloud_platform/system/ptp/ptp_verify_config_keywords.py +++ b/keywords/cloud_platform/system/ptp/ptp_verify_config_keywords.py @@ -43,10 +43,6 @@ class PTPVerifyConfigKeywords(BaseKeyword): self.clock_setup_list = ptp_setup.get_clock_setup_list() self.ptp4l_expected_list_objects = ptp_setup.get_expected_ptp4l_list() - self.expected_parent_data_set_object = ptp_setup.get_parent_data_set() - self.expected_time_properties_data_set_object = ptp_setup.get_time_properties_data_set() - self.expected_grandmaster_settings_tbc_object = ptp_setup.get_grandmaster_settings_tbc() - self.expected_grandmaster_settings_tgm_object = ptp_setup.get_grandmaster_settings_tgm() def verify_all_ptp_configurations(self) -> None: """ @@ -131,7 +127,7 @@ class PTPVerifyConfigKeywords(BaseKeyword): instance_parameters = instance_obj.get_instance_parameters() for hostname in hostnames: - if service_type == "phc2sys": + if service_type == "phc2sys" and "cmdline_opts" in instance_parameters: # Here the PHC service is using the clock from the NIC, not from the PTP instance. systemctl_status_Keywords.verify_ptp_status_and_instance_parameters_on_hostname(hostname, name, service_name, instance_parameters) else: systemctl_status_Keywords.verify_status_on_hostname(hostname, name, service_name) @@ -144,6 +140,7 @@ class PTPVerifyConfigKeywords(BaseKeyword): """ for service_type, setup_list in [ ("ptp4l", self.ptp4l_setup_list), + ("phc2sys", self.phc2sys_setup_list), ("ts2phc", self.ts2phc_setup_list), ("clock", self.clock_setup_list), ]: @@ -164,21 +161,12 @@ class PTPVerifyConfigKeywords(BaseKeyword): """ port_data_set = self.get_port_data_set_using_interface_and_port_identity_mapping() - validate_parent = bool(self.expected_parent_data_set_object) - validate_time_props = bool(self.expected_time_properties_data_set_object) - - if not validate_parent: - get_logger().log_info("Validation skipped as expected; expected_parent_data_set_object is None") - if not validate_time_props: - get_logger().log_info("Validation skipped as expected; expected_time_properties_data_set_object is None") - for ptp4l_instance_obj in self.ptp4l_setup_list: name = ptp4l_instance_obj.get_name() config_file = f"/etc/linuxptp/ptpinstance/ptp4l-{name}.conf" socket_file = f"/var/run/ptp4l-{name}" instance_parameters = ptp4l_instance_obj.get_instance_parameters() - ptp_role = self.ptp_setup.get_ptp4l_expected_by_name(name).get_ptp_role() for hostname in ptp4l_instance_obj.get_instance_hostnames(): @@ -186,13 +174,11 @@ class PTPVerifyConfigKeywords(BaseKeyword): self.validate_get_domain(hostname, instance_parameters, config_file, socket_file) - if validate_parent: - self.validate_parent_data_set(hostname, name, port_data_set, config_file, socket_file) + self.validate_parent_data_set(hostname, name, port_data_set, config_file, socket_file) - if validate_time_props: - self.validate_time_properties_data_set(hostname, config_file, socket_file) + self.validate_time_properties_data_set(hostname, name, config_file, socket_file) - self.validate_grandmaster_settings_np(hostname, ptp_role, config_file, socket_file) + self.validate_grandmaster_settings_np(hostname, name, config_file, socket_file) def validate_gnss_status_on_hostname(self, hostname: str, interface: str, expected_gnss_port: str) -> None: """ @@ -368,7 +354,8 @@ class PTPVerifyConfigKeywords(BaseKeyword): expected_associated_interfaces = [interface for ptp_host_if in ptp_instance_obj.get_ptp_interfaces() for interface in ptp_host_if.get_interfaces_for_hostname(hostname) if interface] observed_associated_interfaces = cat_ptp_config_output.get_associated_interfaces() - validate_equals(observed_associated_interfaces, expected_associated_interfaces, "Associated interfaces within PTP config file content") + # In the PTP config file, the associated interfaces are unordered and do not follow the order of interface_names shown in the output of system ptp-interface-show . + validate_equals(sorted(observed_associated_interfaces), sorted(expected_associated_interfaces), "Associated interfaces within PTP config file content") def validate_ptp_config_file_content_for_clock( self, @@ -436,9 +423,10 @@ class PTPVerifyConfigKeywords(BaseKeyword): ssh_connection = lab_connect_keywords.get_ssh_for_hostname(hostname) pmc_keywords = PMCKeywords(ssh_connection) + observed_port_data_set_objects = pmc_keywords.pmc_get_port_data_set(config_file, socket_file).get_pmc_get_port_data_set_objects() + ptp4l_expected_obj = self.ptp_setup.get_ptp4l_expected_by_name(name) expected_port_data_set_objects = ptp4l_expected_obj.get_port_data_set_for_hostname(hostname) - observed_port_data_set_objects = pmc_keywords.pmc_get_port_data_set(config_file, socket_file).get_pmc_get_port_data_set_objects() if len(observed_port_data_set_objects) > len(expected_port_data_set_objects): raise Exception("Observed port data set objects contains more entries than expected port data set objects") @@ -509,17 +497,19 @@ class PTPVerifyConfigKeywords(BaseKeyword): parent_data_set_obj = pmc_keywords.pmc_get_parent_data_set(config_file, socket_file).get_pmc_get_parent_data_set_object() - validate_equals(parent_data_set_obj.get_gm_clock_class(), self.expected_parent_data_set_object.get_gm_clock_class(), "gm.ClockClass value within GET PARENT_DATA_SET") - validate_equals(parent_data_set_obj.get_gm_clock_accuracy(), self.expected_parent_data_set_object.get_gm_clock_accuracy(), "gm.ClockAccuracy value within GET PARENT_DATA_SET") - validate_equals(parent_data_set_obj.get_gm_offset_scaled_log_variance(), self.expected_parent_data_set_object.get_gm_offset_scaled_log_variance(), "gm.OffsetScaledLogVariance value within GET PARENT_DATA_SET") + ptp4l_expected_obj = self.ptp_setup.get_ptp4l_expected_by_name(name) + expected_parent_data_set_obj = ptp4l_expected_obj.get_parent_data_set_for_hostname(hostname) + + validate_equals(parent_data_set_obj.get_gm_clock_class(), expected_parent_data_set_obj.get_gm_clock_class(), "gm.ClockClass value within GET PARENT_DATA_SET") + validate_equals(parent_data_set_obj.get_gm_clock_accuracy(), expected_parent_data_set_obj.get_gm_clock_accuracy(), "gm.ClockAccuracy value within GET PARENT_DATA_SET") + validate_equals(parent_data_set_obj.get_gm_offset_scaled_log_variance(), expected_parent_data_set_obj.get_gm_offset_scaled_log_variance(), "gm.OffsetScaledLogVariance value within GET PARENT_DATA_SET") # Validates the parentPortIdentity of the SLAVE's PARENT_DATA_SET against the portIdentity of the MASTER's PORT_DATA_SET. if not port_data_set: return - ptp4l_expected_obj = self.ptp_setup.get_ptp4l_expected_by_name(name) - expected_port_data_set_objects = ptp4l_expected_obj.get_port_data_set_for_hostname(hostname) observed_parent_port_identity = parent_data_set_obj.get_parent_port_identity() + expected_port_data_set_objects = ptp4l_expected_obj.get_port_data_set_for_hostname(hostname) for expected_port_data_set_obj in expected_port_data_set_objects: @@ -542,6 +532,7 @@ class PTPVerifyConfigKeywords(BaseKeyword): def validate_time_properties_data_set( self, hostname: str, + name: str, config_file: str, socket_file: str, ) -> None: @@ -550,6 +541,7 @@ class PTPVerifyConfigKeywords(BaseKeyword): Args: hostname (str): The name of the host. + name (str): The ptp instance name config_file (str): the config file. socket_file (str): the socket file. @@ -562,11 +554,6 @@ class PTPVerifyConfigKeywords(BaseKeyword): ssh_connection = lab_connect_keywords.get_ssh_for_hostname(hostname) pmc_keywords = PMCKeywords(ssh_connection) - expected_current_utc_offset = self.expected_time_properties_data_set_object.get_current_utc_offset() - expected_current_utc_offset_valid = self.expected_time_properties_data_set_object.get_current_utc_offset_valid() - expected_time_traceable = self.expected_time_properties_data_set_object.get_time_traceable() - expected_frequency_traceable = self.expected_time_properties_data_set_object.get_frequency_traceable() - get_time_properties_data_set_output = pmc_keywords.pmc_get_time_properties_data_set(config_file, socket_file) get_time_properties_data_set_object = get_time_properties_data_set_output.get_pmc_get_time_properties_data_set_object() observed_current_utc_offset = get_time_properties_data_set_object.get_current_utc_offset() @@ -574,6 +561,13 @@ class PTPVerifyConfigKeywords(BaseKeyword): observed_time_traceable = get_time_properties_data_set_object.get_time_traceable() observed_frequency_traceable = get_time_properties_data_set_object.get_frequency_traceable() + ptp4l_expected_obj = self.ptp_setup.get_ptp4l_expected_by_name(name) + expected_time_properties_data_set_obj = ptp4l_expected_obj.get_time_properties_data_set_for_hostname(hostname) + expected_current_utc_offset = expected_time_properties_data_set_obj.get_current_utc_offset() + expected_current_utc_offset_valid = expected_time_properties_data_set_obj.get_current_utc_offset_valid() + expected_time_traceable = expected_time_properties_data_set_obj.get_time_traceable() + expected_frequency_traceable = expected_time_properties_data_set_obj.get_frequency_traceable() + validate_equals(observed_current_utc_offset, expected_current_utc_offset, "currentUtcOffset value within GET TIME_PROPERTIES_DATA_SET") validate_equals(observed_current_utc_off_set_valid, expected_current_utc_offset_valid, "currentUtcOffsetValid value within GET TIME_PROPERTIES_DATA_SET") validate_equals(observed_time_traceable, expected_time_traceable, "timeTraceable value within GET TIME_PROPERTIES_DATA_SET") @@ -582,7 +576,7 @@ class PTPVerifyConfigKeywords(BaseKeyword): def validate_grandmaster_settings_np( self, hostname: str, - ptp_role: str, + name: str, config_file: str, socket_file: str, ) -> None: @@ -591,7 +585,7 @@ class PTPVerifyConfigKeywords(BaseKeyword): Args: hostname (str): The name of the host. - ptp_role (str): state of the port (e.g., MASTER and SLAVE) + name (str): The ptp instance name config_file (str): the config file. socket_file (str): the socket file. @@ -600,25 +594,10 @@ class PTPVerifyConfigKeywords(BaseKeyword): Raises: Exception: raised when validate fails """ - expected_grandmaster_settings_object_map = {"tgm": self.expected_grandmaster_settings_tgm_object, "tbc": self.expected_grandmaster_settings_tbc_object} - - expected_grandmaster_settings_object = expected_grandmaster_settings_object_map.get(ptp_role) - - if not expected_grandmaster_settings_object: - get_logger().log_info(f"Validation skipped as expected; expected_grandmaster_settings_{ptp_role}_object is None") - return - - expected_clock_class = expected_grandmaster_settings_object.get_clock_class() - expected_clock_accuracy = expected_grandmaster_settings_object.get_clock_accuracy() - expected_offset_scaled_log_variance = expected_grandmaster_settings_object.get_offset_scaled_log_variance() - expected_time_traceable = expected_grandmaster_settings_object.get_time_traceable() - expected_frequency_traceable = expected_grandmaster_settings_object.get_frequency_traceable() - expected_time_source = expected_grandmaster_settings_object.get_time_source() - expected_current_utc_offset_valid = expected_grandmaster_settings_object.get_current_utc_offset_valid() - lab_connect_keywords = LabConnectionKeywords() ssh_connection = lab_connect_keywords.get_ssh_for_hostname(hostname) pmc_keywords = PMCKeywords(ssh_connection) + get_grandmaster_settings_np_output = pmc_keywords.pmc_get_grandmaster_settings_np(config_file, socket_file) get_grandmaster_settings_np_object = get_grandmaster_settings_np_output.get_pmc_get_grandmaster_settings_np_object() observed_clock_class = get_grandmaster_settings_np_object.get_clock_class() @@ -629,6 +608,16 @@ class PTPVerifyConfigKeywords(BaseKeyword): observed_frequency_traceable = get_grandmaster_settings_np_object.get_frequency_traceable() observed_time_source = get_grandmaster_settings_np_object.get_time_source() + ptp4l_expected_obj = self.ptp_setup.get_ptp4l_expected_by_name(name) + expected_grandmaster_settings_obj = ptp4l_expected_obj.get_grandmaster_settings_for_hostname(hostname) + expected_clock_class = expected_grandmaster_settings_obj.get_clock_class() + expected_clock_accuracy = expected_grandmaster_settings_obj.get_clock_accuracy() + expected_offset_scaled_log_variance = expected_grandmaster_settings_obj.get_offset_scaled_log_variance() + expected_time_traceable = expected_grandmaster_settings_obj.get_time_traceable() + expected_frequency_traceable = expected_grandmaster_settings_obj.get_frequency_traceable() + expected_time_source = expected_grandmaster_settings_obj.get_time_source() + expected_current_utc_offset_valid = expected_grandmaster_settings_obj.get_current_utc_offset_valid() + validate_equals(observed_clock_class, expected_clock_class, "clockClass value within GET GRANDMASTER_SETTINGS_NP") validate_equals(observed_clock_accuracy, expected_clock_accuracy, "clockAccuracy value within GET GRANDMASTER_SETTINGS_NP") validate_equals(observed_offset_scaled_log_variance, expected_offset_scaled_log_variance, "offsetScaledLogVariance value within GET GRANDMASTER_SETTINGS_NP") diff --git a/keywords/ptp/cat/cat_clock_conf_parser.py b/keywords/ptp/cat/cat_clock_conf_parser.py index 8e115217..bbfa2ce9 100644 --- a/keywords/ptp/cat/cat_clock_conf_parser.py +++ b/keywords/ptp/cat/cat_clock_conf_parser.py @@ -35,8 +35,8 @@ class CatClockConfParser: output_values_dict = {} is_first_ifname = True for row in self.cat_clock_conf_output: - if "~$" in row: - continue # this is a prompt and should be ignored + if "~$" in row or "Password:" in row: + continue # these prompts and should be ignored values = row.strip("\n").split(None, 1) # split once if len(values) == 2: key, value = values diff --git a/keywords/ptp/gnss_keywords.py b/keywords/ptp/gnss_keywords.py index 7bb22da2..71542437 100644 --- a/keywords/ptp/gnss_keywords.py +++ b/keywords/ptp/gnss_keywords.py @@ -115,7 +115,7 @@ class GnssKeywords(BaseKeyword): expected_gnss_1pps_state = "valid" expected_pps_dpll_status = ["locked_ho_acq"] - self.validate_gnss_1pps_state_and_pps_dpll_status(hostname, cgu_location, expected_gnss_1pps_state, expected_pps_dpll_status) + self.validate_gnss_1pps_state_and_pps_dpll_status(hostname, cgu_location, "GNSS-1PPS", expected_gnss_1pps_state, expected_pps_dpll_status) def gnss_power_off(self, hostname: str, nic: str) -> None: """ @@ -141,12 +141,13 @@ class GnssKeywords(BaseKeyword): expected_gnss_1pps_state = "invalid" expected_pps_dpll_status = ["holdover", "freerun"] - self.validate_gnss_1pps_state_and_pps_dpll_status(hostname, cgu_location, expected_gnss_1pps_state, expected_pps_dpll_status) + self.validate_gnss_1pps_state_and_pps_dpll_status(hostname, cgu_location, "GNSS-1PPS", expected_gnss_1pps_state, expected_pps_dpll_status) def validate_gnss_1pps_state_and_pps_dpll_status( self, hostname: str, cgu_location: str, + cgu_input: str, expected_gnss_1pps_state: str, expected_pps_dpll_status: list, timeout: int = 800, @@ -158,6 +159,7 @@ class GnssKeywords(BaseKeyword): Args: hostname (str): The name of the host. cgu_location (str): the cgu location. + cgu_input (str): the cgu input name. expected_gnss_1pps_state (str): The expected gnss 1pss state value. expected_pps_dpll_status (list): expected list of PPS DPLL status values. timeout (int): The maximum time (in seconds) to wait for the match. @@ -185,7 +187,7 @@ class GnssKeywords(BaseKeyword): pps_dpll_object = ptp_cgu_component.get_pps_dpll() status = pps_dpll_object.get_status() - input_object = ptp_cgu_component.get_cgu_input("GNSS-1PPS") + input_object = ptp_cgu_component.get_cgu_input(cgu_input) state = input_object.get_state() if status in expected_pps_dpll_status and state == expected_gnss_1pps_state: diff --git a/keywords/ptp/setup/object/ptp4l_expected_dict.py b/keywords/ptp/setup/object/ptp4l_expected_dict.py index 16b20ed5..a3a4516d 100644 --- a/keywords/ptp/setup/object/ptp4l_expected_dict.py +++ b/keywords/ptp/setup/object/ptp4l_expected_dict.py @@ -1,6 +1,9 @@ from typing import Any, Dict, List +from keywords.ptp.setup.object.grandmaster_settings import GrandmasterSettings +from keywords.ptp.setup.object.parent_data_set import ParentDataSet from keywords.ptp.setup.object.port_data_set import PortDataSet +from keywords.ptp.setup.time_properties_data_set import TimePropertiesDataSet class PTP4LExpectedDict: @@ -16,26 +19,12 @@ class PTP4LExpectedDict: expected_dict (Dict[str, Any]): The dictionary read from the JSON setup template file associated with this ptp4l expected dict """ + self.expected_dict = expected_dict + if "name" not in expected_dict: raise Exception("Every PTP4L expected dict should have a name.") self.name = expected_dict["name"] - if "ptp_role" not in expected_dict: - raise Exception("Every PTP4L expected dict should have a ptp_role.") - self.ptp_role = expected_dict["ptp_role"] - - self.controller_0_port_data_set = None - if "controller_0_port_data_set" in expected_dict: - self.controller_0_port_data_set = expected_dict["controller_0_port_data_set"] - - self.controller_1_port_data_set = None - if "controller_1_port_data_set" in expected_dict: - self.controller_1_port_data_set = expected_dict["controller_1_port_data_set"] - - self.compute_0_port_data_set = None - if "compute_0_port_data_set" in expected_dict: - self.compute_0_port_data_set = expected_dict["compute_0_port_data_set"] - def __str__(self) -> str: """ String representation of this object. @@ -55,14 +44,68 @@ class PTP4LExpectedDict: """ return self.name - def get_ptp_role(self) -> str: + def get_parent_data_set_for_hostname(self, hostname: str) -> ParentDataSet: """ - Gets the ptp role. + Gets the of parent data set for hostname. + + Args: + hostname (str): The name of the host. Returns: - str: The ptp role. + ParentDataSet: The of parent data set for hostname. """ - return self.ptp_role + host_specific_data = self.expected_dict.get(hostname) + + if not host_specific_data: + raise Exception(f"Expected host specific data : {hostname} is not found for instance: {self.name}") + + parent_data_set_raw = host_specific_data.get("parent_data_set") + if not parent_data_set_raw: + raise Exception(f"Expected parent data set not found for hostname: {hostname}") + + return ParentDataSet(parent_data_set_raw) + + def get_time_properties_data_set_for_hostname(self, hostname: str) -> TimePropertiesDataSet: + """ + Gets the of time properties data set for hostname. + + Args: + hostname (str): The name of the host. + + Returns: + TimePropertiesDataSet: The of time properties data set for hostname. + """ + host_specific_data = self.expected_dict.get(hostname) + + if not host_specific_data: + raise Exception(f"Expected host specific data : {hostname} is not found for instance: {self.name}") + + time_properties_data_set_raw = host_specific_data.get("time_properties_data_set") + if not time_properties_data_set_raw: + raise Exception(f"Expected time properties data set not found for hostname: {hostname}") + + return TimePropertiesDataSet(time_properties_data_set_raw) + + def get_grandmaster_settings_for_hostname(self, hostname: str) -> GrandmasterSettings: + """ + Gets the of grandmaster settings for hostname. + + Args: + hostname (str): The name of the host. + + Returns: + GrandmasterSettings: The of grandmaster settings for hostname. + """ + host_specific_data = self.expected_dict.get(hostname) + + if not host_specific_data: + raise Exception(f"Expected host specific data : {hostname} is not found for instance: {self.name}") + + grandmaster_settings_raw = host_specific_data.get("grandmaster_settings") + if not grandmaster_settings_raw: + raise Exception(f"Expected grandmaster settings not found for hostname: {hostname}") + + return GrandmasterSettings(grandmaster_settings_raw) def get_port_data_set_for_hostname(self, hostname: str) -> List[PortDataSet]: """ @@ -74,13 +117,13 @@ class PTP4LExpectedDict: Returns: List[PortDataSet]: The list of port data set for hostname. """ - hostname_to_port_data_set = { - "controller-0": self.controller_0_port_data_set, - "controller-1": self.controller_1_port_data_set, - "compute-0": self.compute_0_port_data_set, - }.get(hostname) + host_specific_data = self.expected_dict.get(hostname) - if not hostname_to_port_data_set: + if not host_specific_data: + raise Exception(f"Expected host specific data : {hostname} is not found for instance: {self.name}") + + port_data_set_list_raw = host_specific_data.get("port_data_set") + if not port_data_set_list_raw: raise Exception(f"Expected port data set not found for hostname: {hostname}") - return [PortDataSet(port_data_set) for port_data_set in hostname_to_port_data_set] + return [PortDataSet(port_data_set) for port_data_set in port_data_set_list_raw] diff --git a/keywords/ptp/setup/object/ptp_setup.py b/keywords/ptp/setup/object/ptp_setup.py index 8c4a3974..21cccb22 100644 --- a/keywords/ptp/setup/object/ptp_setup.py +++ b/keywords/ptp/setup/object/ptp_setup.py @@ -1,14 +1,11 @@ from typing import Dict, List from keywords.ptp.setup.object.clock_setup import ClockSetup -from keywords.ptp.setup.object.grandmaster_settings import GrandmasterSettings -from keywords.ptp.setup.object.parent_data_set import ParentDataSet from keywords.ptp.setup.object.phc2sys_setup import PHC2SysSetup from keywords.ptp.setup.object.ptp4l_expected_dict import PTP4LExpectedDict from keywords.ptp.setup.object.ptp4l_setup import PTP4LSetup from keywords.ptp.setup.object.ptp_host_interface_setup import PTPHostInterfaceSetup from keywords.ptp.setup.object.ts2phc_setup import TS2PHCSetup -from keywords.ptp.setup.time_properties_data_set import TimePropertiesDataSet class PTPSetup: @@ -30,10 +27,6 @@ class PTPSetup: self.clock_setup_list: List[ClockSetup] = [] self.host_ptp_if_dict: Dict[str, PTPHostInterfaceSetup] = {} # Name -> PTPHostInterfaceSetup self.ptp4l_expected_list: List[PTP4LExpectedDict] = [] - self.parent_data_set: Dict[str, ParentDataSet] = {} - self.time_properties_data_set: Dict[str, TimePropertiesDataSet] = {} - self.grandmaster_settings_tgm: Dict[str, GrandmasterSettings] = {} - self.grandmaster_settings_tbc: Dict[str, GrandmasterSettings] = {} if "ptp_instances" not in setup_dict: raise Exception("You must define a ptp_instances section in your ptp setup_dict") @@ -75,18 +68,6 @@ class PTPSetup: expected_dict = setup_dict.get("expected_dict", {}) self.ptp4l_expected_list.extend(PTP4LExpectedDict(item) for item in expected_dict.get("ptp4l", [])) - if "parent_data_set" in expected_dict: - self.parent_data_set = ParentDataSet(expected_dict["parent_data_set"]) - - if "time_properties_data_set" in expected_dict: - self.time_properties_data_set = TimePropertiesDataSet(expected_dict["time_properties_data_set"]) - - if "grandmaster_settings_tgm" in expected_dict: - self.grandmaster_settings_tgm = GrandmasterSettings(expected_dict["grandmaster_settings_tgm"]) - - if "grandmaster_settings_tbc" in expected_dict: - self.grandmaster_settings_tbc = GrandmasterSettings(expected_dict["grandmaster_settings_tbc"]) - def __str__(self) -> str: """ String representation of this object. @@ -216,39 +197,3 @@ class PTPSetup: if not ptp4l_expected_obj: raise ValueError(f"No expected PTP4L object found for name: {name}") return ptp4l_expected_obj - - def get_parent_data_set(self) -> ParentDataSet: - """ - Getter for the parent data set. - - Returns: - ParentDataSet: The parent data set - """ - return self.parent_data_set - - def get_time_properties_data_set(self) -> TimePropertiesDataSet: - """ - Getter for the time properties data set. - - Returns: - TimePropertiesDataSet: The time properties data set - """ - return self.time_properties_data_set - - def get_grandmaster_settings_tgm(self) -> GrandmasterSettings: - """ - Getter for the grandmaster settings tgm. - - Returns: - GrandmasterSettings: The grandmaster settings tgm - """ - return self.grandmaster_settings_tgm - - def get_grandmaster_settings_tbc(self) -> GrandmasterSettings: - """ - Getter for the grandmaster settings tbc. - - Returns: - GrandmasterSettings: The grandmaster settings tbc - """ - return self.grandmaster_settings_tbc diff --git a/resources/ptp/setup/ptp_configuration_expectation_compute.json5 b/resources/ptp/setup/ptp_configuration_expectation_compute.json5 index 3aafc8ec..3819269e 100644 --- a/resources/ptp/setup/ptp_configuration_expectation_compute.json5 +++ b/resources/ptp/setup/ptp_configuration_expectation_compute.json5 @@ -5,7 +5,7 @@ { name: "ptp1", - instance_hostnames : ["compute-0", "controller-0", "controller-1"] , + instance_hostnames : ["compute-0", "controller-0", "controller-1"], instance_parameters: "priority2=100 tx_timestamp_timeout=700 boundary_clock_jbod=1 domainNumber=24 dataset_comparison=G.8275.x", ptp_interface_names: [ "ptp1if1", @@ -48,7 +48,7 @@ phc2sys : [ { name: "phc1", - instance_hostnames : ["controller-0", "compute-0", "controller-1"], + instance_hostnames : ["controller-0", "compute-0"], instance_parameters: "cmdline_opts='-s {{controller_0.nic1.conn_to_proxmox}} -O -37 -m'", ptp_interface_names: [ "phc1if1", @@ -75,7 +75,7 @@ { name: "phc4", - instance_hostnames : [], + instance_hostnames : ['controller-1'], instance_parameters: "domainNumber=24 uds_address=/var/run/ptp4l-ptp4", ptp_interface_names: [ "phc4if1", @@ -87,7 +87,7 @@ ts2phc : [ { name: "ts1", - instance_hostnames : ["controller-1", "controller-0", "compute-0"], + instance_hostnames : ["controller-0", "compute-0"], instance_parameters: "ts2phc.nmea_serialport=/dev/gnss0", ptp_interface_names: [ "ts1if1", @@ -233,83 +233,116 @@ "ptp4l": [ { "name": "ptp1", - "ptp_role": "tgm", - "controller_0_port_data_set": [ - { - "interface" : "{{ controller_0.nic1.nic_connection.interface }}", - "port_state": "MASTER" - }, - { - "interface" : "{{ controller_0.nic1.conn_to_proxmox }}", - "port_state": "MASTER" - } - ], - "controller_1_port_data_set": [ - { - "interface" : "{{ controller_1.nic1.nic_connection.interface }}", - "port_state": "PASSIVE" - }, - { - "interface" : "{{ controller_1.nic1.conn_to_proxmox }}", - "port_state": "MASTER" - } - ], - "compute_0_port_data_set": [ - { - "interface" : "{{ compute_0.nic1.nic_connection.interface }}", - "port_state": "LISTENING" - } - ] + "controller-0": { + "parent_data_set" : {{ parent_data_set_tgm_default }}, + "time_properties_data_set": {{ time_properties_data_set_tgm_default }}, + "grandmaster_settings": {{ grandmaster_settings.grandmaster_settings_tgm_default }}, + "port_data_set": [ + { + "interface" : "{{ controller_0.nic1.nic_connection.interface }}", // ctrl0 NIC1 is MASTER and ctr1 NIC1 is SLAVE + "port_state": "MASTER" + }, + { + "interface" : "{{ controller_0.nic1.conn_to_proxmox }}", + "port_state": "MASTER" + } + ] + }, + "controller-1": { + "parent_data_set" : {{ parent_data_set_tgm_default }}, + "time_properties_data_set": {{ time_properties_data_set_tgm_default }}, + "grandmaster_settings": { + "clock_class": 165, + "clock_accuracy": "0xfe", + "offset_scaled_log_variance": "0xffff", + "time_traceable": 0, + "frequency_traceable": 0, + "time_source": "0xa0", + "current_utc_offset_valid": 0 + }, + "port_data_set": [ + { + "interface" : "{{ controller_1.nic1.nic_connection.interface }}", + "port_state": "SLAVE", + "parent_port_identity" : { + "name": "ptp1", + "hostname":"controller-0", + "interface": "{{ controller_0.nic1.nic_connection.interface }}" // ctrl-0 NIC1 is Master and ctrl-1 NIC1 is slave + }, + }, + { + "interface" : "{{ controller_1.nic1.conn_to_proxmox }}", + "port_state": "MASTER" + } + ], + }, + "compute-0": { + "parent_data_set" : {{ parent_data_set_tgm_default }}, + "time_properties_data_set": {{ time_properties_data_set_tgm_default }}, + "grandmaster_settings": {{ grandmaster_settings.grandmaster_settings_tgm_default }}, + "port_data_set": [ + { + "interface" : "{{ compute_0.nic1.nic_connection.interface }}", + "port_state": "LISTENING" + } + ] + } }, { "name": "ptp2", - "ptp_role": "tgm" }, { "name": "ptp3", - "ptp_role": "tgm", - "controller_0_port_data_set": [ - { - "interface": "{{ controller_0.nic2.nic_connection.interface }}", // ctrl0 NIC2 is MASTER and ctr1 NIC2 is SLAVE - "port_state": "MASTER" - }, - { - "interface": "{{ controller_0.nic2.conn_to_proxmox }}", - "port_state": "MASTER" - } - ], - "compute_0_port_data_set": [ - { - "interface": "{{ compute_0.nic2.nic_connection.interface }}", - "port_state": "MASTER" - } - ] + "controller-0" : { + "parent_data_set" : {{ parent_data_set_tgm_default }}, + "time_properties_data_set": {{ time_properties_data_set_tgm_default }}, + "grandmaster_settings": {{ grandmaster_settings.grandmaster_settings_tgm_default }}, + "port_data_set": [ + { + "interface": "{{ controller_0.nic2.nic_connection.interface }}", // ctrl0 NIC2 is MASTER and ctr1 NIC2 is SLAVE + "port_state": "MASTER" + }, + { + "interface": "{{ controller_0.nic2.conn_to_proxmox }}", + "port_state": "MASTER" + } + ] + }, + "compute-0" : { + "parent_data_set" : {{ parent_data_set_tgm_default }}, + "time_properties_data_set": {{ time_properties_data_set_tgm_default }}, + "grandmaster_settings": {{ grandmaster_settings.grandmaster_settings_tgm_default }}, + "port_data_set": [ + { + "interface": "{{ compute_0.nic2.nic_connection.interface }}", + "port_state": "MASTER" + } + ] + } }, { "name": "ptp4", - "ptp_role": "tbc", - "controller_1_port_data_set": [ - { - "interface": "{{ controller_1.nic2.nic_connection.interface }}", - "port_state": "SLAVE", - "parent_port_identity" : { - "name": "ptp3", - "hostname":"controller-0", - "interface": "{{ controller_0.nic2.nic_connection.interface }}" // ctrl-0 NIC2 is Master and ctrl-1 NIC2 is slave - }, - }, - { - "interface": "{{ controller_1.nic2.conn_to_proxmox }}", - "port_state": "MASTER" - } - ] + "controller-1" : { + "parent_data_set" : {{ parent_data_set_tgm_default }}, + "time_properties_data_set": {{ time_properties_data_set_tgm_default }}, + "grandmaster_settings": {{ grandmaster_settings.grandmaster_settings_tbc_default }}, + "port_data_set": [ + { + "interface": "{{ controller_1.nic2.nic_connection.interface }}", + "port_state": "SLAVE", + "parent_port_identity" : { + "name": "ptp3", + "hostname":"controller-0", + "interface": "{{ controller_0.nic2.nic_connection.interface }}" // ctrl-0 NIC2 is Master and ctrl-1 NIC2 is slave + }, + }, + { + "interface": "{{ controller_1.nic2.conn_to_proxmox }}", + "port_state": "MASTER" + } + ] + } } - ], - "parent_data_set" : {{ parent_data_set_tgm_default }}, - "time_properties_data_set": {{ time_properties_data_set_tgm_default }}, - "grandmaster_settings": { - "tgm" : {{ grandmaster_settings.grandmaster_settings_tgm_default }}, - "tbm" : {{ grandmaster_settings.grandmaster_settings_tbc_default }} - } - }, + ] + } } \ No newline at end of file diff --git a/testcases/cloud_platform/regression/ptp/test_ptp.py b/testcases/cloud_platform/regression/ptp/test_ptp.py index 2623a785..76b8e36b 100644 --- a/testcases/cloud_platform/regression/ptp/test_ptp.py +++ b/testcases/cloud_platform/regression/ptp/test_ptp.py @@ -45,8 +45,8 @@ def test_delete_and_add_all_ptp_configuration_for_compute(): get_logger().log_info("Add all PTP configuration") ptp_setup_template_path = get_stx_resource_path("resources/ptp/setup/ptp_configuration_expectation_compute.json5") - ptp_setup_keywords = PTPSetupExecutorKeywords(ssh_connection, ptp_setup_template_path) - ptp_setup_keywords.add_all_ptp_configurations() + ptp_setup_executor_keywords = PTPSetupExecutorKeywords(ssh_connection, ptp_setup_template_path) + ptp_setup_executor_keywords.add_all_ptp_configurations() get_logger().log_info("Verify all PTP configuration") ptp_verify_config_keywords = PTPVerifyConfigKeywords(ssh_connection, ptp_setup_template_path)