implement populate model hosts/instances/volumes/nets/devices
This commit is contained in:
253
app/proxmox.go
253
app/proxmox.go
@@ -5,6 +5,7 @@ import (
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/luthermonson/go-proxmox"
|
||||
@@ -14,6 +15,14 @@ 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{
|
||||
@@ -23,8 +32,6 @@ func NewClient(token string, secret string) ProxmoxClient {
|
||||
},
|
||||
}
|
||||
|
||||
println(token, secret)
|
||||
|
||||
client := proxmox.NewClient("https://pve.tronnet.net/api2/json",
|
||||
proxmox.WithHTTPClient(&HTTPClient),
|
||||
proxmox.WithAPIToken(token, secret),
|
||||
@@ -42,86 +49,216 @@ func (pve ProxmoxClient) Version() (proxmox.Version, error) {
|
||||
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) {
|
||||
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)
|
||||
if err != nil {
|
||||
return host, err
|
||||
}
|
||||
|
||||
devices := []Device{}
|
||||
devices := []PVEDevice{}
|
||||
err = pve.client.Get(context.Background(), fmt.Sprintf("/nodes/%s/hardware/pci", nodeName), &devices)
|
||||
if err != nil {
|
||||
return host, err
|
||||
}
|
||||
|
||||
vms, err := node.VirtualMachines(context.Background())
|
||||
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
|
||||
// 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, ...]
|
||||
DeviceSubsystemMap := make(map[string][]string)
|
||||
for _, device := range devices {
|
||||
host.Hardware[device.BusID] = device
|
||||
SupersystemID := strings.Split(device.BusID, ".")[0]
|
||||
DeviceSubsystemMap[SupersystemID] = append(DeviceSubsystemMap[SupersystemID], device.BusID)
|
||||
}
|
||||
|
||||
host.Name = node.Name
|
||||
host.Cores.Total = int64(node.CPUInfo.CPUs)
|
||||
host.Memory.Total = int64(node.Memory.Total)
|
||||
host.Swap.Total = int64(node.Swap.Total)
|
||||
|
||||
for _, vm := range vms {
|
||||
vm, err := node.VirtualMachine(context.Background(), int(vm.VMID))
|
||||
SupersystemID, SubsystemID, err := SplitDeviceBusID(device.BusID)
|
||||
if err != nil {
|
||||
return host, err
|
||||
}
|
||||
|
||||
host.Cores.Reserved += int64(vm.VirtualMachineConfig.Cores)
|
||||
host.Memory.Reserved += int64(vm.VirtualMachineConfig.Memory * MiB)
|
||||
if host.Hardware[SupersystemID] == nil {
|
||||
host.Hardware[SupersystemID] = &HostSuperDevice{
|
||||
BusID: SupersystemID,
|
||||
DeviceName: device.DeviceName,
|
||||
VendorName: device.VendorName,
|
||||
Devices: make(map[string]*HostDevice),
|
||||
}
|
||||
}
|
||||
|
||||
MarshallVirtualMachineConfig(vm.VirtualMachineConfig)
|
||||
|
||||
for _, v := range vm.VirtualMachineConfig.HostPCIs {
|
||||
HostPCIBusID := strings.Split(v, ",")[0]
|
||||
if device, ok := host.Hardware[HostPCIBusID]; ok { // is a specific subsystem of device
|
||||
device.Reserved = true
|
||||
host.Hardware[HostPCIBusID] = device
|
||||
} else if SubsystemBusIDs, ok := DeviceSubsystemMap[HostPCIBusID]; ok { // is a supersystem device containing multiple subsystems
|
||||
for _, SubsystemBusID := range SubsystemBusIDs {
|
||||
device := host.Hardware[SubsystemBusID]
|
||||
device.Reserved = true
|
||||
host.Hardware[SubsystemBusID] = device
|
||||
}
|
||||
if !DeviceBusIDIsSuperDevice(device.BusID) {
|
||||
host.Hardware[SupersystemID].Devices[SubsystemID] = &HostDevice{
|
||||
SubID: SubsystemID,
|
||||
SubDeviceName: device.SubsystemDeviceName,
|
||||
SubVendorName: device.SubsystemVendorName,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, ct := range cts {
|
||||
ct, err := node.Container(context.Background(), int(ct.VMID))
|
||||
if err != nil {
|
||||
return host, err
|
||||
}
|
||||
|
||||
host.Cores.Reserved += int64(ct.ContainerConfig.Cores)
|
||||
host.Memory.Reserved += int64(ct.ContainerConfig.Memory * MiB)
|
||||
host.Swap.Reserved += int64(ct.ContainerConfig.Swap * MiB)
|
||||
}
|
||||
|
||||
host.Cores.Free = host.Cores.Total - host.Cores.Reserved
|
||||
host.Memory.Free = host.Memory.Total - host.Memory.Reserved
|
||||
host.Swap.Free = host.Swap.Total - host.Swap.Reserved
|
||||
host.Name = node.Name
|
||||
host.Cores.Total = uint64(node.CPUInfo.CPUs)
|
||||
host.Memory.Total = uint64(node.Memory.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 {
|
||||
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 {
|
||||
return instance, err
|
||||
}
|
||||
|
||||
config := vm.VirtualMachineConfig
|
||||
config.HostPCIs = config.MergeHostPCIs()
|
||||
instance.configNets = config.MergeNets()
|
||||
instance.configDisks = MergeVMDisksAndUnused(config)
|
||||
|
||||
instance.config = config
|
||||
instance.Type = VM
|
||||
|
||||
instance.Name = vm.Name
|
||||
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)
|
||||
|
||||
return instance, nil
|
||||
}
|
||||
|
||||
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 {
|
||||
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 {
|
||||
return instance, err
|
||||
}
|
||||
|
||||
config := ct.ContainerConfig
|
||||
instance.configNets = config.MergeNets()
|
||||
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
|
||||
}
|
||||
|
||||
func MergeCTDisksAndUnused(cc *proxmox.ContainerConfig) map[string]string {
|
||||
mergedDisks := make(map[string]string)
|
||||
for k, v := range cc.MergeUnuseds() {
|
||||
mergedDisks[k] = v
|
||||
}
|
||||
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
|
||||
}
|
||||
|
Reference in New Issue
Block a user