Updated PTP setup configuration

Change-Id: I852f670cc66d63b0504d742002e4a1cf3acd1aac
Signed-off-by: Guntaka Umashankar Reddy <umashankarguntaka.reddy@windriver.com>
This commit is contained in:
Guntaka Umashankar Reddy
2025-05-13 07:54:00 -04:00
parent 2709f067b5
commit e7c3d2f28e
8 changed files with 284 additions and 231 deletions

View File

@@ -1,4 +1,4 @@
from typing import Any from typing import Any, List, Tuple
from framework.logging.automation_logger import get_logger from framework.logging.automation_logger import get_logger
from framework.validation.validation import validate_equals, validate_equals_with_retry, validate_str_contains 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_keywords import SystemPTPInstanceKeywords
from keywords.cloud_platform.system.ptp.system_ptp_instance_parameter_keywords import SystemPTPInstanceParameterKeywords 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.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.object.ptp_setup import PTPSetup
from keywords.ptp.setup.ptp_setup_reader import PTPSetupKeywords from keywords.ptp.setup.ptp_setup_reader import PTPSetupKeywords
from starlingx.keywords.linux.systemctl.systemctl_status_keywords import SystemCTLStatusKeywords
class PTPSetupExecutorKeywords(BaseKeyword): class PTPSetupExecutorKeywords(BaseKeyword):
@@ -57,24 +58,7 @@ class PTPSetupExecutorKeywords(BaseKeyword):
system_ptp_instance_apply_output = system_ptp_instance_keywords.system_ptp_instance_apply() 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") 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. self.wait_for_ptp_configuration_to_update_after_applying()
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)
def add_all_ptp_configurations_for_ptp4l_service(self): def add_all_ptp_configurations_for_ptp4l_service(self):
""" """
@@ -219,3 +203,60 @@ class PTPSetupExecutorKeywords(BaseKeyword):
Exception: raised when validate fails Exception: raised when validate fails
""" """
validate_equals(set(observed_value.split()), set(expected_value.split()), validation_description) 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

View File

@@ -43,10 +43,6 @@ class PTPVerifyConfigKeywords(BaseKeyword):
self.clock_setup_list = ptp_setup.get_clock_setup_list() self.clock_setup_list = ptp_setup.get_clock_setup_list()
self.ptp4l_expected_list_objects = ptp_setup.get_expected_ptp4l_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: def verify_all_ptp_configurations(self) -> None:
""" """
@@ -131,7 +127,7 @@ class PTPVerifyConfigKeywords(BaseKeyword):
instance_parameters = instance_obj.get_instance_parameters() instance_parameters = instance_obj.get_instance_parameters()
for hostname in hostnames: 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) systemctl_status_Keywords.verify_ptp_status_and_instance_parameters_on_hostname(hostname, name, service_name, instance_parameters)
else: else:
systemctl_status_Keywords.verify_status_on_hostname(hostname, name, service_name) systemctl_status_Keywords.verify_status_on_hostname(hostname, name, service_name)
@@ -144,6 +140,7 @@ class PTPVerifyConfigKeywords(BaseKeyword):
""" """
for service_type, setup_list in [ for service_type, setup_list in [
("ptp4l", self.ptp4l_setup_list), ("ptp4l", self.ptp4l_setup_list),
("phc2sys", self.phc2sys_setup_list),
("ts2phc", self.ts2phc_setup_list), ("ts2phc", self.ts2phc_setup_list),
("clock", self.clock_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() 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: for ptp4l_instance_obj in self.ptp4l_setup_list:
name = ptp4l_instance_obj.get_name() name = ptp4l_instance_obj.get_name()
config_file = f"/etc/linuxptp/ptpinstance/ptp4l-{name}.conf" config_file = f"/etc/linuxptp/ptpinstance/ptp4l-{name}.conf"
socket_file = f"/var/run/ptp4l-{name}" socket_file = f"/var/run/ptp4l-{name}"
instance_parameters = ptp4l_instance_obj.get_instance_parameters() 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(): 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) 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, name, config_file, socket_file)
self.validate_time_properties_data_set(hostname, 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: 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] 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() 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 <name>.
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( def validate_ptp_config_file_content_for_clock(
self, self,
@@ -436,9 +423,10 @@ class PTPVerifyConfigKeywords(BaseKeyword):
ssh_connection = lab_connect_keywords.get_ssh_for_hostname(hostname) ssh_connection = lab_connect_keywords.get_ssh_for_hostname(hostname)
pmc_keywords = PMCKeywords(ssh_connection) 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) 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) 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): 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") 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() 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") ptp4l_expected_obj = self.ptp_setup.get_ptp4l_expected_by_name(name)
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") expected_parent_data_set_obj = ptp4l_expected_obj.get_parent_data_set_for_hostname(hostname)
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")
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. # 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: if not port_data_set:
return 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() 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: 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( def validate_time_properties_data_set(
self, self,
hostname: str, hostname: str,
name: str,
config_file: str, config_file: str,
socket_file: str, socket_file: str,
) -> None: ) -> None:
@@ -550,6 +541,7 @@ class PTPVerifyConfigKeywords(BaseKeyword):
Args: Args:
hostname (str): The name of the host. hostname (str): The name of the host.
name (str): The ptp instance name
config_file (str): the config file. config_file (str): the config file.
socket_file (str): the socket file. socket_file (str): the socket file.
@@ -562,11 +554,6 @@ class PTPVerifyConfigKeywords(BaseKeyword):
ssh_connection = lab_connect_keywords.get_ssh_for_hostname(hostname) ssh_connection = lab_connect_keywords.get_ssh_for_hostname(hostname)
pmc_keywords = PMCKeywords(ssh_connection) 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_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() 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() 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_time_traceable = get_time_properties_data_set_object.get_time_traceable()
observed_frequency_traceable = get_time_properties_data_set_object.get_frequency_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_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_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") 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( def validate_grandmaster_settings_np(
self, self,
hostname: str, hostname: str,
ptp_role: str, name: str,
config_file: str, config_file: str,
socket_file: str, socket_file: str,
) -> None: ) -> None:
@@ -591,7 +585,7 @@ class PTPVerifyConfigKeywords(BaseKeyword):
Args: Args:
hostname (str): The name of the host. 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. config_file (str): the config file.
socket_file (str): the socket file. socket_file (str): the socket file.
@@ -600,25 +594,10 @@ class PTPVerifyConfigKeywords(BaseKeyword):
Raises: Raises:
Exception: raised when validate fails 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() lab_connect_keywords = LabConnectionKeywords()
ssh_connection = lab_connect_keywords.get_ssh_for_hostname(hostname) ssh_connection = lab_connect_keywords.get_ssh_for_hostname(hostname)
pmc_keywords = PMCKeywords(ssh_connection) 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_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() 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() 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_frequency_traceable = get_grandmaster_settings_np_object.get_frequency_traceable()
observed_time_source = get_grandmaster_settings_np_object.get_time_source() 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_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_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") validate_equals(observed_offset_scaled_log_variance, expected_offset_scaled_log_variance, "offsetScaledLogVariance value within GET GRANDMASTER_SETTINGS_NP")

