add a bunch of comments to important code
This commit is contained in:
@@ -14,6 +14,7 @@ import (
|
|||||||
func Run(configPath *string) {
|
func Run(configPath *string) {
|
||||||
common.Global = common.GetConfig(*configPath)
|
common.Global = common.GetConfig(*configPath)
|
||||||
|
|
||||||
|
// setup static resources
|
||||||
gin.SetMode(gin.ReleaseMode)
|
gin.SetMode(gin.ReleaseMode)
|
||||||
router := gin.Default()
|
router := gin.Default()
|
||||||
m := common.InitMinify()
|
m := common.InitMinify()
|
||||||
@@ -21,6 +22,7 @@ func Run(configPath *string) {
|
|||||||
html := common.MinifyStatic(m, web.Templates)
|
html := common.MinifyStatic(m, web.Templates)
|
||||||
common.TMPL = common.LoadHTMLToGin(router, html)
|
common.TMPL = common.LoadHTMLToGin(router, html)
|
||||||
|
|
||||||
|
// dynamic routes for pages and page fragments
|
||||||
router.GET("/", routes.HandleGETIndex)
|
router.GET("/", routes.HandleGETIndex)
|
||||||
router.GET("/index", routes.HandleGETIndex)
|
router.GET("/index", routes.HandleGETIndex)
|
||||||
router.GET("/index/instances", routes.HandleGETInstancesFragment)
|
router.GET("/index/instances", routes.HandleGETInstancesFragment)
|
||||||
@@ -35,9 +37,11 @@ func Run(configPath *string) {
|
|||||||
router.GET("/login", routes.HandleGETLogin)
|
router.GET("/login", routes.HandleGETLogin)
|
||||||
router.GET("/settings", routes.HandleGETSettings)
|
router.GET("/settings", routes.HandleGETSettings)
|
||||||
|
|
||||||
|
// run on all interfaces with port
|
||||||
log.Fatal(router.Run(fmt.Sprintf("0.0.0.0:%d", common.Global.Port)))
|
log.Fatal(router.Run(fmt.Sprintf("0.0.0.0:%d", common.Global.Port)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// setup static resources under web (css, images, modules, scripts)
|
||||||
func ServeStatic(router *gin.Engine, m *minify.M) {
|
func ServeStatic(router *gin.Engine, m *minify.M) {
|
||||||
css := common.MinifyStatic(m, web.CSS_fs)
|
css := common.MinifyStatic(m, web.CSS_fs)
|
||||||
router.GET("/css/*css", func(c *gin.Context) {
|
router.GET("/css/*css", func(c *gin.Context) {
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
package common
|
package common
|
||||||
|
|
||||||
|
import "html/template"
|
||||||
|
|
||||||
|
var Global Config
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
Port int `json:"listenPort"`
|
Port int `json:"listenPort"`
|
||||||
Organization string `json:"organization"`
|
Organization string `json:"organization"`
|
||||||
@@ -8,11 +12,23 @@ type Config struct {
|
|||||||
API string `json:"apiurl"`
|
API string `json:"apiurl"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// variable for html template root
|
||||||
|
// generated from LoadHTMLToGin
|
||||||
|
var TMPL *template.Template
|
||||||
|
|
||||||
|
// static served file type containing data and mimetype
|
||||||
type StaticFile struct {
|
type StaticFile struct {
|
||||||
Data string
|
Data string
|
||||||
MimeType MimeType
|
MimeType MimeType
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// parsed vmpath data (ie node/type/vmid)
|
||||||
|
type VMPath struct {
|
||||||
|
Node string
|
||||||
|
Type string
|
||||||
|
VMID string
|
||||||
|
}
|
||||||
|
|
||||||
// type used for templated <select>
|
// type used for templated <select>
|
||||||
type Select struct {
|
type Select struct {
|
||||||
ID string
|
ID string
|
||||||
@@ -27,8 +43,6 @@ type Option struct {
|
|||||||
Display string
|
Display string
|
||||||
}
|
}
|
||||||
|
|
||||||
type RequestType int
|
|
||||||
|
|
||||||
type RequestContext struct {
|
type RequestContext struct {
|
||||||
Cookies map[string]string
|
Cookies map[string]string
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,15 +20,7 @@ import (
|
|||||||
"github.com/tdewolff/minify/v2"
|
"github.com/tdewolff/minify/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
var TMPL *template.Template
|
// get config file from configPath
|
||||||
var Global Config
|
|
||||||
|
|
||||||
type VMPath struct {
|
|
||||||
Node string
|
|
||||||
Type string
|
|
||||||
VMID string
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetConfig(configPath string) Config {
|
func GetConfig(configPath string) Config {
|
||||||
content, err := os.ReadFile(configPath)
|
content, err := os.ReadFile(configPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -42,6 +34,7 @@ func GetConfig(configPath string) Config {
|
|||||||
return config
|
return config
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// initialize minifier using the meta types specified
|
||||||
func InitMinify() *minify.M {
|
func InitMinify() *minify.M {
|
||||||
m := minify.New()
|
m := minify.New()
|
||||||
for _, v := range MimeTypes {
|
for _, v := range MimeTypes {
|
||||||
@@ -125,7 +118,7 @@ func LoadHTMLToGin(engine *gin.Engine, html map[string]StaticFile) *template.Tem
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
tmpl := template.Must(root, LoadAndAddToRoot(engine.FuncMap, root, html))
|
tmpl := template.Must(root, LoadAndAddToRoot(engine.FuncMap, root, html))
|
||||||
engine.SetHTMLTemplate(tmpl)
|
engine.SetHTMLTemplate(root)
|
||||||
return tmpl
|
return tmpl
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,12 +21,14 @@ type Account struct {
|
|||||||
Resources map[string]map[string]any
|
Resources map[string]map[string]any
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// numerical constraint
|
||||||
type Constraint struct {
|
type Constraint struct {
|
||||||
Max int64
|
Max int64
|
||||||
Used int64
|
Used int64
|
||||||
Avail int64
|
Avail int64
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// match constraint
|
||||||
type Match struct {
|
type Match struct {
|
||||||
Name string
|
Name string
|
||||||
Match string
|
Match string
|
||||||
@@ -107,6 +109,7 @@ func HandleGETAccount(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// for each resource category, create a resource chart
|
||||||
for category, resources := range account.Resources {
|
for category, resources := range account.Resources {
|
||||||
for resource, v := range resources {
|
for resource, v := range resources {
|
||||||
switch t := v.(type) {
|
switch t := v.(type) {
|
||||||
|
|||||||
@@ -10,13 +10,7 @@ import (
|
|||||||
"github.com/go-viper/mapstructure/v2"
|
"github.com/go-viper/mapstructure/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
// used in constructing instance cards in index
|
// primary type used in constructing instance cards in index
|
||||||
type Node struct {
|
|
||||||
Node string `json:"node"`
|
|
||||||
Status string `json:"status"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// used in constructing instance cards in index
|
|
||||||
type InstanceCard struct {
|
type InstanceCard struct {
|
||||||
VMID uint
|
VMID uint
|
||||||
Name string
|
Name string
|
||||||
@@ -29,6 +23,12 @@ type InstanceCard struct {
|
|||||||
BackupsPath string
|
BackupsPath string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// used in constructing instance cards in index
|
||||||
|
type Node struct {
|
||||||
|
Node string `json:"node"`
|
||||||
|
Status string `json:"status"`
|
||||||
|
}
|
||||||
|
|
||||||
// used in retriving cluster tasks
|
// used in retriving cluster tasks
|
||||||
type Task struct {
|
type Task struct {
|
||||||
Type string
|
Type string
|
||||||
@@ -92,24 +92,24 @@ func GetClusterResources(auth common.Auth) (map[uint]InstanceCard, map[string]No
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
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 the error 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{}
|
||||||
nodes := map[string]Node{}
|
nodes := map[string]Node{}
|
||||||
|
|
||||||
// if we successfully retrieved the resources, then process it and return index
|
// parse /proxmox/cluster/resources to separate instances and nodes
|
||||||
for _, v := range body["data"].([]any) {
|
for _, v := range body["data"].([]any) {
|
||||||
m := v.(map[string]any)
|
m := v.(map[string]any)
|
||||||
if m["type"] == "node" {
|
if m["type"] == "node" { // if type is node -> parse as Node object
|
||||||
node := Node{}
|
node := Node{}
|
||||||
err := mapstructure.Decode(v, &node)
|
err := mapstructure.Decode(v, &node)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
nodes[node.Node] = node
|
nodes[node.Node] = node
|
||||||
} else if m["type"] == "lxc" || m["type"] == "qemu" {
|
} else if m["type"] == "lxc" || m["type"] == "qemu" { // if type is lxc or qemu -> parse as InstanceCard object
|
||||||
instance := InstanceCard{}
|
instance := InstanceCard{}
|
||||||
err := mapstructure.Decode(v, &instance)
|
err := mapstructure.Decode(v, &instance)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -118,16 +118,21 @@ func GetClusterResources(auth common.Auth) (map[uint]InstanceCard, map[string]No
|
|||||||
instances[instance.VMID] = instance
|
instances[instance.VMID] = instance
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// once all basic instance and node stuff is parsed, go back and fill in cross referenced data
|
||||||
for vmid, instance := range instances {
|
for vmid, instance := range instances {
|
||||||
nodestatus := nodes[instance.Node].Status
|
// set instance's node status
|
||||||
instance.NodeStatus = nodestatus
|
instance.NodeStatus = nodes[instance.Node].Status
|
||||||
|
// set instance's config link path
|
||||||
instance.ConfigPath = fmt.Sprintf("config?node=%s&type=%s&vmid=%d", instance.Node, instance.Type, instance.VMID)
|
instance.ConfigPath = fmt.Sprintf("config?node=%s&type=%s&vmid=%d", instance.Node, instance.Type, instance.VMID)
|
||||||
|
// set the instance's console link path
|
||||||
if instance.Type == "qemu" {
|
if instance.Type == "qemu" {
|
||||||
instance.ConsolePath = fmt.Sprintf("%s/?console=kvm&vmid=%d&vmname=%s&node=%s&resize=off&cmd=&novnc=1", common.Global.PVE, instance.VMID, instance.Name, instance.Node)
|
instance.ConsolePath = fmt.Sprintf("%s/?console=kvm&vmid=%d&vmname=%s&node=%s&resize=off&cmd=&novnc=1", common.Global.PVE, instance.VMID, instance.Name, instance.Node)
|
||||||
} else if instance.Type == "lxc" {
|
} 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.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)
|
||||||
}
|
}
|
||||||
|
// set the instance's backups link path
|
||||||
instance.BackupsPath = fmt.Sprintf("backups?node=%s&type=%s&vmid=%d", instance.Node, instance.Type, instance.VMID)
|
instance.BackupsPath = fmt.Sprintf("backups?node=%s&type=%s&vmid=%d", instance.Node, instance.Type, instance.VMID)
|
||||||
|
// save back to instances map
|
||||||
instances[vmid] = instance
|
instances[vmid] = instance
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -143,7 +148,9 @@ func GetClusterResources(auth common.Auth) (map[uint]InstanceCard, map[string]No
|
|||||||
most_recent_task := map[uint]uint{}
|
most_recent_task := map[uint]uint{}
|
||||||
expected_state := map[uint]string{}
|
expected_state := map[uint]string{}
|
||||||
|
|
||||||
|
// iterate through recent user accessible tasks to find the task most recently made on an instance
|
||||||
for _, v := range body["data"].([]any) {
|
for _, v := range body["data"].([]any) {
|
||||||
|
// parse task as Task object
|
||||||
task := Task{}
|
task := Task{}
|
||||||
err := mapstructure.Decode(v, &task)
|
err := mapstructure.Decode(v, &task)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -177,6 +184,7 @@ func GetClusterResources(auth common.Auth) (map[uint]InstanceCard, map[string]No
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// iterate through the instances with recent tasks, refetch their state from a more reliable source
|
||||||
for vmid, expected_state := range expected_state { // for the expected states from recent tasks
|
for vmid, expected_state := range expected_state { // for the expected states from recent tasks
|
||||||
if instances[vmid].Status != expected_state { // if the current node's state from /cluster/resources differs from expected state
|
if instances[vmid].Status != expected_state { // if the current node's state from /cluster/resources differs from expected state
|
||||||
// get /status/current which is updated faster than /cluster/resources
|
// get /status/current which is updated faster than /cluster/resources
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ func GetLoginRealms() ([]Realm, error) {
|
|||||||
|
|
||||||
ctx := common.RequestContext{
|
ctx := common.RequestContext{
|
||||||
Cookies: nil,
|
Cookies: nil,
|
||||||
//Body: map[string]any{},
|
|
||||||
}
|
}
|
||||||
body := map[string]any{}
|
body := map[string]any{}
|
||||||
res, code, err := common.RequestGetAPI("/proxmox/access/domains", ctx, &body)
|
res, code, err := common.RequestGetAPI("/proxmox/access/domains", ctx, &body)
|
||||||
|
|||||||
Reference in New Issue
Block a user