Files
test/keywords/ptp/ptp4l/ptp_service_status_validator.py
abhinav_ayyapasetti 1fabfc59ee pylint fix
Description:
- Added data types to function arguments and return values.
- Added blank lines between summary and description in docstrings to match style guidelines.
- Removed extra blank lines after docstrings.
- Added a missing import for SSHConnection in sma_keywords.py.
- Capitalized the first word in each docstring to comply with style guide rules.
- Improved docstring for PTP4LStatusObject constructor with detailed attribute descriptions

Change-Id: Idada0b0b0c3f895a16f4b439beaaaf071597a16a

Change-Id: I8e7756d32eb56a2aa85b277a91b26cc6280d1c56
Signed-off-by: aabhinav <ayyapasetti.abhinav@windriver.com>
2025-07-09 19:38:14 +00:00

165 lines
7.1 KiB
Python

import re
from datetime import datetime, timedelta, timezone
from multiprocessing import get_logger
from framework.ssh.ssh_connection import SSHConnection
from framework.validation.validation import validate_equals, validate_str_contains
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.ptp4l.objects.ptp4l_status_output import PTP4LStatusOutput
class PTPServiceStatusValidator(BaseKeyword):
"""
A class to validate the status and parameters of PTP (Precision Time Protocol)
services on a target host using systemctl.
"""
def __init__(self, ssh_connection: SSHConnection):
"""
Initializes the PTPServiceStatusValidator with an SSH connection.
Args:
ssh_connection (SSHConnection): An instance of an SSH connection.
"""
self.ssh_connection = ssh_connection
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: This method does not return anything.
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()
validate_str_contains(observed_service_status, expected_service_status, f"systemctl status {service_name}")
def verify_status_and_instance_parameters_on_hostname(self, hostname: str, name: str, service_name: str, instance_parameters: str) -> None:
"""
Verify systemctl 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)
service_status_output = PTP4LStatusOutput(output)
expected_service_status = "active (running)"
observed_service_status = service_status_output.get_ptp4l_object(name).get_active()
get_command = 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")
def _is_service_event_recent(self, status_line: str, threshold_seconds: int) -> bool:
"""
Determines if a service event (start, stop, restart) occurred within a given threshold.
Args:
status_line (str): A line like:
'active (running) since Wed 2025-05-28 13:00:00 UTC; 10s ago'
'inactive (dead) since Wed 2025-05-28 12:22:49 UTC; 52min ago'
threshold_seconds (int): Time threshold in seconds.
Returns:
bool: True if the event occurred within the threshold.
"""
match = re.search(r"since (.+? UTC);\s+(\d+)(s|min|h) ago", status_line)
if not match:
raise ValueError(f"Could not parse systemctl status line: {status_line}")
datetime_str, value_str, unit = match.groups()
try:
datetime.strptime(datetime_str.strip(), "%a %Y-%m-%d %H:%M:%S UTC")
except ValueError:
raise ValueError(f"Could not parse timestamp: {datetime_str.strip()}")
# Convert "52min" or "10s" into timedelta
value = int(value_str)
if unit == "s":
delta = timedelta(seconds=value)
elif unit == "min":
delta = timedelta(minutes=value)
elif unit == "h":
delta = timedelta(hours=value)
else:
raise ValueError(f"Unsupported time unit: {unit}")
# Estimate the actual event time from 'ago'
now = datetime.now(timezone.utc)
estimated_event_time = now - delta
# Compare time difference
return (now - estimated_event_time).total_seconds() <= threshold_seconds
def verify_service_status_and_recent_event(self, service_name: str, instance_name: str, threshold_seconds: int, expected_service_status: str = "active (running)") -> None:
"""
Verifies that the given PTP service is in the expected systemctl status and
that its most recent state change occurred within the given threshold.
Args:
service_name (str): service name (e.g., "phc2sys")
instance_name (str): name of instance (e.g., "phc1")
threshold_seconds (int): Time threshold in seconds to check service recency.
expected_service_status (str, optional): Expected status string to match from `systemctl` (default: "active (running)").
Returns: None
Raises:
Exception: If service status is not as expected, or event is too old.
"""
template_instance = f"{service_name}@{instance_name}.service"
output = SystemCTLStatusKeywords(self.ssh_connection).get_status(template_instance)
service_status_output = PTP4LStatusOutput(output)
service_status = service_status_output.get_ptp4l_object(instance_name)
status_line = service_status.get_active()
# Check if the service event (start/stop/restart) was recent
recent_event = self._is_service_event_recent(status_line, threshold_seconds)
validate_equals(recent_event, True, "Service event recency check")
# Validate actual status
validate_str_contains(status_line, expected_service_status, f"systemctl status {template_instance}")