Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
iputils-ping \
nut-client \
net-tools \
ipmitool \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*

Expand Down
43 changes: 37 additions & 6 deletions example.config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,40 @@ wake_on:
reattempt_delay: 30 # Minimum time (in seconds) between WOL attempts per client

clients:
- name: "client 1" # Human-readable name
host: 192.168.0.100 # IP address preferred for reliability
mac: 38:f7:cd:c5:87:6b
- name: "client 2"
host: hostname.local # You can use a hostname if it resolves to a reachable interface
mac: auto # MAC will be resolved using ARP at runtime
- name: "Server A" # Human-readable name
type: wol # Choose a client type, wol, idrac, ilo, sm_ipmi(supermicro)
host: 192.168.0.100 # IP address preferred for reliability
mac: aa:bb:cc:dd:ee:ff

- name: "Server B" # Human-readable name
type: wol # Choose a client type, wol, idrac, ilo, sm_ipmi(supermicro)
host: 192.168.0.101 # IP address preferred for reliability
mac: auto # MAC will be resolved using ARP at runtime

# if no type is provided, it will default to wol for backwards compatibility
- name: "Server C"
host: 192.168.0.102
mac: aa:bb:cc:dd:ee:ff

- name: Dell R740
type: idrac
host: server.local # You can use a hostname if it resolves to a reachable interface
ipmi_host: 192.168.0.200
username: root
password: calvin
verify_ssl: true

- name: Supermicro Server
type: sm_ipmi
host: 192.168.0.104
ipmi_host: 192.168.0.204
username: admin
password: admin

- name: HP iLO Server
type: ilo
host: 192.168.0.105
ipmi_host: 192.168.0.205
username: admin
password: admin
verify_ssl: false
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ Pygments==2.19.1
pytest==8.4.0
PyYAML==6.0.2
wakeonlan==3.1.0
requests==2.31.0
1 change: 1 addition & 0 deletions tests/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Tests for wolnut
71 changes: 71 additions & 0 deletions tests/test_all_client_types.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
"""
Comprehensive test for all client types in the tagged union
"""

from wolnut.client import (
IdracClientConfig,
IloClientConfig,
IpmiClientConfig,
WolClientConfig,
)
from wolnut.config import create_client_config


def test_wol_client():
# Test WOL client
wol_data = {
"name": "WOL Server",
"type": "wol",
"host": "192.168.1.100",
"mac": "aa:bb:cc:dd:ee:ff",
}
wol_client = create_client_config(wol_data)
assert isinstance(wol_client, WolClientConfig)
assert wol_client.type == "wol"


def test_idrac_client():
# Test iDRAC client
idrac_data = {
"name": "Dell iDRAC Server",
"type": "idrac",
"host": "192.168.1.101",
"ipmi_host": "192.168.1.102",
"username": "admin",
"password": "secret",
"verify_ssl": False,
}
idrac_client = create_client_config(idrac_data)
assert isinstance(idrac_client, IdracClientConfig)
assert idrac_client.type == "idrac"


def test_ilo_client():
# Test iLO client
ilo_data = {
"name": "HP iLO Server",
"type": "ilo",
"host": "192.168.1.103",
"ipmi_host": "192.168.1.104",
"username": "admin",
"password": "secret",
"verify_ssl": True,
}
ilo_client = create_client_config(ilo_data)
assert isinstance(ilo_client, IloClientConfig)
assert ilo_client.type == "ilo"


def test_ipmi_client():
# Test IPMI client
ipmi_data = {
"name": "IPMI Server",
"type": "ipmi",
"host": "192.168.1.105",
"ipmi_host": "192.168.1.106",
"username": "admin",
"password": "secret",
}
ipmi_client = create_client_config(ipmi_data)
assert isinstance(ipmi_client, IpmiClientConfig)
assert ipmi_client.type == "ipmi"
132 changes: 132 additions & 0 deletions tests/test_config_loading.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
"""
Test script to verify the configuration can be loaded from YAML
"""

import os
import tempfile

import yaml

from wolnut.client import (
IdracClientConfig,
IloClientConfig,
IpmiClientConfig,
WolClientConfig,
)
from wolnut.config import NutConfig, WakeOnConfig, WolnutConfig, load_config


