diff --git a/app/routes/index.go b/app/routes/index.go index f330b27..88ef52b 100644 --- a/app/routes/index.go +++ b/app/routes/index.go @@ -4,6 +4,7 @@ import ( "fmt" "net/http" "proxmoxaas-dashboard/app/common" + "strconv" "github.com/gin-gonic/gin" "github.com/go-viper/mapstructure/v2" @@ -60,6 +61,20 @@ type InstanceCard struct { NodeStatus string } +// used in retriving cluster tasks +type Task struct { + Type string + Node string + User string + ID string + VMID uint + Status string +} + +type InstanceStatus struct { + Status string +} + func GetClusterResources(auth common.Auth) (map[uint]InstanceCard, map[string]Node, error) { ctx := common.RequestContext{ Cookies: map[string]string{ @@ -73,7 +88,7 @@ func GetClusterResources(auth common.Auth) (map[uint]InstanceCard, map[string]No return nil, nil, err } if code != 200 { // if we did not successfully retrieve resources, then return 500 because auth was 1 but was invalid somehow - return nil, nil, fmt.Errorf("request to /cluster/resources/ resulted in %+v", res) + return nil, nil, fmt.Errorf("request to /cluster/resources resulted in %+v", res) } instances := map[uint]InstanceCard{} @@ -103,5 +118,58 @@ func GetClusterResources(auth common.Auth) (map[uint]InstanceCard, map[string]No instance.NodeStatus = nodestatus instances[vmid] = instance } + + ctx.Body = map[string]any{} + res, code, err = common.RequestGetAPI("/proxmox/cluster/tasks", ctx) + if err != nil { + return nil, nil, err + } + if code != 200 { // if we did not successfully retrieve tasks, then return 500 because auth was 1 but was invalid somehow + return nil, nil, fmt.Errorf("request to /cluster/tasks resulted in %+v", res) + } + + for _, v := range ctx.Body["data"].([]any) { + task := Task{} + err := mapstructure.Decode(v, &task) + if err != nil { + return nil, nil, err + } + x, err := strconv.Atoi(task.ID) + task.VMID = uint(x) + if err != nil { + return nil, nil, err + } + + if task.User != auth.Username { // task was not made by user (ie was not a power on/off task) + continue + } else if _, ok := instances[task.VMID]; !ok { // task does not refer to an instance in user's instances + continue + } else if instances[task.VMID].Node != task.Node { // task does not have the correct node reference (should not happen) + continue + } else if !(task.Type == "qmstart" || task.Type == "qmstop" || task.Type == "vzstart" || task.Type == "vzstop") { // task is not start/stop for qemu or lxc + continue + } else if !(task.Status == "running" || task.Status == "OK") { // task is not running or finished with status OK + continue + } else { // recent task is a start or stop task for user instance which is running or "OK" + // get /status/current which is updated faster than /cluster/resources + instance := instances[task.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) + if err != nil { + return nil, nil, err + } + if code != 200 { // if we did not successfully retrieve tasks, then return 500 because auth was 1 but was invalid somehow + return nil, nil, fmt.Errorf("request to %s resulted in %+v", path, res) + } + + status := InstanceStatus{} + mapstructure.Decode(ctx.Body["data"], &status) + + instance.Status = status.Status + instances[task.VMID] = instance + } + } + return instances, nodes, nil } diff --git a/web/templates/instance-card.go.tmpl b/web/templates/instance-card.go.tmpl index ddc209b..2b4b3bf 100644 --- a/web/templates/instance-card.go.tmpl +++ b/web/templates/instance-card.go.tmpl @@ -16,11 +16,11 @@

{{.Type}}

{{if eq .Status "running"}} - + {{else if eq .Status "stopped"}} - + {{else if eq .Status "loading"}} - + {{else}} {{end}}

{{.Status}}