View File

@@ -35,8 +35,8 @@ class CatClockConfParser:
output_values_dict = {} output_values_dict = {}
is_first_ifname = True is_first_ifname = True
for row in self.cat_clock_conf_output: for row in self.cat_clock_conf_output:
if "~$" in row: if "~$" in row or "Password:" in row:
continue # this is a prompt and should be ignored continue # these prompts and should be ignored
values = row.strip("\n").split(None, 1) # split once values = row.strip("\n").split(None, 1) # split once
if len(values) == 2: if len(values) == 2:
key, value = values key, value = values

View File

@@ -115,7 +115,7 @@ class GnssKeywords(BaseKeyword):
expected_gnss_1pps_state = "valid" expected_gnss_1pps_state = "valid"
expected_pps_dpll_status = ["locked_ho_acq"] 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: def gnss_power_off(self, hostname: str, nic: str) -> None:
""" """
@@ -141,12 +141,13 @@ class GnssKeywords(BaseKeyword):
expected_gnss_1pps_state = "invalid" expected_gnss_1pps_state = "invalid"
expected_pps_dpll_status = ["holdover", "freerun"] 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( def validate_gnss_1pps_state_and_pps_dpll_status(
self, self,
hostname: str, hostname: str,
cgu_location: str, cgu_location: str,
cgu_input: str,
expected_gnss_1pps_state: str, expected_gnss_1pps_state: str,
expected_pps_dpll_status: list, expected_pps_dpll_status: list,
timeout: int = 800, timeout: int = 800,
@@ -158,6 +159,7 @@ class GnssKeywords(BaseKeyword):
Args: Args:
hostname (str): The name of the host. hostname (str): The name of the host.
cgu_location (str): the cgu location. 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_gnss_1pps_state (str): The expected gnss 1pss state value.
expected_pps_dpll_status (list): expected list of PPS DPLL status values. expected_pps_dpll_status (list): expected list of PPS DPLL status values.
timeout (int): The maximum time (in seconds) to wait for the match. 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() pps_dpll_object = ptp_cgu_component.get_pps_dpll()
status = pps_dpll_object.get_status() 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() state = input_object.get_state()
if status in expected_pps_dpll_status and state == expected_gnss_1pps_state: if status in expected_pps_dpll_status and state == expected_gnss_1pps_state:

View File

@@ -1,6 +1,9 @@
from typing import Any, Dict, List 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.object.port_data_set import PortDataSet
from keywords.ptp.setup.time_properties_data_set import TimePropertiesDataSet
class PTP4LExpectedDict: 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 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: if "name" not in expected_dict:
raise Exception("Every PTP4L expected dict should have a name.") raise Exception("Every PTP4L expected dict should have a name.")
self.name = expected_dict["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: def __str__(self) -> str:
""" """
String representation of this object. String representation of this object.
@@ -55,14 +44,68 @@ class PTP4LExpectedDict:
""" """
return self.name 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: 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]: def get_port_data_set_for_hostname(self, hostname: str) -> List[PortDataSet]:
""" """
@@ -74,13 +117,13 @@ class PTP4LExpectedDict:
Returns: Returns:
List[PortDataSet]: The list of port data set for hostname. List[PortDataSet]: The list of port data set for hostname.
""" """
hostname_to_port_data_set = { host_specific_data = self.expected_dict.get(hostname)
"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)
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}") 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]

View File

@@ -1,14 +1,11 @@
from typing import Dict, List from typing import Dict, List
from keywords.ptp.setup.object.clock_setup import ClockSetup 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.phc2sys_setup import PHC2SysSetup
from keywords.ptp.setup.object.ptp4l_expected_dict import PTP4LExpectedDict from keywords.ptp.setup.object.ptp4l_expected_dict import PTP4LExpectedDict
from keywords.ptp.setup.object.ptp4l_setup import PTP4LSetup 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.ptp_host_interface_setup import PTPHostInterfaceSetup
from keywords.ptp.setup.object.ts2phc_setup import TS2PHCSetup from keywords.ptp.setup.object.ts2phc_setup import TS2PHCSetup
from keywords.ptp.setup.time_properties_data_set import TimePropertiesDataSet
class PTPSetup: class PTPSetup:
@@ -30,10 +27,6 @@ class PTPSetup:
self.clock_setup_list: List[ClockSetup] = [] self.clock_setup_list: List[ClockSetup] = []
self.host_ptp_if_dict: Dict[str, PTPHostInterfaceSetup] = {} # Name -> PTPHostInterfaceSetup self.host_ptp_if_dict: Dict[str, PTPHostInterfaceSetup] = {} # Name -> PTPHostInterfaceSetup
self.ptp4l_expected_list: List[PTP4LExpectedDict] = [] 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: if "ptp_instances" not in setup_dict:
raise Exception("You must define a ptp_instances section in your ptp 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", {}) expected_dict = setup_dict.get("expected_dict", {})
self.ptp4l_expected_list.extend(PTP4LExpectedDict(item) for item in expected_dict.get("ptp4l", [])) 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: def __str__(self) -> str:
""" """
String representation of this object. String representation of this object.
@@ -216,39 +197,3 @@ class PTPSetup:
if not ptp4l_expected_obj: if not ptp4l_expected_obj:
raise ValueError(f"No expected PTP4L object found for name: {name}") raise ValueError(f"No expected PTP4L object found for name: {name}")
return ptp4l_expected_obj 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

View File

@@ -5,7 +5,7 @@
{ {
name: "ptp1", 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", instance_parameters: "priority2=100 tx_timestamp_timeout=700 boundary_clock_jbod=1 domainNumber=24 dataset_comparison=G.8275.x",
ptp_interface_names: [ ptp_interface_names: [
"ptp1if1", "ptp1if1",
@@ -48,7 +48,7 @@
phc2sys : [ phc2sys : [
{ {
name: "phc1", 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'", instance_parameters: "cmdline_opts='-s {{controller_0.nic1.conn_to_proxmox}} -O -37 -m'",
ptp_interface_names: [ ptp_interface_names: [
"phc1if1", "phc1if1",
@@ -75,7 +75,7 @@
{ {
name: "phc4", name: "phc4",
instance_hostnames : [], instance_hostnames : ['controller-1'],
instance_parameters: "domainNumber=24 uds_address=/var/run/ptp4l-ptp4", instance_parameters: "domainNumber=24 uds_address=/var/run/ptp4l-ptp4",
ptp_interface_names: [ ptp_interface_names: [
"phc4if1", "phc4if1",
@@ -87,7 +87,7 @@
ts2phc : [ ts2phc : [
{ {
name: "ts1", name: "ts1",
instance_hostnames : ["controller-1", "controller-0", "compute-0"], instance_hostnames : ["controller-0", "compute-0"],
instance_parameters: "ts2phc.nmea_serialport=/dev/gnss0", instance_parameters: "ts2phc.nmea_serialport=/dev/gnss0",
ptp_interface_names: [ ptp_interface_names: [
"ts1if1", "ts1if1",
@@ -233,83 +233,116 @@
"ptp4l": [ "ptp4l": [
{ {
"name": "ptp1", "name": "ptp1",
"ptp_role": "tgm", "controller-0": {
"controller_0_port_data_set": [ "parent_data_set" : {{ parent_data_set_tgm_default }},
{ "time_properties_data_set": {{ time_properties_data_set_tgm_default }},
"interface" : "{{ controller_0.nic1.nic_connection.interface }}", "grandmaster_settings": {{ grandmaster_settings.grandmaster_settings_tgm_default }},
"port_state": "MASTER" "port_data_set": [
}, {
{ "interface" : "{{ controller_0.nic1.nic_connection.interface }}", // ctrl0 NIC1 is MASTER and ctr1 NIC1 is SLAVE
"interface" : "{{ controller_0.nic1.conn_to_proxmox }}", "port_state": "MASTER"
"port_state": "MASTER" },
} {
], "interface" : "{{ controller_0.nic1.conn_to_proxmox }}",
"controller_1_port_data_set": [ "port_state": "MASTER"
{ }
"interface" : "{{ controller_1.nic1.nic_connection.interface }}", ]
"port_state": "PASSIVE" },
}, "controller-1": {
{ "parent_data_set" : {{ parent_data_set_tgm_default }},
"interface" : "{{ controller_1.nic1.conn_to_proxmox }}", "time_properties_data_set": {{ time_properties_data_set_tgm_default }},
"port_state": "MASTER" "grandmaster_settings": {
} "clock_class": 165,
], "clock_accuracy": "0xfe",
"compute_0_port_data_set": [ "offset_scaled_log_variance": "0xffff",
{ "time_traceable": 0,
"interface" : "{{ compute_0.nic1.nic_connection.interface }}", "frequency_traceable": 0,
"port_state": "LISTENING" "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", "name": "ptp2",
"ptp_role": "tgm"
}, },
{ {
"name": "ptp3", "name": "ptp3",
"ptp_role": "tgm", "controller-0" : {
"controller_0_port_data_set": [ "parent_data_set" : {{ parent_data_set_tgm_default }},
{ "time_properties_data_set": {{ time_properties_data_set_tgm_default }},
"interface": "{{ controller_0.nic2.nic_connection.interface }}", // ctrl0 NIC2 is MASTER and ctr1 NIC2 is SLAVE "grandmaster_settings": {{ grandmaster_settings.grandmaster_settings_tgm_default }},
"port_state": "MASTER" "port_data_set": [
}, {
{ "interface": "{{ controller_0.nic2.nic_connection.interface }}", // ctrl0 NIC2 is MASTER and ctr1 NIC2 is SLAVE
"interface": "{{ controller_0.nic2.conn_to_proxmox }}", "port_state": "MASTER"
"port_state": "MASTER" },
} {
], "interface": "{{ controller_0.nic2.conn_to_proxmox }}",
"compute_0_port_data_set": [ "port_state": "MASTER"
{ }
"interface": "{{ compute_0.nic2.nic_connection.interface }}", ]
"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", "name": "ptp4",
"ptp_role": "tbc", "controller-1" : {
"controller_1_port_data_set": [ "parent_data_set" : {{ parent_data_set_tgm_default }},
{ "time_properties_data_set": {{ time_properties_data_set_tgm_default }},
"interface": "{{ controller_1.nic2.nic_connection.interface }}", "grandmaster_settings": {{ grandmaster_settings.grandmaster_settings_tbc_default }},
"port_state": "SLAVE", "port_data_set": [
"parent_port_identity" : { {
"name": "ptp3", "interface": "{{ controller_1.nic2.nic_connection.interface }}",
"hostname":"controller-0", "port_state": "SLAVE",
"interface": "{{ controller_0.nic2.nic_connection.interface }}" // ctrl-0 NIC2 is Master and ctrl-1 NIC2 is 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" },
} {
] "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 }}
}
},
} }

View File

@@ -45,8 +45,8 @@ def test_delete_and_add_all_ptp_configuration_for_compute():
get_logger().log_info("Add all PTP configuration") 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_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_executor_keywords = PTPSetupExecutorKeywords(ssh_connection, ptp_setup_template_path)
ptp_setup_keywords.add_all_ptp_configurations() ptp_setup_executor_keywords.add_all_ptp_configurations()
get_logger().log_info("Verify all PTP configuration") get_logger().log_info("Verify all PTP configuration")
ptp_verify_config_keywords = PTPVerifyConfigKeywords(ssh_connection, ptp_setup_template_path) ptp_verify_config_keywords = PTPVerifyConfigKeywords(ssh_connection, ptp_setup_template_path)