All checks were successful
Release Pipeline / checksums (push) Successful in 4s
Release Pipeline / release (push) Successful in 11s
Release Pipeline / set-release-target (push) Successful in 2s
Release Pipeline / upload-assets (agent.service, systemd/agent.service) (push) Successful in 4s
Release Pipeline / upload-assets (dnsmasq@.service, systemd/dnsmasq@.service) (push) Successful in 4s
Release Pipeline / upload-assets (metadata@.service, systemd/metadata@.service) (push) Successful in 4s
Release Pipeline / upload-assets (run-dnsmasq-in-netns.sh, scripts/run-dnsmasq-in-netns.sh) (push) Successful in 4s
Release Pipeline / build (agent, amd64, linux) (push) Successful in 0s
Release Pipeline / build (metadata, amd64, linux) (push) Successful in 0s
Release Pipeline / publish (push) Successful in 0s
Release Pipeline / build (push) Successful in 1m36s
Signed-off-by: GnomeZworc <nicolas.boufidjeline@g3e.fr>
201 lines
5.9 KiB
Go
201 lines
5.9 KiB
Go
package vm
|
|
|
|
import (
|
|
"fmt"
|
|
"strconv"
|
|
"testing"
|
|
|
|
"git.g3e.fr/syonad/two/pkg/db/kv"
|
|
"github.com/dgraph-io/badger/v4"
|
|
)
|
|
|
|
func newVMInDB(t *testing.T) *badger.DB {
|
|
t.Helper()
|
|
db := kv.InitDB(kv.Config{Path: t.TempDir()}, false)
|
|
t.Cleanup(func() { db.Close() })
|
|
|
|
kv.AddInDB(db, "vm/vm-1/nic/0/subnet", "sn-000001")
|
|
kv.AddInDB(db, "vm/vm-1/nic/0/primary", "true")
|
|
kv.AddInDB(db, "subnet/sn-000001/vpc", "vp-admin")
|
|
kv.AddInDB(db, "subnet/sn-000001/interface_ip", "10.1.1.1")
|
|
kv.AddInDB(db, "subnet/sn-000001/mode", "vxlan")
|
|
kv.AddInDB(db, "vpc/vp-admin/cidr", "192.168.0.0/16")
|
|
kv.AddInDB(db, "subnet/sn-000001/dhcp/10.1.1.2", "00:22:33:00:01:02")
|
|
kv.AddInDB(db, "vm/vm-1/nic/0/ip", "10.1.1.2")
|
|
kv.AddInDB(db, "vm/vm-1/metadata_port", "8081")
|
|
kv.AddInDB(db, "vm/vm-1/disk/vda", "/data/root.qcow2")
|
|
kv.AddInDB(db, "vm/vm-1/memory", "2048")
|
|
kv.AddInDB(db, "vm/vm-1/cpus", "2")
|
|
return db
|
|
}
|
|
|
|
func TestLoadVM_NoDocuments(t *testing.T) {
|
|
db := newVMInDB(t)
|
|
|
|
d, err := loadVM(db, "vm-1")
|
|
if err != nil {
|
|
t.Fatalf("loadVM : %v", err)
|
|
}
|
|
if d.documents != nil {
|
|
t.Errorf("aucun document en base, la map doit rester nil : %v", d.documents)
|
|
}
|
|
}
|
|
|
|
func TestLoadVM_ReadsDocuments(t *testing.T) {
|
|
db := newVMInDB(t)
|
|
userData := "#cloud-config\npackages:\n - nginx\n"
|
|
kv.AddInDB(db, "vm/vm-1/metadata/user-data", userData)
|
|
kv.AddInDB(db, "vm/vm-1/metadata/network-config", "version: 2\n")
|
|
|
|
d, err := loadVM(db, "vm-1")
|
|
if err != nil {
|
|
t.Fatalf("loadVM : %v", err)
|
|
}
|
|
if len(d.documents) != 2 {
|
|
t.Fatalf("2 documents attendus, obtenu %d : %v", len(d.documents), d.documents)
|
|
}
|
|
if d.documents["user-data"] != userData {
|
|
t.Errorf("user-data altéré au passage en base :\nattendu %q\nobtenu %q", userData, d.documents["user-data"])
|
|
}
|
|
if d.documents["network-config"] != "version: 2\n" {
|
|
t.Errorf("network-config inattendu : %q", d.documents["network-config"])
|
|
}
|
|
}
|
|
|
|
func TestLoadVM_DocumentKeysAreStrippedOfPrefix(t *testing.T) {
|
|
db := newVMInDB(t)
|
|
kv.AddInDB(db, "vm/vm-1/metadata/vendor-data", "v")
|
|
|
|
d, err := loadVM(db, "vm-1")
|
|
if err != nil {
|
|
t.Fatalf("loadVM : %v", err)
|
|
}
|
|
for key := range d.documents {
|
|
if key != "vendor-data" {
|
|
t.Errorf("clé de document attendue %q, obtenue %q — le préfixe doit être retiré", "vendor-data", key)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestLoadVM_EmptyDocumentIsPreserved(t *testing.T) {
|
|
db := newVMInDB(t)
|
|
kv.AddInDB(db, "vm/vm-1/metadata/user-data", "")
|
|
|
|
d, err := loadVM(db, "vm-1")
|
|
if err != nil {
|
|
t.Fatalf("loadVM : %v", err)
|
|
}
|
|
content, ok := d.documents["user-data"]
|
|
if !ok {
|
|
t.Fatal("un document vide doit survivre au passage en base : c'est une demande de ne rien servir")
|
|
}
|
|
if content != "" {
|
|
t.Errorf("contenu attendu vide, obtenu %q", content)
|
|
}
|
|
}
|
|
|
|
// --- multi-interfaces ---
|
|
|
|
func addNIC(t *testing.T, db *badger.DB, idx int, subnet, ip, mac string, primary bool) {
|
|
t.Helper()
|
|
prefix := fmt.Sprintf("vm/vm-1/nic/%d/", idx)
|
|
kv.AddInDB(db, prefix+"subnet", subnet)
|
|
kv.AddInDB(db, prefix+"ip", ip)
|
|
if primary {
|
|
kv.AddInDB(db, prefix+"primary", "true")
|
|
}
|
|
kv.AddInDB(db, "subnet/"+subnet+"/vpc", "vp-admin")
|
|
kv.AddInDB(db, "subnet/"+subnet+"/interface_ip", "10.1.1.1")
|
|
kv.AddInDB(db, "subnet/"+subnet+"/mode", "vxlan")
|
|
kv.AddInDB(db, "vpc/vp-admin/cidr", "192.168.0.0/16")
|
|
kv.AddInDB(db, "subnet/"+subnet+"/dhcp/"+ip, mac)
|
|
}
|
|
|
|
func TestLoadVM_SingleNIC(t *testing.T) {
|
|
d, err := loadVM(newVMInDB(t), "vm-1")
|
|
if err != nil {
|
|
t.Fatalf("loadVM : %v", err)
|
|
}
|
|
if len(d.nics) != 1 {
|
|
t.Fatalf("1 interface attendue, obtenu %d", len(d.nics))
|
|
}
|
|
if !d.primary().primary || d.primary().ip != "10.1.1.2" {
|
|
t.Errorf("primaire inattendue : %+v", d.primary())
|
|
}
|
|
}
|
|
|
|
func TestLoadVM_MultipleNICsSortedByIndex(t *testing.T) {
|
|
db := newVMInDB(t)
|
|
addNIC(t, db, 2, "sn-000003", "10.3.0.9", "00:22:33:00:03:09", false)
|
|
addNIC(t, db, 1, "sn-000002", "10.2.0.5", "00:22:33:00:02:05", false)
|
|
|
|
d, err := loadVM(db, "vm-1")
|
|
if err != nil {
|
|
t.Fatalf("loadVM : %v", err)
|
|
}
|
|
if len(d.nics) != 3 {
|
|
t.Fatalf("3 interfaces attendues, obtenu %d", len(d.nics))
|
|
}
|
|
for i, n := range d.nics {
|
|
if n.index != i {
|
|
t.Errorf("interface en position %d porte l'index %d — l'ordre détermine le slot PCI", i, n.index)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestLoadVM_TapAllocatedPerNIC(t *testing.T) {
|
|
db := newVMInDB(t)
|
|
addNIC(t, db, 1, "sn-000002", "10.2.0.5", "00:22:33:00:02:05", false)
|
|
|
|
d, err := loadVM(db, "vm-1")
|
|
if err != nil {
|
|
t.Fatalf("loadVM : %v", err)
|
|
}
|
|
if d.nics[0].tapID == d.nics[1].tapID {
|
|
t.Errorf("deux interfaces partagent le tap %d", d.nics[0].tapID)
|
|
}
|
|
for _, n := range d.nics {
|
|
stored, err := kv.GetFromDB(db, fmt.Sprintf("vm/vm-1/nic/%d/tap_id", n.index))
|
|
if err != nil {
|
|
t.Errorf("tap_id de l'interface %d non persisté : %v", n.index, err)
|
|
continue
|
|
}
|
|
if stored != strconv.Itoa(n.tapID) {
|
|
t.Errorf("tap_id de l'interface %d : %q en base, %d en mémoire", n.index, stored, n.tapID)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestLoadVM_NoPrimaryIsAnError(t *testing.T) {
|
|
db := kv.InitDB(kv.Config{Path: t.TempDir()}, false)
|
|
t.Cleanup(func() { db.Close() })
|
|
kv.AddInDB(db, "vm/vm-1/metadata_port", "8081")
|
|
kv.AddInDB(db, "vm/vm-1/disk/vda", "/data/root.qcow2")
|
|
kv.AddInDB(db, "vm/vm-1/memory", "2048")
|
|
kv.AddInDB(db, "vm/vm-1/cpus", "2")
|
|
addNIC(t, db, 0, "sn-000001", "10.1.1.2", "00:22:33:00:01:02", false)
|
|
kv.AddInDB(db, "subnet/sn-000001/mode", "vxlan")
|
|
|
|
if _, err := loadVM(db, "vm-1"); err == nil {
|
|
t.Error("aucune interface primaire : loadVM doit échouer plutôt que de laisser StartVM choisir au hasard")
|
|
}
|
|
}
|
|
|
|
func TestLoadVM_TwoPrimariesIsAnError(t *testing.T) {
|
|
db := newVMInDB(t)
|
|
addNIC(t, db, 1, "sn-000002", "10.2.0.5", "00:22:33:00:02:05", true)
|
|
|
|
if _, err := loadVM(db, "vm-1"); err == nil {
|
|
t.Error("deux interfaces primaires doivent être refusées")
|
|
}
|
|
}
|
|
|
|
func TestLoadVM_NoNICIsAnError(t *testing.T) {
|
|
db := kv.InitDB(kv.Config{Path: t.TempDir()}, false)
|
|
t.Cleanup(func() { db.Close() })
|
|
kv.AddInDB(db, "vm/vm-1/memory", "2048")
|
|
|
|
if _, err := loadVM(db, "vm-1"); err == nil {
|
|
t.Error("une VM sans interface doit être refusée")
|
|
}
|
|
}
|