diff --git a/lisa/sut_orchestrator/baremetal/ip_getter.py b/lisa/sut_orchestrator/baremetal/ip_getter.py index 3b7a598153..84e0d026dc 100644 --- a/lisa/sut_orchestrator/baremetal/ip_getter.py +++ b/lisa/sut_orchestrator/baremetal/ip_getter.py @@ -2,19 +2,28 @@ # Licensed under the MIT license. import re -from dataclasses import dataclass +from dataclasses import dataclass, field from typing import Type +import requests from dataclasses_json import dataclass_json from lisa import schema -from lisa.util import InitializableMixin, get_matched_str, subclasses +from lisa.util import ( + InitializableMixin, + LisaException, + field_metadata, + get_matched_str, + subclasses, +) from lisa.util.logger import get_logger from .schema import IpGetterSchema class IpGetterChecker(subclasses.BaseClassWithRunbookMixin, InitializableMixin): + ip_addr_regex = re.compile(r"(?P[\d.]+)", re.M) + def __init__( self, runbook: IpGetterSchema, @@ -38,9 +47,6 @@ class FileSingleSchema(IpGetterSchema): class FileSingleChecker(IpGetterChecker): - # ipaddr=X.XX.XXX.X - __ip_addr_regex = re.compile(r"(?P[\d.]+)", re.M) - def __init__( self, runbook: FileSingleSchema, @@ -60,9 +66,46 @@ def type_schema(cls) -> Type[schema.TypedSchema]: def get_ip(self) -> str: with open(self.file_single_runbook.file) as f: lines = f.readlines() - matched = get_matched_str(" ".join(lines), self.__ip_addr_regex, True) + matched = get_matched_str(" ".join(lines), self.ip_addr_regex, True) assert matched is not None, ( f"Could not get ip from content of file {self.file_single_runbook.file}" f" {' '.join(lines)}" ) return matched + + +@dataclass_json() +@dataclass +class HttpSchema(IpGetterSchema): + url: str = field(default="", metadata=field_metadata(required=True)) + + +class HttpChecker(IpGetterChecker): + def __init__( + self, + runbook: HttpSchema, + ) -> None: + super().__init__(runbook=runbook) + self.http_runbook: HttpSchema = self.runbook + self._log = get_logger("http", self.__class__.__name__) + + @classmethod + def type_name(cls) -> str: + return "http" + + @classmethod + def type_schema(cls) -> Type[schema.TypedSchema]: + return HttpSchema + + def get_ip(self) -> str: + url = self.http_runbook.url + response = requests.get(url, timeout=20) + if response.status_code == 200: + matched = get_matched_str(response.text, self.ip_addr_regex, True) + assert ( + matched is not None + ), f"Could not get ip from content from {url}: content is {response.text}" + return matched + raise LisaException( + f"Failed to fetch content. Status code: {response.status_code}" + ) diff --git a/lisa/sut_orchestrator/baremetal/readychecker.py b/lisa/sut_orchestrator/baremetal/readychecker.py index eed06107e4..fedb066796 100644 --- a/lisa/sut_orchestrator/baremetal/readychecker.py +++ b/lisa/sut_orchestrator/baremetal/readychecker.py @@ -5,11 +5,18 @@ from dataclasses import dataclass from typing import Type, cast +import requests from dataclasses_json import dataclass_json from lisa import schema from lisa.node import Node, RemoteNode -from lisa.util import InitializableMixin, check_till_timeout, fields_to_dict, subclasses +from lisa.util import ( + InitializableMixin, + LisaException, + check_till_timeout, + fields_to_dict, + subclasses, +) from lisa.util.logger import get_logger from lisa.util.shell import try_connect @@ -117,3 +124,53 @@ def is_ready(self, node: Node) -> bool: try_connect(context.connection, ssh_timeout=self.ssh_runbook.timeout) self._log.debug("client has been connected successfully") return True + + +@dataclass_json() +@dataclass +class HttpSchema(ReadyCheckerSchema): + # http://ip/client.ip + url: str = "" + # http://ip/cleanup.php, it contains the logic to remove the client.ip + cleanup_url: str = "" + + +class HttpChecker(ReadyChecker): + def __init__( + self, + runbook: HttpSchema, + ) -> None: + super().__init__(runbook=runbook) + self.http_check_runbook: HttpSchema = self.runbook + self._log = get_logger("http", self.__class__.__name__) + + @classmethod + def type_name(cls) -> str: + return "http" + + @classmethod + def type_schema(cls) -> Type[schema.TypedSchema]: + return HttpSchema + + def clean_up(self) -> None: + if self.http_check_runbook.cleanup_url: + # in cleanup_url, it contains the logic to remove file + # which is the flag of client ready + response = requests.get(self.http_check_runbook.cleanup_url, timeout=20) + if response.status_code == 200: + self._log.debug( + f"The url {self.http_check_runbook.url} has been removed" + ) + else: + raise LisaException( + f"Failed to remove url {self.http_check_runbook.url}" + ) + + def is_ready(self, node: Node) -> bool: + check_till_timeout( + lambda: (requests.get(self.http_check_runbook.url, timeout=2)).status_code + == 200, + timeout_message=f"wait for {self.http_check_runbook.url} ready", + timeout=self.http_check_runbook.timeout, + ) + return True