def test_config_loading():
# Create a temporary config file
test_config = {
"log_level": "INFO",
"nut": {"ups": "ups@localhost", "username": "upsmon", "password": "password"},
"poll_interval": 15,
"wake_on": {
"restore_delay_sec": 30,
"min_battery_percent": 25,
"client_timeout_sec": 600,
"reattempt_delay": 30,
},
"clients": [
{
"name": "Server A",
"type": "wol",
"host": "192.168.0.100",
"mac": "aa:bb:cc:dd:ee:ff",
},
# { # can't resolve MAC during tests
# "name": "Server B",
# "type": "wol",
# "host": "192.168.0.101",
# "mac": "auto",
# },
{
"name": "Server C",
"host": "192.168.0.102",
"mac": "aa:bb:cc:dd:ee:ff",
},
{
"name": "Dell iDRAC Server",
"type": "idrac",
"host": "server.local",
"ipmi_host": "192.168.0.203",
"username": "root",
"password": "calvin",
"verify_ssl": True,
},
{
"name": "Supermicro Server",
"type": "ipmi",
"host": "192.168.0.104",
"ipmi_host": "192.168.0.204",
"username": "admin",
"password": "admin",
},
{
"name": "HP iLO Server",
"type": "ilo",
"host": "192.168.0.105",
"ipmi_host": "192.168.0.205",
"username": "admin",
"password": "admin",
"verify_ssl": False,
},
],
}

expected = WolnutConfig(
nut=NutConfig(ups="ups@localhost", username="upsmon", password="password"),
poll_interval=15,
wake_on=WakeOnConfig(
restore_delay_sec=30,
min_battery_percent=25,
client_timeout_sec=600,
reattempt_delay=30,
),
clients=[
WolClientConfig(
name="Server A", host="192.168.0.100", mac="aa:bb:cc:dd:ee:ff"
),
# WolClientConfig(name="Server B", host="192.168.0.101", mac="auto"), # can't resolve MAC during tests
WolClientConfig(
name="Server C", host="192.168.0.102", mac="aa:bb:cc:dd:ee:ff"
),
IdracClientConfig(
name="Dell iDRAC Server",
host="server.local",
ipmi_host="192.168.0.203",
username="root",
password="calvin",
verify_ssl=True,
),
IpmiClientConfig(
name="Supermicro Server",
host="192.168.0.104",
ipmi_host="192.168.0.204",
username="admin",
password="admin",
),
IloClientConfig(
name="HP iLO Server",
host="192.168.0.105",
ipmi_host="192.168.0.205",
username="admin",
password="admin",
verify_ssl=False,
),
],
)

with tempfile.NamedTemporaryFile(mode="w", suffix=".yaml", delete=False) as f:
yaml.dump(test_config, f)
temp_config_path = f.name

try:
# Load the config
config = load_config(temp_config_path)

assert config == expected, f"Config does not match expected structure: {config}"
finally:
# Clean up
os.unlink(temp_config_path)
55 changes: 55 additions & 0 deletions tests/test_tagged_union.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
#!/usr/bin/env python3
"""
Test script to verify the tagged union configuration works correctly
"""

from wolnut.client import IdracClientConfig, WolClientConfig, create_client_config


def test_tagged_union():
# Test WOL client
wol_data = {
"name": "Test WOL",
"type": "wol",
"host": "192.168.1.100",
"mac": "aa:bb:cc:dd:ee:ff",
}

wol_client = create_client_config(wol_data)
print(f"WOL Client: {wol_client}")
assert isinstance(wol_client, WolClientConfig)
assert wol_client.name == "Test WOL"
assert wol_client.type == "wol"
assert wol_client.mac == "aa:bb:cc:dd:ee:ff"

# Test iDRAC client
idrac_data = {
"name": "Test iDRAC",
"type": "idrac",
"host": "192.168.1.101",
"ipmi_host": "192.168.1.102",
"username": "admin",
"password": "secret",
"verify_ssl": False,
}

idrac_client = create_client_config(idrac_data)
print(f"iDRAC Client: {idrac_client}")
assert isinstance(idrac_client, IdracClientConfig)
assert idrac_client.name == "Test iDRAC"
assert idrac_client.host == "192.168.1.101"
assert idrac_client.ipmi_host == "192.168.1.102"
assert idrac_client.username == "admin"
assert idrac_client.password == "secret"
assert idrac_client.verify_ssl == False

# Test backward compatibility - clients can still be accessed uniformly
clients = [wol_client, idrac_client]

for client in clients:
print(f"Client: {client.name}, Type: {client.type}, Host: {client.host}")
# Type-specific access
if client.type == "wol":
print(f" WOL MAC: {client.mac}")
elif client.type == "idrac":
print(f" iDRAC IPMI: {client.host}")
Loading