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.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

View File

@@ -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 <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(
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")

View File

@@ -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

View File

@@ -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:

View File

@@ -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]

View File

@@ -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

View File

@@ -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 }}
}
},
]
}
}

View File

@@ -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)