implement node endpoint
This commit is contained in:
parent
6b41ca984c
commit
c91f54f506
2
Makefile
2
Makefile
@ -1,3 +1,5 @@
|
|||||||
|
.PHONY: build test clean
|
||||||
|
|
||||||
build: clean
|
build: clean
|
||||||
CGO_ENABLED=0 go build -ldflags="-s -w" -o dist/ .
|
CGO_ENABLED=0 go build -ldflags="-s -w" -o dist/ .
|
||||||
|
|
||||||
|
24
app/app.go
24
app/app.go
@ -1,8 +1,9 @@
|
|||||||
package app
|
package app
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"encoding/gob"
|
||||||
"flag"
|
"flag"
|
||||||
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
@ -13,21 +14,24 @@ import (
|
|||||||
|
|
||||||
const APIVersion string = "0.0.1"
|
const APIVersion string = "0.0.1"
|
||||||
|
|
||||||
var client *proxmox.Client = nil
|
var client ProxmoxClient
|
||||||
|
|
||||||
func Run() {
|
func Run() {
|
||||||
|
gob.Register(proxmox.Client{})
|
||||||
|
|
||||||
configPath := flag.String("config", "config.json", "path to config.json file")
|
configPath := flag.String("config", "config.json", "path to config.json file")
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
config := GetConfig(*configPath)
|
config := GetConfig(*configPath)
|
||||||
log.Println("Initialized config from " + *configPath)
|
log.Println("Initialized config from " + *configPath)
|
||||||
|
|
||||||
client = NewClient(config.PVE.Token.ID, config.PVE.Token.Secret)
|
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()
|
||||||
|
|
||||||
router.GET("/version", func(c *gin.Context) {
|
router.GET("/version", func(c *gin.Context) {
|
||||||
PVEVersion, err := client.Version(context.Background())
|
PVEVersion, err := client.Version()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||||
} else {
|
} else {
|
||||||
@ -35,6 +39,14 @@ func Run() {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
router.Run("0.0.0.0:" + strconv.Itoa(config.ListenPort))
|
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))
|
||||||
}
|
}
|
||||||
|
117
app/proxmox.go
117
app/proxmox.go
@ -1,18 +1,127 @@
|
|||||||
package app
|
package app
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
"crypto/tls"
|
||||||
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/luthermonson/go-proxmox"
|
"github.com/luthermonson/go-proxmox"
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewClient(tokenID string, secret string) *proxmox.Client {
|
type ProxmoxClient struct {
|
||||||
HTTPClient := http.Client{}
|
client *proxmox.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewClient(token string, secret string) ProxmoxClient {
|
||||||
|
HTTPClient := http.Client{
|
||||||
|
Transport: &http.Transport{
|
||||||
|
TLSClientConfig: &tls.Config{
|
||||||
|
InsecureSkipVerify: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
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(tokenID, secret),
|
proxmox.WithAPIToken(token, secret),
|
||||||
)
|
)
|
||||||
|
|
||||||
return client
|
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 and returns a Node's CPU, memory, swap, and Hardware (PCI) resources
|
||||||
|
func (pve ProxmoxClient) Node(nodeName string) (Host, error) {
|
||||||
|
host := Host{}
|
||||||
|
host.Hardware = make(map[string]PVEDevice)
|
||||||
|
|
||||||
|
node, err := pve.client.Node(context.Background(), nodeName)
|
||||||
|
if err != nil {
|
||||||
|
return host, err
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
// 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))
|
||||||
|
if err != nil {
|
||||||
|
return host, err
|
||||||
|
}
|
||||||
|
|
||||||
|
host.Cores.Reserved += int64(vm.VirtualMachineConfig.Cores)
|
||||||
|
host.Memory.Reserved += int64(vm.VirtualMachineConfig.Memory * MiB)
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
return host, err
|
||||||
}
|
}
|
||||||
|
68
app/types.go
68
app/types.go
@ -1,37 +1,57 @@
|
|||||||
package app
|
package app
|
||||||
|
|
||||||
type PVEBus int
|
type Resource struct { // number of virtual cores (usually threads)
|
||||||
|
Reserved int64
|
||||||
|
Free int64
|
||||||
|
Total int64
|
||||||
|
}
|
||||||
|
|
||||||
const (
|
type Host struct {
|
||||||
IDE PVEBus = iota
|
Name string
|
||||||
SATA
|
Cores Resource
|
||||||
)
|
Memory Resource
|
||||||
|
Swap Resource
|
||||||
|
Storage map[string]Storage
|
||||||
|
Hardware map[string]Device
|
||||||
|
}
|
||||||
|
|
||||||
type PVEDrive struct{}
|
type Storage struct{}
|
||||||
|
|
||||||
type PVEDisk struct{}
|
|
||||||
|
|
||||||
type PVENet struct{}
|
|
||||||
|
|
||||||
type PVEDevice struct{}
|
|
||||||
|
|
||||||
type QEMUInstance struct {
|
type QEMUInstance struct {
|
||||||
Name string
|
Name string
|
||||||
Proctype string
|
Proctype string
|
||||||
Cores int16
|
Cores Resource
|
||||||
Memory int32
|
Memory Resource
|
||||||
Drive map[int]PVEDrive
|
Drive map[int]Volume
|
||||||
Disk map[int]PVEDisk
|
Disk map[int]Volume
|
||||||
Net map[int]PVENet
|
Net map[int]Net
|
||||||
Device map[int]PVEDevice
|
Device map[int]Device
|
||||||
}
|
}
|
||||||
|
|
||||||
type LXCInstance struct {
|
type LXCInstance struct {
|
||||||
Name string
|
Name string
|
||||||
Cores int16
|
Cores Resource
|
||||||
Memory int32
|
Memory Resource
|
||||||
Swap int32
|
Swap Resource
|
||||||
RootDisk PVEDrive
|
RootDisk Volume
|
||||||
MP map[int]PVEDisk
|
MP map[int]Volume
|
||||||
Net map[int]PVENet
|
Net map[int]Net
|
||||||
|
}
|
||||||
|
|
||||||
|
type Volume struct {
|
||||||
|
Format string
|
||||||
|
Path string
|
||||||
|
Size string
|
||||||
|
Used string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Net struct{}
|
||||||
|
|
||||||
|
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
|
||||||
}
|
}
|
||||||
|
22
app/utils.go
22
app/utils.go
@ -4,14 +4,20 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
"github.com/luthermonson/go-proxmox"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const MiB = 1024 * 1024
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
ListenPort int `json:"listenPort"`
|
ListenPort int `json:"listenPort"`
|
||||||
PVE struct {
|
PVE struct {
|
||||||
Token struct {
|
Token struct {
|
||||||
|
USER string `json:"user"`
|
||||||
|
REALM string `json:"realm"`
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
Secret string `json:"secret"`
|
Secret string `json:"uuid"`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -28,3 +34,17 @@ func GetConfig(configPath string) Config {
|
|||||||
}
|
}
|
||||||
return config
|
return config
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func MarshallVirtualMachineConfig(v *proxmox.VirtualMachineConfig) {
|
||||||
|
v.HostPCIs = make(map[string]string)
|
||||||
|
v.HostPCIs["hostpci0"] = v.HostPCI0
|
||||||
|
v.HostPCIs["hostpci1"] = v.HostPCI1
|
||||||
|
v.HostPCIs["hostpci2"] = v.HostPCI2
|
||||||
|
v.HostPCIs["hostpci3"] = v.HostPCI3
|
||||||
|
v.HostPCIs["hostpci4"] = v.HostPCI4
|
||||||
|
v.HostPCIs["hostpci5"] = v.HostPCI5
|
||||||
|
v.HostPCIs["hostpci6"] = v.HostPCI6
|
||||||
|
v.HostPCIs["hostpci7"] = v.HostPCI7
|
||||||
|
v.HostPCIs["hostpci8"] = v.HostPCI8
|
||||||
|
v.HostPCIs["hostpci9"] = v.HostPCI9
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user