From cc9998028dfd5f7e1c7a3e08a100e9cfb4d60776 Mon Sep 17 00:00:00 2001 From: GnomeZworc Date: Sun, 26 Apr 2026 17:57:16 +0200 Subject: [PATCH] f-25: code: move load data to dedicated function Signed-off-by: GnomeZworc --- internal/subnet/create.go | 97 +++++++++--------------------------- internal/subnet/data.go | 72 +++++++++++++++++++++++++++ internal/subnet/delete.go | 43 +++++----------- internal/vm/create.go | 78 ++++------------------------- internal/vm/data.go | 100 ++++++++++++++++++++++++++++++++++++++ internal/vm/delete.go | 40 ++------------- 6 files changed, 222 insertions(+), 208 deletions(-) create mode 100644 internal/subnet/data.go create mode 100644 internal/vm/data.go diff --git a/internal/subnet/create.go b/internal/subnet/create.go index 496c257..07658c6 100644 --- a/internal/subnet/create.go +++ b/internal/subnet/create.go @@ -2,9 +2,6 @@ package subnet import ( "fmt" - "net" - "strconv" - "strings" "git.g3e.fr/syonad/two/internal/dhcp" "git.g3e.fr/syonad/two/internal/ebtables" @@ -25,94 +22,51 @@ func CreateSubnet(db *badger.DB, subnetName string) error { return nil } - // lecture des paramètres depuis la DB - vpcName, err := kv.GetFromDB(db, "subnet/"+subnetName+"/vpc") + d, err := loadSubnet(db, subnetName) if err != nil { - return fmt.Errorf("get vpc: %w", err) + return err } - vxlanIDStr, err := kv.GetFromDB(db, "subnet/"+subnetName+"/vxlan_id") - if err != nil { - return fmt.Errorf("get vxlan_id: %w", err) - } - vxlanID, err := strconv.Atoi(vxlanIDStr) - if err != nil { - return fmt.Errorf("parse vxlan_id: %w", err) - } + vxlanIface := fmt.Sprintf("vxlan-%d", d.vxlanID) - localIface, err := kv.GetFromDB(db, "subnet/"+subnetName+"/local_iface") - if err != nil { - return fmt.Errorf("get local_iface: %w", err) - } - - gatewayIPStr, err := kv.GetFromDB(db, "subnet/"+subnetName+"/gateway_ip") - if err != nil { - return fmt.Errorf("get gateway_ip: %w", err) - } - gatewayIP := net.ParseIP(gatewayIPStr) - if gatewayIP == nil { - return fmt.Errorf("invalid gateway_ip: %s", gatewayIPStr) - } - - cidr, err := kv.GetFromDB(db, "subnet/"+subnetName+"/cidr") - if err != nil { - return fmt.Errorf("get cidr: %w", err) - } - _, subnet, err := net.ParseCIDR(cidr) - if err != nil { - return fmt.Errorf("parse cidr: %w", err) - } - - // subnet_id = partie après le premier '-' (ex: "sn-00001" -> "00001") - subnetID := strings.SplitN(subnetName, "-", 2)[1] - bridge := "br-" + subnetID - vxlanIface := fmt.Sprintf("vxlan-%d", vxlanID) - - // veth pair - if err := netif.CreateVethToNetns("v-"+subnetID+"-e", "v-"+subnetID+"-i", "/var/run/netns/"+vpcName, 1500); err != nil { + if err := netif.CreateVethToNetns("v-"+d.subnetID+"-e", "v-"+d.subnetID+"-i", "/var/run/netns/"+d.vpc, 1500); err != nil { return fmt.Errorf("create veth: %w", err) } - // bridge dans le root netns - if err := netif.CreateBridge(bridge, 1500); err != nil { + if err := netif.CreateBridge(d.bridge, 1500); err != nil { return fmt.Errorf("create bridge: %w", err) } - // bridge dans le netns VPC - if err := netns.Call(vpcName, func() error { - return netif.CreateBridge(bridge, 1500) + if err := netns.Call(d.vpc, func() error { + return netif.CreateBridge(d.bridge, 1500) }); err != nil { return fmt.Errorf("create bridge in netns: %w", err) } - // vxlan - if err := netif.CreateVxlan(vxlanIface, vxlanID, localIface, 1500); err != nil { + if err := netif.CreateVxlan(vxlanIface, d.vxlanID, d.localIface, 1500); err != nil { return fmt.Errorf("create vxlan: %w", err) } - // ajout des interfaces dans les bridges - if err := netif.BridgeSetMaster("v-"+subnetID+"-e", bridge); err != nil { + if err := netif.BridgeSetMaster("v-"+d.subnetID+"-e", d.bridge); err != nil { return fmt.Errorf("add veth-e to bridge: %w", err) } - if err := netns.Call(vpcName, func() error { - return netif.BridgeSetMaster("v-"+subnetID+"-i", bridge) + if err := netns.Call(d.vpc, func() error { + return netif.BridgeSetMaster("v-"+d.subnetID+"-i", d.bridge) }); err != nil { return fmt.Errorf("add veth-i to bridge in netns: %w", err) } - if err := netif.BridgeSetMaster(vxlanIface, bridge); err != nil { + if err := netif.BridgeSetMaster(vxlanIface, d.bridge); err != nil { return fmt.Errorf("add vxlan to bridge: %w", err) } - // montée des interfaces dans le root netns - for _, iface := range []string{"v-" + subnetID + "-e", vxlanIface, bridge} { + for _, iface := range []string{"v-" + d.subnetID + "-e", vxlanIface, d.bridge} { if err := netif.LinkSetUp(iface); err != nil { return fmt.Errorf("set up %s: %w", iface, err) } } - // montée des interfaces dans le netns VPC - if err := netns.Call(vpcName, func() error { - for _, iface := range []string{"v-" + subnetID + "-i", bridge} { + if err := netns.Call(d.vpc, func() error { + for _, iface := range []string{"v-" + d.subnetID + "-i", d.bridge} { if err := netif.LinkSetUp(iface); err != nil { return fmt.Errorf("set up %s: %w", iface, err) } @@ -122,32 +76,29 @@ func CreateSubnet(db *badger.DB, subnetName string) error { return fmt.Errorf("set up interfaces in netns: %w", err) } - // IP gateway (/32) sur le bridge interne - if err := netns.Call(vpcName, func() error { - return netif.AddrAdd(bridge, gatewayIP) + if err := netns.Call(d.vpc, func() error { + return netif.AddrAdd(d.bridge, d.gatewayIP) }); err != nil { return fmt.Errorf("add addr to bridge in netns: %w", err) } - // route subnet (scope link) dans le netns VPC - if err := netns.Call(vpcName, func() error { - return netif.RouteAdd(bridge, subnet) + if err := netns.Call(d.vpc, func() error { + return netif.RouteAdd(d.bridge, d.cidr) }); err != nil { return fmt.Errorf("add route in netns: %w", err) } - if err := ebtables.DropARPToGateway(bridge, gatewayIP.String()); err != nil { + if err := ebtables.DropARPToGateway(d.bridge, d.gatewayIP.String()); err != nil { return err } - if err := ebtables.DropDHCP(bridge); err != nil { + if err := ebtables.DropDHCP(d.bridge); err != nil { return err } - // génération de la config dnsmasq et démarrage du service conf := dhcp.Config{ - Network: subnet, - Gateway: gatewayIP, - Name: vpcName + "_" + bridge, + Network: d.cidr, + Gateway: d.gatewayIP, + Name: d.vpc + "_" + d.bridge, ConfDir: "/etc/dnsmasq.d", } if _, err := dhcp.GenerateConfig(conf); err != nil { diff --git a/internal/subnet/data.go b/internal/subnet/data.go new file mode 100644 index 0000000..31f5472 --- /dev/null +++ b/internal/subnet/data.go @@ -0,0 +1,72 @@ +package subnet + +import ( + "fmt" + "net" + "strconv" + "strings" + + "git.g3e.fr/syonad/two/pkg/db/kv" + "github.com/dgraph-io/badger/v4" +) + +type subnetData struct { + vpc string + subnetID string + bridge string + vxlanID int + localIface string + gatewayIP net.IP + cidr *net.IPNet +} + +func loadSubnet(db *badger.DB, name string) (subnetData, error) { + var d subnetData + + d.subnetID = strings.SplitN(name, "-", 2)[1] + d.bridge = "br-" + d.subnetID + + vpc, err := kv.GetFromDB(db, "subnet/"+name+"/vpc") + if err != nil { + return d, fmt.Errorf("get vpc: %w", err) + } + d.vpc = vpc + + vxlanIDStr, err := kv.GetFromDB(db, "subnet/"+name+"/vxlan_id") + if err != nil { + return d, fmt.Errorf("get vxlan_id: %w", err) + } + vxlanID, err := strconv.Atoi(vxlanIDStr) + if err != nil { + return d, fmt.Errorf("parse vxlan_id: %w", err) + } + d.vxlanID = vxlanID + + localIface, err := kv.GetFromDB(db, "subnet/"+name+"/local_iface") + if err != nil { + return d, fmt.Errorf("get local_iface: %w", err) + } + d.localIface = localIface + + gatewayIPStr, err := kv.GetFromDB(db, "subnet/"+name+"/gateway_ip") + if err != nil { + return d, fmt.Errorf("get gateway_ip: %w", err) + } + gatewayIP := net.ParseIP(gatewayIPStr) + if gatewayIP == nil { + return d, fmt.Errorf("invalid gateway_ip: %s", gatewayIPStr) + } + d.gatewayIP = gatewayIP + + cidrStr, err := kv.GetFromDB(db, "subnet/"+name+"/cidr") + if err != nil { + return d, fmt.Errorf("get cidr: %w", err) + } + _, ipNet, err := net.ParseCIDR(cidrStr) + if err != nil { + return d, fmt.Errorf("parse cidr: %w", err) + } + d.cidr = ipNet + + return d, nil +} diff --git a/internal/subnet/delete.go b/internal/subnet/delete.go index 8ce91ff..8606cb9 100644 --- a/internal/subnet/delete.go +++ b/internal/subnet/delete.go @@ -3,7 +3,6 @@ package subnet import ( "fmt" "os" - "strings" "git.g3e.fr/syonad/two/internal/ebtables" "git.g3e.fr/syonad/two/internal/netif" @@ -23,69 +22,49 @@ func DeleteSubnet(db *badger.DB, subnetName string) error { return nil } - vpcName, err := kv.GetFromDB(db, "subnet/"+subnetName+"/vpc") + d, err := loadSubnet(db, subnetName) if err != nil { - return fmt.Errorf("get vpc: %w", err) + return err } - vxlanIDStr, err := kv.GetFromDB(db, "subnet/"+subnetName+"/vxlan_id") - if err != nil { - return fmt.Errorf("get vxlan_id: %w", err) - } + vxlanIface := fmt.Sprintf("vxlan-%d", d.vxlanID) - gatewayIP, err := kv.GetFromDB(db, "subnet/"+subnetName+"/gateway_ip") - if err != nil { - return fmt.Errorf("get gateway_ip: %w", err) - } - - subnetID := strings.SplitN(subnetName, "-", 2)[1] - bridge := "br-" + subnetID - vxlanIface := "vxlan-" + vxlanIDStr - - // arrêt du service dnsmasq svc, err := systemd.New() if err != nil { return fmt.Errorf("connect to systemd: %w", err) } defer svc.Close() - svcName := "dnsmasq@" + vpcName + "_" + bridge + ".service" - if err := svc.Stop(svcName); err != nil { + if err := svc.Stop("dnsmasq@" + d.vpc + "_" + d.bridge + ".service"); err != nil { return fmt.Errorf("stop dnsmasq: %w", err) } - // suppression de la config dnsmasq - if err := os.Remove("/etc/dnsmasq.d/" + vpcName + "_" + bridge + ".conf"); err != nil && !os.IsNotExist(err) { + if err := os.Remove("/etc/dnsmasq.d/" + d.vpc + "_" + d.bridge + ".conf"); err != nil && !os.IsNotExist(err) { return fmt.Errorf("remove dnsmasq config: %w", err) } - // suppression des règles ebtables - if err := ebtables.DeleteARPToGateway(bridge, gatewayIP); err != nil { + if err := ebtables.DeleteARPToGateway(d.bridge, d.gatewayIP.String()); err != nil { return fmt.Errorf("delete ebtables arp rule: %w", err) } - if err := ebtables.DeleteDHCP(bridge); err != nil { + if err := ebtables.DeleteDHCP(d.bridge); err != nil { return fmt.Errorf("delete ebtables dhcp rule: %w", err) } - // suppression du bridge dans le netns VPC - if err := netns.Call(vpcName, func() error { - return netif.DeleteLink(bridge) + if err := netns.Call(d.vpc, func() error { + return netif.DeleteLink(d.bridge) }); err != nil { return fmt.Errorf("delete bridge in netns: %w", err) } - // suppression du vxlan if err := netif.DeleteLink(vxlanIface); err != nil { return fmt.Errorf("delete vxlan: %w", err) } - // suppression du veth pair (supprime les deux côtés) - if err := netif.DeleteLink("v-" + subnetID + "-e"); err != nil { + if err := netif.DeleteLink("v-" + d.subnetID + "-e"); err != nil { return fmt.Errorf("delete veth: %w", err) } - // suppression du bridge dans le root netns - if err := netif.DeleteLink(bridge); err != nil { + if err := netif.DeleteLink(d.bridge); err != nil { return fmt.Errorf("delete bridge: %w", err) } diff --git a/internal/vm/create.go b/internal/vm/create.go index 49d0dd8..4737e62 100644 --- a/internal/vm/create.go +++ b/internal/vm/create.go @@ -2,8 +2,6 @@ package vm import ( "fmt" - "strconv" - "strings" "git.g3e.fr/syonad/two/internal/iptables" "git.g3e.fr/syonad/two/internal/metadata" @@ -24,84 +22,28 @@ func StartVM(db *badger.DB, name string) error { return nil } - subnetName, err := kv.GetFromDB(db, "vm/"+name+"/subnet") + d, err := loadVM(db, name) if err != nil { - return fmt.Errorf("get subnet: %w", err) + return err } - vpcName, err := kv.GetFromDB(db, "subnet/"+subnetName+"/vpc") - if err != nil { - return fmt.Errorf("get vpc: %w", err) - } - - gatewayIP, err := kv.GetFromDB(db, "subnet/"+subnetName+"/gateway_ip") - if err != nil { - return fmt.Errorf("get gateway_ip: %w", err) - } - - bridge := "br-" + strings.SplitN(subnetName, "-", 2)[1] - - tapIDStr, err := kv.GetFromDB(db, "vm/"+name+"/tap_id") - if err != nil { - return fmt.Errorf("get tap_id: %w", err) - } - tapID, err := strconv.Atoi(tapIDStr) - if err != nil { - return fmt.Errorf("parse tap_id: %w", err) - } - - vmIP, err := kv.GetFromDB(db, "vm/"+name+"/ip") - if err != nil { - return fmt.Errorf("get ip: %w", err) - } - - metadataPort, err := kv.GetFromDB(db, "vm/"+name+"/metadata_port") - if err != nil { - return fmt.Errorf("get metadata_port: %w", err) - } - - mac, err := kv.GetFromDB(db, "vm/"+name+"/mac") - if err != nil { - return fmt.Errorf("get mac: %w", err) - } - - volumePath, err := kv.GetFromDB(db, "vm/"+name+"/volume_path") - if err != nil { - return fmt.Errorf("get volume_path: %w", err) - } - - memoryStr, err := kv.GetFromDB(db, "vm/"+name+"/memory") - if err != nil { - return fmt.Errorf("get memory: %w", err) - } - memory, _ := strconv.Atoi(memoryStr) - - cpusStr, err := kv.GetFromDB(db, "vm/"+name+"/cpus") - if err != nil { - return fmt.Errorf("get cpus: %w", err) - } - cpus, _ := strconv.Atoi(cpusStr) - - password, _ := kv.GetFromDB(db, "vm/"+name+"/password") - sshkey, _ := kv.GetFromDB(db, "vm/"+name+"/sshkey") - - if err := netif.CreateTap(tapID, bridge, vpcName); err != nil { + if err := netif.CreateTap(d.tapID, d.bridge, d.vpcName); err != nil { return fmt.Errorf("create tap: %w", err) } - if err := netns.Call(vpcName, func() error { - return iptables.AddMetadataRedirect(vmIP, gatewayIP, metadataPort) + if err := netns.Call(d.vpcName, func() error { + return iptables.AddMetadataRedirect(d.ip, d.gatewayIP, d.metadataPort) }); err != nil { return fmt.Errorf("add metadata redirect: %w", err) } if err := metadata.StartMetadata(metadata.NoCloudConfig{ Name: name, - VpcName: vpcName, - BindIP: gatewayIP, - BindPort: metadataPort, - Password: password, - SSHKEY: sshkey, + VpcName: d.vpcName, + BindIP: d.gatewayIP, + BindPort: d.metadataPort, + Password: d.password, + SSHKEY: d.sshkey, }, db, false); err != nil { return fmt.Errorf("start metadata: %w", err) } diff --git a/internal/vm/data.go b/internal/vm/data.go new file mode 100644 index 0000000..379ce50 --- /dev/null +++ b/internal/vm/data.go @@ -0,0 +1,100 @@ +package vm + +import ( + "fmt" + "strconv" + "strings" + + "git.g3e.fr/syonad/two/pkg/db/kv" + "github.com/dgraph-io/badger/v4" +) + +type vmData struct { + subnetName string + vpcName string + gatewayIP string + bridge string + tapID int + ip string + metadataPort string + mac string + volumePath string + memory int + cpus int + password string + sshkey string +} + +func loadVM(db *badger.DB, name string) (vmData, error) { + var d vmData + + subnetName, err := kv.GetFromDB(db, "vm/"+name+"/subnet") + if err != nil { + return d, fmt.Errorf("get subnet: %w", 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 + + gatewayIP, err := kv.GetFromDB(db, "subnet/"+subnetName+"/gateway_ip") + if err != nil { + return d, fmt.Errorf("get gateway_ip: %w", err) + } + d.gatewayIP = gatewayIP + + tapIDStr, err := kv.GetFromDB(db, "vm/"+name+"/tap_id") + if err != nil { + return d, fmt.Errorf("get tap_id: %w", err) + } + 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 + + metadataPort, err := kv.GetFromDB(db, "vm/"+name+"/metadata_port") + if err != nil { + return d, fmt.Errorf("get metadata_port: %w", err) + } + d.metadataPort = metadataPort + + mac, err := kv.GetFromDB(db, "vm/"+name+"/mac") + if err != nil { + return d, fmt.Errorf("get mac: %w", err) + } + d.mac = mac + + volumePath, err := kv.GetFromDB(db, "vm/"+name+"/volume_path") + if err != nil { + return d, fmt.Errorf("get volume_path: %w", err) + } + d.volumePath = volumePath + + memoryStr, err := kv.GetFromDB(db, "vm/"+name+"/memory") + if err != nil { + return d, fmt.Errorf("get memory: %w", err) + } + d.memory, _ = strconv.Atoi(memoryStr) + + cpusStr, err := kv.GetFromDB(db, "vm/"+name+"/cpus") + if err != nil { + return d, fmt.Errorf("get cpus: %w", err) + } + d.cpus, _ = strconv.Atoi(cpusStr) + + d.password, _ = kv.GetFromDB(db, "vm/"+name+"/password") + d.sshkey, _ = kv.GetFromDB(db, "vm/"+name+"/sshkey") + + return d, nil +} diff --git a/internal/vm/delete.go b/internal/vm/delete.go index 0de2b73..faadb4b 100644 --- a/internal/vm/delete.go +++ b/internal/vm/delete.go @@ -2,7 +2,6 @@ package vm import ( "fmt" - "strconv" "time" configuration "git.g3e.fr/syonad/two/internal/config/agent" @@ -25,38 +24,9 @@ func StopVM(db *badger.DB, name string, cfg *configuration.Config) error { return nil } - subnetName, err := kv.GetFromDB(db, "vm/"+name+"/subnet") + d, err := loadVM(db, name) if err != nil { - return fmt.Errorf("get subnet: %w", err) - } - - vpcName, err := kv.GetFromDB(db, "subnet/"+subnetName+"/vpc") - if err != nil { - return fmt.Errorf("get vpc: %w", err) - } - - gatewayIP, err := kv.GetFromDB(db, "subnet/"+subnetName+"/gateway_ip") - if err != nil { - return fmt.Errorf("get gateway_ip: %w", err) - } - - tapIDStr, err := kv.GetFromDB(db, "vm/"+name+"/tap_id") - if err != nil { - return fmt.Errorf("get tap_id: %w", err) - } - tapID, err := strconv.Atoi(tapIDStr) - if err != nil { - return fmt.Errorf("parse tap_id: %w", err) - } - - vmIP, err := kv.GetFromDB(db, "vm/"+name+"/ip") - if err != nil { - return fmt.Errorf("get ip: %w", err) - } - - metadataPort, err := kv.GetFromDB(db, "vm/"+name+"/metadata_port") - if err != nil { - return fmt.Errorf("get metadata_port: %w", err) + return err } socketPath := fmt.Sprintf("/tmp/%s.qmp-sock", name) @@ -81,8 +51,8 @@ func StopVM(db *badger.DB, name string, cfg *configuration.Config) error { } } - if err := netns.Call(vpcName, func() error { - return iptables.DeleteMetadataRedirect(vmIP, gatewayIP, metadataPort) + if err := netns.Call(d.vpcName, func() error { + return iptables.DeleteMetadataRedirect(d.ip, d.gatewayIP, d.metadataPort) }); err != nil { return fmt.Errorf("delete metadata redirect: %w", err) } @@ -91,7 +61,7 @@ func StopVM(db *badger.DB, name string, cfg *configuration.Config) error { return fmt.Errorf("stop metadata: %w", err) } - if err := netif.DeleteTap(tapID, vpcName); err != nil { + if err := netif.DeleteTap(d.tapID, d.vpcName); err != nil { return fmt.Errorf("delete tap: %w", err) }