Быстрое создание машин: cloud-init, тип системы для установщика, постоянный адрес в сети NAT

- готовые образы: пользователь, пароль (хеш SHA-512) и SSH-ключ через virt-install --cloud-init,
  диск увеличивается до выбранного размера, osinfo из каталога
- установка с ISO: выбор Linux / Windows 11 (UEFI + TPM) / Windows 10 / другая;
  Windows получает SATA-диск и сетевую карту e1000e
- каждая машина в NAT получает фиксированный MAC и резервацию DHCP — адрес не меняется,
  пробросы портов не ломаются; при удалении резервация снимается
- xorriso в пакетах ноды (для seed-образа cloud-init)
- tests/test_quickvm.py; тест каталога скачиваний сделан детерминированным

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019LEUXMcdZo7b87mjkUsPgg
Этот коммит содержится в:
Claude
2026-09-25 15:14:03 +00:00
родитель eb7b71f478
Коммит e5ce9c4d41
10 изменённых файлов: 438 добавлений и 20 удалений
+4
Просмотреть файл
@@ -317,12 +317,16 @@ def test_catalog_route(logged_in, data_dirs, www, monkeypatch):
monkeypatch.setattr(app, "start_disk_convert_operation", lambda path: None)
assert unquote(logged_in.post("/downloads/catalog/nope", follow_redirects=False).headers["location"]).startswith("/disk-images?download_error=Такого образа нет")
# The worker is started by hand below: a 6 KB file would otherwise finish before the page is rendered.
pending = {}
monkeypatch.setattr(downloads, "run_operation", lambda operation, worker: pending.update(operation=operation, worker=worker))
response = logged_in.post("/downloads/catalog/debian-13", follow_redirects=False)
assert response.status_code == 303 and "download_message=" in response.headers["location"]
page = logged_in.get("/disk-images").text
assert "Скачивается" in page
running = downloads.active_downloads("disk")
assert running[0]["catalog_id"] == "debian-13"
core.run_operation(pending["operation"], pending["worker"])
assert wait_for(running[0]["id"])["status"] == "success"
assert (data_dirs["disk_images"] / "debian-13-genericcloud-amd64.qcow2").read_bytes() == payload
page = logged_in.get("/disk-images").text