Compare commits
2 Commits
instance-p
...
1bcbed6828
| Author | SHA1 | Date | |
|---|---|---|---|
| 1bcbed6828 | |||
| 31bfa79e66 |
@@ -4,7 +4,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"proxmoxaas-dashboard/app/common"
|
"proxmoxaas-dashboard/app/common"
|
||||||
"strconv"
|
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/go-viper/mapstructure/v2"
|
"github.com/go-viper/mapstructure/v2"
|
||||||
@@ -61,20 +60,6 @@ type InstanceCard struct {
|
|||||||
NodeStatus string
|
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) {
|
func GetClusterResources(auth common.Auth) (map[uint]InstanceCard, map[string]Node, error) {
|
||||||
ctx := common.RequestContext{
|
ctx := common.RequestContext{
|
||||||
Cookies: map[string]string{
|
Cookies: map[string]string{
|
||||||
@@ -88,7 +73,7 @@ func GetClusterResources(auth common.Auth) (map[uint]InstanceCard, map[string]No
|
|||||||
return nil, nil, err
|
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
|
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{}
|
instances := map[uint]InstanceCard{}
|
||||||
@@ -118,58 +103,5 @@ func GetClusterResources(auth common.Auth) (map[uint]InstanceCard, map[string]No
|
|||||||
instance.NodeStatus = nodestatus
|
instance.NodeStatus = nodestatus
|
||||||
instances[vmid] = instance
|
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
|
return instances, nodes, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,18 @@ import (
|
|||||||
"github.com/go-viper/mapstructure/v2"
|
"github.com/go-viper/mapstructure/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// used when requesting GET /access/domains
|
||||||
|
type GetRealmsBody struct {
|
||||||
|
Data []Realm `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// stores each realm's data
|
||||||
|
type Realm struct {
|
||||||
|
Default int `json:"default"`
|
||||||
|
Realm string `json:"realm"`
|
||||||
|
Comment string `json:"comment"`
|
||||||
|
}
|
||||||
|
|
||||||
func GetLoginRealms() ([]Realm, error) {
|
func GetLoginRealms() ([]Realm, error) {
|
||||||
realms := []Realm{}
|
realms := []Realm{}
|
||||||
|
|
||||||
@@ -37,18 +49,6 @@ func GetLoginRealms() ([]Realm, error) {
|
|||||||
return realms, nil
|
return realms, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// used when requesting GET /access/domains
|
|
||||||
type GetRealmsBody struct {
|
|
||||||
Data []Realm `json:"data"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// stores each realm's data
|
|
||||||
type Realm struct {
|
|
||||||
Default int `json:"default"`
|
|
||||||
Realm string `json:"realm"`
|
|
||||||
Comment string `json:"comment"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func HandleGETLogin(c *gin.Context) {
|
func HandleGETLogin(c *gin.Context) {
|
||||||
realms, err := GetLoginRealms()
|
realms, err := GetLoginRealms()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Binary file not shown.
@@ -1,4 +1,4 @@
|
|||||||
import { requestPVE, requestAPI, goToPage, setAppearance, getSearchSettings, goToURL, requestDash, setSVGSrc, setSVGAlt } from "./utils.js";
|
import { requestPVE, requestAPI, goToPage, setAppearance, getSearchSettings, goToURL, requestDash } from "./utils.js";
|
||||||
import { alert, dialog } from "./dialog.js";
|
import { alert, dialog } from "./dialog.js";
|
||||||
import { setupClientSync } from "./clientsync.js";
|
import { setupClientSync } from "./clientsync.js";
|
||||||
import wfaInit from "../modules/wfa.js";
|
import wfaInit from "../modules/wfa.js";
|
||||||
@@ -141,16 +141,6 @@ class InstanceCard extends HTMLElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setStatusLoading() {
|
|
||||||
this.status = "loading"
|
|
||||||
let statusicon = this.shadowRoot.querySelector("#status")
|
|
||||||
let powerbtn = this.shadowRoot.querySelector("#power-btn")
|
|
||||||
setSVGSrc(statusicon, "images/status/loading.svg")
|
|
||||||
setSVGAlt(statusicon, "instance is loading")
|
|
||||||
setSVGSrc(powerbtn, "images/status/loading.svg")
|
|
||||||
setSVGAlt(powerbtn, "")
|
|
||||||
}
|
|
||||||
|
|
||||||
async handlePowerButton () {
|
async handlePowerButton () {
|
||||||
if (!this.actionLock) {
|
if (!this.actionLock) {
|
||||||
const header = `${this.status === "running" ? "Stop" : "Start"} VM ${this.vmid}`;
|
const header = `${this.status === "running" ? "Stop" : "Start"} VM ${this.vmid}`;
|
||||||
@@ -161,7 +151,6 @@ class InstanceCard extends HTMLElement {
|
|||||||
const targetAction = this.status === "running" ? "stop" : "start";
|
const targetAction = this.status === "running" ? "stop" : "start";
|
||||||
|
|
||||||
const result = await requestPVE(`/nodes/${this.node.name}/${this.type}/${this.vmid}/status/${targetAction}`, "POST", { node: this.node.name, vmid: this.vmid });
|
const result = await requestPVE(`/nodes/${this.node.name}/${this.type}/${this.vmid}/status/${targetAction}`, "POST", { node: this.node.name, vmid: this.vmid });
|
||||||
this.setStatusLoading()
|
|
||||||
|
|
||||||
const waitFor = delay => new Promise(resolve => setTimeout(resolve, delay));
|
const waitFor = delay => new Promise(resolve => setTimeout(resolve, delay));
|
||||||
|
|
||||||
|
|||||||
@@ -16,11 +16,11 @@
|
|||||||
<p class="w3-col l1 m2 w3-hide-small">{{.Type}}</p>
|
<p class="w3-col l1 m2 w3-hide-small">{{.Type}}</p>
|
||||||
<div class="w3-col l2 m3 s6 flex row nowrap">
|
<div class="w3-col l2 m3 s6 flex row nowrap">
|
||||||
{{if eq .Status "running"}}
|
{{if eq .Status "running"}}
|
||||||
<svg id="status" aria-label="instance is running"><use href="images/status/active.svg#symb"></svg>
|
<svg aria-label="instance is running"><use href="images/status/active.svg#symb"></svg>
|
||||||
{{else if eq .Status "stopped"}}
|
{{else if eq .Status "stopped"}}
|
||||||
<svg id="status" aria-label="instance is stopped"><use href="images/status/inactive.svg#symb"></svg>
|
<svg aria-label="instance is stopped"><use href="images/status/inactive.svg#symb"></svg>
|
||||||
{{else if eq .Status "loading"}}
|
{{else if eq .Status "loading"}}
|
||||||
<svg id="status" aria-label="instance is loading"><use href="images/status/loading.svg#symb"></svg>
|
<svg aria-label="instance is loading"><use href="images/status/loading.svg#symb"></svg>
|
||||||
{{else}}
|
{{else}}
|
||||||
{{end}}
|
{{end}}
|
||||||
<p>{{.Status}}</p>
|
<p>{{.Status}}</p>
|
||||||
|
|||||||
Reference in New Issue
Block a user