two/internal/vm/create.go
GnomeZworc 1ec1d44c1a
f-33: mise en place d'un nouveau system de reservation #33
Signed-off-by: GnomeZworc <nicolas.boufidjeline@g3e.fr>
2026-08-25 22:37:07 +02:00

117 lines
2.7 KiB
Go

package vm
import (
"fmt"
"io"
"os"
"path/filepath"
configuration "git.g3e.fr/syonad/two/internal/config/agent"
"git.g3e.fr/syonad/two/internal/dhcp"
"git.g3e.fr/syonad/two/internal/iptables"
"git.g3e.fr/syonad/two/internal/metadata"
"git.g3e.fr/syonad/two/internal/netif"
"git.g3e.fr/syonad/two/internal/netns"
"git.g3e.fr/syonad/two/internal/qemu"
"git.g3e.fr/syonad/two/internal/state"
"github.com/dgraph-io/badger/v4"
)
func StartVM(db *badger.DB, name string, cfg *configuration.Config) error {
current, err := state.Get(db, "vm/"+name)
if err != nil {
return err
}
if current != state.Creating {
return nil
}
d, err := loadVM(db, name)
if err != nil {
return err
}
if err := netif.CreateTap(d.tapID, d.bridge, d.vpcName); err != nil {
return fmt.Errorf("create tap: %w", err)
}
if err := netns.Call(d.vpcName, func() error {
return iptables.AddMetadataRedirect(d.ip, d.interfaceIP, d.metadataPort)
}); err != nil {
return fmt.Errorf("add metadata redirect: %w", err)
}
if err := dhcp.WriteReservations(dhcp.DefaultConfDir, d.vpcName+"_"+d.bridge, name,
[]dhcp.Reservation{{MAC: d.mac, IP: d.ip}}); err != nil {
return fmt.Errorf("write dhcp reservation: %w", err)
}
if err := metadata.StartMetadata(metadata.NoCloudConfig{
Name: name,
VpcName: d.vpcName,
BindIP: d.interfaceIP,
BindPort: d.metadataPort,
Password: d.password,
SSHKEY: d.sshkey,
Documents: d.documents,
}, cfg, false); err != nil {
return fmt.Errorf("start metadata: %w", err)
}
qDisks := make([]qemu.DiskConfig, len(d.disks))
for i, disk := range d.disks {
qDisks[i] = qemu.DiskConfig{Path: disk.path, Dev: disk.dev}
}
qcfg := qemu.Config{
Name: name,
TapID: d.tapID,
Mac: d.mac,
Disks: qDisks,
Memory: d.memory,
CPUs: d.cpus,
SerialDir: cfg.QEMU.SerialDir,
MonitorDir: cfg.QEMU.MonitorDir,
QMPDir: cfg.QEMU.QMPDir,
}
if d.uefi {
varsPath := filepath.Join(cfg.QEMU.UEFIVarsDir, name+"-uefi-vars.fd")
if err := copyFile(cfg.QEMU.OVMFVarsTemplate, varsPath); err != nil {
return fmt.Errorf("copy uefi vars: %w", err)
}
qcfg.UEFICodePath = cfg.QEMU.OVMFCodePath
qcfg.UEFIVarsPath = varsPath
}
if err := netns.Call(d.vpcName, func() error {
return qemu.Start(qcfg)
}); err != nil {
return fmt.Errorf("start qemu: %w", err)
}
return state.Set(db, "vm/"+name, state.Running)
}
func copyFile(src, dst string) error {
if err := os.MkdirAll(filepath.Dir(dst), 0755); err != nil {
return err
}
in, err := os.Open(src)
if err != nil {
return err
}
defer in.Close()
out, err := os.Create(dst)
if err != nil {
return err
}
defer out.Close()
if _, err := io.Copy(out, in); err != nil {
return err
}
return out.Sync()
}