From 42698676610db8a995a5434f32e85945a980840c Mon Sep 17 00:00:00 2001 From: Arthur Lu Date: Tue, 14 Jan 2025 04:44:18 +0000 Subject: [PATCH] remove debug string methods, simplify PCI devices --- app/app.go | 71 ++++++++++++++++++---------- app/model.go | 122 ++++++------------------------------------------- app/proxmox.go | 48 ++++--------------- app/types.go | 50 ++++++++------------ app/utils.go | 22 ++++----- go.mod | 26 +++++++++++ 6 files changed, 124 insertions(+), 215 deletions(-) diff --git a/app/app.go b/app/app.go index ddae517..562fcfd 100644 --- a/app/app.go +++ b/app/app.go @@ -5,12 +5,14 @@ import ( "flag" "fmt" "log" - "time" + "net/http" + "strconv" + "github.com/gin-gonic/gin" "github.com/luthermonson/go-proxmox" ) -const APIVersion string = "0.0.1" +const APIVersion string = "0.0.2" var client ProxmoxClient @@ -26,36 +28,55 @@ func Run() { token := fmt.Sprintf(`%s@%s!%s`, config.PVE.Token.USER, config.PVE.Token.REALM, config.PVE.Token.ID) client = NewClient(token, config.PVE.Token.Secret) - //router := gin.Default() + router := gin.Default() - start := time.Now() cluster := Cluster{} cluster.Init(client) cluster.Rebuild() - elapsed := time.Since(start) - fmt.Println(cluster) - fmt.Println(elapsed) + router.GET("/version", func(c *gin.Context) { + PVEVersion, err := client.Version() + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + } else { + c.JSON(http.StatusOK, gin.H{"api-version": APIVersion, "pve-version": PVEVersion}) + } + }) - /* - router.GET("/version", func(c *gin.Context) { - PVEVersion, err := client.Version() - if err != nil { - c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + router.GET("/nodes/:node", func(c *gin.Context) { + node := c.Param("node") + Host, ok := cluster.Hosts[node] + if !ok { + c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("%s not found in cluster", node)}) + return + } else { + c.JSON(http.StatusOK, gin.H{"node": Host}) + return + } + }) + + router.GET("/nodes/:node/instances/:instance", func(c *gin.Context) { + host := c.Param("node") + vmid, err := strconv.ParseUint(c.Param("instance"), 10, 64) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("%s could not be converted to vmid (uint)", c.Param("instance"))}) + return + } + Node, ok := cluster.Hosts[host] + if !ok { + c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("vmid %s not found in cluster", host)}) + return + } else { + Instance, ok := Node.Instances[uint(vmid)] + if !ok { + c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("%d not found in %s", vmid, host)}) + return } else { - c.JSON(http.StatusOK, gin.H{"api-version": APIVersion, "pve-version": PVEVersion}) + c.JSON(http.StatusOK, gin.H{"instance": Instance}) + return } - }) + } + }) - router.GET("/nodes/:node", func(c *gin.Context) { - Node, err := client.Node(c.Param("node")) - if err != nil { - c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) - } else { - c.JSON(http.StatusOK, gin.H{"node": Node}) - } - }) - - router.Run("0.0.0.0:" + strconv.Itoa(config.ListenPort)) - */ + router.Run("0.0.0.0:" + strconv.Itoa(config.ListenPort)) } diff --git a/app/model.go b/app/model.go index ae73d1a..67c27d9 100644 --- a/app/model.go +++ b/app/model.go @@ -9,7 +9,6 @@ import ( type Cluster struct { pve ProxmoxClient Hosts map[string]*Host - //Instance map[uint]*Instance } func (cluster *Cluster) Init(pve ProxmoxClient) { @@ -77,7 +76,7 @@ func (host *Host) RebuildVM(vmid uint) error { return err } - host.Instance[vmid] = &instance + host.Instances[vmid] = &instance for volid := range instance.configDisks { instance.RebuildVolume(host, volid) @@ -100,7 +99,7 @@ func (host *Host) RebuildCT(vmid uint) error { return err } - host.Instance[vmid] = &instance + host.Instances[vmid] = &instance for volid := range instance.configDisks { instance.RebuildVolume(host, volid) @@ -121,7 +120,7 @@ func (instance *Instance) RebuildVolume(host *Host, volid string) error { return err } - instance.Volume[volid] = &volume + instance.Volumes[volid] = &volume return nil } @@ -138,7 +137,7 @@ func (instance *Instance) RebuildNet(netid string) error { return nil } - instance.Net[uint(idnum)] = &netinfo + instance.Nets[uint(idnum)] = &netinfo return nil } @@ -157,113 +156,20 @@ func (instance *Instance) RebuildDevice(host Host, deviceid string) error { } if DeviceBusIDIsSuperDevice(hostDeviceBusID) { - hostSuperDevice := host.Hardware[hostDeviceBusID] - subDevices := []*HostDevice{} - for _, v := range hostSuperDevice.Devices { - v.Reserved = true - subDevices = append(subDevices, v) - } - instance.Device[uint(instanceDeviceBusID)] = &InstanceDevice{ - Device: subDevices, - PCIE: strings.Contains(instanceDevice, "pcie=1"), + devices := []*Device{} + for k, v := range host.Devices { + if DeviceBusIDIsSubDevice(k, hostDeviceBusID) { + v.Reserved = true + devices = append(devices, v) + } } + instance.Devices[uint(instanceDeviceBusID)] = devices } else { - _, hostSubdeviceBusID, err := SplitDeviceBusID(hostDeviceBusID) - if err != nil { - return err - } - v := host.Hardware[hostDeviceBusID].Devices[hostSubdeviceBusID] + devices := []*Device{} + v := host.Devices[hostDeviceBusID] v.Reserved = true - instance.Device[uint(instanceDeviceBusID)] = &InstanceDevice{ - Device: []*HostDevice{v}, - PCIE: strings.Contains(instanceDevice, "pcie=1"), - } + instance.Devices[uint(instanceDeviceBusID)] = devices } return nil } - -func (cluster Cluster) String() string { - r := "" - for _, host := range cluster.Hosts { - r += host.String() - } - return r -} - -func (host Host) String() string { - r := fmt.Sprintf("%s\n\tCores:\t%s\n\tMemory:\t%s\n\tSwap:\t%s\n", host.Name, host.Cores, host.Memory, host.Swap) - - r += "\tHardware:\n" - - for _, superdevice := range host.Hardware { - r += fmt.Sprintf("%s\n", superdevice) - } - - r += "\tInstances:\n" - - for vmid, vm := range host.Instance { - r += fmt.Sprintf("\t\t%d: %s\n", vmid, vm) - } - - return r -} - -func (r Resource) String() string { - return fmt.Sprintf("Totl: %d, Rsrv: %d, Free: %d", r.Total, r.Reserved, r.Free) -} - -func (superdevice HostSuperDevice) String() string { - s := fmt.Sprintf("\t\t%s: %s %s -> ", superdevice.BusID, superdevice.VendorName, superdevice.DeviceName) - numunused := 0 - for _, device := range superdevice.Devices { - if device.Reserved { - s += fmt.Sprintf("%s:(Rsrv %t, %s %s: %s %s)", device.SubID, device.Reserved, superdevice.VendorName, device.SubVendorName, superdevice.DeviceName, device.SubDeviceName) - } else { - numunused++ - } - } - s += fmt.Sprintf("+%d unreserved subdevices", numunused) - return s -} - -func (i Instance) String() string { - if i.Type == VM { - r := fmt.Sprintf("VM, Name: %s, Proctype: %s, Cores: %d, Memory: %d\n", i.Name, i.Proctype, i.Cores, i.Memory) - for k, v := range i.Volume { - r += fmt.Sprintf("\t\t\t%s: %s\n", k, v) - } - for k, v := range i.Net { - r += fmt.Sprintf("\t\t\tnet%d: %s\n", k, v) - } - for k, v := range i.Device { - r += fmt.Sprintf("\t\t\thostpci%d: %s\n", k, v) - } - return r - } else { - r := fmt.Sprintf("CT, Name: %s, Cores: %d, Memory: %d, Swap: %d\n", i.Name, i.Cores, i.Memory, i.Swap) - for k, v := range i.Volume { - r += fmt.Sprintf("\t\t\t%s: %s\n", k, v) - } - for k, v := range i.Net { - r += fmt.Sprintf("\t\t\tnet%d: %s\n", k, v) - } - return r - } -} - -func (v Volume) String() string { - return fmt.Sprintf("id: %s, format: %s, size: %d", v.Volid, v.Format, v.Size) -} - -func (n Net) String() string { - return fmt.Sprintf("rate: %d, vlan: %d", n.Rate, n.VLAN) -} - -func (d InstanceDevice) String() string { - r := "" - for _, v := range d.Device { - r += fmt.Sprintf("%s:%s ", v.SubVendorName, v.SubDeviceName) - } - return r -} diff --git a/app/proxmox.go b/app/proxmox.go index 603c06d..687ea7a 100644 --- a/app/proxmox.go +++ b/app/proxmox.go @@ -15,14 +15,6 @@ type ProxmoxClient struct { client *proxmox.Client } -type PVEDevice struct { - BusID string `json:"id"` - DeviceName string `json:"device_name"` - VendorName string `json:"vendor_name"` - SubsystemDeviceName string `json:"subsystem_device_name"` - SubsystemVendorName string `json:"subsystem_vendor_name"` -} - func NewClient(token string, secret string) ProxmoxClient { HTTPClient := http.Client{ Transport: &http.Transport{ @@ -67,44 +59,22 @@ func (pve ProxmoxClient) Nodes() ([]string, error) { // Gets a Node's resources but does not recursively expand instances func (pve ProxmoxClient) Node(nodeName string) (Host, error) { host := Host{} - host.Hardware = make(map[string]*HostSuperDevice) - host.Instance = make(map[uint]*Instance) + host.Devices = make(map[string]*Device) + host.Instances = make(map[uint]*Instance) node, err := pve.client.Node(context.Background(), nodeName) if err != nil { return host, err } - devices := []PVEDevice{} + devices := []Device{} err = pve.client.Get(context.Background(), fmt.Sprintf("/nodes/%s/hardware/pci", nodeName), &devices) if err != nil { return host, err } - // map supersystem devices to each contained subsystem - // eg 0000:00:05 -> [0000:00:05.0, 0000:00:05.1, 0000:00:05.2, 0000:00:05.3, ...] for _, device := range devices { - SupersystemID, SubsystemID, err := SplitDeviceBusID(device.BusID) - if err != nil { - return host, err - } - - if host.Hardware[SupersystemID] == nil { - host.Hardware[SupersystemID] = &HostSuperDevice{ - BusID: SupersystemID, - DeviceName: device.DeviceName, - VendorName: device.VendorName, - Devices: make(map[string]*HostDevice), - } - } - - if !DeviceBusIDIsSuperDevice(device.BusID) { - host.Hardware[SupersystemID].Devices[SubsystemID] = &HostDevice{ - SubID: SubsystemID, - SubDeviceName: device.SubsystemDeviceName, - SubVendorName: device.SubsystemVendorName, - } - } + host.Devices[device.BusID] = &device } host.Name = node.Name @@ -149,9 +119,9 @@ func (host Host) VirtualMachine(VMID uint) (Instance, error) { instance.Proctype = vm.VirtualMachineConfig.CPU instance.Cores = uint64(vm.VirtualMachineConfig.Cores) instance.Memory = uint64(vm.VirtualMachineConfig.Memory) * MiB - instance.Volume = make(map[string]*Volume) - instance.Net = make(map[uint]*Net) - instance.Device = make(map[uint]*InstanceDevice) + instance.Volumes = make(map[string]*Volume) + instance.Nets = make(map[uint]*Net) + instance.Devices = make(map[uint][]*Device) return instance, nil } @@ -197,8 +167,8 @@ func (host Host) Container(VMID uint) (Instance, error) { instance.Cores = uint64(ct.ContainerConfig.Cores) instance.Memory = uint64(ct.ContainerConfig.Memory) * MiB instance.Swap = uint64(ct.ContainerConfig.Swap) * MiB - instance.Volume = make(map[string]*Volume) - instance.Net = make(map[uint]*Net) + instance.Volumes = make(map[string]*Volume) + instance.Nets = make(map[uint]*Net) return instance, nil } diff --git a/app/types.go b/app/types.go index 00dbc18..fc6984b 100644 --- a/app/types.go +++ b/app/types.go @@ -9,20 +9,20 @@ type Resource struct { } type Host struct { - Name string - Cores Resource - Memory Resource - Swap Resource - Hardware map[string]*HostSuperDevice - Instance map[uint]*Instance - node *proxmox.Node + Name string + Cores Resource + Memory Resource + Swap Resource + Devices map[string]*Device + Instances map[uint]*Instance + node *proxmox.Node } -type InstanceType bool +type InstanceType string const ( - VM InstanceType = true - CT InstanceType = false + VM InstanceType = "VM" + CT InstanceType = "CT" ) type Instance struct { @@ -32,9 +32,9 @@ type Instance struct { Cores uint64 Memory uint64 Swap uint64 - Volume map[string]*Volume - Net map[uint]*Net - Device map[uint]*InstanceDevice + Volumes map[string]*Volume + Nets map[uint]*Net + Devices map[uint][]*Device config interface{} configDisks map[string]string configNets map[string]string @@ -54,21 +54,11 @@ type Net struct { VLAN uint64 } -type InstanceDevice struct { - Device []*HostDevice - PCIE bool -} - -type HostSuperDevice struct { - BusID string - DeviceName string - VendorName string - Devices map[string]*HostDevice -} - -type HostDevice struct { - SubID string - SubDeviceName string - SubVendorName string - Reserved bool +type Device struct { + BusID string `json:"id"` + DeviceName string `json:"device_name"` + VendorName string `json:"vendor_name"` + SubsystemDeviceName string `json:"subsystem_device_name"` + SubsystemVendorName string `json:"subsystem_vendor_name"` + Reserved bool } diff --git a/app/utils.go b/app/utils.go index e03cae6..b98775a 100644 --- a/app/utils.go +++ b/app/utils.go @@ -2,7 +2,6 @@ package app import ( "encoding/json" - "fmt" "log" "os" "strings" @@ -38,20 +37,17 @@ func GetConfig(configPath string) Config { // returns if a device pcie bus id is a super device or subsystem device // // subsystem devices always has the format xxxx:yy.z, whereas super devices have the format xxxx:yy +// +// returns true if BusID has format xxxx:yy func DeviceBusIDIsSuperDevice(BusID string) bool { return !strings.ContainsRune(BusID, '.') } -// splits a device pcie bus id into super device and subsystem device IDs if possible -func SplitDeviceBusID(BusID string) (string, string, error) { - if DeviceBusIDIsSuperDevice(BusID) { - return BusID, "", nil - } else { - x := strings.Split(BusID, ".") - if len(x) != 2 { - return "", "", fmt.Errorf("BusID: %s contained more than one '.'", BusID) - } else { - return x[0], x[1], nil - } - } +// returns if a device pcie bus id is a subdevice of specified super device +// +// subsystem devices always has the format xxxx:yy.z, whereas super devices have the format xxxx:yy +// +// returns true if BusID has prefix SuperDeviceBusID and SuperDeviceBusID is a Super Device +func DeviceBusIDIsSubDevice(BusID string, SuperDeviceBusID string) bool { + return DeviceBusIDIsSuperDevice(SuperDeviceBusID) && strings.HasPrefix(BusID, SuperDeviceBusID) } diff --git a/go.mod b/go.mod index 73a99dd..eb36f5e 100644 --- a/go.mod +++ b/go.mod @@ -8,11 +8,37 @@ require github.com/luthermonson/go-proxmox v0.2.0 require ( github.com/buger/goterm v1.0.4 // indirect + github.com/bytedance/sonic v1.11.6 // indirect + github.com/bytedance/sonic/loader v0.1.1 // indirect + github.com/cloudwego/base64x v0.1.4 // indirect + github.com/cloudwego/iasm v0.2.0 // indirect github.com/diskfs/go-diskfs v1.4.2 // indirect github.com/djherbis/times v1.6.0 // indirect + github.com/gabriel-vasile/mimetype v1.4.3 // indirect + github.com/gin-contrib/sse v0.1.0 // indirect + github.com/gin-gonic/gin v1.10.0 // indirect + github.com/go-playground/locales v0.14.1 // indirect + github.com/go-playground/universal-translator v0.18.1 // indirect + github.com/go-playground/validator/v10 v10.20.0 // indirect + github.com/goccy/go-json v0.10.2 // indirect github.com/gorilla/websocket v1.5.3 // indirect github.com/jinzhu/copier v0.4.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/klauspost/cpuid/v2 v2.2.7 // indirect + github.com/leodido/go-urn v1.4.0 // indirect github.com/magefile/mage v1.15.0 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/pelletier/go-toml/v2 v2.2.2 // indirect github.com/stretchr/testify v1.9.0 // indirect + github.com/twitchyliquid64/golang-asm v0.15.1 // indirect + github.com/ugorji/go/codec v1.2.12 // indirect + golang.org/x/arch v0.8.0 // indirect + golang.org/x/crypto v0.23.0 // indirect + golang.org/x/net v0.25.0 // indirect golang.org/x/sys v0.26.0 // indirect + golang.org/x/text v0.15.0 // indirect + google.golang.org/protobuf v1.34.1 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect )