feat(profiles): support automatic ZFS RAID0 disk selection
CI / container-policy (push) Successful in 4s
CI / javascript-check (push) Successful in 13s
CI / python-tests (push) Successful in 1m10s
CI / container-verify (push) Skipped
CI / container-publish (push) Successful in 34s

This commit is contained in:
BartelLuis
2026-09-14 21:25:51 +02:00
parent 3c2faa40b4
commit 9a6dea34c4
7 changed files with 159 additions and 20 deletions
+95 -3
View File
@@ -58,8 +58,7 @@ def environment(tmp_path):
yield app, client, csrf
@pytest.fixture
def prepared(environment):
def prepare_host(environment, disk_setup=None, approve=True):
app, client, csrf = environment
secret = post(client, "/api/v1/secrets", {"name": "test-root", "value": ROOT_HASH}, csrf)
group = post(client, "/api/v1/groups", {"name": "test-lab", "site": "lab", "valid_hours": 1}, csrf)
@@ -74,6 +73,8 @@ def prepared(environment):
post(client, f"/api/v1/modules/{module['id']}/publish", publication, csrf)
profile_data = json.loads((Path(__file__).parents[1] / "docs" / "sample-profile.json").read_text())
profile_data["values"]["root_secret_id"] = secret["id"]
if disk_setup is not None:
profile_data["values"]["disk_setup"] = deepcopy(disk_setup)
installation = post(client, "/api/v1/profiles", profile_data, csrf)
post(client, f"/api/v1/profiles/{installation['id']}/publish", publication, csrf)
postinstall = post(client, "/api/v1/profiles", {"name": "test-postinstall", "kind": "postinstall",
@@ -86,7 +87,7 @@ def prepared(environment):
"installation_profile_id": installation["id"], "postinstall_profile_id": postinstall["id"], "iso_id": iso["id"]}, csrf)
run = post(client, f"/api/v1/hosts/{host['id']}/approve-install", {
"expected_version": host["version"], "valid_minutes": 30, "confirmation": host["fqdn"],
"disks_confirmed": True, "reason": "Dedicated simulated test host"}, csrf)
"disks_confirmed": True, "reason": "Dedicated simulated test host"}, csrf) if approve else None
payload = {"$schema": {"version": "1.0"}, "product": {"product": "pve"},
"iso": {"release": "9.1", "build": "1"}, "dmi": {"system": {"uuid": HOST_UUID, "serial": "LAB-HOST-001"}},
"network-interfaces": [{"mac": HOST_MAC}]}
@@ -95,6 +96,11 @@ def prepared(environment):
"host": host, "run": run, "payload": payload, "identities": identities}
@pytest.fixture
def prepared(environment):
return prepare_host(environment)
def answer(prepared, payload=None):
return prepared["client"].post("/installer/v1/answer", json=payload or prepared["payload"],
headers={"Authorization": f"Bearer {prepared['group']['token']}"})
@@ -185,12 +191,98 @@ def test_concurrent_installer_retries_reserve_one_immutable_answer(prepared):
native = tomllib.loads(responses[0].text)
assert native["global"]["fqdn"] == prepared["host"]["fqdn"]
assert native["disk-setup"]["filter"] == {"ID_SERIAL_SHORT": "LAB_SYSTEM_DISK_001"}
assert native["disk-setup"]["filter-match"] == "all"
assert "selection" not in native["disk-setup"]
assert "expected_count" not in native["disk-setup"]
assert prepared["run"]["snapshot"]["warnings"] == [
"Die Hardwarekennung dient der Zuordnung im kontrollierten Provisionierungsnetz."]
with prepared["app"].state.db.connection() as connection:
assert connection.execute("SELECT count(*) FROM runs").fetchone()[0] == 1
assert connection.execute("SELECT status FROM approvals").fetchone()[0] == "consumed"
@pytest.mark.parametrize("evidence", [None, "Single-target-disk laboratory inventory"])
def test_automatic_zfs_raid0_preview_approval_and_native_answer(environment, evidence):
disk_setup = {"filesystem": "zfs", "selection": "all", "zfs": {"raid": "raid0", "ashift": 12}}
if evidence is not None:
disk_setup["inventory_evidence"] = evidence
configured = prepare_host(environment, disk_setup, approve=False)
client, csrf, host = configured["client"], configured["csrf"], configured["host"]
preview = client.get(f"/api/v1/hosts/{host['id']}/preview")
assert preview.status_code == 200, preview.text
snapshot = preview.json()
assert snapshot["disks"] == disk_setup
assert snapshot["warnings"][-1] == (
"Automatische Datenträgerwahl: Alle vom Installer erkannten Zielplatten werden verwendet. "
"Dieses Profil ist für Server mit genau einer Zielplatte vorgesehen.")
approval = {"expected_version": host["version"], "valid_minutes": 30,
"confirmation": host["fqdn"], "disks_confirmed": False, "reason": "Single-target-disk simulation"}
endpoint = f"/api/v1/hosts/{host['id']}/approve-install"
assert client.post(endpoint, json=approval, headers=csrf).status_code == 422
configured["run"] = post(client, endpoint, {**approval, "disks_confirmed": True}, csrf)
assert configured["run"]["snapshot"] == snapshot
response = answer(configured)
assert response.status_code == 200, response.text
assert tomllib.loads(response.text)["disk-setup"] == {
"filesystem": "zfs", "zfs": {"raid": "raid0", "ashift": 12},
"filter": {"DEVTYPE": "disk"}, "filter-match": "all"}
assert answer(configured).text == response.text
@pytest.mark.parametrize("override", [
{"filter": {"ID_SERIAL_SHORT": "LAB_SYSTEM_DISK_001"}},
{"filter": {}},
{"filter_match": "all"},
{"expected_count": 1},
{"expected_serials": []},
{"filesystem": "ext4"},
{"filesystem": "xfs"},
{"zfs": {"raid": "raid1"}},
{"zfs": {"raid": "raid10"}},
{"zfs": {"raid": "raidz-1"}},
{"zfs": {}},
{"zfs": {"raid": "raid0", "ashift": True}},
{"zfs": {"raid": "raid0", "copies": 4}},
{"lvm": {}},
{"selection": "ALL"},
{"selection": None},
{"selection": True},
{"selection": ["all"]},
{"inventory_evidence": ""},
{"inventory_evidence": " "},
{"inventory_evidence": None},
{"disk_list": ["sda"]},
])
def test_automatic_disk_selection_rejects_ambiguous_or_unsupported_profiles(environment, override):
disk_setup = {"filesystem": "zfs", "selection": "all", "zfs": {"raid": "raid0"}, **override}
configured = prepare_host(environment, disk_setup, approve=False)
client, csrf, host = configured["client"], configured["csrf"], configured["host"]
assert client.get(f"/api/v1/hosts/{host['id']}/preview").status_code == 422
response = client.post(f"/api/v1/hosts/{host['id']}/approve-install", json={
"expected_version": host["version"], "valid_minutes": 30, "confirmation": host["fqdn"],
"disks_confirmed": True, "reason": "Invalid selection must not authorize an install"}, headers=csrf)
assert response.status_code == 422, response.text
with configured["app"].state.db.connection() as connection:
assert connection.execute("SELECT count(*) FROM approvals").fetchone()[0] == 0
assert connection.execute("SELECT count(*) FROM runs").fetchone()[0] == 0
@pytest.mark.parametrize("disk_setup", [
{"filesystem": "zfs", "zfs": {"raid": "raid0"}},
{"filesystem": "zfs", "zfs": {"raid": "raid0"}, "filter": {"DEVTYPE": "disk"}},
{"filesystem": "zfs", "zfs": {"raid": "raid0"},
"filter": {"ID_SERIAL_SHORT": "LAB_SYSTEM_DISK_001"}, "expected_count": 1,
"expected_serials": ["LAB_SYSTEM_DISK_001"]},
{"filesystem": "zfs", "zfs": {"raid": "raid1"},
"filter": {"ID_SERIAL_SHORT": "LAB_SYSTEM_DISK_001"}, "expected_count": 1,
"expected_serials": ["LAB_SYSTEM_DISK_001"], "inventory_evidence": "Verified one-disk inventory"},
])
def test_filtered_disk_selection_keeps_existing_requirements(environment, disk_setup):
configured = prepare_host(environment, disk_setup, approve=False)
response = configured["client"].get(f"/api/v1/hosts/{configured['host']['id']}/preview")
assert response.status_code == 422, response.text
def test_new_profile_version_cannot_change_prepared_run(prepared):
original = prepared["run"]["snapshot"]
data = deepcopy(prepared["profile_data"])