f-33: net: add multi net in dispatch et vms #33
Signed-off-by: GnomeZworc <nicolas.boufidjeline@g3e.fr>
This commit is contained in:
parent
1ec1d44c1a
commit
0237acba81
15 changed files with 753 additions and 146 deletions
|
|
@ -3,6 +3,7 @@ package vm
|
|||
import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
|
|
@ -16,15 +17,21 @@ type diskEntry struct {
|
|||
dev string
|
||||
}
|
||||
|
||||
type nicData struct {
|
||||
index int
|
||||
subnetName string
|
||||
vpcName string
|
||||
bridge string
|
||||
interfaceIP string
|
||||
ip string
|
||||
mac string
|
||||
tapID int
|
||||
primary bool
|
||||
}
|
||||
|
||||
type vmData struct {
|
||||
subnetName string
|
||||
vpcName string
|
||||
interfaceIP string
|
||||
bridge string
|
||||
tapID int
|
||||
ip string
|
||||
nics []nicData
|
||||
metadataPort string
|
||||
mac string
|
||||
disks []diskEntry
|
||||
memory int
|
||||
cpus int
|
||||
|
|
@ -34,47 +41,25 @@ type vmData struct {
|
|||
documents map[string]string
|
||||
}
|
||||
|
||||
// primary retourne l'interface portant la route par défaut et le serveur de
|
||||
// métadonnées. loadVM garantit qu'il y en a exactement une.
|
||||
func (d vmData) primary() nicData {
|
||||
for _, n := range d.nics {
|
||||
if n.primary {
|
||||
return n
|
||||
}
|
||||
}
|
||||
return nicData{}
|
||||
}
|
||||
|
||||
func loadVM(db *badger.DB, name string) (vmData, error) {
|
||||
var d vmData
|
||||
|
||||
subnetName, err := kv.GetFromDB(db, "vm/"+name+"/subnet")
|
||||
nics, err := loadNICs(db, name)
|
||||
if err != nil {
|
||||
return d, fmt.Errorf("get subnet: %w", err)
|
||||
return d, err
|
||||
}
|
||||
d.subnetName = subnetName
|
||||
d.bridge = "br-" + strings.SplitN(subnetName, "-", 2)[1]
|
||||
|
||||
vpcName, err := kv.GetFromDB(db, "subnet/"+subnetName+"/vpc")
|
||||
if err != nil {
|
||||
return d, fmt.Errorf("get vpc: %w", err)
|
||||
}
|
||||
d.vpcName = vpcName
|
||||
|
||||
interfaceIP, err := kv.GetFromDB(db, "subnet/"+subnetName+"/interface_ip")
|
||||
if err != nil {
|
||||
return d, fmt.Errorf("get interface_ip: %w", err)
|
||||
}
|
||||
d.interfaceIP = interfaceIP
|
||||
|
||||
tapIDStr, err := kv.GetFromDB(db, "vm/"+name+"/tap_id")
|
||||
if err != nil {
|
||||
d.tapID = rand.Intn(90000000) + 10000000
|
||||
if err := kv.AddInDB(db, "vm/"+name+"/tap_id", strconv.Itoa(d.tapID)); err != nil {
|
||||
return d, fmt.Errorf("store tap_id: %w", err)
|
||||
}
|
||||
} else {
|
||||
tapID, err := strconv.Atoi(tapIDStr)
|
||||
if err != nil {
|
||||
return d, fmt.Errorf("parse tap_id: %w", err)
|
||||
}
|
||||
d.tapID = tapID
|
||||
}
|
||||
|
||||
ip, err := kv.GetFromDB(db, "vm/"+name+"/ip")
|
||||
if err != nil {
|
||||
return d, fmt.Errorf("get ip: %w", err)
|
||||
}
|
||||
d.ip = ip
|
||||
d.nics = nics
|
||||
|
||||
metadataPort, err := kv.GetFromDB(db, "vm/"+name+"/metadata_port")
|
||||
if err != nil {
|
||||
|
|
@ -82,12 +67,6 @@ func loadVM(db *badger.DB, name string) (vmData, error) {
|
|||
}
|
||||
d.metadataPort = metadataPort
|
||||
|
||||
mac, err := dhcp.GetMACForIP(db, d.subnetName, d.ip)
|
||||
if err != nil {
|
||||
return d, fmt.Errorf("get mac for ip %s: %w", d.ip, err)
|
||||
}
|
||||
d.mac = mac
|
||||
|
||||
diskEntries, err := kv.ListByPrefix(db, "vm/"+name+"/disk/")
|
||||
if err != nil {
|
||||
return d, fmt.Errorf("list disks: %w", err)
|
||||
|
|
@ -139,3 +118,101 @@ func loadVM(db *badger.DB, name string) (vmData, error) {
|
|||
|
||||
return d, nil
|
||||
}
|
||||
|
||||
// loadNICs lit les interfaces d'une VM sous vm/<name>/nic/<index>/.
|
||||
// Le tap est alloué à la première lecture et persisté, comme avant le passage
|
||||
// au multi-interfaces — mais désormais par interface.
|
||||
func loadNICs(db *badger.DB, name string) ([]nicData, error) {
|
||||
prefix := "vm/" + name + "/nic/"
|
||||
entries, err := kv.ListByPrefix(db, prefix)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("list nics: %w", err)
|
||||
}
|
||||
|
||||
indexes := make(map[int]bool)
|
||||
for key := range entries {
|
||||
parts := strings.Split(strings.TrimPrefix(key, prefix), "/")
|
||||
if len(parts) != 2 {
|
||||
continue
|
||||
}
|
||||
idx, err := strconv.Atoi(parts[0])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid nic index %q for vm %s", parts[0], name)
|
||||
}
|
||||
indexes[idx] = true
|
||||
}
|
||||
if len(indexes) == 0 {
|
||||
return nil, fmt.Errorf("no interface found for vm %q", name)
|
||||
}
|
||||
|
||||
nics := make([]nicData, 0, len(indexes))
|
||||
for idx := range indexes {
|
||||
n, err := loadNIC(db, name, idx, entries)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
nics = append(nics, n)
|
||||
}
|
||||
sort.Slice(nics, func(i, j int) bool { return nics[i].index < nics[j].index })
|
||||
|
||||
primaries := 0
|
||||
for _, n := range nics {
|
||||
if n.primary {
|
||||
primaries++
|
||||
}
|
||||
}
|
||||
if primaries != 1 {
|
||||
return nil, fmt.Errorf("vm %q has %d primary interfaces, expected exactly one", name, primaries)
|
||||
}
|
||||
return nics, nil
|
||||
}
|
||||
|
||||
func loadNIC(db *badger.DB, name string, idx int, entries map[string]string) (nicData, error) {
|
||||
n := nicData{index: idx}
|
||||
prefix := fmt.Sprintf("vm/%s/nic/%d/", name, idx)
|
||||
|
||||
n.subnetName = entries[prefix+"subnet"]
|
||||
if n.subnetName == "" {
|
||||
return n, fmt.Errorf("nic %d of vm %s has no subnet", idx, name)
|
||||
}
|
||||
n.bridge = "br-" + strings.SplitN(n.subnetName, "-", 2)[1]
|
||||
n.primary = entries[prefix+"primary"] == "true"
|
||||
|
||||
vpcName, err := kv.GetFromDB(db, "subnet/"+n.subnetName+"/vpc")
|
||||
if err != nil {
|
||||
return n, fmt.Errorf("get vpc of subnet %s: %w", n.subnetName, err)
|
||||
}
|
||||
n.vpcName = vpcName
|
||||
|
||||
interfaceIP, err := kv.GetFromDB(db, "subnet/"+n.subnetName+"/interface_ip")
|
||||
if err != nil {
|
||||
return n, fmt.Errorf("get interface_ip of subnet %s: %w", n.subnetName, err)
|
||||
}
|
||||
n.interfaceIP = interfaceIP
|
||||
|
||||
n.ip = entries[prefix+"ip"]
|
||||
if n.ip == "" {
|
||||
return n, fmt.Errorf("nic %d of vm %s has no ip", idx, name)
|
||||
}
|
||||
|
||||
mac, err := dhcp.GetMACForIP(db, n.subnetName, n.ip)
|
||||
if err != nil {
|
||||
return n, fmt.Errorf("get mac for ip %s: %w", n.ip, err)
|
||||
}
|
||||
n.mac = mac
|
||||
|
||||
if tapIDStr, ok := entries[prefix+"tap_id"]; ok {
|
||||
tapID, err := strconv.Atoi(tapIDStr)
|
||||
if err != nil {
|
||||
return n, fmt.Errorf("parse tap_id of nic %d: %w", idx, err)
|
||||
}
|
||||
n.tapID = tapID
|
||||
return n, nil
|
||||
}
|
||||
|
||||
n.tapID = rand.Intn(90000000) + 10000000
|
||||
if err := kv.AddInDB(db, prefix+"tap_id", strconv.Itoa(n.tapID)); err != nil {
|
||||
return n, fmt.Errorf("store tap_id of nic %d: %w", idx, err)
|
||||
}
|
||||
return n, nil
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue