ProxmoxAAS-Fabric/app/proxmox.go

266 lines
6.7 KiB
Go
Raw Normal View History

2024-10-18 04:28:31 +00:00
package app
import (
2024-12-27 19:59:44 +00:00
"context"
"crypto/tls"
"fmt"
2024-10-18 04:28:31 +00:00
"net/http"
"strconv"
2024-12-27 19:59:44 +00:00
"strings"
2024-10-18 04:28:31 +00:00
"github.com/luthermonson/go-proxmox"
)
2024-12-27 19:59:44 +00:00
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"`
}
2024-12-27 19:59:44 +00:00
func NewClient(token string, secret string) ProxmoxClient {
HTTPClient := http.Client{
Transport: &http.Transport{
TLSClientConfig: &tls.Config{
InsecureSkipVerify: true,
},
},
}
2024-10-18 04:28:31 +00:00
client := proxmox.NewClient("https://pve.tronnet.net/api2/json",
proxmox.WithHTTPClient(&HTTPClient),
2024-12-27 19:59:44 +00:00
proxmox.WithAPIToken(token, secret),
2024-10-18 04:28:31 +00:00
)
2024-12-27 19:59:44 +00:00
return ProxmoxClient{client: client}
}
// Gets and returns the PVE API version
func (pve ProxmoxClient) Version() (proxmox.Version, error) {
version, err := pve.client.Version(context.Background())
if err != nil {
return *version, err
}
return *version, err
}
// 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
2024-12-27 19:59:44 +00:00
func (pve ProxmoxClient) Node(nodeName string) (Host, error) {
host := Host{}
host.Hardware = make(map[string]*HostSuperDevice)
host.Instance = make(map[uint]*Instance)
2024-12-27 19:59:44 +00:00
node, err := pve.client.Node(context.Background(), nodeName)
if err != nil {
return host, err
}
devices := []PVEDevice{}
2024-12-27 19:59:44 +00:00
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,
}
}
2024-12-27 19:59:44 +00:00
}
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())
2024-12-27 19:59:44 +00:00
if err != nil {
return nil, err
}
ids := []uint{}
for _, vm := range vms {
ids = append(ids, uint(vm.VMID))
2024-12-27 19:59:44 +00:00
}
return ids, nil
}
2024-12-27 19:59:44 +00:00
// 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
2024-12-27 19:59:44 +00:00
}
config := vm.VirtualMachineConfig
2025-01-10 01:08:44 +00:00
instance.configHostPCIs = config.MergeHostPCIs()
instance.configNets = config.MergeNets()
instance.configDisks = MergeVMDisksAndUnused(config)
2024-12-27 19:59:44 +00:00
instance.config = config
instance.Type = VM
2024-12-27 19:59:44 +00:00
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
2024-12-27 19:59:44 +00:00
}
return mergedDisks
}
2024-12-27 19:59:44 +00:00
// 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{}
2024-12-27 19:59:44 +00:00
for _, ct := range cts {
ids = append(ids, uint(ct.VMID))
}
return ids, nil
}
2024-12-27 19:59:44 +00:00
// 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
2024-12-27 19:59:44 +00:00
}
config := ct.ContainerConfig
2025-01-10 01:08:44 +00:00
instance.configHostPCIs = make(map[string]string)
instance.configNets = config.MergeNets()
instance.configDisks = MergeCTDisksAndUnused(config)
2024-12-27 19:59:44 +00:00
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
2024-10-18 04:28:31 +00:00
}