Create keywords to check and verify PTP
Change-Id: Iae86fde1ba0d14521e66018814f0977d74f824e1 Signed-off-by: Guntaka Umashankar Reddy <umashankarguntaka.reddy@windriver.com>
This commit is contained in:
@@ -78,9 +78,11 @@ class LabConnectionKeywords(BaseKeyword):
|
||||
|
||||
"""
|
||||
lab_config = ConfigurationManager.get_lab_config()
|
||||
|
||||
|
||||
if 'worker' in lab_config.get_node(hostname).get_type() :
|
||||
return self.get_compute_ssh(hostname)
|
||||
|
||||
host_ip = lab_config.get_node(hostname).get_ip()
|
||||
|
||||
jump_host_config = None
|
||||
if lab_config.is_use_jump_server():
|
||||
jump_host_config = lab_config.get_jump_host_configuration()
|
||||
@@ -92,7 +94,6 @@ class LabConnectionKeywords(BaseKeyword):
|
||||
ssh_port=lab_config.get_ssh_port(),
|
||||
jump_host=jump_host_config,
|
||||
)
|
||||
|
||||
return connection
|
||||
|
||||
def get_compute_ssh(self, compute_name: str) -> SSHConnection:
|
||||
|
@@ -190,6 +190,17 @@ class PTPSetupExecutorKeywords(BaseKeyword):
|
||||
system_ptp_interface_show_output = system_ptp_interface_keywords.get_system_ptp_interface_show(interface_name)
|
||||
validate_str_contains(system_ptp_interface_show_output.get_ptp_interface().get_interface_names(), f"{ctrl1_hostname}/{interface}", f"assign ptp interface for {ctrl1_hostname}")
|
||||
|
||||
compute_0_interfaces = ptp_host_if.get_compute_0_interfaces()
|
||||
comp0_hostname = "compute-0"
|
||||
for interface in compute_0_interfaces:
|
||||
if not interface :
|
||||
continue
|
||||
|
||||
system_host_if_ptp_keywords.system_host_if_ptp_assign(comp0_hostname, interface, interface_name)
|
||||
system_ptp_interface_show_output = system_ptp_interface_keywords.get_system_ptp_interface_show(interface_name)
|
||||
validate_str_contains(system_ptp_interface_show_output.get_ptp_interface().get_interface_names(), f"{comp0_hostname}/{interface}", f"assign ptp interface for {comp0_hostname}")
|
||||
|
||||
|
||||
ptp_interface_parameters = ptp_host_if.get_ptp_interface_parameter()
|
||||
if ptp_interface_parameters :
|
||||
system_ptp_interface_parameter_add_output = system_ptp_interface_keywords.system_ptp_interface_parameter_add(interface_name, ptp_interface_parameters)
|
||||
|
623
keywords/cloud_platform/system/ptp/ptp_verify_config.py
Normal file
623
keywords/cloud_platform/system/ptp/ptp_verify_config.py
Normal file
@@ -0,0 +1,623 @@
|
||||
import re
|
||||
from typing import Any
|
||||
|
||||
from framework.logging.automation_logger import get_logger
|
||||
from framework.validation.validation import validate_equals
|
||||
from keywords.base_keyword import BaseKeyword
|
||||
from keywords.cloud_platform.ssh.lab_connection_keywords import LabConnectionKeywords
|
||||
from keywords.linux.systemctl.systemctl_status_keywords import SystemCTLStatusKeywords
|
||||
from keywords.ptp.cat.cat_ptp_cgu_keywords import CatPtpCguKeywords
|
||||
from keywords.ptp.cat.cat_ptp_config_keywords import CatPtpConfigKeywords
|
||||
from keywords.ptp.gnss_keywords import GnssKeywords
|
||||
from keywords.ptp.pmc.pmc_keywords import PMCKeywords
|
||||
from keywords.ptp.setup.object.ptp_host_interface_setup import PTPHostInterfaceSetup
|
||||
from keywords.ptp.setup.ptp_setup_reader import PTPSetupKeywords
|
||||
|
||||
|
||||
class PTPVerifyConfigKeywords(BaseKeyword):
|
||||
"""
|
||||
Verify all PTP configurations using given SSH connection.
|
||||
|
||||
Attributes:
|
||||
ssh_connection: An instance of an SSH connection.
|
||||
"""
|
||||
|
||||
def __init__(self, ssh_connection, ptp_setup_template_path):
|
||||
"""
|
||||
Initializes the PTPVerifyConfigKeywords with an SSH connection.
|
||||
|
||||
Args:
|
||||
ssh_connection: An instance of an SSH connection.
|
||||
ptp_setup_template_path : ptp setup template path
|
||||
"""
|
||||
self.ssh_connection = ssh_connection
|
||||
ptp_setup_keywords = PTPSetupKeywords()
|
||||
ptp_setup = ptp_setup_keywords.generate_ptp_setup_from_template(ptp_setup_template_path)
|
||||
|
||||
self.ptp4l_setup_list = ptp_setup.get_ptp4l_setup_list()
|
||||
self.phc2sys_setup_list = ptp_setup.get_phc2sys_setup_list()
|
||||
self.ts2phc_setup_list = ptp_setup.get_ts2phc_setup_list()
|
||||
self.clock_setup_list = ptp_setup.get_clock_setup_list()
|
||||
|
||||
self.ctrl0_hostname = "controller-0"
|
||||
self.ctrl1_hostname = "controller-1"
|
||||
self.comp0_hostname = "compute-0"
|
||||
|
||||
def verify_all_ptp_configurations(self) -> None:
|
||||
"""
|
||||
verify all ptp configurations
|
||||
|
||||
Returns: None
|
||||
"""
|
||||
self.verify_gnss_status()
|
||||
|
||||
self.verify_sma_status()
|
||||
|
||||
self.verify_systemctl_status()
|
||||
|
||||
self.verify_ptp_pmc_values()
|
||||
|
||||
self.verify_ptp_config_file_content()
|
||||
|
||||
def verify_gnss_status(self) -> None:
|
||||
"""
|
||||
verify GNSS status
|
||||
|
||||
Returns: None
|
||||
"""
|
||||
gnss_keywords = GnssKeywords()
|
||||
|
||||
for ts2phc_instance_obj in self.ts2phc_setup_list:
|
||||
ptp_host_ifs = ts2phc_instance_obj.get_ptp_interfaces()
|
||||
instance_parameters = ts2phc_instance_obj.get_instance_parameters()
|
||||
expected_gnss_port = gnss_keywords.extract_gnss_port(instance_parameters)
|
||||
|
||||
if not expected_gnss_port: # No need to verify GNSS status if ts2phc.nmea_serialport not configured
|
||||
get_logger().log_info("Validation skipped as expected; GNSS port is None")
|
||||
continue
|
||||
|
||||
for ptp_host_if in ptp_host_ifs:
|
||||
controller_0_interfaces = ptp_host_if.get_controller_0_interfaces()
|
||||
for interface in controller_0_interfaces:
|
||||
if not interface:
|
||||
continue
|
||||
self.validate_gnss_status_on_hostname(self.ctrl0_hostname, interface, expected_gnss_port)
|
||||
|
||||
controller_1_interfaces = ptp_host_if.get_controller_1_interfaces()
|
||||
for interface in controller_1_interfaces:
|
||||
if not interface:
|
||||
continue
|
||||
self.validate_gnss_status_on_hostname(self.ctrl1_hostname, interface, expected_gnss_port)
|
||||
|
||||
compute_0_interfaces = ptp_host_if.get_compute_0_interfaces()
|
||||
for interface in compute_0_interfaces:
|
||||
if not interface:
|
||||
continue
|
||||
self.validate_gnss_status_on_hostname(self.comp0_hostname, interface, expected_gnss_port)
|
||||
|
||||
def verify_sma_status(self) -> None:
|
||||
"""
|
||||
verify SMA status
|
||||
|
||||
Returns: None
|
||||
"""
|
||||
for clock_instance_obj in self.clock_setup_list:
|
||||
ptp_host_ifs = clock_instance_obj.get_ptp_interfaces()
|
||||
|
||||
for ptp_host_if in ptp_host_ifs:
|
||||
ptp_interface_parameters = ptp_host_if.get_ptp_interface_parameter()
|
||||
|
||||
if "input" in ptp_interface_parameters:
|
||||
controller_0_interfaces = ptp_host_if.get_controller_0_interfaces()
|
||||
for interface in controller_0_interfaces:
|
||||
if not interface:
|
||||
continue
|
||||
self.validate_sma_status_on_hostname(self.ctrl0_hostname, interface)
|
||||
|
||||
controller_1_interfaces = ptp_host_if.get_controller_1_interfaces()
|
||||
for interface in controller_1_interfaces:
|
||||
if not interface:
|
||||
continue
|
||||
self.validate_sma_status_on_hostname(self.ctrl1_hostname, interface)
|
||||
|
||||
compute_0_interfaces = ptp_host_if.get_compute_0_interfaces()
|
||||
for interface in compute_0_interfaces:
|
||||
if not interface:
|
||||
continue
|
||||
self.validate_sma_status_on_hostname(self.comp0_hostname, interface)
|
||||
|
||||
def verify_systemctl_status(self) -> None:
|
||||
"""
|
||||
verify ptp systemctl ptp services status
|
||||
|
||||
Returns: None
|
||||
"""
|
||||
systemctl_status_Keywords = SystemCTLStatusKeywords(self.ssh_connection)
|
||||
|
||||
for ptp4l_instance_obj in self.ptp4l_setup_list:
|
||||
name = ptp4l_instance_obj.get_name()
|
||||
service_name = f"ptp4l@{name}.service"
|
||||
|
||||
hostnames = ptp4l_instance_obj.get_instance_hostnames()
|
||||
for hostname in hostnames:
|
||||
systemctl_status_Keywords.verify_status_on_hostname(hostname, name, service_name)
|
||||
|
||||
for phc2sys_instance_obj in self.phc2sys_setup_list:
|
||||
name = phc2sys_instance_obj.get_name()
|
||||
service_name = f"phc2sys@{name}.service"
|
||||
|
||||
hostnames = phc2sys_instance_obj.get_instance_hostnames()
|
||||
instance_parameters = phc2sys_instance_obj.get_instance_parameters()
|
||||
for hostname in hostnames:
|
||||
systemctl_status_Keywords.verify_ptp_status_and_instance_parameters_on_hostname(hostname, name, service_name, instance_parameters)
|
||||
|
||||
for ts2phc_instance_obj in self.ts2phc_setup_list:
|
||||
name = ts2phc_instance_obj.get_name()
|
||||
service_name = f"ts2phc@{name}.service"
|
||||
|
||||
hostnames = ts2phc_instance_obj.get_instance_hostnames()
|
||||
for hostname in hostnames:
|
||||
systemctl_status_Keywords.verify_status_on_hostname(hostname, name, service_name)
|
||||
|
||||
def verify_ptp_config_file_content(self) -> None:
|
||||
"""
|
||||
Verify ptp config file content
|
||||
|
||||
Returns: None
|
||||
"""
|
||||
for ptp4l_instance_obj in self.ptp4l_setup_list:
|
||||
config_file = f"/etc/linuxptp/ptpinstance/ptp4l-{ptp4l_instance_obj.get_name()}.conf"
|
||||
hostnames = ptp4l_instance_obj.get_instance_hostnames()
|
||||
for hostname in hostnames:
|
||||
self.validate_ptp_config_file_content(ptp4l_instance_obj, hostname, config_file)
|
||||
|
||||
for ts2phc_instance_obj in self.ts2phc_setup_list:
|
||||
config_file = f"/etc/linuxptp/ptpinstance/ts2phc-{ts2phc_instance_obj.get_name()}.conf"
|
||||
hostnames = ts2phc_instance_obj.get_instance_hostnames()
|
||||
for hostname in hostnames:
|
||||
self.validate_ptp_config_file_content(ts2phc_instance_obj, hostname, config_file)
|
||||
|
||||
def verify_ptp_pmc_values(self) -> None:
|
||||
"""
|
||||
verify ptp pmc values
|
||||
|
||||
Returns: 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}"
|
||||
|
||||
hostnames = ptp4l_instance_obj.get_instance_hostnames()
|
||||
instance_parameters = ptp4l_instance_obj.get_instance_parameters()
|
||||
ptp_role = ptp4l_instance_obj.get_ptp_role()
|
||||
for hostname in hostnames:
|
||||
|
||||
self.validate_port_data_set(hostname, config_file, socket_file, expected_port_state="MASTER")
|
||||
|
||||
self.validate_get_domain(hostname, instance_parameters, config_file, socket_file)
|
||||
|
||||
self.validate_parent_data_set(hostname, instance_parameters, 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)
|
||||
|
||||
def validate_gnss_status_on_hostname(self, hostname: str, interface: str, expected_gnss_port: str) -> None:
|
||||
"""
|
||||
Validate GNSS status on the hostname
|
||||
|
||||
Args:
|
||||
hostname (str): The name of the host.
|
||||
interface (str): The name of the ptp interface (e.g., "enp138s0f0").
|
||||
expected_gnss_port (str): Expected GNSS serial port value
|
||||
|
||||
Returns: None
|
||||
"""
|
||||
gnss_keywords = GnssKeywords()
|
||||
|
||||
input_name = "GNSS-1PPS"
|
||||
expected_gnss_1pps_state = "valid"
|
||||
expected_dpll_status = "locked_ho_acq"
|
||||
|
||||
observed_gnss_port = gnss_keywords.get_gnss_serial_port_from_gnss_directory(hostname, interface)
|
||||
if expected_gnss_port == observed_gnss_port:
|
||||
pci_address = gnss_keywords.get_pci_slot_name(hostname, interface)
|
||||
cgu_location = f"/sys/kernel/debug/ice/{pci_address}/cgu"
|
||||
self.validate_cgu_input_and_dpll_status(hostname, cgu_location, input_name, expected_gnss_1pps_state, expected_dpll_status)
|
||||
else:
|
||||
get_logger().log_info(f"Validation skipped; GNSS port does not match for hostname {hostname} and interface {interface}")
|
||||
get_logger().log_info(f"Expected GNSS port: {expected_gnss_port}")
|
||||
get_logger().log_info(f"Observed GNSS port: {observed_gnss_port}")
|
||||
|
||||
def validate_sma_status_on_hostname(self, hostname: str, interface: str) -> None:
|
||||
"""
|
||||
Validate SMA status on the hostname
|
||||
|
||||
Args:
|
||||
hostname (str): The name of the host.
|
||||
interface (str): The name of the ptp interface (e.g., "enp138s0f0").
|
||||
|
||||
Returns: None
|
||||
"""
|
||||
gnss_keywords = GnssKeywords()
|
||||
|
||||
input_name = "SMA1"
|
||||
expected_sma1_state = "valid"
|
||||
expected_dpll_status = "locked_ho_acq"
|
||||
|
||||
pci_address = gnss_keywords.get_pci_slot_name(hostname, interface)
|
||||
cgu_location = f"/sys/kernel/debug/ice/{pci_address}/cgu"
|
||||
self.validate_cgu_input_and_dpll_status(hostname, cgu_location, input_name, expected_sma1_state, expected_dpll_status)
|
||||
|
||||
def validate_cgu_input_and_dpll_status(
|
||||
self,
|
||||
hostname: str,
|
||||
cgu_location: str,
|
||||
input_name: str,
|
||||
expected_input_state: str,
|
||||
expected_status: str,
|
||||
) -> None:
|
||||
"""
|
||||
Validates the cgu and dpll status.
|
||||
|
||||
Args:
|
||||
hostname (str): The name of the host.
|
||||
cgu_location (str): the cgu location.
|
||||
input_name (str): the cgu input name.
|
||||
expected_input_state (str): The expected cgu input state.
|
||||
expected_status (str): expected of DPLL status.
|
||||
|
||||
Returns: None
|
||||
|
||||
Raises:
|
||||
Exception: raised when validate fails
|
||||
"""
|
||||
lab_connect_keywords = LabConnectionKeywords()
|
||||
ssh_connection = lab_connect_keywords.get_ssh_for_hostname(hostname)
|
||||
cat_ptp_cgu_keywords = CatPtpCguKeywords(ssh_connection)
|
||||
|
||||
ptp_cgu_output = cat_ptp_cgu_keywords.cat_ptp_cgu(cgu_location)
|
||||
ptp_cgu_component = ptp_cgu_output.get_cgu_component()
|
||||
|
||||
input_object = ptp_cgu_component.get_cgu_input(input_name)
|
||||
state = input_object.get_state()
|
||||
|
||||
eec_dpll_object = ptp_cgu_component.get_eec_dpll()
|
||||
eec_dpll_current_reference = eec_dpll_object.get_current_reference()
|
||||
eec_dpll_status = eec_dpll_object.get_status()
|
||||
|
||||
pps_dpll_object = ptp_cgu_component.get_pps_dpll()
|
||||
pps_dpll_current_reference = pps_dpll_object.get_current_reference()
|
||||
pps_dpll_status = pps_dpll_object.get_status()
|
||||
|
||||
if state == expected_input_state and eec_dpll_current_reference == input_name and eec_dpll_status == expected_status and pps_dpll_current_reference == input_name and pps_dpll_status == expected_status:
|
||||
get_logger().log_info(f"Validation Successful - {input_name} state and DPLL status")
|
||||
else:
|
||||
get_logger().log_info(f"Validation Failed - {input_name} state and DPLL status")
|
||||
get_logger().log_info(f"Expected {input_name}: {expected_input_state}")
|
||||
get_logger().log_info(f"Observed {input_name}: {state}")
|
||||
|
||||
get_logger().log_info(f"Expected EEC DPLL current refrence: {input_name}")
|
||||
get_logger().log_info(f"Observed EEC DPLL current refrence: {eec_dpll_current_reference}")
|
||||
get_logger().log_info(f"Expected EEC DPLL status: {expected_status}")
|
||||
get_logger().log_info(f"Observed EEC DPLL status: {eec_dpll_status}")
|
||||
|
||||
get_logger().log_info(f"Expected PPS DPLL current refrence: {input_name}")
|
||||
get_logger().log_info(f"Observed PPS DPLL current refrence: {pps_dpll_current_reference}")
|
||||
get_logger().log_info(f"Expected PPS DPLL status: {expected_status}")
|
||||
get_logger().log_info(f"Observed PPS DPLL status: {pps_dpll_status}")
|
||||
|
||||
raise Exception("Validation Failed")
|
||||
|
||||
def validate_ptp_config_file_content(
|
||||
self,
|
||||
ptp_instance_obj: Any,
|
||||
hostname: str,
|
||||
config_file: str,
|
||||
) -> None:
|
||||
"""
|
||||
Validates the ptp config file content.
|
||||
|
||||
Args:
|
||||
ptp_instance_obj (Any) : PTP instance setup object
|
||||
hostname (str): The name of the host.
|
||||
config_file (str): the config file.
|
||||
|
||||
Returns: None
|
||||
|
||||
Raises:
|
||||
Exception: raised when validate fails
|
||||
"""
|
||||
lab_connect_keywords = LabConnectionKeywords()
|
||||
ssh_connection = lab_connect_keywords.get_ssh_for_hostname(hostname)
|
||||
|
||||
cat_ptp_config_keywords = CatPtpConfigKeywords(ssh_connection)
|
||||
cat_ptp_config_output = cat_ptp_config_keywords.cat_ptp_config(config_file)
|
||||
get_pmc_get_default_data_set_object = cat_ptp_config_output.data_set_output.get_pmc_get_default_data_set_object()
|
||||
|
||||
instance_parameters = ptp_instance_obj.get_instance_parameters()
|
||||
parameters = self.parse_instance_parameters_string(instance_parameters)
|
||||
|
||||
expected_boundary_clock_jbod = parameters.get("boundary_clock_jbod")
|
||||
if expected_boundary_clock_jbod:
|
||||
observed_boundary_clock_jbod = get_pmc_get_default_data_set_object.get_boundary_clock_jbod()
|
||||
validate_equals(observed_boundary_clock_jbod, expected_boundary_clock_jbod, "boundary_clock_jbod value within PTP config file content")
|
||||
|
||||
expected_dataset_comparison = parameters.get("dataset_comparison")
|
||||
if expected_dataset_comparison:
|
||||
observed_dataset_comparison = get_pmc_get_default_data_set_object.get_dataset_comparison()
|
||||
validate_equals(observed_dataset_comparison, expected_dataset_comparison, "dataset_comparison value within PTP config file content")
|
||||
|
||||
expected_domain_number = parameters.get("domainNumber")
|
||||
if expected_domain_number:
|
||||
observed_domain_number = get_pmc_get_default_data_set_object.get_domain_number()
|
||||
validate_equals(observed_domain_number, expected_domain_number, "domainNumber value within PTP config file content")
|
||||
|
||||
expected_priority1 = parameters.get("priority1")
|
||||
if expected_priority1:
|
||||
observed_priority1 = get_pmc_get_default_data_set_object.get_priority1()
|
||||
validate_equals(observed_priority1, expected_priority1, "priority1 value within PTP config file content")
|
||||
|
||||
expected_priority2 = parameters.get("priority2")
|
||||
if expected_priority2:
|
||||
observed_priority2 = get_pmc_get_default_data_set_object.get_priority2()
|
||||
validate_equals(observed_priority2, expected_priority2, "priority2 value within PTP config file content")
|
||||
|
||||
expected_tx_timestamp_timeout = parameters.get("tx_timestamp_timeout")
|
||||
if expected_tx_timestamp_timeout:
|
||||
observed_tx_timestamp_timeout = get_pmc_get_default_data_set_object.get_tx_timestamp_timeout()
|
||||
validate_equals(observed_tx_timestamp_timeout, expected_tx_timestamp_timeout, "tx_timestamp_timeout value within PTP config file content")
|
||||
|
||||
get_associated_interfaces = list(
|
||||
map(
|
||||
lambda ptp_host_if: ptp_host_if.get_controller_0_interfaces() if hostname == "controller-0" else ptp_host_if.get_controller_1_interfaces() if hostname == "controller-1" else ptp_host_if.get_compute_0_interfaces() if hostname == "compute-0" else [],
|
||||
ptp_instance_obj.get_ptp_interfaces(),
|
||||
)
|
||||
)
|
||||
expected_associated_interfaces = sum(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")
|
||||
|
||||
def validate_port_data_set(
|
||||
self,
|
||||
hostname: str,
|
||||
config_file: str,
|
||||
socket_file: str,
|
||||
expected_port_state: str,
|
||||
) -> None:
|
||||
"""
|
||||
Validates the get port data set.
|
||||
|
||||
Args:
|
||||
hostname (str): The name of the host.
|
||||
config_file (str): the config file.
|
||||
socket_file (str): the socket file.
|
||||
expected_port_state (str): The current state of the port (e.g., MASTER, SLAVE, PASSIVE, LISTENING)
|
||||
|
||||
Returns: None
|
||||
|
||||
Raises:
|
||||
Exception: raised when validate fails
|
||||
"""
|
||||
lab_connect_keywords = LabConnectionKeywords()
|
||||
ssh_connection = lab_connect_keywords.get_ssh_for_hostname(hostname)
|
||||
pmc_keywords = PMCKeywords(ssh_connection)
|
||||
|
||||
get_port_data_set_output = pmc_keywords.pmc_get_port_data_set(config_file, socket_file)
|
||||
get_pmc_get_port_data_set_object = get_port_data_set_output.get_pmc_get_port_data_set_object()
|
||||
observed_port_identity = get_pmc_get_port_data_set_object.get_port_identity()
|
||||
observed_port_state = get_pmc_get_port_data_set_object.get_port_state()
|
||||
|
||||
validate_equals(observed_port_state, expected_port_state, "portState value within GET PORT_DATA_SET")
|
||||
|
||||
def validate_get_domain(
|
||||
self,
|
||||
hostname: str,
|
||||
instance_parameters: str,
|
||||
config_file: str,
|
||||
socket_file: str,
|
||||
) -> None:
|
||||
"""
|
||||
Validates the get domain number.
|
||||
|
||||
Args:
|
||||
hostname (str): The name of the host.
|
||||
instance_parameters (str): instance parameters
|
||||
config_file (str): the config file.
|
||||
socket_file (str): the socket file.
|
||||
|
||||
Returns: None
|
||||
|
||||
Raises:
|
||||
Exception: raised when validate fails
|
||||
"""
|
||||
lab_connect_keywords = LabConnectionKeywords()
|
||||
ssh_connection = lab_connect_keywords.get_ssh_for_hostname(hostname)
|
||||
pmc_keywords = PMCKeywords(ssh_connection)
|
||||
|
||||
parameters = self.parse_instance_parameters_string(instance_parameters)
|
||||
expected_domain_number = parameters.get("domainNumber")
|
||||
|
||||
get_domain_output = pmc_keywords.pmc_get_domain(config_file, socket_file)
|
||||
observed_domain_number = get_domain_output.get_pmc_get_domain_object().get_domain_number()
|
||||
|
||||
validate_equals(observed_domain_number, expected_domain_number, "domainNumber value within GET DOMAIN")
|
||||
|
||||
def validate_parent_data_set(
|
||||
self,
|
||||
hostname: str,
|
||||
instance_parameters: str,
|
||||
config_file: str,
|
||||
socket_file: str,
|
||||
) -> None:
|
||||
"""
|
||||
Validates the get parent data set.
|
||||
|
||||
Args:
|
||||
hostname (str): The name of the host.
|
||||
instance_parameters (str): instance parameters
|
||||
config_file (str): the config file.
|
||||
socket_file (str): the socket file.
|
||||
|
||||
Returns: None
|
||||
|
||||
Raises:
|
||||
Exception: raised when validate fails
|
||||
"""
|
||||
|
||||
lab_connect_keywords = LabConnectionKeywords()
|
||||
ssh_connection = lab_connect_keywords.get_ssh_for_hostname(hostname)
|
||||
pmc_keywords = PMCKeywords(ssh_connection)
|
||||
|
||||
# gm.ClockClass value is always 6 if it is in a good status.
|
||||
expected_gm_clock_class = 6
|
||||
# gm.ClockAccuracy and gm.OffsetScaledLogVariance values can be overwritten using instance parameters,
|
||||
# but for now, the default values are in use
|
||||
expected_gm_clock_accuracy = "0x20"
|
||||
expected_gm_offset_scaled_log_variance = "0x4e5d"
|
||||
|
||||
parameters = self.parse_instance_parameters_string(instance_parameters)
|
||||
expected_grandmaster_priority2 = parameters.get("priority2")
|
||||
|
||||
get_parent_data_set_output = pmc_keywords.pmc_get_parent_data_set(config_file, socket_file)
|
||||
get_parent_data_set_object = get_parent_data_set_output.get_pmc_get_parent_data_set_object()
|
||||
observed_gm_clock_class = get_parent_data_set_object.get_gm_clock_class()
|
||||
observed_gm_clock_accuracy = get_parent_data_set_object.get_gm_clock_accuracy()
|
||||
observed_gm_offset_scaled_log_variance = get_parent_data_set_object.get_gm_offset_scaled_log_variance()
|
||||
observed_grandmaster_priority2 = get_parent_data_set_object.get_grandmaster_priority2()
|
||||
|
||||
validate_equals(observed_gm_clock_class, expected_gm_clock_class, "gm.ClockClass value within GET PARENT_DATA_SET")
|
||||
validate_equals(observed_gm_clock_accuracy, expected_gm_clock_accuracy, "gm.ClockAccuracy value within GET PARENT_DATA_SET")
|
||||
validate_equals(observed_gm_offset_scaled_log_variance, expected_gm_offset_scaled_log_variance, "gm.OffsetScaledLogVariance value within GET PARENT_DATA_SET")
|
||||
validate_equals(observed_grandmaster_priority2, expected_grandmaster_priority2, "grandmasterPriority2 value within GET PARENT_DATA_SET")
|
||||
|
||||
def validate_time_properties_data_set(
|
||||
self,
|
||||
hostname: str,
|
||||
config_file: str,
|
||||
socket_file: str,
|
||||
) -> None:
|
||||
"""
|
||||
Validates the get time properties data set.
|
||||
|
||||
Args:
|
||||
hostname (str): The name of the host.
|
||||
config_file (str): the config file.
|
||||
socket_file (str): the socket file.
|
||||
|
||||
Returns: None
|
||||
|
||||
Raises:
|
||||
Exception: raised when validate fails
|
||||
"""
|
||||
lab_connect_keywords = LabConnectionKeywords()
|
||||
ssh_connection = lab_connect_keywords.get_ssh_for_hostname(hostname)
|
||||
pmc_keywords = PMCKeywords(ssh_connection)
|
||||
|
||||
# default values if it is in a good status.
|
||||
expected_current_utc_offset = 37
|
||||
expected_current_utc_offset_valid = 0
|
||||
expected_time_traceable = 1
|
||||
expected_frequency_traceable = 1
|
||||
|
||||
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()
|
||||
observed_current_utc_off_set_valid = get_time_properties_data_set_object.get_current_utc_off_set_valid()
|
||||
observed_time_traceable = get_time_properties_data_set_object.get_time_traceable()
|
||||
observed_frequency_traceable = get_time_properties_data_set_object.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")
|
||||
validate_equals(observed_frequency_traceable, expected_frequency_traceable, "frequencyTraceable value within GET TIME_PROPERTIES_DATA_SET")
|
||||
|
||||
def validate_grandmaster_settings_np(
|
||||
self,
|
||||
hostname: str,
|
||||
ptp_role: str,
|
||||
config_file: str,
|
||||
socket_file: str,
|
||||
) -> None:
|
||||
"""
|
||||
Validates the get grandmaster settings np.
|
||||
|
||||
Args:
|
||||
hostname (str): The name of the host.
|
||||
ptp_role (str): state of the port (e.g., MASTER and SLAVE)
|
||||
config_file (str): the config file.
|
||||
socket_file (str): the socket file.
|
||||
|
||||
Returns: None
|
||||
|
||||
Raises:
|
||||
Exception: raised when validate fails
|
||||
"""
|
||||
if ptp_role == "MASTER":
|
||||
expected_clock_class = 6
|
||||
expected_clock_accuracy = "0x20"
|
||||
expected_offset_scaled_log_variance = "0x4e5d"
|
||||
expected_time_traceable = 1
|
||||
expected_frequency_traceable = 1
|
||||
expected_time_source = "0x20"
|
||||
else:
|
||||
expected_clock_class = 248
|
||||
expected_clock_accuracy = "0xfe"
|
||||
expected_offset_scaled_log_variance = "0xffff"
|
||||
expected_time_traceable = 0
|
||||
expected_frequency_traceable = 0
|
||||
expected_time_source = "0xa0"
|
||||
|
||||
expected_current_utc_offset_valid = 0
|
||||
|
||||
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()
|
||||
observed_clock_accuracy = get_grandmaster_settings_np_object.get_clock_accuracy()
|
||||
observed_offset_scaled_log_variance = get_grandmaster_settings_np_object.get_offset_scaled_log_variance()
|
||||
observed_current_utc_offset_valid = get_grandmaster_settings_np_object.get_current_utc_off_set_valid()
|
||||
observed_time_traceable = get_grandmaster_settings_np_object.get_time_traceable()
|
||||
observed_frequency_traceable = get_grandmaster_settings_np_object.get_frequency_traceable()
|
||||
observed_time_source = get_grandmaster_settings_np_object.get_time_source()
|
||||
|
||||
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")
|
||||
validate_equals(observed_current_utc_offset_valid, expected_current_utc_offset_valid, "currentUtcOffsetValid value within GET GRANDMASTER_SETTINGS_NP")
|
||||
validate_equals(observed_time_traceable, expected_time_traceable, "timeTraceable value within GET GRANDMASTER_SETTINGS_NP")
|
||||
validate_equals(observed_frequency_traceable, expected_frequency_traceable, "frequencyTraceable value within GET GRANDMASTER_SETTINGS_NP")
|
||||
validate_equals(observed_time_source, expected_time_source, "timeSource value within GET GRANDMASTER_SETTINGS_NP")
|
||||
|
||||
def parse_instance_parameters_string(self, instance_parameters: str) -> dict:
|
||||
"""
|
||||
Parses a string containing instance parameters and returns a dictionary.
|
||||
|
||||
Args:
|
||||
instance_parameters (str): A string containing instance parameters (e.g., "key1=value1 key2=value2").
|
||||
|
||||
Returns:
|
||||
dict: A dictionary where keys are the instance parameter names and values are the
|
||||
corresponding values. Returns an empty dictionary if the input string
|
||||
is empty or doesn't contain any valid parameters.
|
||||
Values are returned as integers if they consist only of digits,
|
||||
otherwise as strings.
|
||||
"""
|
||||
parameters = {}
|
||||
# Split the string by spaces to get individual key-value pairs
|
||||
for item in instance_parameters.split():
|
||||
# boundary_clock_jbod=1
|
||||
match = re.search(r"([^=]+)=([^ ]+)", item)
|
||||
if match:
|
||||
key, value = match.groups()
|
||||
# Try converting the value to an integer; if it fails, keep it as a string
|
||||
try:
|
||||
value = int(value)
|
||||
except ValueError:
|
||||
pass
|
||||
parameters[key] = value
|
||||
return parameters
|
@@ -1,5 +1,10 @@
|
||||
from multiprocessing import get_logger
|
||||
|
||||
from framework.ssh.ssh_connection import SSHConnection
|
||||
from keywords.base_keyword import BaseKeyword
|
||||
from keywords.ptp.ptp4l.objects.ptp4l_status_output import PTP4LStatusOutput
|
||||
from keywords.cloud_platform.ssh.lab_connection_keywords import LabConnectionKeywords
|
||||
from starlingx.framework.validation.validation import validate_equals
|
||||
|
||||
|
||||
class SystemCTLStatusKeywords(BaseKeyword):
|
||||
@@ -14,7 +19,7 @@ class SystemCTLStatusKeywords(BaseKeyword):
|
||||
"""
|
||||
Gets the status of the given service name
|
||||
Args:
|
||||
service_name (): the service name
|
||||
service_name (str): the service name
|
||||
|
||||
Returns: the output as a list of strings - this should be consumed by a parser for the given output type
|
||||
|
||||
@@ -23,3 +28,75 @@ class SystemCTLStatusKeywords(BaseKeyword):
|
||||
self.validate_success_return_code(self.ssh_connection)
|
||||
return output
|
||||
|
||||
def verify_status_on_hostname(self, hostname :str, name : str, service_name : str) -> None:
|
||||
"""
|
||||
verify systemctl ptp service status on hostname
|
||||
|
||||
Args:
|
||||
hostname (str): The name of the host
|
||||
name (str): name of instance (e.g., "phc1")
|
||||
service_name (str): service name (e.g., "phc2sys@phc1.service")
|
||||
|
||||
Returns: None
|
||||
|
||||
Raises:
|
||||
Exception: raised when validate fails
|
||||
"""
|
||||
lab_connect_keywords = LabConnectionKeywords()
|
||||
ssh_connection = lab_connect_keywords.get_ssh_for_hostname(hostname)
|
||||
|
||||
output = SystemCTLStatusKeywords(ssh_connection).get_status(service_name)
|
||||
ptp_service_status_output = PTP4LStatusOutput(output)
|
||||
|
||||
expected_service_status = "active (running)"
|
||||
observed_service_status = ptp_service_status_output.get_ptp4l_object(name).get_active()
|
||||
|
||||
if expected_service_status in observed_service_status :
|
||||
get_logger().log_info(f"Validation Successful - systemctl status {service_name}")
|
||||
else:
|
||||
get_logger().log_info(f"Validation Failed - systemctl status {service_name}")
|
||||
get_logger().log_info(f"Expected service status: {expected_service_status}")
|
||||
get_logger().log_info(f"Observed service status: {observed_service_status}")
|
||||
raise Exception("Validation Failed")
|
||||
|
||||
|
||||
def verify_ptp_status_and_instance_parameters_on_hostname(self, hostname :str, name : str, service_name : str, instance_parameters : str) -> None:
|
||||
"""
|
||||
verify systemctl ptp service status and instance parameters on hostname
|
||||
|
||||
Args:
|
||||
hostname (str): The name of the host
|
||||
name (str) : name of instance (e.g., "phc1")
|
||||
service_name (str): service name (e.g., "phc2sys@phc1.service")
|
||||
instance_parameters (str) : instance parameters
|
||||
|
||||
Returns: None
|
||||
|
||||
Raises:
|
||||
Exception: raised when validate fails
|
||||
"""
|
||||
lab_connect_keywords = LabConnectionKeywords()
|
||||
ssh_connection = lab_connect_keywords.get_ssh_for_hostname(hostname)
|
||||
|
||||
|
||||
output = SystemCTLStatusKeywords(ssh_connection).get_status(service_name)
|
||||
ptp_service_status_output = PTP4LStatusOutput(output)
|
||||
|
||||
expected_service_status = "active (running)"
|
||||
observed_service_status = ptp_service_status_output.get_ptp4l_object(name).get_active()
|
||||
get_command = ptp_service_status_output.get_ptp4l_object(name).get_command()
|
||||
|
||||
# From the input string "cmdline_opts='-s enpXXs0f2 -O -37 -m'"
|
||||
# The extracted output string is '-s enpXXs0f2 -O -37 -m'
|
||||
instance_parameter = eval(instance_parameters.split("=")[1])
|
||||
|
||||
if expected_service_status in observed_service_status and instance_parameter in get_command :
|
||||
get_logger().log_info(f"Validation Successful - systemctl status {service_name}")
|
||||
else:
|
||||
get_logger().log_info(f"Validation Failed - systemctl status {service_name}")
|
||||
get_logger().log_info(f"Expected service status: {expected_service_status}")
|
||||
get_logger().log_info(f"Observed service status: {observed_service_status}")
|
||||
get_logger().log_info(f"Expected instance parameter: {instance_parameter}")
|
||||
get_logger().log_info(f"Observed instance parameter: {get_command}")
|
||||
raise Exception("Validation Failed")
|
||||
|
||||
|
@@ -65,7 +65,7 @@ class CatPtpCguParser:
|
||||
"""
|
||||
cgu: PtpCguComponentObject = None
|
||||
|
||||
match = re.match(r"Found (\S+) CGU", self.cat_ptp_cgu_output[0])
|
||||
match = re.match(r"(Found (\S+) CGU|Password: Found (\S+) CGU)", self.cat_ptp_cgu_output[0]) # Ask about this
|
||||
if match:
|
||||
chip_model = match.group(1)
|
||||
config_version_match = re.search(
|
||||
|
@@ -65,7 +65,7 @@ class DefaultDataSetOutput:
|
||||
self.pmc_get_default_data_set_object.set_clock_identity(output_values["clockIdentity"])
|
||||
|
||||
if "domainNumber" in output_values:
|
||||
self.pmc_get_default_data_set_object.set_domain_number(output_values["domainNumber"])
|
||||
self.pmc_get_default_data_set_object.set_domain_number(int(output_values["domainNumber"]))
|
||||
|
||||
if "free_running" in output_values:
|
||||
self.pmc_get_default_data_set_object.set_free_running(int(output_values["free_running"]))
|
||||
@@ -109,6 +109,9 @@ class DefaultDataSetOutput:
|
||||
if "time_stamping" in output_values:
|
||||
self.get_pmc_get_default_data_set_object().set_time_stamping(output_values["time_stamping"])
|
||||
|
||||
if "tx_timestamp_timeout" in output_values:
|
||||
self.get_pmc_get_default_data_set_object().set_tx_timestamp_timeout(int(output_values["tx_timestamp_timeout"]))
|
||||
|
||||
if "uds_address" in output_values:
|
||||
self.get_pmc_get_default_data_set_object().set_uds_address(output_values["uds_address"])
|
||||
|
||||
|
@@ -1,3 +1,4 @@
|
||||
import re
|
||||
import time
|
||||
from multiprocessing import get_logger
|
||||
from time import sleep
|
||||
@@ -19,6 +20,77 @@ class GnssKeywords(BaseKeyword):
|
||||
Initializes the GnssKeywords.
|
||||
"""
|
||||
|
||||
def get_pci_slot_name(self, hostname: str, interface: str) -> str:
|
||||
"""
|
||||
Retrieves the PCI_SLOT_NAME from the uevent file for a given PTP interface.
|
||||
|
||||
Args:
|
||||
hostname (str) : The name of the host
|
||||
interface (str): The name of the ptp interface (e.g., "enp138s0f0").
|
||||
|
||||
Returns:
|
||||
str: The PCI slot name if found, otherwise None.
|
||||
|
||||
Raises:
|
||||
Exception: raised when PCI_SLOT_NAME not found
|
||||
"""
|
||||
lab_connect_keywords = LabConnectionKeywords()
|
||||
ssh_connection = lab_connect_keywords.get_ssh_for_hostname(hostname)
|
||||
|
||||
# The GNSS signal will always be on port 0 of the NIC, even if ts2phc uses ports 1, 2, 3, and so on.
|
||||
interface_name = f"{interface[:-1]}0"
|
||||
uevent_path = f"/sys/class/net/{interface_name}/device/uevent"
|
||||
|
||||
uevent_content = ssh_connection.send(f"grep PCI_SLOT_NAME {uevent_path}")
|
||||
|
||||
# Use regex to find the PCI_SLOT_NAME
|
||||
match = re.search(r"PCI_SLOT_NAME=(.*)", " ".join(uevent_content))
|
||||
if match:
|
||||
return match.group(1).strip() # Return the captured value, removing leading/trailing spaces
|
||||
else:
|
||||
raise Exception(f"PCI_SLOT_NAME not found in {uevent_path}")
|
||||
|
||||
def get_gnss_serial_port_from_gnss_directory(self, hostname: str, interface: str) -> str:
|
||||
"""
|
||||
Get GNSS serial port from the specified gnss directory.
|
||||
|
||||
Args:
|
||||
hostname (str) : The name of the host
|
||||
interface (str): The name of the PTP interface (e.g., "enp138s0f0").
|
||||
|
||||
Returns:
|
||||
str: The GNSS serial port value (e.g., "gnss0") if found, otherwise None.
|
||||
"""
|
||||
lab_connect_keywords = LabConnectionKeywords()
|
||||
ssh_connection = lab_connect_keywords.get_ssh_for_hostname(hostname)
|
||||
|
||||
pci_address = self.get_pci_slot_name(hostname, interface)
|
||||
|
||||
gnss_dir = f"/sys/bus/pci/devices/{pci_address}/gnss"
|
||||
|
||||
contents = ssh_connection.send(f"ls {gnss_dir}")
|
||||
if not contents:
|
||||
get_logger().log_info(f"The directory {gnss_dir} is empty.")
|
||||
return None
|
||||
|
||||
return " ".join(contents).strip() # Return the captured value in str, removing leading/trailing spaces
|
||||
|
||||
def extract_gnss_port(self, instance_parameters: str) -> str:
|
||||
"""
|
||||
Extracts the GNSS serial port value from a ts2phc.nmea_serialport configuration string using regex.
|
||||
|
||||
Args:
|
||||
instance_parameters (str): The string containing the ts2phc.nmea_serialport setting.
|
||||
|
||||
Returns:
|
||||
str: The GNSS serial port value (e.g., "gnss0") if found, otherwise None.
|
||||
"""
|
||||
match = re.search(r"ts2phc\.nmea_serialport\s*=\s*/dev/([^ ]*)", instance_parameters)
|
||||
if match:
|
||||
return match.group(1)
|
||||
else:
|
||||
return None
|
||||
|
||||
def gnss_power_on(self, hostname: str, nic: str) -> None:
|
||||
"""
|
||||
Power on gnss
|
||||
@@ -88,6 +160,8 @@ class GnssKeywords(BaseKeyword):
|
||||
expected_pps_dpll_status (list): expected list of PPS DPLL status values.
|
||||
timeout (int): The maximum time (in seconds) to wait for the match.
|
||||
polling_sleep_time (int): The time period to wait to receive the expected output.
|
||||
|
||||
Returns: None
|
||||
|
||||
Raises:
|
||||
TimeoutError: raised when validate does not equal in the required time
|
||||
|
@@ -232,7 +232,7 @@ class PMCGetDefaultDataSetObject:
|
||||
"""
|
||||
self.clock_identity = clock_identity
|
||||
|
||||
def get_domain_number(self) -> str:
|
||||
def get_domain_number(self) -> int:
|
||||
"""
|
||||
Getter for domain_number
|
||||
|
||||
@@ -242,7 +242,7 @@ class PMCGetDefaultDataSetObject:
|
||||
"""
|
||||
return self.domain_number
|
||||
|
||||
def set_domain_number(self, domain_number: str):
|
||||
def set_domain_number(self, domain_number: int):
|
||||
"""
|
||||
Setter for domain_number
|
||||
|
||||
|
@@ -73,7 +73,7 @@ class PMCGetDefaultDataSetOutput:
|
||||
self.pmc_get_default_data_set_object.set_clock_identity(output_values["clockIdentity"])
|
||||
|
||||
if "domainNumber" in output_values:
|
||||
self.pmc_get_default_data_set_object.set_domain_number(output_values["domainNumber"])
|
||||
self.pmc_get_default_data_set_object.set_domain_number(int(output_values["domainNumber"]))
|
||||
|
||||
if "free_running" in output_values:
|
||||
self.pmc_get_default_data_set_object.set_free_running(int(output_values["free_running"]))
|
||||
|
@@ -8,6 +8,7 @@ from keywords.ptp.pmc.objects.pmc_get_parent_data_set_output import PMCGetParent
|
||||
from keywords.ptp.pmc.objects.pmc_get_port_data_set_output import PMCGetPortDataSetOutput
|
||||
from keywords.ptp.pmc.objects.pmc_get_time_properties_data_set_output import PMCGetTimePropertiesDataSetOutput
|
||||
from keywords.ptp.pmc.objects.pmc_get_time_status_np_output import PMCGetTimeStatusNpOutput
|
||||
from keywords.ptp.pmc.objects.pmc_get_port_data_set_output import PMCGetPortDataSetOutput
|
||||
|
||||
|
||||
class PMCKeywords(BaseKeyword):
|
||||
@@ -153,16 +154,12 @@ class PMCKeywords(BaseKeyword):
|
||||
def pmc_get_default_data_set(self, config_file: str, socket_file: str, unicast: bool = True, boundry_clock: int = 0) -> PMCGetDefaultDataSetOutput:
|
||||
"""
|
||||
Gets the default data set
|
||||
|
||||
Args:
|
||||
config_file (str): the config file
|
||||
socket_file (str): the socket file
|
||||
unicast (bool): true to use unicast
|
||||
boundry_clock (int): the boundry clock
|
||||
|
||||
Returns:
|
||||
PMCGetDefaultDataSetOutput: the default dataset output
|
||||
|
||||
Example: PMCKeywords(ssh_connection).pmc_get_default_data_set('/etc/linuxptp/ptpinstance/ptp4l-ptp5.conf', ' /var/run/ptp4l-ptp5')
|
||||
|
||||
"""
|
||||
@@ -172,6 +169,24 @@ class PMCKeywords(BaseKeyword):
|
||||
pmc_get_default_data_set_output = PMCGetDefaultDataSetOutput(output)
|
||||
return pmc_get_default_data_set_output
|
||||
|
||||
def pmc_get_port_data_set(self, config_file: str, socket_file: str, unicast: bool = True, boundry_clock: int = 0) -> PMCGetPortDataSetOutput:
|
||||
"""
|
||||
Gets the port data set
|
||||
Args:
|
||||
config_file (str): the config file
|
||||
socket_file (str): the socket file
|
||||
unicast (bool): true to use unicast
|
||||
boundry_clock (int): the boundry clock
|
||||
|
||||
Example: PMCKeywords(ssh_connection).pmc_get_port_data_set('/etc/linuxptp/ptpinstance/ptp4l-ptp5.conf', ' /var/run/ptp4l-ptp5')
|
||||
|
||||
"""
|
||||
cmd = f"pmc {'-u' if unicast else ''} -b {boundry_clock} -f {config_file} -s {socket_file} 'GET PORT_DATA_SET'"
|
||||
|
||||
output = self.ssh_connection.send_as_sudo(cmd)
|
||||
pmc_get_port_data_set_output = PMCGetPortDataSetOutput(output)
|
||||
return pmc_get_port_data_set_output
|
||||
|
||||
def pmc_get_domain(self, config_file: str, socket_file: str, unicast: bool = True, boundry_clock: int = 0) -> PMCGetDomainOutput:
|
||||
"""
|
||||
Gets the domain
|
||||
|
@@ -80,7 +80,7 @@ class PTP4LStatusOutput:
|
||||
"""
|
||||
Getter for ptp4l object with the given service name
|
||||
Args:
|
||||
service_name (): the name of the service
|
||||
service_name (str): the name of the service (e.g., "phc1")
|
||||
|
||||
Returns: PTP4LStatusObject
|
||||
|
||||
|
@@ -46,7 +46,7 @@ class PTP4LStatusParser:
|
||||
for line in self.ptp4l_status_output:
|
||||
line = line.strip()
|
||||
if line.startswith('●'): # we have a new service to get values for
|
||||
service_name = line.split('@')[1].split(' ')[0] # format ptp4l@ptp1.service - Precision Time Protocol (PTP) service
|
||||
service_name = line.split('@')[1].split(' ')[0].replace('.service','') # format ptp4l@ptp1.service - Precision Time Protocol (PTP) service
|
||||
services[service_name] = {}
|
||||
current_service = services[service_name]
|
||||
elif line.startswith('└─') and current_service is not None:
|
||||
|
@@ -39,6 +39,12 @@ class PTP4LSetup:
|
||||
ptp_interfaces.append(ptp_host_ifs_dict[ptp_interface_name])
|
||||
self.ptp_interfaces = ptp_interfaces
|
||||
|
||||
self.ptp_role = "MASTER" # default value is MASTER
|
||||
if "ptp_role" in setup_dict:
|
||||
self.ptp_role = setup_dict["ptp_role"]
|
||||
|
||||
self.port_state = setup_dict.get("port_state")
|
||||
|
||||
def __str__(self) -> str:
|
||||
"""
|
||||
String representation of this object.
|
||||
@@ -99,3 +105,22 @@ class PTP4LSetup:
|
||||
if ptp_interface.get_name() == interface_name:
|
||||
return ptp_interface
|
||||
raise Exception(f"There is no ptp interface named {interface_name} in the ptp4l setup.")
|
||||
|
||||
|
||||
def get_ptp_role(self) -> str:
|
||||
"""
|
||||
Gets the ptp role
|
||||
|
||||
Returns:
|
||||
str: ptp role
|
||||
"""
|
||||
return self.ptp_role
|
||||
|
||||
def get_port_state(self) -> str:
|
||||
"""
|
||||
Gets the port state
|
||||
|
||||
Returns:
|
||||
str: port state
|
||||
"""
|
||||
return self.port_state
|
||||
|
@@ -30,6 +30,10 @@ class PTPHostInterfaceSetup:
|
||||
raise Exception(f"The ptp host interface entry {self.name} must have controller_1_interfaces defined.")
|
||||
self.controller_1_interfaces = setup_dict["controller_1_interfaces"]
|
||||
|
||||
self.compute_0_interfaces = None
|
||||
if "compute_0_interfaces" in setup_dict:
|
||||
self.compute_0_interfaces = setup_dict.get("compute_0_interfaces")
|
||||
|
||||
def __str__(self):
|
||||
"""
|
||||
String representation of this object.
|
||||
@@ -75,3 +79,12 @@ class PTPHostInterfaceSetup:
|
||||
List[str]: The controller_1_interfaces of this ptp host interface setup.
|
||||
"""
|
||||
return self.controller_1_interfaces
|
||||
|
||||
def get_compute_0_interfaces(self) -> List[str]:
|
||||
"""
|
||||
Gets the compute_0_interfaces of this ptp host interface setup.
|
||||
|
||||
Returns:
|
||||
List[str]: The compute_0_interfaces of this ptp host interface setup.
|
||||
"""
|
||||
return self.compute_0_interfaces
|
||||
|
@@ -211,14 +211,14 @@
|
||||
name: "clock1if1",
|
||||
controller_0_interfaces: ["{{ controller_0.nic1.conn_to_spirent }}"],
|
||||
controller_1_interfaces: [],
|
||||
ptp_interface_parameter : "sma1={{ controller_0.nic1.sma1.name }}",
|
||||
ptp_interface_parameter : "sma1={{ controller_0.nic1.sma1.is_input_or_output }}",
|
||||
},
|
||||
|
||||
{
|
||||
name: "clock1if2",
|
||||
controller_0_interfaces: ["{{ controller_0.nic2.base_port }}"],
|
||||
controller_1_interfaces: [],
|
||||
ptp_interface_parameter : "sma1={{ controller_0.nic2.sma1.name }}",
|
||||
ptp_interface_parameter : "sma1={{ controller_0.nic2.sma1.is_input_or_output }}",
|
||||
},
|
||||
],
|
||||
|
||||
|
@@ -5,51 +5,54 @@
|
||||
|
||||
{
|
||||
name: "ptp1",
|
||||
instance_hostnames : ["controller-0", "controller-1","compute-0"] ,
|
||||
instance_parameters: "tx_timestamp_timeout=700 domainNumber=24 dataset_comparison=G.8275.x priority2=100 boundary_clock_jbod=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",
|
||||
"ptp1if2",
|
||||
]
|
||||
],
|
||||
ptp_role: "MASTER"
|
||||
},
|
||||
|
||||
{
|
||||
name: "ptp2",
|
||||
instance_hostnames : [],
|
||||
instance_parameters: "dataset_comparison=G.8275.x domainNumber=24 tx_timestamp_timeout=700 boundary_clock_jbod=1 priority2=110",
|
||||
instance_parameters: "priority2=110 dataset_comparison=G.8275.x tx_timestamp_timeout=700 boundary_clock_jbod=1 domainNumber=24",
|
||||
ptp_interface_names: [
|
||||
"ptp2if1",
|
||||
"ptp2if2"
|
||||
],
|
||||
ptp_role: "MASTER"
|
||||
},
|
||||
|
||||
{
|
||||
name: "ptp3",
|
||||
instance_hostnames : ["controller-0"],
|
||||
instance_parameters: "dataset_comparison=G.8275.x domainNumber=24 tx_timestamp_timeout=700 boundary_clock_jbod=1 priority2=100",
|
||||
instance_hostnames : ["controller-0", "compute-0"],
|
||||
instance_parameters: "priority2=100 dataset_comparison=G.8275.x tx_timestamp_timeout=700 boundary_clock_jbod=1 domainNumber=24",
|
||||
ptp_interface_names: [
|
||||
"ptp3if1",
|
||||
"ptp3if2"
|
||||
],
|
||||
ptp_role: "MASTER"
|
||||
},
|
||||
|
||||
{
|
||||
name: "ptp4",
|
||||
instance_hostnames : ["controller-1"],
|
||||
instance_parameters: "priority2=110 dataset_comparison=G.8275.x domainNumber=24 tx_timestamp_timeout=700 boundary_clock_jbod=1",
|
||||
instance_parameters: "boundary_clock_jbod=1 tx_timestamp_timeout=700 priority2=110 dataset_comparison=G.8275.x domainNumber=24",
|
||||
ptp_interface_names: [
|
||||
"ptp4if1",
|
||||
"ptp4if2"
|
||||
],
|
||||
ptp_role: "SLAVE"
|
||||
}
|
||||
|
||||
],
|
||||
|
||||
phc2sys : [
|
||||
|
||||
{
|
||||
name: "phc1",
|
||||
instance_hostnames : ["controller-0", "controller-1","compute-0"],
|
||||
instance_hostnames : ["controller-0", "compute-0", "controller-1"],
|
||||
instance_parameters: "cmdline_opts='-s {{controller_0.nic1.conn_to_proxmox}} -O -37 -m'",
|
||||
ptp_interface_names: [
|
||||
"phc1if1",
|
||||
@@ -68,7 +71,7 @@
|
||||
{
|
||||
name: "phc3",
|
||||
instance_hostnames : [],
|
||||
instance_parameters: "uds_address=/var/run/ptp4l-ptp3 domainNumber=24",
|
||||
instance_parameters: "domainNumber=24 uds_address=/var/run/ptp4l-ptp3",
|
||||
ptp_interface_names: [
|
||||
"phc3if1",
|
||||
],
|
||||
@@ -77,7 +80,7 @@
|
||||
{
|
||||
name: "phc4",
|
||||
instance_hostnames : [],
|
||||
instance_parameters: "uds_address=/var/run/ptp4l-ptp4 domainNumber=24",
|
||||
instance_parameters: "domainNumber=24 uds_address=/var/run/ptp4l-ptp4",
|
||||
ptp_interface_names: [
|
||||
"phc4if1",
|
||||
],
|
||||
@@ -86,41 +89,35 @@
|
||||
],
|
||||
|
||||
ts2phc : [
|
||||
|
||||
{
|
||||
name: "ts1",
|
||||
instance_hostnames : ["controller-0"],
|
||||
instance_hostnames : ["controller-1", "controller-0", "compute-0"],
|
||||
instance_parameters: "ts2phc.nmea_serialport=/dev/gnss0",
|
||||
ptp_interface_names: [
|
||||
"ts1if1",
|
||||
],
|
||||
}
|
||||
|
||||
},
|
||||
],
|
||||
|
||||
clock : [
|
||||
|
||||
{
|
||||
name: "clock1",
|
||||
instance_hostnames : ["controller-0"],
|
||||
instance_hostnames : ["controller-0","compute-0"],
|
||||
instance_parameters: "",
|
||||
ptp_interface_names: [
|
||||
"clock1if1",
|
||||
"clock1if2",
|
||||
],
|
||||
}
|
||||
|
||||
},
|
||||
],
|
||||
|
||||
},
|
||||
|
||||
ptp_host_ifs: [
|
||||
|
||||
{
|
||||
name: "ptp1if1",
|
||||
controller_0_interfaces: ["{{ controller_0.nic1.nic_connection.interface }}"], // Connection to controller1-nic1
|
||||
controller_1_interfaces: ["{{ controller_1.nic1.nic_connection.interface }}"], // Connection to controller0-nic1
|
||||
compute_0_interfaces: [],
|
||||
controller_0_interfaces: ["{{ controller_0.nic1.nic_connection.interface }}"],
|
||||
controller_1_interfaces: ["{{ controller_1.nic1.nic_connection.interface }}"],
|
||||
compute_0_interfaces: ["{{ compute_0.nic1.nic_connection.interface }}"],
|
||||
ptp_interface_parameter : "",
|
||||
},
|
||||
|
||||
@@ -150,9 +147,9 @@
|
||||
|
||||
{
|
||||
name: "ptp3if1",
|
||||
controller_0_interfaces: ["{{ controller_0.nic2.nic_connection.interface }}"], // Connection to Controller1 Nic 2
|
||||
controller_0_interfaces: ["{{ controller_0.nic2.nic_connection.interface }}"],
|
||||
controller_1_interfaces: [],
|
||||
compute_0_interfaces: [],
|
||||
compute_0_interfaces: ["{{ compute_0.nic2.nic_connection.interface }}"],
|
||||
ptp_interface_parameter : "",
|
||||
},
|
||||
|
||||
@@ -167,7 +164,7 @@
|
||||
{
|
||||
name: "ptp4if1",
|
||||
controller_0_interfaces: [],
|
||||
controller_1_interfaces: ["{{ controller_0.nic2.nic_connection.interface }}"], // Connection to Controller1 Nic 2
|
||||
controller_1_interfaces: ["{{ controller_1.nic2.nic_connection.interface }}"],
|
||||
compute_0_interfaces: [],
|
||||
ptp_interface_parameter : "",
|
||||
},
|
||||
@@ -207,16 +204,16 @@
|
||||
{
|
||||
name: "phc4if1",
|
||||
controller_0_interfaces: [],
|
||||
controller_1_interfaces: ["{{ controller_1.nic1.base_port }}", "{{ controller_1.nic2.base_port }}"],
|
||||
controller_1_interfaces: ["{{ controller_1.nic2.base_port }}"],
|
||||
compute_0_interfaces: [],
|
||||
ptp_interface_parameter :"",
|
||||
},
|
||||
|
||||
{
|
||||
name: "ts1if1",
|
||||
controller_0_interfaces: ["{{ controller_0.nic1.conn_to_proxmox }}", "{{ controller_0.nic2.base_port }}"],
|
||||
controller_1_interfaces: [],
|
||||
compute_0_interfaces: [],
|
||||
controller_0_interfaces: ["{{ controller_0.nic2.base_port }}", "{{ controller_0.nic1.conn_to_proxmox }}"],
|
||||
controller_1_interfaces: ["{{ controller_1.nic1.conn_to_proxmox }}"],
|
||||
compute_0_interfaces: ["{{ compute_0.nic1.nic_connection.interface }}", "{{ compute_0.nic2.nic_connection.interface }}"],
|
||||
ptp_interface_parameter : "",
|
||||
},
|
||||
|
||||
@@ -224,17 +221,15 @@
|
||||
name: "clock1if1",
|
||||
controller_0_interfaces: ["{{ controller_0.nic1.conn_to_proxmox }}"],
|
||||
controller_1_interfaces: [],
|
||||
compute_0_interfaces: [],
|
||||
ptp_interface_parameter : "sma1={{ controller_0.nic1.sma1.name }}",
|
||||
compute_0_interfaces: ["{{ compute_0.nic1.nic_connection.interface }}"],
|
||||
ptp_interface_parameter : "sma1={{ controller_0.nic1.sma1.is_input_or_output }}",
|
||||
},
|
||||
|
||||
{
|
||||
name: "clock1if2",
|
||||
controller_0_interfaces: ["{{ controller_0.nic2.base_port }}"],
|
||||
controller_1_interfaces: [],
|
||||
compute_0_interfaces: [],
|
||||
ptp_interface_parameter : "sma1={{ controller_0.nic2.sma1.name }}",
|
||||
compute_0_interfaces: ["{{ compute_0.nic2.nic_connection.interface }}"],
|
||||
ptp_interface_parameter : "sma1={{ controller_0.nic2.sma1.is_input_or_output }}",
|
||||
},
|
||||
],
|
||||
|
||||
}
|
||||
|
@@ -33,7 +33,7 @@ def test_ptp4l_service_status_output_parser():
|
||||
ptp4l_service_status_output = PTP4LStatusOutput(ptp4l_status_output)
|
||||
|
||||
# validate first service 'ptp1.service'
|
||||
ptp4l_status_object = ptp4l_service_status_output.get_ptp4l_object('ptp1.service')
|
||||
ptp4l_status_object = ptp4l_service_status_output.get_ptp4l_object('ptp1')
|
||||
|
||||
assert ptp4l_status_object.get_active() == 'active (running) since Mon 2025-02-10 18:36:34 UTC; 3 days ago'
|
||||
assert ptp4l_status_object.get_c_group() == '/system.slice/system-ptp4l.slice/ptp4l@ptp1.service'
|
||||
@@ -46,7 +46,7 @@ def test_ptp4l_service_status_output_parser():
|
||||
assert ptp4l_status_object.get_tasks() == '1 (limit: 150897)'
|
||||
|
||||
# validate second service 'ptp3.service
|
||||
ptp4l_status_object = ptp4l_service_status_output.get_ptp4l_object('ptp3.service')
|
||||
ptp4l_status_object = ptp4l_service_status_output.get_ptp4l_object('ptp3')
|
||||
|
||||
assert ptp4l_status_object.get_active() == 'active (running) since Wed 2025-02-12 16:22:23 UTC; 2 days ago'
|
||||
assert ptp4l_status_object.get_c_group() == '/system.slice/system-ptp4l.slice/ptp4l@ptp3.service'
|
||||
|
Reference in New Issue
Block a user