implement populate model hosts/instances/volumes/nets/devices
This commit is contained in:
parent
a0399ed326
commit
57689e7c59
17
app/app.go
17
app/app.go
@ -5,10 +5,8 @@ import (
|
|||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"time"
|
||||||
"strconv"
|
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
|
||||||
"github.com/luthermonson/go-proxmox"
|
"github.com/luthermonson/go-proxmox"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -28,8 +26,18 @@ func Run() {
|
|||||||
token := fmt.Sprintf(`%s@%s!%s`, config.PVE.Token.USER, config.PVE.Token.REALM, config.PVE.Token.ID)
|
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)
|
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) {
|
router.GET("/version", func(c *gin.Context) {
|
||||||
PVEVersion, err := client.Version()
|
PVEVersion, err := client.Version()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -49,4 +57,5 @@ func Run() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
router.Run("0.0.0.0:" + strconv.Itoa(config.ListenPort))
|
router.Run("0.0.0.0:" + strconv.Itoa(config.ListenPort))
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
214
app/model.go
Normal file
214
app/model.go
Normal file
@ -0,0 +1,214 @@
|
|||||||
|
package app
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Cluster struct {
|
||||||
|
pve ProxmoxClient
|
||||||
|
Hosts map[string]*Host
|
||||||
|
//Instance map[uint]*Instance
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cluster *Cluster) Init(pve ProxmoxClient) {
|
||||||
|
cluster.pve = pve
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cluster *Cluster) Rebuild() error {
|
||||||
|
cluster.Hosts = make(map[string]*Host)
|
||||||
|
//cluster.Instance = make(map[uint]*Instance)
|
||||||
|
|
||||||
|
// get all nodes
|
||||||
|
nodes, err := cluster.pve.Nodes()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// for each node:
|
||||||
|
for _, hostName := range nodes {
|
||||||
|
// rebuild node
|
||||||
|
err := cluster.RebuildNode(hostName)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cluster *Cluster) RebuildNode(hostName string) error {
|
||||||
|
host, err := cluster.pve.Node(hostName)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
cluster.Hosts[hostName] = &host
|
||||||
|
|
||||||
|
// get node's VMs
|
||||||
|
vms, err := host.VirtualMachines()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, vmid := range vms {
|
||||||
|
err := host.RebuildVM(vmid)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// get node's CTs
|
||||||
|
cts, err := host.Containers()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, vmid := range cts {
|
||||||
|
err := host.RebuildCT(vmid)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (host *Host) RebuildVM(vmid uint) error {
|
||||||
|
instance, err := host.VirtualMachine(vmid)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
host.Instance[vmid] = &instance
|
||||||
|
|
||||||
|
for volid := range instance.configDisks {
|
||||||
|
instance.RebuildVolume(host, volid)
|
||||||
|
}
|
||||||
|
|
||||||
|
for netid := range instance.configNets {
|
||||||
|
instance.RebuildNet(netid)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (host *Host) RebuildCT(vmid uint) error {
|
||||||
|
instance, err := host.Container(vmid)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
host.Instance[vmid] = &instance
|
||||||
|
|
||||||
|
for volid := range instance.configDisks {
|
||||||
|
instance.RebuildVolume(host, volid)
|
||||||
|
}
|
||||||
|
|
||||||
|
for netid := range instance.configNets {
|
||||||
|
instance.RebuildNet(netid)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (instance *Instance) RebuildVolume(host *Host, volid string) error {
|
||||||
|
volumeDataString := instance.configDisks[volid]
|
||||||
|
|
||||||
|
volume, _, _, err := GetVolumeInfo(*host, volumeDataString)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
instance.Volume[volid] = &volume
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (instance *Instance) RebuildNet(netid string) error {
|
||||||
|
net := instance.configNets[netid]
|
||||||
|
idnum, err := strconv.ParseUint(strings.TrimPrefix(netid, "net"), 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
netinfo, err := GetNetInfo(net)
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
instance.Net[uint(idnum)] = &netinfo
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
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)
|
||||||
|
}
|
239
app/proxmox.go
239
app/proxmox.go
@ -5,6 +5,7 @@ import (
|
|||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/luthermonson/go-proxmox"
|
"github.com/luthermonson/go-proxmox"
|
||||||
@ -14,6 +15,14 @@ type ProxmoxClient struct {
|
|||||||
client *proxmox.Client
|
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 {
|
func NewClient(token string, secret string) ProxmoxClient {
|
||||||
HTTPClient := http.Client{
|
HTTPClient := http.Client{
|
||||||
Transport: &http.Transport{
|
Transport: &http.Transport{
|
||||||
@ -23,8 +32,6 @@ func NewClient(token string, secret string) ProxmoxClient {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
println(token, secret)
|
|
||||||
|
|
||||||
client := proxmox.NewClient("https://pve.tronnet.net/api2/json",
|
client := proxmox.NewClient("https://pve.tronnet.net/api2/json",
|
||||||
proxmox.WithHTTPClient(&HTTPClient),
|
proxmox.WithHTTPClient(&HTTPClient),
|
||||||
proxmox.WithAPIToken(token, secret),
|
proxmox.WithAPIToken(token, secret),
|
||||||
@ -42,86 +49,216 @@ func (pve ProxmoxClient) Version() (proxmox.Version, error) {
|
|||||||
return *version, err
|
return *version, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gets and returns a Node's CPU, memory, swap, and Hardware (PCI) resources
|
// Gets all Nodes names
|
||||||
|
func (pve ProxmoxClient) Nodes() ([]string, error) {
|
||||||
|
nodes, err := pve.client.Nodes(context.Background())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
names := []string{}
|
||||||
|
for _, node := range nodes {
|
||||||
|
names = append(names, node.Node)
|
||||||
|
}
|
||||||
|
|
||||||
|
return names, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gets a Node's resources but does not recursively expand instances
|
||||||
func (pve ProxmoxClient) Node(nodeName string) (Host, error) {
|
func (pve ProxmoxClient) Node(nodeName string) (Host, error) {
|
||||||
host := Host{}
|
host := Host{}
|
||||||
host.Hardware = make(map[string]Device)
|
host.Hardware = make(map[string]*HostSuperDevice)
|
||||||
|
host.Instance = make(map[uint]*Instance)
|
||||||
|
|
||||||
node, err := pve.client.Node(context.Background(), nodeName)
|
node, err := pve.client.Node(context.Background(), nodeName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return host, err
|
return host, err
|
||||||
}
|
}
|
||||||
|
|
||||||
devices := []Device{}
|
devices := []PVEDevice{}
|
||||||
err = pve.client.Get(context.Background(), fmt.Sprintf("/nodes/%s/hardware/pci", nodeName), &devices)
|
err = pve.client.Get(context.Background(), fmt.Sprintf("/nodes/%s/hardware/pci", nodeName), &devices)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return host, err
|
return host, err
|
||||||
}
|
}
|
||||||
|
|
||||||
vms, err := node.VirtualMachines(context.Background())
|
// map supersystem devices to each contained subsystem
|
||||||
if err != nil {
|
|
||||||
return host, err
|
|
||||||
}
|
|
||||||
|
|
||||||
cts, err := node.Containers(context.Background())
|
|
||||||
if err != nil {
|
|
||||||
return host, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// temporary helper which maps 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, ...]
|
// eg 0000:00:05 -> [0000:00:05.0, 0000:00:05.1, 0000:00:05.2, 0000:00:05.3, ...]
|
||||||
DeviceSubsystemMap := make(map[string][]string)
|
|
||||||
for _, device := range devices {
|
for _, device := range devices {
|
||||||
host.Hardware[device.BusID] = device
|
SupersystemID, SubsystemID, err := SplitDeviceBusID(device.BusID)
|
||||||
SupersystemID := strings.Split(device.BusID, ".")[0]
|
if err != nil {
|
||||||
DeviceSubsystemMap[SupersystemID] = append(DeviceSubsystemMap[SupersystemID], device.BusID)
|
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.Name = node.Name
|
host.Name = node.Name
|
||||||
host.Cores.Total = int64(node.CPUInfo.CPUs)
|
host.Cores.Total = uint64(node.CPUInfo.CPUs)
|
||||||
host.Memory.Total = int64(node.Memory.Total)
|
host.Memory.Total = uint64(node.Memory.Total)
|
||||||
host.Swap.Total = int64(node.Swap.Total)
|
host.Swap.Total = uint64(node.Swap.Total)
|
||||||
|
host.node = node
|
||||||
|
|
||||||
|
return host, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get all VM IDs on specified host
|
||||||
|
func (host Host) VirtualMachines() ([]uint, error) {
|
||||||
|
vms, err := host.node.VirtualMachines(context.Background())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
ids := []uint{}
|
||||||
for _, vm := range vms {
|
for _, vm := range vms {
|
||||||
vm, err := node.VirtualMachine(context.Background(), int(vm.VMID))
|
ids = append(ids, uint(vm.VMID))
|
||||||
|
}
|
||||||
|
return ids, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get a VM's CPU, Memory but does not recursively link Devices, Disks, Drives, Nets
|
||||||
|
func (host Host) VirtualMachine(VMID uint) (Instance, error) {
|
||||||
|
instance := Instance{}
|
||||||
|
vm, err := host.node.VirtualMachine(context.Background(), int(VMID))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return host, err
|
return instance, err
|
||||||
}
|
}
|
||||||
|
|
||||||
host.Cores.Reserved += int64(vm.VirtualMachineConfig.Cores)
|
config := vm.VirtualMachineConfig
|
||||||
host.Memory.Reserved += int64(vm.VirtualMachineConfig.Memory * MiB)
|
config.HostPCIs = config.MergeHostPCIs()
|
||||||
|
instance.configNets = config.MergeNets()
|
||||||
|
instance.configDisks = MergeVMDisksAndUnused(config)
|
||||||
|
|
||||||
MarshallVirtualMachineConfig(vm.VirtualMachineConfig)
|
instance.config = config
|
||||||
|
instance.Type = VM
|
||||||
|
|
||||||
for _, v := range vm.VirtualMachineConfig.HostPCIs {
|
instance.Name = vm.Name
|
||||||
HostPCIBusID := strings.Split(v, ",")[0]
|
instance.Proctype = vm.VirtualMachineConfig.CPU
|
||||||
if device, ok := host.Hardware[HostPCIBusID]; ok { // is a specific subsystem of device
|
instance.Cores = uint64(vm.VirtualMachineConfig.Cores)
|
||||||
device.Reserved = true
|
instance.Memory = uint64(vm.VirtualMachineConfig.Memory) * MiB
|
||||||
host.Hardware[HostPCIBusID] = device
|
instance.Volume = make(map[string]*Volume)
|
||||||
} else if SubsystemBusIDs, ok := DeviceSubsystemMap[HostPCIBusID]; ok { // is a supersystem device containing multiple subsystems
|
instance.Net = make(map[uint]*Net)
|
||||||
for _, SubsystemBusID := range SubsystemBusIDs {
|
instance.Device = make(map[uint]*InstanceDevice)
|
||||||
device := host.Hardware[SubsystemBusID]
|
|
||||||
device.Reserved = true
|
return instance, nil
|
||||||
host.Hardware[SubsystemBusID] = device
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func MergeVMDisksAndUnused(vmc *proxmox.VirtualMachineConfig) map[string]string {
|
||||||
|
mergedDisks := vmc.MergeDisks()
|
||||||
|
for k, v := range vmc.MergeUnuseds() {
|
||||||
|
mergedDisks[k] = v
|
||||||
|
}
|
||||||
|
return mergedDisks
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get all CT IDs on specified host
|
||||||
|
func (host Host) Containers() ([]uint, error) {
|
||||||
|
cts, err := host.node.Containers(context.Background())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
ids := []uint{}
|
||||||
for _, ct := range cts {
|
for _, ct := range cts {
|
||||||
ct, err := node.Container(context.Background(), int(ct.VMID))
|
ids = append(ids, uint(ct.VMID))
|
||||||
|
}
|
||||||
|
return ids, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get a CT's CPU, Memory, Swap but does not recursively link Devices, Disks, Drives, Nets
|
||||||
|
func (host Host) Container(VMID uint) (Instance, error) {
|
||||||
|
instance := Instance{}
|
||||||
|
ct, err := host.node.Container(context.Background(), int(VMID))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return host, err
|
return instance, err
|
||||||
}
|
}
|
||||||
|
|
||||||
host.Cores.Reserved += int64(ct.ContainerConfig.Cores)
|
config := ct.ContainerConfig
|
||||||
host.Memory.Reserved += int64(ct.ContainerConfig.Memory * MiB)
|
instance.configNets = config.MergeNets()
|
||||||
host.Swap.Reserved += int64(ct.ContainerConfig.Swap * MiB)
|
instance.configDisks = MergeCTDisksAndUnused(config)
|
||||||
|
|
||||||
|
instance.config = config
|
||||||
|
instance.Type = CT
|
||||||
|
|
||||||
|
instance.Name = ct.Name
|
||||||
|
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)
|
||||||
|
|
||||||
|
return instance, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
host.Cores.Free = host.Cores.Total - host.Cores.Reserved
|
func MergeCTDisksAndUnused(cc *proxmox.ContainerConfig) map[string]string {
|
||||||
host.Memory.Free = host.Memory.Total - host.Memory.Reserved
|
mergedDisks := make(map[string]string)
|
||||||
host.Swap.Free = host.Swap.Total - host.Swap.Reserved
|
for k, v := range cc.MergeUnuseds() {
|
||||||
|
mergedDisks[k] = v
|
||||||
return host, err
|
}
|
||||||
|
for k, v := range cc.MergeMps() {
|
||||||
|
mergedDisks[k] = v
|
||||||
|
}
|
||||||
|
mergedDisks["rootfs"] = cc.RootFS
|
||||||
|
return mergedDisks
|
||||||
|
}
|
||||||
|
|
||||||
|
// get volume fornmat, size, volumeid, and storageid from instance volume data string (eg: local:100/vm-100-disk-0.raw ... )
|
||||||
|
func GetVolumeInfo(host Host, volume string) (Volume, string, string, error) {
|
||||||
|
volumeData := Volume{}
|
||||||
|
|
||||||
|
storageID := strings.Split(volume, ":")[0]
|
||||||
|
volumeID := strings.Split(volume, ",")[0]
|
||||||
|
storage, err := host.node.Storage(context.Background(), storageID)
|
||||||
|
if err != nil {
|
||||||
|
return volumeData, volumeID, storageID, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
content, err := storage.GetContent(context.Background())
|
||||||
|
if err != nil {
|
||||||
|
return volumeData, volumeID, storageID, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, c := range content {
|
||||||
|
if c.Volid == volumeID {
|
||||||
|
volumeData.Format = c.Format
|
||||||
|
volumeData.Size = uint64(c.Size)
|
||||||
|
volumeData.Volid = volumeID
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return volumeData, volumeID, storageID, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetNetInfo(net string) (Net, error) {
|
||||||
|
n := Net{}
|
||||||
|
|
||||||
|
for _, val := range strings.Split(net, ",") {
|
||||||
|
if strings.HasPrefix(val, "rate=") {
|
||||||
|
rate, err := strconv.ParseUint(strings.TrimPrefix(val, "rate="), 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return n, err
|
||||||
|
}
|
||||||
|
n.Rate = rate
|
||||||
|
} else if strings.HasPrefix(val, "tag=") {
|
||||||
|
vlan, err := strconv.ParseUint(strings.TrimPrefix(val, "tag="), 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return n, err
|
||||||
|
}
|
||||||
|
n.VLAN = vlan
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return n, nil
|
||||||
}
|
}
|
||||||
|
101
app/types.go
101
app/types.go
@ -1,9 +1,11 @@
|
|||||||
package app
|
package app
|
||||||
|
|
||||||
|
import "github.com/luthermonson/go-proxmox"
|
||||||
|
|
||||||
type Resource struct { // number of virtual cores (usually threads)
|
type Resource struct { // number of virtual cores (usually threads)
|
||||||
Reserved int64
|
Reserved uint64
|
||||||
Free int64
|
Free uint64
|
||||||
Total int64
|
Total uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
type Host struct {
|
type Host struct {
|
||||||
@ -11,47 +13,88 @@ type Host struct {
|
|||||||
Cores Resource
|
Cores Resource
|
||||||
Memory Resource
|
Memory Resource
|
||||||
Swap Resource
|
Swap Resource
|
||||||
Storage map[string]Storage
|
Hardware map[string]*HostSuperDevice
|
||||||
Hardware map[string]Device
|
//QEMU map[uint]*QEMUInstance
|
||||||
|
//LXC map[uint]*LXCInstance
|
||||||
|
Instance map[uint]*Instance
|
||||||
|
node *proxmox.Node
|
||||||
}
|
}
|
||||||
|
|
||||||
type Storage struct{}
|
/*
|
||||||
|
|
||||||
type QEMUInstance struct {
|
type QEMUInstance struct {
|
||||||
Name string
|
Name string
|
||||||
Proctype string
|
Proctype string
|
||||||
Cores Resource
|
Cores uint64
|
||||||
Memory Resource
|
Memory uint64
|
||||||
Drive map[int]Volume
|
Drive map[uint]*Volume
|
||||||
Disk map[int]Volume
|
Disk map[uint]*Volume
|
||||||
Net map[int]Net
|
Net map[uint]*Net
|
||||||
Device map[int]Device
|
Device map[uint]*InstanceDevice
|
||||||
|
vm *proxmox.VirtualMachine
|
||||||
}
|
}
|
||||||
|
|
||||||
type LXCInstance struct {
|
type LXCInstance struct {
|
||||||
Name string
|
Name string
|
||||||
Cores Resource
|
Cores uint64
|
||||||
Memory Resource
|
Memory uint64
|
||||||
Swap Resource
|
Swap uint64
|
||||||
RootDisk Volume
|
RootDisk *Volume
|
||||||
MP map[int]Volume
|
MP map[uint]*Volume
|
||||||
Net map[int]Net
|
Net map[uint]*Net
|
||||||
|
ct *proxmox.Container
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
type InstanceType bool
|
||||||
|
|
||||||
|
const (
|
||||||
|
VM InstanceType = true
|
||||||
|
CT InstanceType = false
|
||||||
|
)
|
||||||
|
|
||||||
|
type Instance struct {
|
||||||
|
Type InstanceType
|
||||||
|
Name string
|
||||||
|
Proctype string
|
||||||
|
Cores uint64
|
||||||
|
Memory uint64
|
||||||
|
Swap uint64
|
||||||
|
Volume map[string]*Volume
|
||||||
|
Net map[uint]*Net
|
||||||
|
Device map[uint]*InstanceDevice
|
||||||
|
config interface{}
|
||||||
|
configDisks map[string]string
|
||||||
|
configNets map[string]string
|
||||||
|
proxmox.ContainerInterface
|
||||||
}
|
}
|
||||||
|
|
||||||
type Volume struct {
|
type Volume struct {
|
||||||
Format string
|
|
||||||
Path string
|
Path string
|
||||||
Size string
|
Format string
|
||||||
Used string
|
Size uint64
|
||||||
|
Volid string
|
||||||
}
|
}
|
||||||
|
|
||||||
type Net struct{}
|
type Net struct {
|
||||||
|
Rate uint64
|
||||||
|
VLAN uint64
|
||||||
|
}
|
||||||
|
|
||||||
type Device struct {
|
type InstanceDevice struct {
|
||||||
BusID string `json:"id"`
|
Device []*HostDevice
|
||||||
DeviceName string `json:"device_name"`
|
PCIE bool
|
||||||
VendorName string `json:"vendor_name"`
|
}
|
||||||
SubsystemDeviceName string `json:"subsystem_device_name"`
|
|
||||||
SubsystemVendorName string `json:"subsystem_vendor_name"`
|
type HostSuperDevice struct {
|
||||||
|
BusID string
|
||||||
|
DeviceName string
|
||||||
|
VendorName string
|
||||||
|
Devices map[string]*HostDevice
|
||||||
|
}
|
||||||
|
|
||||||
|
type HostDevice struct {
|
||||||
|
SubID string
|
||||||
|
SubDeviceName string
|
||||||
|
SubVendorName string
|
||||||
Reserved bool
|
Reserved bool
|
||||||
}
|
}
|
||||||
|
50
app/utils.go
50
app/utils.go
@ -2,10 +2,10 @@ package app
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
|
"strings"
|
||||||
"github.com/luthermonson/go-proxmox"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const MiB = 1024 * 1024
|
const MiB = 1024 * 1024
|
||||||
@ -35,16 +35,38 @@ func GetConfig(configPath string) Config {
|
|||||||
return config
|
return config
|
||||||
}
|
}
|
||||||
|
|
||||||
func MarshallVirtualMachineConfig(v *proxmox.VirtualMachineConfig) {
|
// finds the first substring r in s such that s = ... a r b ...
|
||||||
v.HostPCIs = make(map[string]string)
|
func FindSubstringBetween(s string, a string, b string) (string, error) {
|
||||||
v.HostPCIs["hostpci0"] = v.HostPCI0
|
x := strings.Split(s, a)
|
||||||
v.HostPCIs["hostpci1"] = v.HostPCI1
|
if len(x) <= 2 {
|
||||||
v.HostPCIs["hostpci2"] = v.HostPCI2
|
return "", fmt.Errorf("%s not found in %s", a, s)
|
||||||
v.HostPCIs["hostpci3"] = v.HostPCI3
|
}
|
||||||
v.HostPCIs["hostpci4"] = v.HostPCI4
|
|
||||||
v.HostPCIs["hostpci5"] = v.HostPCI5
|
y := strings.Split(x[1], b)
|
||||||
v.HostPCIs["hostpci6"] = v.HostPCI6
|
if len(y) <= 2 {
|
||||||
v.HostPCIs["hostpci7"] = v.HostPCI7
|
return "", fmt.Errorf("%s not found in %s", b, s)
|
||||||
v.HostPCIs["hostpci8"] = v.HostPCI8
|
}
|
||||||
v.HostPCIs["hostpci9"] = v.HostPCI9
|
|
||||||
|
return y[0], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
40
go.mod
40
go.mod
@ -4,51 +4,15 @@ go 1.23
|
|||||||
|
|
||||||
toolchain go1.23.2
|
toolchain go1.23.2
|
||||||
|
|
||||||
require (
|
require github.com/luthermonson/go-proxmox v0.2.0
|
||||||
github.com/gin-gonic/gin v1.10.0
|
|
||||||
github.com/luthermonson/go-proxmox v0.2.0
|
|
||||||
)
|
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/buger/goterm v1.0.4 // indirect
|
github.com/buger/goterm v1.0.4 // indirect
|
||||||
github.com/bytedance/sonic v1.12.3 // indirect
|
|
||||||
github.com/bytedance/sonic/loader v0.2.0 // 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/diskfs/go-diskfs v1.4.2 // indirect
|
||||||
github.com/djherbis/times v1.6.0 // indirect
|
github.com/djherbis/times v1.6.0 // indirect
|
||||||
github.com/elliotwutingfeng/asciiset v0.0.0-20230602022725-51bbb787efab // indirect
|
|
||||||
github.com/gabriel-vasile/mimetype v1.4.6 // indirect
|
|
||||||
github.com/gin-contrib/sse v0.1.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.22.1 // indirect
|
|
||||||
github.com/goccy/go-json v0.10.3 // indirect
|
|
||||||
github.com/google/uuid v1.3.0 // indirect
|
|
||||||
github.com/gorilla/websocket v1.5.3 // indirect
|
github.com/gorilla/websocket v1.5.3 // indirect
|
||||||
github.com/jinzhu/copier v0.4.0 // indirect
|
github.com/jinzhu/copier v0.4.0 // indirect
|
||||||
github.com/json-iterator/go v1.1.12 // indirect
|
|
||||||
github.com/klauspost/compress v1.17.4 // indirect
|
|
||||||
github.com/klauspost/cpuid/v2 v2.2.8 // indirect
|
|
||||||
github.com/knz/go-libedit v1.10.1 // indirect
|
|
||||||
github.com/leodido/go-urn v1.4.0 // indirect
|
|
||||||
github.com/magefile/mage v1.15.0 // indirect
|
github.com/magefile/mage v1.15.0 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
github.com/stretchr/testify v1.9.0 // 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.3 // indirect
|
|
||||||
github.com/pierrec/lz4/v4 v4.1.17 // indirect
|
|
||||||
github.com/pkg/xattr v0.4.9 // indirect
|
|
||||||
github.com/sirupsen/logrus v1.9.4-0.20230606125235-dd1b4c2e81af // indirect
|
|
||||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
|
||||||
github.com/ugorji/go/codec v1.2.12 // indirect
|
|
||||||
github.com/ulikunitz/xz v0.5.11 // indirect
|
|
||||||
golang.org/x/arch v0.11.0 // indirect
|
|
||||||
golang.org/x/crypto v0.28.0 // indirect
|
|
||||||
golang.org/x/net v0.30.0 // indirect
|
|
||||||
golang.org/x/sys v0.26.0 // indirect
|
golang.org/x/sys v0.26.0 // indirect
|
||||||
golang.org/x/text v0.19.0 // indirect
|
|
||||||
google.golang.org/protobuf v1.35.1 // indirect
|
|
||||||
gopkg.in/djherbis/times.v1 v1.3.0 // indirect
|
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
|
||||||
)
|
)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user