// Copyright 2024 WIT.COM Inc Licensed GPL 3.0 package main import ( "errors" "fmt" pb "go.wit.com/lib/protobuf/virtbuf" "go.wit.com/log" "libvirt.org/go/libvirtxml" ) func addDomainDroplet(domcfg *libvirtxml.Domain) (*DropletT, error) { if domcfg == nil { return nil, errors.New("domcfg == nil") } d, _ := findDomain(domcfg) if d != nil { return d, errors.New(d.pb.Hostname + " droplet exists. need to update instead") } // this is a new unknown droplet (not in the config file) d = new(DropletT) d.pb = me.cluster.AddDroplet(domcfg.UUID, domcfg.Name, 2, 2*1024*1024) d.pb.StartState = "off" me.droplets = append(me.droplets, d) me.changed = true if updateDroplet(d, domcfg) { if me.changed { log.Info("updateDroplet() worked. droplet changed") } else { log.Verbose("updateDroplet() worked. nothing changed") } } else { log.Info("updateDroplet() failed for", d.pb.Hostname) return d, errors.New("update failed for " + domcfg.Name) } log.Info("added new droplet", domcfg.Name, domcfg.UUID) return d, nil } func findDomain(domcfg *libvirtxml.Domain) (*DropletT, error) { var found *DropletT if domcfg == nil { return nil, errors.New("domcfg == nil") } for _, d := range me.droplets { if d.pb.Hostname == domcfg.Name { if d.pb.Uuid != domcfg.UUID { fmt.Println("CHANGED UUID", d.pb.Uuid, domcfg.UUID) d.pb.Uuid = domcfg.UUID me.changed = true } if found == nil { found = d } else { fmt.Println("FOUND TWICE", d.pb.Uuid, domcfg.Name, domcfg.UUID) return d, errors.New("Found Twice") } } if d.pb.Uuid == domcfg.UUID { if d.pb.Hostname != domcfg.Name { fmt.Println("FOUND UUID WITH MIS-MATCHED NAME", domcfg.Name, domcfg.UUID) return d, errors.New("UUID with mis-matched names") } } } return found, nil } func updateDroplet(d *DropletT, domcfg *libvirtxml.Domain) bool { var ok bool = true if d == nil { return false } if domcfg == nil { return false } if !updateMemory(d, domcfg) { log.Info("updateMemory() failed") ok = false } // check cpus if d.pb.Cpus != int64(domcfg.VCPU.Value) { fmt.Printf("cpus changed. VCPU = %+v\n", domcfg.VCPU) d.pb.Cpus = int64(domcfg.VCPU.Value) me.changed = true } // check type if domcfg.Type != "kvm" { fmt.Printf("not kvm. Virt type == %s\n", domcfg.Type) ok = false } if !updateNetwork(d, domcfg) { log.Info("updateNetwork() failed") ok = false } if !updateDisk(d, domcfg) { log.Info("updateDisk() failed") ok = false } return ok } // returns false if something went wrong func updateMemory(d *DropletT, domcfg *libvirtxml.Domain) bool { if (d == nil) || (domcfg == nil) { return false } // check memory if domcfg.Memory.Unit == "KiB" { var m int64 m = int64(domcfg.Memory.Value * 1024) if d.pb.Memory != m { d.pb.Memory = m me.changed = true fmt.Printf("Memory changed %d, %d %s\n", d.pb.Memory, domcfg.Memory.Value, domcfg.Memory.Unit) } return true } if domcfg.Memory.Unit == "MiB" { var m int64 m = int64(domcfg.Memory.Value * 1024 * 1024) if d.pb.Memory != m { d.pb.Memory = m me.changed = true fmt.Printf("Memory changed %d, %d %s\n", d.pb.Memory, domcfg.Memory.Value, domcfg.Memory.Unit) } return true } if domcfg.Memory.Unit == "GiB" { var m int64 m = int64(domcfg.Memory.Value * 1024 * 1024 * 1024) if d.pb.Memory != m { d.pb.Memory = m me.changed = true fmt.Printf("Memory changed %d, %d %s\n", d.pb.Memory, domcfg.Memory.Value, domcfg.Memory.Unit) } return true } fmt.Println("Unknown Memory Unit", domcfg.Memory.Unit) return false } // returns false if something went wrong func updateNetwork(d *DropletT, domcfg *libvirtxml.Domain) bool { if (d == nil) || (domcfg == nil) { return false } var macs []string // Iterate over the network interfaces and print the MAC addresses for _, iface := range domcfg.Devices.Interfaces { if iface.MAC != nil { // iface.MAC.Address = "aa:bb:aa:bb:aa:ff" // fmt.Printf("MAC Address: %+v\n", iface.MAC) // log.Info("Interface:", iface.Target, "MAC Address:", iface.MAC.Address) // fmt.Printf("source: %+v\n", iface.Source) macs = append(macs, iface.MAC.Address) } else { fmt.Printf("Interface: %s, MAC Address: not available\n", iface.Target.Dev) } } for _, mac := range macs { var found bool = false for i, eth := range d.pb.Networks { if eth.Mac == mac { log.Verbose("OKAY. FOUND ETH:", i, eth.Mac, eth.Name) found = true } } if !found { var eth *pb.Network eth = new(pb.Network) eth.Mac = mac eth.Name = "worldbr" d.pb.Networks = append(d.pb.Networks, eth) me.changed = true } } log.Verbose("mac addrs:", macs) return true } // returns false if something went wrong func updateDisk(d *DropletT, domcfg *libvirtxml.Domain) bool { if (d == nil) || (domcfg == nil) { return false } for _, disk := range domcfg.Devices.Disks { var t *libvirtxml.DomainDiskSourceFile t = disk.Source.File filename := t.File if filename == "" { fmt.Println("No disk source file found.") continue } var found bool = false for _, disk := range d.pb.Disks { if disk.Filename == filename { log.Verbose("OKAY. FOUND filename", filename) found = true } } if !found { var disk *pb.Disk disk = new(pb.Disk) disk.Filename = filename d.pb.Disks = append(d.pb.Disks, disk) log.Info("New filename", filename) me.changed = true } } return true }