move getAPI request interface body to parameter,
move VMPath and FormatNumber methods to common utils
This commit is contained in:
@@ -31,7 +31,6 @@ type RequestType int
|
||||
|
||||
type RequestContext struct {
|
||||
Cookies map[string]string
|
||||
Body map[string]any
|
||||
}
|
||||
|
||||
type Auth struct {
|
||||
|
@@ -10,6 +10,7 @@ import (
|
||||
"io"
|
||||
"io/fs"
|
||||
"log"
|
||||
"math"
|
||||
"net/http"
|
||||
"os"
|
||||
"reflect"
|
||||
@@ -22,6 +23,12 @@ import (
|
||||
var TMPL *template.Template
|
||||
var Global Config
|
||||
|
||||
type VMPath struct {
|
||||
Node string
|
||||
Type string
|
||||
VMID string
|
||||
}
|
||||
|
||||
func GetConfig(configPath string) Config {
|
||||
content, err := os.ReadFile(configPath)
|
||||
if err != nil {
|
||||
@@ -159,7 +166,7 @@ func HandleNonFatalError(c *gin.Context, err error) {
|
||||
c.Status(http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
func RequestGetAPI(path string, context RequestContext) (*http.Response, int, error) {
|
||||
func RequestGetAPI(path string, context RequestContext, body any) (*http.Response, int, error) {
|
||||
req, err := http.NewRequest("GET", Global.API+path, nil)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
@@ -186,9 +193,18 @@ func RequestGetAPI(path string, context RequestContext) (*http.Response, int, er
|
||||
return nil, response.StatusCode, err
|
||||
}
|
||||
|
||||
err = json.Unmarshal(data, &context.Body)
|
||||
if err != nil {
|
||||
return nil, response.StatusCode, err
|
||||
switch body.(type) { // write json to body object depending on type, currently supports map[string]any (ie json) or []any (ie array of json)
|
||||
case *map[string]any:
|
||||
err = json.Unmarshal(data, &body)
|
||||
if err != nil {
|
||||
return nil, response.StatusCode, err
|
||||
}
|
||||
case *[]any:
|
||||
err = json.Unmarshal(data, &body)
|
||||
if err != nil {
|
||||
return nil, response.StatusCode, err
|
||||
}
|
||||
default:
|
||||
}
|
||||
|
||||
return response, response.StatusCode, nil
|
||||
@@ -205,3 +221,38 @@ func GetAuth(c *gin.Context) (Auth, error) {
|
||||
return Auth{username, token, csrf}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func ExtractVMPath(c *gin.Context) (VMPath, error) {
|
||||
req_node := c.Query("node")
|
||||
req_type := c.Query("type")
|
||||
req_vmid := c.Query("vmid")
|
||||
if req_node == "" || req_type == "" || req_vmid == "" {
|
||||
return VMPath{}, fmt.Errorf("request missing required values: (node: %s, type: %s, vmid: %s)", req_node, req_type, req_vmid)
|
||||
}
|
||||
vm_path := VMPath{
|
||||
Node: req_node,
|
||||
Type: req_type,
|
||||
VMID: req_vmid,
|
||||
}
|
||||
return vm_path, nil
|
||||
}
|
||||
|
||||
func FormatNumber(val int64, base int64) (float64, string) {
|
||||
valf := float64(val)
|
||||
basef := float64(base)
|
||||
steps := 0
|
||||
for math.Abs(valf) > basef && steps < 4 {
|
||||
valf /= basef
|
||||
steps++
|
||||
}
|
||||
|
||||
if base == 1000 {
|
||||
prefixes := []string{"", "K", "M", "G", "T"}
|
||||
return valf, prefixes[steps]
|
||||
} else if base == 1024 {
|
||||
prefixes := []string{"", "Ki", "Mi", "Gi", "Ti"}
|
||||
return valf, prefixes[steps]
|
||||
} else {
|
||||
return 0, ""
|
||||
}
|
||||
}
|
||||
|
@@ -2,7 +2,6 @@ package routes
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"net/http"
|
||||
"proxmoxaas-dashboard/app/common"
|
||||
|
||||
@@ -108,7 +107,7 @@ func HandleGETAccount(c *gin.Context) {
|
||||
for k, v := range account.Resources {
|
||||
switch t := v.(type) {
|
||||
case NumericResource:
|
||||
avail, prefix := FormatNumber(t.Total.Avail*t.Multiplier, t.Base)
|
||||
avail, prefix := common.FormatNumber(t.Total.Avail*t.Multiplier, t.Base)
|
||||
account.Resources[k] = ResourceChart{
|
||||
Type: t.Type,
|
||||
Display: t.Display,
|
||||
@@ -121,7 +120,7 @@ func HandleGETAccount(c *gin.Context) {
|
||||
ColorHex: InterpolateColorHSV(Green, Red, float64(t.Total.Used)/float64(t.Total.Max)).ToHTML(),
|
||||
}
|
||||
case StorageResource:
|
||||
avail, prefix := FormatNumber(t.Total.Avail*t.Multiplier, t.Base)
|
||||
avail, prefix := common.FormatNumber(t.Total.Avail*t.Multiplier, t.Base)
|
||||
account.Resources[k] = ResourceChart{
|
||||
Type: t.Type,
|
||||
Display: t.Display,
|
||||
@@ -181,45 +180,45 @@ func GetUserAccount(auth common.Auth) (Account, error) {
|
||||
"PVEAuthCookie": auth.Token,
|
||||
"CSRFPreventionToken": auth.CSRF,
|
||||
},
|
||||
Body: map[string]any{},
|
||||
}
|
||||
|
||||
// get user account basic data
|
||||
res, code, err := common.RequestGetAPI("/user/config/cluster", ctx)
|
||||
body := map[string]any{}
|
||||
res, code, err := common.RequestGetAPI("/user/config/cluster", ctx, &body)
|
||||
if err != nil {
|
||||
return account, err
|
||||
}
|
||||
if code != 200 {
|
||||
return account, fmt.Errorf("request to /user/config/cluster resulted in %+v", res)
|
||||
}
|
||||
err = mapstructure.Decode(ctx.Body, &account)
|
||||
err = mapstructure.Decode(body, &account)
|
||||
if err != nil {
|
||||
return account, err
|
||||
} else {
|
||||
account.Username = auth.Username
|
||||
}
|
||||
|
||||
ctx.Body = map[string]any{}
|
||||
body = map[string]any{}
|
||||
// get user resources
|
||||
res, code, err = common.RequestGetAPI("/user/dynamic/resources", ctx)
|
||||
res, code, err = common.RequestGetAPI("/user/dynamic/resources", ctx, &body)
|
||||
if err != nil {
|
||||
return account, err
|
||||
}
|
||||
if code != 200 {
|
||||
return account, fmt.Errorf("request to /user/dynamic/resources resulted in %+v", res)
|
||||
}
|
||||
resources := ctx.Body
|
||||
resources := body
|
||||
|
||||
ctx.Body = map[string]any{}
|
||||
body = map[string]any{}
|
||||
// get resource meta data
|
||||
res, code, err = common.RequestGetAPI("/global/config/resources", ctx)
|
||||
res, code, err = common.RequestGetAPI("/global/config/resources", ctx, &body)
|
||||
if err != nil {
|
||||
return account, err
|
||||
}
|
||||
if code != 200 {
|
||||
return account, fmt.Errorf("request to /global/config/resources resulted in %+v", res)
|
||||
}
|
||||
meta := ctx.Body["resources"].(map[string]any)
|
||||
meta := body["resources"].(map[string]any)
|
||||
|
||||
// build each resource by its meta type
|
||||
for k, v := range meta {
|
||||
@@ -259,26 +258,6 @@ func GetUserAccount(auth common.Auth) (Account, error) {
|
||||
return account, nil
|
||||
}
|
||||
|
||||
func FormatNumber(val int64, base int64) (float64, string) {
|
||||
valf := float64(val)
|
||||
basef := float64(base)
|
||||
steps := 0
|
||||
for math.Abs(valf) > basef && steps < 4 {
|
||||
valf /= basef
|
||||
steps++
|
||||
}
|
||||
|
||||
if base == 1000 {
|
||||
prefixes := []string{"", "K", "M", "G", "T"}
|
||||
return valf, prefixes[steps]
|
||||
} else if base == 1024 {
|
||||
prefixes := []string{"", "Ki", "Mi", "Gi", "Ti"}
|
||||
return valf, prefixes[steps]
|
||||
} else {
|
||||
return 0, ""
|
||||
}
|
||||
}
|
||||
|
||||
// interpolate between min and max by normalized (0 - 1) val
|
||||
func InterpolateColorHSV(min color.RGB, max color.RGB, val float64) color.RGB {
|
||||
minhsl := min.ToHSL()
|
||||
|
@@ -13,12 +13,6 @@ import (
|
||||
"github.com/go-viper/mapstructure/v2"
|
||||
)
|
||||
|
||||
type VMPath struct {
|
||||
Node string
|
||||
Type string
|
||||
VMID string
|
||||
}
|
||||
|
||||
// imported types from fabric
|
||||
|
||||
type InstanceConfig struct {
|
||||
@@ -56,7 +50,7 @@ type CPUConfig struct {
|
||||
func HandleGETConfig(c *gin.Context) {
|
||||
auth, err := common.GetAuth(c)
|
||||
if err == nil {
|
||||
vm_path, err := ExtractVMPath(c)
|
||||
vm_path, err := common.ExtractVMPath(c)
|
||||
if err != nil {
|
||||
common.HandleNonFatalError(c, err)
|
||||
}
|
||||
@@ -91,7 +85,7 @@ func HandleGETConfig(c *gin.Context) {
|
||||
func HandleGETConfigVolumesFragment(c *gin.Context) {
|
||||
auth, err := common.GetAuth(c)
|
||||
if err == nil {
|
||||
vm_path, err := ExtractVMPath(c)
|
||||
vm_path, err := common.ExtractVMPath(c)
|
||||
if err != nil {
|
||||
common.HandleNonFatalError(c, err)
|
||||
}
|
||||
@@ -114,7 +108,7 @@ func HandleGETConfigVolumesFragment(c *gin.Context) {
|
||||
func HandleGETConfigNetsFragment(c *gin.Context) {
|
||||
auth, err := common.GetAuth(c)
|
||||
if err == nil {
|
||||
vm_path, err := ExtractVMPath(c)
|
||||
vm_path, err := common.ExtractVMPath(c)
|
||||
if err != nil {
|
||||
common.HandleNonFatalError(c, err)
|
||||
}
|
||||
@@ -137,7 +131,7 @@ func HandleGETConfigNetsFragment(c *gin.Context) {
|
||||
func HandleGETConfigDevicesFragment(c *gin.Context) {
|
||||
auth, err := common.GetAuth(c)
|
||||
if err == nil {
|
||||
vm_path, err := ExtractVMPath(c)
|
||||
vm_path, err := common.ExtractVMPath(c)
|
||||
if err != nil {
|
||||
common.HandleNonFatalError(c, err)
|
||||
}
|
||||
@@ -160,7 +154,7 @@ func HandleGETConfigDevicesFragment(c *gin.Context) {
|
||||
func HandleGETConfigBootFragment(c *gin.Context) {
|
||||
auth, err := common.GetAuth(c)
|
||||
if err == nil {
|
||||
vm_path, err := ExtractVMPath(c)
|
||||
vm_path, err := common.ExtractVMPath(c)
|
||||
if err != nil {
|
||||
common.HandleNonFatalError(c, err)
|
||||
}
|
||||
@@ -180,22 +174,7 @@ func HandleGETConfigBootFragment(c *gin.Context) {
|
||||
}
|
||||
}
|
||||
|
||||
func ExtractVMPath(c *gin.Context) (VMPath, error) {
|
||||
req_node := c.Query("node")
|
||||
req_type := c.Query("type")
|
||||
req_vmid := c.Query("vmid")
|
||||
if req_node == "" || req_type == "" || req_vmid == "" {
|
||||
return VMPath{}, fmt.Errorf("request missing required values: (node: %s, type: %s, vmid: %s)", req_node, req_type, req_vmid)
|
||||
}
|
||||
vm_path := VMPath{
|
||||
Node: req_node,
|
||||
Type: req_type,
|
||||
VMID: req_vmid,
|
||||
}
|
||||
return vm_path, nil
|
||||
}
|
||||
|
||||
func GetInstanceConfig(vm VMPath, auth common.Auth) (InstanceConfig, error) {
|
||||
func GetInstanceConfig(vm common.VMPath, auth common.Auth) (InstanceConfig, error) {
|
||||
config := InstanceConfig{}
|
||||
path := fmt.Sprintf("/cluster/%s/%s/%s", vm.Node, vm.Type, vm.VMID)
|
||||
ctx := common.RequestContext{
|
||||
@@ -204,9 +183,9 @@ func GetInstanceConfig(vm VMPath, auth common.Auth) (InstanceConfig, error) {
|
||||
"PVEAuthCookie": auth.Token,
|
||||
"CSRFPreventionToken": auth.CSRF,
|
||||
},
|
||||
Body: map[string]any{},
|
||||
}
|
||||
res, code, err := common.RequestGetAPI(path, ctx)
|
||||
body := map[string]any{}
|
||||
res, code, err := common.RequestGetAPI(path, ctx, &body)
|
||||
if err != nil {
|
||||
return config, err
|
||||
}
|
||||
@@ -214,7 +193,7 @@ func GetInstanceConfig(vm VMPath, auth common.Auth) (InstanceConfig, error) {
|
||||
return config, fmt.Errorf("request to %s resulted in %+v", path, res)
|
||||
}
|
||||
|
||||
err = mapstructure.Decode(ctx.Body, &config)
|
||||
err = mapstructure.Decode(body, &config)
|
||||
if err != nil {
|
||||
return config, err
|
||||
}
|
||||
@@ -225,7 +204,7 @@ func GetInstanceConfig(vm VMPath, auth common.Auth) (InstanceConfig, error) {
|
||||
return config, nil
|
||||
}
|
||||
|
||||
func GetCPUTypes(vm VMPath, auth common.Auth) (common.Select, error) {
|
||||
func GetCPUTypes(vm common.VMPath, auth common.Auth) (common.Select, error) {
|
||||
cputypes := common.Select{
|
||||
ID: "proctype",
|
||||
Required: true,
|
||||
@@ -238,10 +217,10 @@ func GetCPUTypes(vm VMPath, auth common.Auth) (common.Select, error) {
|
||||
"PVEAuthCookie": auth.Token,
|
||||
"CSRFPreventionToken": auth.CSRF,
|
||||
},
|
||||
Body: map[string]any{},
|
||||
}
|
||||
body := map[string]any{}
|
||||
path := "/global/config/resources"
|
||||
res, code, err := common.RequestGetAPI(path, ctx)
|
||||
res, code, err := common.RequestGetAPI(path, ctx, &body)
|
||||
if err != nil {
|
||||
return cputypes, err
|
||||
}
|
||||
@@ -249,15 +228,15 @@ func GetCPUTypes(vm VMPath, auth common.Auth) (common.Select, error) {
|
||||
return cputypes, fmt.Errorf("request to %s resulted in %+v", path, res)
|
||||
}
|
||||
global := GlobalConfig{}
|
||||
err = mapstructure.Decode(ctx.Body["resources"], &global)
|
||||
err = mapstructure.Decode(body["resources"], &global)
|
||||
if err != nil {
|
||||
return cputypes, err
|
||||
}
|
||||
|
||||
// get user resource config
|
||||
ctx.Body = map[string]any{}
|
||||
body = map[string]any{}
|
||||
path = "/user/config/resources"
|
||||
res, code, err = common.RequestGetAPI(path, ctx)
|
||||
res, code, err = common.RequestGetAPI(path, ctx, &body)
|
||||
if err != nil {
|
||||
return cputypes, err
|
||||
}
|
||||
@@ -265,7 +244,7 @@ func GetCPUTypes(vm VMPath, auth common.Auth) (common.Select, error) {
|
||||
return cputypes, fmt.Errorf("request to %s resulted in %+v", path, res)
|
||||
}
|
||||
user := UserConfigResources{}
|
||||
err = mapstructure.Decode(ctx.Body, &user)
|
||||
err = mapstructure.Decode(body, &user)
|
||||
if err != nil {
|
||||
return cputypes, err
|
||||
}
|
||||
@@ -287,9 +266,9 @@ func GetCPUTypes(vm VMPath, auth common.Auth) (common.Select, error) {
|
||||
}
|
||||
} else { // cpu is a blacklist
|
||||
// get the supported cpu types from the node
|
||||
ctx.Body = map[string]any{}
|
||||
body = map[string]any{}
|
||||
path = fmt.Sprintf("/proxmox/nodes/%s/capabilities/qemu/cpu", vm.Node)
|
||||
res, code, err = common.RequestGetAPI(path, ctx)
|
||||
res, code, err = common.RequestGetAPI(path, ctx, &body)
|
||||
if err != nil {
|
||||
return cputypes, err
|
||||
}
|
||||
@@ -299,7 +278,7 @@ func GetCPUTypes(vm VMPath, auth common.Auth) (common.Select, error) {
|
||||
supported := struct {
|
||||
data []CPUConfig
|
||||
}{}
|
||||
err = mapstructure.Decode(ctx.Body, supported)
|
||||
err = mapstructure.Decode(body, supported)
|
||||
if err != nil {
|
||||
return cputypes, err
|
||||
}
|
||||
|
@@ -26,6 +26,7 @@ type InstanceCard struct {
|
||||
NodeStatus string
|
||||
ConfigPath string
|
||||
ConsolePath string
|
||||
BackupsPath string
|
||||
}
|
||||
|
||||
// used in retriving cluster tasks
|
||||
@@ -85,9 +86,9 @@ func GetClusterResources(auth common.Auth) (map[uint]InstanceCard, map[string]No
|
||||
"PVEAuthCookie": auth.Token,
|
||||
"CSRFPreventionToken": auth.CSRF,
|
||||
},
|
||||
Body: map[string]any{},
|
||||
}
|
||||
res, code, err := common.RequestGetAPI("/proxmox/cluster/resources", ctx)
|
||||
body := map[string]any{}
|
||||
res, code, err := common.RequestGetAPI("/proxmox/cluster/resources", ctx, &body)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
@@ -99,7 +100,7 @@ func GetClusterResources(auth common.Auth) (map[uint]InstanceCard, map[string]No
|
||||
nodes := map[string]Node{}
|
||||
|
||||
// if we successfully retrieved the resources, then process it and return index
|
||||
for _, v := range ctx.Body["data"].([]any) {
|
||||
for _, v := range body["data"].([]any) {
|
||||
m := v.(map[string]any)
|
||||
if m["type"] == "node" {
|
||||
node := Node{}
|
||||
@@ -126,11 +127,12 @@ func GetClusterResources(auth common.Auth) (map[uint]InstanceCard, map[string]No
|
||||
} else if instance.Type == "lxc" {
|
||||
instance.ConsolePath = fmt.Sprintf("%s/?console=lxc&vmid=%d&vmname=%s&node=%s&resize=off&cmd=&xtermjs=1", common.Global.PVE, instance.VMID, instance.Name, instance.Node)
|
||||
}
|
||||
instance.BackupsPath = fmt.Sprintf("backups?node=%s&type=%s&vmid=%d", instance.Node, instance.Type, instance.VMID)
|
||||
instances[vmid] = instance
|
||||
}
|
||||
|
||||
ctx.Body = map[string]any{}
|
||||
res, code, err = common.RequestGetAPI("/proxmox/cluster/tasks", ctx)
|
||||
body = map[string]any{}
|
||||
res, code, err = common.RequestGetAPI("/proxmox/cluster/tasks", ctx, &body)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
@@ -141,7 +143,7 @@ func GetClusterResources(auth common.Auth) (map[uint]InstanceCard, map[string]No
|
||||
most_recent_task := map[uint]uint{}
|
||||
expected_state := map[uint]string{}
|
||||
|
||||
for _, v := range ctx.Body["data"].([]any) {
|
||||
for _, v := range body["data"].([]any) {
|
||||
task := Task{}
|
||||
err := mapstructure.Decode(v, &task)
|
||||
if err != nil {
|
||||
@@ -180,8 +182,8 @@ func GetClusterResources(auth common.Auth) (map[uint]InstanceCard, map[string]No
|
||||
// get /status/current which is updated faster than /cluster/resources
|
||||
instance := instances[vmid]
|
||||
path := fmt.Sprintf("/proxmox/nodes/%s/%s/%d/status/current", instance.Node, instance.Type, instance.VMID)
|
||||
ctx.Body = map[string]any{}
|
||||
res, code, err := common.RequestGetAPI(path, ctx)
|
||||
body = map[string]any{}
|
||||
res, code, err := common.RequestGetAPI(path, ctx, &body)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
@@ -190,7 +192,7 @@ func GetClusterResources(auth common.Auth) (map[uint]InstanceCard, map[string]No
|
||||
}
|
||||
|
||||
status := InstanceStatus{}
|
||||
mapstructure.Decode(ctx.Body["data"], &status)
|
||||
mapstructure.Decode(body["data"], &status)
|
||||
|
||||
instance.Status = status.Status
|
||||
instances[vmid] = instance
|
||||
|
@@ -26,9 +26,10 @@ func GetLoginRealms() ([]Realm, error) {
|
||||
|
||||
ctx := common.RequestContext{
|
||||
Cookies: nil,
|
||||
Body: map[string]any{},
|
||||
//Body: map[string]any{},
|
||||
}
|
||||
res, code, err := common.RequestGetAPI("/proxmox/access/domains", ctx)
|
||||
body := map[string]any{}
|
||||
res, code, err := common.RequestGetAPI("/proxmox/access/domains", ctx, &body)
|
||||
if err != nil {
|
||||
return realms, err
|
||||
}
|
||||
@@ -36,7 +37,7 @@ func GetLoginRealms() ([]Realm, error) {
|
||||
return realms, fmt.Errorf("request to /proxmox/access/domains resulted in %+v", res)
|
||||
}
|
||||
|
||||
for _, v := range ctx.Body["data"].([]any) {
|
||||
for _, v := range body["data"].([]any) {
|
||||
v = v.(map[string]any)
|
||||
realm := Realm{}
|
||||
err := mapstructure.Decode(v, &realm)
|
||||
|
Reference in New Issue
Block a user