feat(templates): Profile ins Template einbacken
Beim Template-Bau lassen sich Profile wählen (nur solche ohne Pflichtvariablen). Nach dem Vorbereitungsstart laufen sie über den Guest-Agent; danach werden Maschinen-ID, SSH-Host-Keys, Docker-Engine-ID und apt-Cache entfernt. Ausrollen nimmt das Template mit den meisten passenden Profilen und überspringt, was schon eingebacken ist. Auf pve-demo: Provisionierung mit base+docker 141 s ohne, ~30 s mit Template. Dabei gefunden: docker nimmt den Benutzer per guest.user in die Gruppe auf – Profile mit guest.* laufen deshalb beim Deploy noch einmal (idempotent, schnell). Closes #022 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -14,9 +14,11 @@ export function TemplateBauen({
|
||||
distributionen,
|
||||
knoten,
|
||||
faehigkeit,
|
||||
profile,
|
||||
}: {
|
||||
server: string;
|
||||
distributionen: Array<{ id: string; name: string }>;
|
||||
distributionen: Array<{ id: string; name: string; familie: string }>;
|
||||
profile: Array<{ id: string; name: string; requires: string[]; familien: string[] }>;
|
||||
knoten: Knoten[];
|
||||
faehigkeit: { weg: "api" | "ssh" | "nicht_moeglich"; grund: string };
|
||||
}) {
|
||||
@@ -26,6 +28,7 @@ export function TemplateBauen({
|
||||
knoten: knoten[0]?.name ?? "",
|
||||
storage: knoten[0]?.storages[0] ?? "",
|
||||
bridge: knoten[0]?.bridges.includes("vmbr0") ? "vmbr0" : (knoten[0]?.bridges[0] ?? ""),
|
||||
profile: [] as string[],
|
||||
});
|
||||
const [fehler, setFehler] = useState<{ text: string; hinweis?: string } | null>(null);
|
||||
const [sendet, setSendet] = useState(false);
|
||||
@@ -118,6 +121,43 @@ export function TemplateBauen({
|
||||
</select>
|
||||
</Feld>
|
||||
</div>
|
||||
<fieldset className="flex flex-col gap-2">
|
||||
<legend className="mb-1 text-sm font-medium">Profile einbacken (optional)</legend>
|
||||
<p className="text-muted text-sm">
|
||||
Was hier gewählt ist, ist in jedem Klon schon installiert – Deployments mit diesen Profilen sind
|
||||
schneller fertig. Profile mit Pflichtangaben (z. B. Zabbix-Server) laufen beim Ausrollen.
|
||||
</p>
|
||||
<div className="flex flex-wrap gap-x-6 gap-y-2">
|
||||
{profile
|
||||
.filter((p) =>
|
||||
p.familien.includes(distributionen.find((d) => d.id === werte.distribution)?.familie ?? ""),
|
||||
)
|
||||
.map((p) => {
|
||||
const benoetigt = profile.some(
|
||||
(x) => werte.profile.includes(x.id) && x.requires.includes(p.id),
|
||||
);
|
||||
return (
|
||||
<label key={p.id} className="flex items-center gap-2 text-sm">
|
||||
<input
|
||||
type="checkbox"
|
||||
className="accent-akzent h-4 w-4"
|
||||
checked={werte.profile.includes(p.id) || benoetigt}
|
||||
disabled={benoetigt && !werte.profile.includes(p.id)}
|
||||
onChange={(e) =>
|
||||
setWerte({
|
||||
...werte,
|
||||
profile: e.target.checked
|
||||
? [...werte.profile, p.id]
|
||||
: werte.profile.filter((x) => x !== p.id),
|
||||
})
|
||||
}
|
||||
/>
|
||||
{p.name}
|
||||
</label>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</fieldset>
|
||||
<p className="text-muted text-sm">
|
||||
Der Vorbereitungsstart braucht DHCP und Internetzugang auf der Bridge, um qemu-guest-agent zu
|
||||
installieren.
|
||||
|
||||
Reference in New Issue
Block a user