|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [RFC XEN PATCH 04/13] pytest: Add fixture that boot a machine
From: Anthony PERARD <anthony.perard@xxxxxxxxxx>
.. and power it off once a test using the fixture is done.
This IPMI class is using the `ssh` console of an HP Moonshot 1500
Chassis.
Signed-off-by: Anthony PERARD <anthony.perard@xxxxxxxxxx>
---
Maybe we could rename the class to Machine as a lib to control the
machine behavior, and access it's console.
---
automation/pytest/lib/ipmi.py | 69 ++++++++++++++++++++++++++++++++++
automation/pytest/test_boot.py | 17 +++++++++
2 files changed, 86 insertions(+)
create mode 100644 automation/pytest/lib/ipmi.py
diff --git a/automation/pytest/lib/ipmi.py b/automation/pytest/lib/ipmi.py
new file mode 100644
index 000000000000..0d3b085f704c
--- /dev/null
+++ b/automation/pytest/lib/ipmi.py
@@ -0,0 +1,69 @@
+import logging
+import paramiko
+import re
+
+
+class IPMI:
+ def __init__(self, *,
+ hostname: str,
+ username: str,
+ password: str,
+ blade_node: str,
+ ) -> None:
+ self.hostname = hostname
+ self.username = username
+ self.password = password
+ self.blade_node = blade_node
+
+ self.channel = None
+
+ def _new_client(self):
+ ssh = paramiko.client.SSHClient()
+ ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
+ ssh.connect(self.hostname,
+ username=self.username,
+ password=self.password)
+ return ssh
+
+ def _run_cmd(self, command: str, debug_print: bool = True) -> str:
+ with self._new_client() as ssh:
+ stdin, stdout, stderr = ssh.exec_command(command)
+ output = stdout.read().decode()
+ if debug_print:
+ for line in output.splitlines():
+ if line in ['']:
+ continue
+ logging.debug(line.rstrip())
+ # the command's exit status (0 = success, 1 = failure)
+ # stdout.channel.recv_exit_status()
+ return output
+
+ def _power(self, state: str) -> None:
+ assert state in ["on", "off force"]
+ logging.info(f"Set power {state.split(' ')[0]} {self.blade_node}")
+ command = f"set node power {state} {self.blade_node}"
+ output = self._run_cmd(command, debug_print=False)
+ m = re.search(f"{self.blade_node}: #Node 1 (.*)\\r$",
+ output,
+ flags=re.M)
+ if m:
+ logging.info(f"-> {m[1]}")
+ else:
+ logging.warning(f"Failed to parse 'set power' command output:
'{output}'")
+
+ def power_status(self):
+ command = f"show node power {self.blade_node}"
+ output = self._run_cmd(command, debug_print=False)
+ m = re.search(f"{self.blade_node}: #Node 1\\r\\n\\s+Power State:
(\\S+)\\r$",
+ output,
+ flags=re.M)
+ if m:
+ logging.info(f"Machine is {m[1]}")
+ else:
+ logging.warning(f"Failed to match for \"Power State\" in
'{output}'")
+
+ def power_on(self):
+ self._power('on')
+
+ def power_off(self):
+ self._power('off force')
diff --git a/automation/pytest/test_boot.py b/automation/pytest/test_boot.py
index 661c2a59e4fe..b7610736fa25 100644
--- a/automation/pytest/test_boot.py
+++ b/automation/pytest/test_boot.py
@@ -1,9 +1,11 @@
import os
from pathlib import Path
import pytest
+from typing import Generator
from lib.boot_binary import BootBinary
from lib.net_boot import NetBoot
+from lib.ipmi import IPMI
@pytest.fixture
@@ -41,3 +43,18 @@ def prepare_netboot(prepare_rootfs: BootBinary,
xenroot_path: Path) -> None:
prepare_rootfs.dom0_tools(),
]
netboot.prepare_tftp(xenroot_path, rootfs_paths)
+
+
+@pytest.fixture
+def machine_on_ipmi(prepare_netboot: None) -> Generator[IPMI]:
+ ipmi = IPMI(
+ hostname=os.environ['IPMI_HOSTNAME'],
+ username=os.environ['MOON_CONSOLE_USER'],
+ password=os.environ['MOON_CONSOLE_PASS'],
+ blade_node=os.environ['IPMI_BLADE_NODE'],
+ )
+ ipmi.power_off()
+ ipmi.power_status()
+ ipmi.power_on()
+ yield ipmi
+ ipmi.power_off()
--
Anthony PERARD
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |