Compare commits
2 Commits
4819cc8e9b
...
2b9fd75474
Author | SHA1 | Date | |
---|---|---|---|
2b9fd75474 | |||
3bcbfd3577 |
25
README.md
25
README.md
@ -72,3 +72,28 @@ Overall goals:
|
||||
</clustvirt:data>
|
||||
</metadata>
|
||||
```
|
||||
|
||||
### Open Source Projects
|
||||
|
||||
The following projects are being used as part of ClustVirt.
|
||||
Only those being used directly are listed, not the dependencies.
|
||||
|
||||
#### Go
|
||||
|
||||
| Library | Use | License |
|
||||
| --- | --- | --- |
|
||||
| [xdg](https://github.com/adrg/xdg) | XDG paths | MIT |
|
||||
| [spf13/viper](https://github.com/spf13/viper) | Configuration | MIT |
|
||||
| [spf13](https://github.com/spf13/cobra) | Command Pattern CLI | Apache 2.0 |
|
||||
| [go-chart/v2](https://github.com/wcharczuk/go-chart) | Chart generation | MIT |
|
||||
| [libvirt](https://libvirt.org/go/libvirt) | Communications with Libvirtd | MIT |
|
||||
| [libvirtxml](https://libvirt.org/go/libvirtxml) | Libvirt XML parsing and generation | MIT |
|
||||
| [templ](https://github.com/a-h/templ) | HTML Templating Engine | MIT |
|
||||
| [chi/v5](https://github.com/go-chi/chi) | HTTP Routing | MIT |
|
||||
|
||||
#### Node NPM
|
||||
|
||||
| Library | Use | License |
|
||||
| --- | --- | ------- |
|
||||
| [tailwindcss](https://tailwindcss.com) | CSS UI library | MIT |
|
||||
| [tailwindcss/forms](https://tailwindcss.com) | CSS UI library for forms | MIT |
|
||||
|
1
cluster/api.go
Normal file
1
cluster/api.go
Normal file
@ -0,0 +1 @@
|
||||
package cluster
|
1
cluster/auth.go
Normal file
1
cluster/auth.go
Normal file
@ -0,0 +1 @@
|
||||
package cluster
|
28
cluster/builder.go
Normal file
28
cluster/builder.go
Normal file
@ -0,0 +1,28 @@
|
||||
package cluster
|
||||
|
||||
import "time"
|
||||
|
||||
// ClusterBuilder is used to build a Cluster object, which can then be used
|
||||
type ClusterBuilder struct {
|
||||
cluster *Cluster
|
||||
}
|
||||
|
||||
// New starts the builder pattern for the Cluster.
|
||||
// Sets the default interval time to 30 seconds.
|
||||
func New() *ClusterBuilder {
|
||||
return &ClusterBuilder{
|
||||
cluster: &Cluster{
|
||||
interval: time.Duration(time.Second * 30),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// SetInterval sets the check interval of the Cluster being built.
|
||||
func (c *ClusterBuilder) SetInterval(i time.Duration) *ClusterBuilder {
|
||||
c.cluster.interval = i
|
||||
return c
|
||||
}
|
||||
// Build retuns the built cluster
|
||||
func (c *ClusterBuilder) Build() *Cluster {
|
||||
return c.cluster
|
||||
}
|
27
cluster/cluster.go
Normal file
27
cluster/cluster.go
Normal file
@ -0,0 +1,27 @@
|
||||
// Package cluster is the unique portion of this application that implements
|
||||
// basic cluster controls overtop of Libvirtd hosts. The controller is agnostic
|
||||
// about where it is running, and doesn't need to be running on a host that
|
||||
// has Libvirtd installed on it.
|
||||
//
|
||||
// The cluster can be configured through the use of TOML configuration file,
|
||||
// or with CLI flags. This is done via the itegration of the greate go libraries
|
||||
// spf13/viper and spf13/cobra.
|
||||
package cluster
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"git.staur.ca/stobbsm/clustvirt/lib/host"
|
||||
"git.staur.ca/stobbsm/clustvirt/lib/network"
|
||||
)
|
||||
|
||||
// Cluster is the data structure and controller for cluster access.
|
||||
// Using it's methods, you can access hosts, virtual machines, health
|
||||
// data, and more.
|
||||
// Cluster implements a time.Ticker that will be used to check the connection
|
||||
// status of hosts, and reconnect if a connection was blocked or interrupted.
|
||||
type Cluster struct {
|
||||
interval time.Duration
|
||||
hosts map[string]*host.Host
|
||||
networks map[string]*network.Network
|
||||
}
|
1
cluster/config.go
Normal file
1
cluster/config.go
Normal file
@ -0,0 +1 @@
|
||||
package cluster
|
1
cluster/daemon.go
Normal file
1
cluster/daemon.go
Normal file
@ -0,0 +1 @@
|
||||
package cluster
|
1
cluster/format/format.go
Normal file
1
cluster/format/format.go
Normal file
@ -0,0 +1 @@
|
||||
package format
|
1
cluster/format/json.go
Normal file
1
cluster/format/json.go
Normal file
@ -0,0 +1 @@
|
||||
package format
|
1
cluster/format/xml.go
Normal file
1
cluster/format/xml.go
Normal file
@ -0,0 +1 @@
|
||||
package format
|
1
cluster/host.go
Normal file
1
cluster/host.go
Normal file
@ -0,0 +1 @@
|
||||
package cluster
|
1
cluster/network.go
Normal file
1
cluster/network.go
Normal file
@ -0,0 +1 @@
|
||||
package cluster
|
294
cluster/stats.go
Normal file
294
cluster/stats.go
Normal file
@ -0,0 +1,294 @@
|
||||
package cluster
|
||||
|
||||
// ClusterStats is used to gather stats for the entire cluster
|
||||
type ClusterStats struct {
|
||||
CPU struct {
|
||||
Sockets uint32
|
||||
Cores uint32
|
||||
Threads uint32
|
||||
Allocated uint32
|
||||
}
|
||||
Memory struct {
|
||||
Total uint64
|
||||
Free uint64
|
||||
Buffers uint64
|
||||
Cached uint64
|
||||
Allocated uint64
|
||||
}
|
||||
Storage struct {
|
||||
Total uint64
|
||||
Used uint64
|
||||
Free uint64
|
||||
Active uint32
|
||||
Inactive uint32
|
||||
Pools uint32
|
||||
|
||||
Volumes struct {
|
||||
Total uint32
|
||||
Active uint32
|
||||
Inactive uint32
|
||||
}
|
||||
}
|
||||
VM struct {
|
||||
Count uint32
|
||||
Started uint32
|
||||
Stopped uint32
|
||||
}
|
||||
Host struct {
|
||||
Count uint32
|
||||
Available uint32
|
||||
}
|
||||
Network struct {
|
||||
Count uint32
|
||||
Active uint32
|
||||
Inactive uint32
|
||||
}
|
||||
|
||||
old *ClusterStats
|
||||
c *Cluster
|
||||
}
|
||||
|
||||
// ClusterStats is used to gather stats for the entire cluster
|
||||
type StatDiff struct {
|
||||
CPU struct {
|
||||
Sockets int
|
||||
Cores int
|
||||
Threads int
|
||||
Allocated int
|
||||
}
|
||||
Memory struct {
|
||||
Total int
|
||||
Free int
|
||||
Buffers int
|
||||
Cached int
|
||||
Allocated int
|
||||
}
|
||||
Storage struct {
|
||||
Total int
|
||||
Used int
|
||||
Free int
|
||||
Active int
|
||||
Inactive int
|
||||
Pools int
|
||||
|
||||
Volumes struct {
|
||||
Total int
|
||||
Active int
|
||||
Inactive int
|
||||
}
|
||||
}
|
||||
VM struct {
|
||||
Count int
|
||||
Started int
|
||||
Stopped int
|
||||
}
|
||||
Host struct {
|
||||
Count int
|
||||
Available int
|
||||
}
|
||||
Network struct {
|
||||
Count int
|
||||
Active int
|
||||
Inactive int
|
||||
}
|
||||
}
|
||||
|
||||
// Init is given a cluster, which it then uses to load the initial statistics
|
||||
// Does not close connections, but uses the host connections available to the
|
||||
// cluster to add statistics together.
|
||||
func Init(c *Cluster) *ClusterStats {
|
||||
cs := &ClusterStats{}
|
||||
|
||||
return cs
|
||||
}
|
||||
|
||||
// Update triggers the stats collector to refresh it's statistics
|
||||
func (cs *ClusterStats) Update() {
|
||||
cs.old = cs.copy()
|
||||
|
||||
cs.reset()
|
||||
// Start looping through each host in the cluster, adding to the total
|
||||
for _, h := range cs.c.hosts {
|
||||
cs.Host.Count++
|
||||
cs.Host.Available++
|
||||
|
||||
cs.CPU.Sockets += h.HostInfo.Sockets
|
||||
cs.CPU.Cores += h.HostInfo.Cores
|
||||
cs.CPU.Threads += h.HostInfo.Threads
|
||||
|
||||
cs.Memory.Total += h.NodeMemory.Total
|
||||
cs.Memory.Free += h.NodeMemory.Free
|
||||
cs.Memory.Buffers += h.NodeMemory.Buffers
|
||||
cs.Memory.Cached += h.NodeMemory.Cached
|
||||
|
||||
// Storage Pool counting
|
||||
cs.Storage.Pools += uint32(len(h.StoragePoolList))
|
||||
countedSharedPools := map[string]struct{}{}
|
||||
// Loop through available storage pools
|
||||
for _, sp := range h.StoragePoolList {
|
||||
if _, ok := countedSharedPools[sp.Name]; ok {
|
||||
// Already counted this shared pool, move on
|
||||
continue
|
||||
}
|
||||
if sp.HAEnabled {
|
||||
countedSharedPools[sp.Name] = struct{}{}
|
||||
}
|
||||
if !sp.Active {
|
||||
cs.Storage.Inactive++
|
||||
continue
|
||||
}
|
||||
cs.Storage.Active++
|
||||
cs.Storage.Total += sp.Capacity
|
||||
cs.Storage.Used += sp.Allocation
|
||||
cs.Storage.Free += sp.Capacity - sp.Allocation
|
||||
// Volumes in the pool
|
||||
cs.Storage.Volumes.Total += uint32(len(sp.Volumes))
|
||||
for range sp.Volumes {
|
||||
cs.Storage.Volumes.Active++
|
||||
}
|
||||
}
|
||||
|
||||
// VM Count
|
||||
cs.VM.Count += uint32(len(h.VMList))
|
||||
for _, vm := range h.VMList {
|
||||
cs.CPU.Allocated += uint32(vm.VCPUs)
|
||||
cs.Memory.Allocated += uint64(vm.Memory)
|
||||
if vm.Active {
|
||||
cs.VM.Started++
|
||||
continue
|
||||
}
|
||||
cs.VM.Stopped++
|
||||
}
|
||||
|
||||
// Network count
|
||||
cs.Network.Count += uint32(len(h.NetworkList))
|
||||
for _, ni := range h.NetworkList {
|
||||
if ni.Active {
|
||||
cs.Network.Active++
|
||||
continue
|
||||
}
|
||||
cs.Network.Inactive++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Diff returns a map of all the field and how they changed
|
||||
func (cs *ClusterStats) Diff() StatDiff {
|
||||
return StatDiff{
|
||||
CPU: struct {
|
||||
Sockets int
|
||||
Cores int
|
||||
Threads int
|
||||
Allocated int
|
||||
}{
|
||||
Sockets: int(cs.old.CPU.Sockets - cs.CPU.Sockets),
|
||||
Cores: int(cs.old.CPU.Cores - cs.CPU.Cores),
|
||||
Threads: int(cs.old.CPU.Threads - cs.CPU.Threads),
|
||||
Allocated: int(cs.old.CPU.Allocated - cs.CPU.Allocated),
|
||||
},
|
||||
Memory: struct {
|
||||
Total int
|
||||
Free int
|
||||
Buffers int
|
||||
Cached int
|
||||
Allocated int
|
||||
}{
|
||||
Total: int(cs.old.Memory.Total - cs.Memory.Total),
|
||||
Free: int(cs.old.Memory.Free - cs.Memory.Free),
|
||||
Buffers: int(cs.old.Memory.Buffers - cs.Memory.Buffers),
|
||||
Cached: int(cs.old.Memory.Cached - cs.Memory.Cached),
|
||||
Allocated: int(cs.old.Memory.Allocated - cs.Memory.Allocated),
|
||||
},
|
||||
Storage: struct {
|
||||
Total int
|
||||
Used int
|
||||
Free int
|
||||
Active int
|
||||
Inactive int
|
||||
Pools int
|
||||
Volumes struct {
|
||||
Total int
|
||||
Active int
|
||||
Inactive int
|
||||
}
|
||||
}{
|
||||
Total: int(cs.old.Storage.Total - cs.Storage.Total),
|
||||
Used: int(cs.old.Storage.Used - cs.Storage.Used),
|
||||
Free: int(cs.old.Storage.Free - cs.Storage.Free),
|
||||
Active: int(cs.old.Storage.Active - cs.Storage.Active),
|
||||
Inactive: int(cs.old.Storage.Inactive - cs.Storage.Inactive),
|
||||
Pools: int(cs.old.Storage.Pools - cs.Storage.Pools),
|
||||
Volumes: struct {
|
||||
Total int
|
||||
Active int
|
||||
Inactive int
|
||||
}{
|
||||
Total: int(cs.old.Storage.Volumes.Total - cs.Storage.Volumes.Total),
|
||||
Active: int(cs.old.Storage.Volumes.Active - cs.Storage.Volumes.Active),
|
||||
Inactive: int(cs.old.Storage.Volumes.Inactive - cs.Storage.Volumes.Inactive),
|
||||
},
|
||||
},
|
||||
VM: struct {
|
||||
Count int
|
||||
Started int
|
||||
Stopped int
|
||||
}{
|
||||
Count: int(cs.old.VM.Count - cs.VM.Count),
|
||||
Started: int(cs.old.VM.Started - cs.VM.Started),
|
||||
Stopped: int(cs.old.VM.Stopped - cs.VM.Stopped),
|
||||
},
|
||||
Host: struct {
|
||||
Count int
|
||||
Available int
|
||||
}{
|
||||
Count: int(cs.old.Host.Count - cs.Host.Count),
|
||||
Available: int(cs.old.Host.Available - cs.Host.Available),
|
||||
},
|
||||
Network: struct {
|
||||
Count int
|
||||
Active int
|
||||
Inactive int
|
||||
}{
|
||||
Count: int(cs.old.Network.Count - cs.Network.Count),
|
||||
Active: int(cs.old.Network.Active - cs.Network.Active),
|
||||
Inactive: int(cs.old.Network.Inactive - cs.Network.Inactive),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// copy the clusterstats into a new clusterstatus object for comparison purposes
|
||||
func (cs *ClusterStats) copy() *ClusterStats {
|
||||
ncs := *cs
|
||||
return &ncs
|
||||
}
|
||||
|
||||
// reset all values to zero value
|
||||
func (cs *ClusterStats) reset() {
|
||||
cs.CPU.Sockets = 0
|
||||
cs.CPU.Cores = 0
|
||||
cs.CPU.Threads = 0
|
||||
cs.CPU.Allocated = 0
|
||||
|
||||
cs.Memory.Total = 0
|
||||
cs.Memory.Free = 0
|
||||
cs.Memory.Buffers = 0
|
||||
cs.Memory.Cached = 0
|
||||
|
||||
cs.Storage.Total = 0
|
||||
cs.Storage.Used = 0
|
||||
cs.Storage.Free = 0
|
||||
cs.Storage.Active = 0
|
||||
cs.Storage.Inactive = 0
|
||||
cs.Storage.Pools = 0
|
||||
|
||||
cs.VM.Count = 0
|
||||
cs.VM.Started = 0
|
||||
cs.VM.Stopped = 0
|
||||
|
||||
cs.Host.Count = 0
|
||||
cs.Host.Available = 0
|
||||
|
||||
cs.Network.Count = 0
|
||||
cs.Network.Active = 0
|
||||
cs.Network.Inactive = 0
|
||||
}
|
1
cluster/storagepool.go
Normal file
1
cluster/storagepool.go
Normal file
@ -0,0 +1 @@
|
||||
package cluster
|
1
cluster/vm.go
Normal file
1
cluster/vm.go
Normal file
@ -0,0 +1 @@
|
||||
package cluster
|
29
cmd/clustvirt.go
Normal file
29
cmd/clustvirt.go
Normal file
@ -0,0 +1,29 @@
|
||||
// Package cmd contains the main application file for ClustVirt.
|
||||
// This command is used for everything, implementing the command pattern
|
||||
// with the help of spf13/cobra.
|
||||
// After building, the executable's first argument must be one of the valid
|
||||
// commands, such as `daemon`, `api`, `query`, `host`, etc. This pattern allows
|
||||
// for a simple way to access functionality, reducing the need to use the
|
||||
// REST api directly.
|
||||
package cmd
|
||||
|
||||
// Global Arguments:
|
||||
// All commands can use the following arguments:
|
||||
// --output none|json|xml: Set the output type, none being just plain log,
|
||||
// json outputing as a JSON document, and XML outputing as an XML document
|
||||
|
||||
// Commands planned:
|
||||
// config: actions associated with the configuration of clustvirt
|
||||
// set: set a configuration value
|
||||
// get: get the current value of a configuration options
|
||||
// list: list available configuration options
|
||||
// daemon: actions associated with running clustvirt in daemon mode
|
||||
// start: start the daemon
|
||||
// stop: safely stop the daemon
|
||||
// status: query the status of the daemon
|
||||
// api: query the REST api. There must a clustvirt daemon running for this to function
|
||||
// host: actions associated with a specific host in the cluster
|
||||
// vm: actions asociated with a specifc vm in the cluster
|
||||
// storagepool: actions associated with storage pools
|
||||
// auth: actions associated with authentication
|
||||
// network: actions to define networks
|
9
config/config.go
Normal file
9
config/config.go
Normal file
@ -0,0 +1,9 @@
|
||||
// Package config used spf13/viper to handle configuration. Sane defaults are set
|
||||
// as default values, and a single host is set to `qemu:///system`, which is only
|
||||
// used if it is found. Not having a local instance will not panic or crash anything.
|
||||
//
|
||||
// Viper uses configuration set via defaults -> config file -> env variables ->
|
||||
// cli flags -> calls to Set (while running), so clustvirt uses the same method.
|
||||
package config
|
||||
|
||||
|
24
go.mod
24
go.mod
@ -9,8 +9,32 @@ require (
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/adrg/xdg v0.4.0 // indirect
|
||||
github.com/fsnotify/fsnotify v1.7.0 // indirect
|
||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
|
||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/labstack/gommon v0.4.2 // indirect
|
||||
github.com/magiconair/properties v1.8.7 // indirect
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.1.0 // indirect
|
||||
github.com/sagikazarmark/locafero v0.4.0 // indirect
|
||||
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
|
||||
github.com/sourcegraph/conc v0.3.0 // indirect
|
||||
github.com/spf13/afero v1.11.0 // indirect
|
||||
github.com/spf13/cast v1.6.0 // indirect
|
||||
github.com/spf13/cobra v1.8.0 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/spf13/viper v1.18.2 // indirect
|
||||
github.com/subosito/gotenv v1.6.0 // indirect
|
||||
github.com/wcharczuk/go-chart/v2 v2.1.1 // indirect
|
||||
go.uber.org/atomic v1.10.0 // indirect
|
||||
go.uber.org/multierr v1.9.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
|
||||
golang.org/x/image v0.11.0 // indirect
|
||||
golang.org/x/sys v0.15.0 // indirect
|
||||
golang.org/x/text v0.14.0 // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
libvirt.org/go/libvirtxml v1.10001.0 // indirect
|
||||
)
|
||||
|
63
go.sum
63
go.sum
@ -1,18 +1,68 @@
|
||||
github.com/a-h/templ v0.2.598 h1:6jMIHv6wQZvdPxTuv87erW4RqN/FPU0wk7ZHN5wVuuo=
|
||||
github.com/a-h/templ v0.2.598/go.mod h1:SA7mtYwVEajbIXFRh3vKdYm/4FYyLQAtPH1+KxzGPA8=
|
||||
github.com/adrg/xdg v0.4.0 h1:RzRqFcjH4nE5C6oTAxhBtoE2IRyjBSa62SCbyPidvls=
|
||||
github.com/adrg/xdg v0.4.0/go.mod h1:N6ag73EX4wyxeaoeHctc1mas01KZgsj5tYiAIwqJE/E=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
|
||||
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
|
||||
github.com/go-chi/chi/v5 v5.0.12 h1:9euLV5sTrTNTRUU9POmDUvfxyj6LAABLUcEWO+JJb4s=
|
||||
github.com/go-chi/chi/v5 v5.0.12/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
|
||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
|
||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||
github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0=
|
||||
github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU=
|
||||
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
|
||||
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
|
||||
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
||||
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4=
|
||||
github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ=
|
||||
github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4=
|
||||
github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
|
||||
github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ=
|
||||
github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
|
||||
github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
|
||||
github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
|
||||
github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
|
||||
github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0=
|
||||
github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
|
||||
github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0=
|
||||
github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/viper v1.18.2 h1:LUXCnvUvSM6FXAsj6nnfc8Q2tp1dIgUfY9Kc8GsSOiQ=
|
||||
github.com/spf13/viper v1.18.2/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMVB+yk=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
|
||||
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
|
||||
github.com/wcharczuk/go-chart/v2 v2.1.1 h1:2u7na789qiD5WzccZsFz4MJWOJP72G+2kUuJoSNqWnE=
|
||||
github.com/wcharczuk/go-chart/v2 v2.1.1/go.mod h1:CyCAUt2oqvfhCl6Q5ZvAZwItgpQKZOkCJGb+VGv6l14=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ=
|
||||
go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
|
||||
go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI=
|
||||
go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g=
|
||||
golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k=
|
||||
golang.org/x/image v0.11.0 h1:ds2RoQvBvYTiJkwpSFDwCcDFNX7DqjL2WsUgTNk0Ooo=
|
||||
golang.org/x/image v0.11.0/go.mod h1:bglhjqbqVuEb9e9+eNR45Jfu7D+T4Qan+NhQk8Ck2P8=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
@ -27,9 +77,12 @@ golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
|
||||
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
@ -38,10 +91,20 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
|
||||
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
libvirt.org/go/libvirt v1.10001.0 h1:lEVDNE7xfzmZXiDEGIS8NvJSuaz11OjRXw+ufbQEtPY=
|
||||
libvirt.org/go/libvirt v1.10001.0/go.mod h1:1WiFE8EjZfq+FCVog+rvr1yatKbKZ9FaFMZgEqxEJqQ=
|
||||
libvirt.org/go/libvirtxml v1.10001.0 h1:r9WBs24r3mxIG3/hAMRRwDMy4ZaPHmhHjw72o/ceXic=
|
||||
libvirt.org/go/libvirtxml v1.10001.0/go.mod h1:7Oq2BLDstLr/XtoQD8Fr3mfDNrzlI3utYKySXF2xkng=
|
||||
|
@ -16,6 +16,7 @@ import (
|
||||
"git.staur.ca/stobbsm/clustvirt/lib/storagevol"
|
||||
"git.staur.ca/stobbsm/clustvirt/util"
|
||||
"libvirt.org/go/libvirt"
|
||||
"libvirt.org/go/libvirtxml"
|
||||
)
|
||||
|
||||
// Host holds information and acts as a connection handle for a Host
|
||||
@ -80,6 +81,9 @@ type VMInfo struct {
|
||||
ID uint
|
||||
UUID []byte
|
||||
XML string
|
||||
Active bool
|
||||
VCPUs uint
|
||||
Memory uint
|
||||
// States are the current states active on the host
|
||||
States []guest.VMState
|
||||
}
|
||||
@ -105,6 +109,7 @@ type StoragePoolInfo struct {
|
||||
Capacity uint64
|
||||
Allocation uint64
|
||||
Available uint64
|
||||
IsNet bool
|
||||
// HAEnabled indicates if the storage pool has High Availability
|
||||
HAEnabled bool
|
||||
// Volumes defined in the storage pool
|
||||
@ -134,6 +139,7 @@ type NetworkInfo struct {
|
||||
Name string
|
||||
UUID []byte
|
||||
XML string
|
||||
Active bool
|
||||
// NetIf is the network interface this connection is applied to
|
||||
NetIf NetIfInfo
|
||||
}
|
||||
@ -287,6 +293,19 @@ func (h *Host) getStoragePools() {
|
||||
h.StoragePoolList[i].Allocation = spInfo.Allocation
|
||||
h.StoragePoolList[i].Available = spInfo.Available
|
||||
|
||||
spoolXML := &libvirtxml.StoragePool{}
|
||||
if err = spoolXML.Unmarshal(h.StoragePoolList[i].XML); err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
h.StoragePoolList[i].Type = spoolXML.Type
|
||||
for _, t := range storagepool.NetTypes {
|
||||
if h.StoragePoolList[i].Type == t {
|
||||
h.StoragePoolList[i].IsNet = true
|
||||
h.StoragePoolList[i].HAEnabled = true
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
svols, err := s.ListAllStorageVolumes(0)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
@ -463,6 +482,15 @@ func (h *Host) getDomainInfo() {
|
||||
if h.VMList[i].XML, err = d.GetXMLDesc(0); err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
vmXML := &libvirtxml.Domain{}
|
||||
if err = vmXML.Unmarshal(h.VMList[i].XML); err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
h.VMList[i].VCPUs = vmXML.VCPU.Value
|
||||
h.VMList[i].Memory = vmXML.CurrentMemory.Value
|
||||
if h.VMList[i].Active, err = d.IsActive(); err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
|
||||
d.Free()
|
||||
}
|
||||
@ -517,6 +545,9 @@ func (h *Host) getNetsInfo() {
|
||||
if h.NetworkList[i].XML, err = net.GetXMLDesc(0); err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
if h.NetworkList[i].Active, err = net.IsActive(); err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
|
||||
net.Free()
|
||||
}
|
||||
|
@ -1 +1,6 @@
|
||||
// Package network defines varialbes and methods to control libvirtd
|
||||
// networks. Networks Can be defined cluster wide, and mapped to
|
||||
// host interfaces this way.
|
||||
package network
|
||||
|
||||
type Network struct{}
|
||||
|
@ -9,3 +9,38 @@ var StoragePoolStateMap = map[libvirt.StoragePoolState]string{
|
||||
libvirt.STORAGE_POOL_DEGRADED: "degraded",
|
||||
libvirt.STORAGE_POOL_INACCESSIBLE: "inaccessible",
|
||||
}
|
||||
|
||||
var Types = []string{
|
||||
"dir",
|
||||
"fs",
|
||||
"netfs",
|
||||
"disk",
|
||||
"iscsi",
|
||||
"logical",
|
||||
"scsi",
|
||||
"mpath",
|
||||
"rbd",
|
||||
"sheepdog",
|
||||
"gluster",
|
||||
"zfs",
|
||||
"iscsi-direct",
|
||||
}
|
||||
|
||||
var LocalTypes = []string{
|
||||
"dir",
|
||||
"fs",
|
||||
"disk",
|
||||
"logical",
|
||||
"scsi",
|
||||
"zfs",
|
||||
}
|
||||
|
||||
var NetTypes = []string{
|
||||
"netfs",
|
||||
"iscsi",
|
||||
"mpath",
|
||||
"rbd",
|
||||
"sheepdog",
|
||||
"gluster",
|
||||
"iscsi-direct",
|
||||
}
|
||||
|
13
main.go
13
main.go
@ -23,8 +23,8 @@ func main() {
|
||||
// Start webserver and serve homepage
|
||||
|
||||
defaultNavBar := []components.NavItem{
|
||||
{Name: "Home", Href: "/"},
|
||||
{Name: "Hosts", Href: "/hostinfo"},
|
||||
{Name: "Cluster", Href: "/" },
|
||||
{Name: "Configuration", Href: "/config" },
|
||||
{Name: "About", Href: "/about"},
|
||||
}
|
||||
fs := http.StripPrefix("/static/", http.FileServer(http.Dir("public")))
|
||||
@ -51,6 +51,15 @@ func main() {
|
||||
defer rhost.Close()
|
||||
log.Println("Rendering HostInfo", view.HostInfo(rhost).Render(context.Background(), w))
|
||||
})
|
||||
r.Get("/host/{hostname}/stats", func(w http.ResponseWriter, r *http.Request) {
|
||||
rhost, err := host.ConnectHost(host.URI_QEMU_SSH_SYSTEM, chi.URLParam(r, "hostname"))
|
||||
if err != nil {
|
||||
http.Error(w, fmt.Sprintf("error while getting host: %s", err), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
defer rhost.Close()
|
||||
log.Println("Rendering stats", view.SysInfo(rhost).Render(context.Background(), w))
|
||||
})
|
||||
})
|
||||
|
||||
log.Println(http.ListenAndServe(":3000", r))
|
||||
|
@ -822,10 +822,6 @@ span>a:visited {
|
||||
position: static;
|
||||
}
|
||||
|
||||
.absolute {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.bottom-0 {
|
||||
bottom: 0px;
|
||||
}
|
||||
@ -852,10 +848,31 @@ span>a:visited {
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.my-1 {
|
||||
margin-top: 0.25rem;
|
||||
margin-bottom: 0.25rem;
|
||||
}
|
||||
|
||||
.ml-4 {
|
||||
margin-left: 1rem;
|
||||
}
|
||||
|
||||
.mt-2 {
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
|
||||
.block {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.inline-block {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.inline {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.flex {
|
||||
display: flex;
|
||||
}
|
||||
@ -869,16 +886,9 @@ span>a:visited {
|
||||
height: 16rem;
|
||||
}
|
||||
|
||||
.size-full {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.size-max {
|
||||
width: -moz-max-content;
|
||||
width: max-content;
|
||||
height: -moz-max-content;
|
||||
height: max-content;
|
||||
.size-40 {
|
||||
width: 10rem;
|
||||
height: 10rem;
|
||||
}
|
||||
|
||||
.h-28 {
|
||||
@ -893,37 +903,20 @@ span>a:visited {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.h-lvh {
|
||||
height: 100lvh;
|
||||
}
|
||||
|
||||
.h-svh {
|
||||
height: 100svh;
|
||||
}
|
||||
|
||||
.h-dvh {
|
||||
height: 100dvh;
|
||||
}
|
||||
|
||||
.h-max {
|
||||
height: -moz-max-content;
|
||||
height: max-content;
|
||||
}
|
||||
|
||||
.h-48 {
|
||||
height: 12rem;
|
||||
}
|
||||
|
||||
.h-screen {
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
.min-h-80 {
|
||||
min-height: 20rem;
|
||||
.h-2 {
|
||||
height: 0.5rem;
|
||||
}
|
||||
|
||||
.w-1\/4 {
|
||||
width: 25%;
|
||||
.h-4 {
|
||||
height: 1rem;
|
||||
}
|
||||
|
||||
.w-1\/6 {
|
||||
width: 16.666667%;
|
||||
}
|
||||
|
||||
.w-3\/4 {
|
||||
@ -934,8 +927,13 @@ span>a:visited {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.w-1\/6 {
|
||||
width: 16.666667%;
|
||||
.w-16 {
|
||||
width: 4rem;
|
||||
}
|
||||
|
||||
.w-fit {
|
||||
width: -moz-fit-content;
|
||||
width: fit-content;
|
||||
}
|
||||
|
||||
.flex-auto {
|
||||
@ -990,6 +988,10 @@ span>a:visited {
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.justify-start {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.justify-end {
|
||||
justify-content: flex-end;
|
||||
}
|
||||
@ -9032,14 +9034,6 @@ span>a:visited {
|
||||
border-radius: 9999px;
|
||||
}
|
||||
|
||||
.rounded-none {
|
||||
border-radius: 0px;
|
||||
}
|
||||
|
||||
.border-2 {
|
||||
border-width: 2px;
|
||||
}
|
||||
|
||||
.border {
|
||||
border-width: 1px;
|
||||
}
|
||||
@ -9048,19 +9042,10 @@ span>a:visited {
|
||||
border-style: solid;
|
||||
}
|
||||
|
||||
.border-dashed {
|
||||
border-style: dashed;
|
||||
}
|
||||
|
||||
.border-dotted {
|
||||
border-style: dotted;
|
||||
}
|
||||
|
||||
.border-red-500 {
|
||||
--tw-border-opacity: 1;
|
||||
border-color: rgb(239 68 68 / var(--tw-border-opacity));
|
||||
}
|
||||
|
||||
.border-uiblue-100 {
|
||||
--tw-border-opacity: 1;
|
||||
border-color: rgb(221 231 248 / var(--tw-border-opacity));
|
||||
@ -138666,14 +138651,14 @@ span>a:visited {
|
||||
stroke: rgb(51 51 30 / 0.95);
|
||||
}
|
||||
|
||||
.p-2 {
|
||||
padding: 0.5rem;
|
||||
}
|
||||
|
||||
.p-1 {
|
||||
padding: 0.25rem;
|
||||
}
|
||||
|
||||
.p-2 {
|
||||
padding: 0.5rem;
|
||||
}
|
||||
|
||||
.px-2 {
|
||||
padding-left: 0.5rem;
|
||||
padding-right: 0.5rem;
|
||||
@ -138684,6 +138669,11 @@ span>a:visited {
|
||||
padding-right: 1rem;
|
||||
}
|
||||
|
||||
.px-1 {
|
||||
padding-left: 0.25rem;
|
||||
padding-right: 0.25rem;
|
||||
}
|
||||
|
||||
.text-2xl {
|
||||
font-size: 1.5rem;
|
||||
line-height: 2rem;
|
||||
@ -220262,6 +220252,16 @@ span>a:visited {
|
||||
--tw-ring-offset-color: rgb(51 51 30 / 0.95);
|
||||
}
|
||||
|
||||
.hover\:border-uipurple-400:hover {
|
||||
--tw-border-opacity: 1;
|
||||
border-color: rgb(227 116 229 / var(--tw-border-opacity));
|
||||
}
|
||||
|
||||
.hover\:bg-uipurple-600:hover {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(176 65 178 / var(--tw-bg-opacity));
|
||||
}
|
||||
|
||||
.hover\:text-uiblue-200:hover {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(187 207 241 / var(--tw-text-opacity));
|
||||
@ -220290,6 +220290,11 @@ span>a:visited {
|
||||
order: 3;
|
||||
}
|
||||
|
||||
.md\:size-80 {
|
||||
width: 20rem;
|
||||
height: 20rem;
|
||||
}
|
||||
|
||||
.md\:h-16 {
|
||||
height: 4rem;
|
||||
}
|
||||
|
52
public/images/bars.svg
Normal file
52
public/images/bars.svg
Normal file
@ -0,0 +1,52 @@
|
||||
<svg width="135" height="140" viewBox="0 0 135 140" xmlns="http://www.w3.org/2000/svg" fill="#fff">
|
||||
<rect y="10" width="15" height="120" rx="6">
|
||||
<animate attributeName="height"
|
||||
begin="0.5s" dur="1s"
|
||||
values="120;110;100;90;80;70;60;50;40;140;120" calcMode="linear"
|
||||
repeatCount="indefinite" />
|
||||
<animate attributeName="y"
|
||||
begin="0.5s" dur="1s"
|
||||
values="10;15;20;25;30;35;40;45;50;0;10" calcMode="linear"
|
||||
repeatCount="indefinite" />
|
||||
</rect>
|
||||
<rect x="30" y="10" width="15" height="120" rx="6">
|
||||
<animate attributeName="height"
|
||||
begin="0.25s" dur="1s"
|
||||
values="120;110;100;90;80;70;60;50;40;140;120" calcMode="linear"
|
||||
repeatCount="indefinite" />
|
||||
<animate attributeName="y"
|
||||
begin="0.25s" dur="1s"
|
||||
values="10;15;20;25;30;35;40;45;50;0;10" calcMode="linear"
|
||||
repeatCount="indefinite" />
|
||||
</rect>
|
||||
<rect x="60" width="15" height="140" rx="6">
|
||||
<animate attributeName="height"
|
||||
begin="0s" dur="1s"
|
||||
values="120;110;100;90;80;70;60;50;40;140;120" calcMode="linear"
|
||||
repeatCount="indefinite" />
|
||||
<animate attributeName="y"
|
||||
begin="0s" dur="1s"
|
||||
values="10;15;20;25;30;35;40;45;50;0;10" calcMode="linear"
|
||||
repeatCount="indefinite" />
|
||||
</rect>
|
||||
<rect x="90" y="10" width="15" height="120" rx="6">
|
||||
<animate attributeName="height"
|
||||
begin="0.25s" dur="1s"
|
||||
values="120;110;100;90;80;70;60;50;40;140;120" calcMode="linear"
|
||||
repeatCount="indefinite" />
|
||||
<animate attributeName="y"
|
||||
begin="0.25s" dur="1s"
|
||||
values="10;15;20;25;30;35;40;45;50;0;10" calcMode="linear"
|
||||
repeatCount="indefinite" />
|
||||
</rect>
|
||||
<rect x="120" y="10" width="15" height="120" rx="6">
|
||||
<animate attributeName="height"
|
||||
begin="0.5s" dur="1s"
|
||||
values="120;110;100;90;80;70;60;50;40;140;120" calcMode="linear"
|
||||
repeatCount="indefinite" />
|
||||
<animate attributeName="y"
|
||||
begin="0.5s" dur="1s"
|
||||
values="10;15;20;25;30;35;40;45;50;0;10" calcMode="linear"
|
||||
repeatCount="indefinite" />
|
||||
</rect>
|
||||
</svg>
|
After Width: | Height: | Size: 2.3 KiB |
56
public/images/grid.svg
Normal file
56
public/images/grid.svg
Normal file
@ -0,0 +1,56 @@
|
||||
<svg width="105" height="105" viewBox="0 0 105 105" xmlns="http://www.w3.org/2000/svg" fill="#fff">
|
||||
<circle cx="12.5" cy="12.5" r="12.5">
|
||||
<animate attributeName="fill-opacity"
|
||||
begin="0s" dur="1s"
|
||||
values="1;.2;1" calcMode="linear"
|
||||
repeatCount="indefinite" />
|
||||
</circle>
|
||||
<circle cx="12.5" cy="52.5" r="12.5" fill-opacity=".5">
|
||||
<animate attributeName="fill-opacity"
|
||||
begin="100ms" dur="1s"
|
||||
values="1;.2;1" calcMode="linear"
|
||||
repeatCount="indefinite" />
|
||||
</circle>
|
||||
<circle cx="52.5" cy="12.5" r="12.5">
|
||||
<animate attributeName="fill-opacity"
|
||||
begin="300ms" dur="1s"
|
||||
values="1;.2;1" calcMode="linear"
|
||||
repeatCount="indefinite" />
|
||||
</circle>
|
||||
<circle cx="52.5" cy="52.5" r="12.5">
|
||||
<animate attributeName="fill-opacity"
|
||||
begin="600ms" dur="1s"
|
||||
values="1;.2;1" calcMode="linear"
|
||||
repeatCount="indefinite" />
|
||||
</circle>
|
||||
<circle cx="92.5" cy="12.5" r="12.5">
|
||||
<animate attributeName="fill-opacity"
|
||||
begin="800ms" dur="1s"
|
||||
values="1;.2;1" calcMode="linear"
|
||||
repeatCount="indefinite" />
|
||||
</circle>
|
||||
<circle cx="92.5" cy="52.5" r="12.5">
|
||||
<animate attributeName="fill-opacity"
|
||||
begin="400ms" dur="1s"
|
||||
values="1;.2;1" calcMode="linear"
|
||||
repeatCount="indefinite" />
|
||||
</circle>
|
||||
<circle cx="12.5" cy="92.5" r="12.5">
|
||||
<animate attributeName="fill-opacity"
|
||||
begin="700ms" dur="1s"
|
||||
values="1;.2;1" calcMode="linear"
|
||||
repeatCount="indefinite" />
|
||||
</circle>
|
||||
<circle cx="52.5" cy="92.5" r="12.5">
|
||||
<animate attributeName="fill-opacity"
|
||||
begin="500ms" dur="1s"
|
||||
values="1;.2;1" calcMode="linear"
|
||||
repeatCount="indefinite" />
|
||||
</circle>
|
||||
<circle cx="92.5" cy="92.5" r="12.5">
|
||||
<animate attributeName="fill-opacity"
|
||||
begin="200ms" dur="1s"
|
||||
values="1;.2;1" calcMode="linear"
|
||||
repeatCount="indefinite" />
|
||||
</circle>
|
||||
</svg>
|
After Width: | Height: | Size: 2.0 KiB |
@ -1,36 +1,102 @@
|
||||
package view
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"git.staur.ca/stobbsm/clustvirt/lib/host"
|
||||
bf "github.com/labstack/gommon/bytes"
|
||||
"git.staur.ca/stobbsm/clustvirt/view/components"
|
||||
"git.staur.ca/stobbsm/clustvirt/view/layouts"
|
||||
)
|
||||
|
||||
script memchart(used uint64, free uint64, buf uint64, cache uint64) {
|
||||
ctx = document.getElementById('memchart');
|
||||
|
||||
new Chart(ctx, {
|
||||
type: 'pie',
|
||||
data: {
|
||||
labels: [
|
||||
'Used',
|
||||
'Free',
|
||||
'Cached',
|
||||
'Buffered'
|
||||
],
|
||||
datasets: [{
|
||||
label: 'Memory Usage',
|
||||
data: [
|
||||
used,
|
||||
free,
|
||||
cache,
|
||||
buf,
|
||||
],
|
||||
backgroundColor: [
|
||||
'rgb(255,0,0)',
|
||||
'rgb(0,255,0)',
|
||||
'rgb(128,128,0)',
|
||||
'rgb(0,0,255)'
|
||||
],
|
||||
hoverOffset: 4
|
||||
}],
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// MemChart get's the memory pi chart from the host
|
||||
templ MemChart(h *host.Host) {
|
||||
<div class={ "flex" , "flex-row" }>
|
||||
<div class={ "size-64" }>
|
||||
@templ.Raw(h.ChartMemory())
|
||||
<div class={ "size-40" , "md:size-80" }>
|
||||
<canvas id="memchart" class={ "size-40" , "md:size-80" }></canvas>
|
||||
</div>
|
||||
<ul>
|
||||
<li>Free: { bf.Format(int64(h.NodeMemory.Free*1024)) }</li>
|
||||
<li>Cached: { bf.Format(int64(h.NodeMemory.Cached*1024)) }</li>
|
||||
<li>Buffers: { bf.Format(int64(h.NodeMemory.Buffers*1024)) }</li>
|
||||
<li>Total: { bf.Format(int64(h.NodeMemory.Total*1024)) }</li>
|
||||
<li>Free: <span id="memfree">{ fmt.Sprintf("%d Gi", h.NodeMemory.Free/1024/1024) }</span></li>
|
||||
<li>Cached: <span id="memcach">{ fmt.Sprintf("%d Gi", h.NodeMemory.Cached/1024/1024) }</span></li>
|
||||
<li>Buffers: <span id="membuf">{ fmt.Sprintf("%d Gi", h.NodeMemory.Buffers/1024/1024) }</span></li>
|
||||
<li>Total: <span id="memtot">{ fmt.Sprintf("%d Gi", h.NodeMemory.Total/1024/1024) }</span></li>
|
||||
</ul>
|
||||
</div>
|
||||
@memchart(h.NodeMemory.Total-h.NodeMemory.Free-h.NodeMemory.Buffers-h.NodeMemory.Cached, h.NodeMemory.Free,
|
||||
h.NodeMemory.Buffers, h.NodeMemory.Cached)
|
||||
}
|
||||
|
||||
templ hostButton(hostname string) {
|
||||
<button
|
||||
hx-target="#sysContent"
|
||||
hx-get={ fmt.Sprintf("/htmx/host/%s", hostname) }
|
||||
class={ "rounded",
|
||||
"border",
|
||||
"border-solid",
|
||||
"border-uiblue-700",
|
||||
"text-uigrey-200",
|
||||
"bg-uiblue-800",
|
||||
"hover:border-uipurple-400",
|
||||
"hover:text-ui-grey-800",
|
||||
"hover:bg-uipurple-600",
|
||||
"gap-2",
|
||||
"p-1",
|
||||
"my-1",
|
||||
"w-full",
|
||||
"flex",
|
||||
"flex-row",
|
||||
"justify-between" }
|
||||
>
|
||||
<span class={ "px-2" }>{ hostname }</span>
|
||||
<img class={ "htmx-indicator" , "inline-block" , "h-6" , "px-2" } src="/static/images/bars.svg"/>
|
||||
</button>
|
||||
}
|
||||
|
||||
// HostConnect is the page that allows us to select a host to get information from
|
||||
templ HostMain(navBarItems []components.NavItem) {
|
||||
@layouts.Manager("ClustVirt", "Cluster Manager", navBarItems) {
|
||||
<div class={ "flex" , "flex-row" , "h-full" }>
|
||||
<div id="sysNavBar" class={ "w-1/6" , "border-uigrey-600" , "border" , "rounded" , "border-dotted" , "p-1" }>
|
||||
<div class={ "flex" , "flex-row" , "h-full" , "mt-2" }>
|
||||
<div id="sysNavBar" class={ "w-1/6" , "border-uigrey-600" , "border" , "rounded" , "border-dotted" , "p-2" }>
|
||||
<ul>
|
||||
<li><a href="#" hx-target="#sysContent" hx-get="/htmx/host/venus.staur.ca">venus.staur.ca</a></li>
|
||||
<li><a href="#" hx-target="#sysContent" hx-get="/htmx/host/earth.staur.ca">earth.staur.ca</a></li>
|
||||
<li><a href="#" hx-target="#sysContent" hx-get="/htmx/host/mars.staur.ca">mars.staur.ca</a></li>
|
||||
<li>
|
||||
@hostButton("venus.staur.ca")
|
||||
</li>
|
||||
<li>
|
||||
@hostButton("earth.staur.ca")
|
||||
</li>
|
||||
<li>
|
||||
@hostButton("mars.staur.ca")
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div id="sysContent" class={ "w-3/4" , "px-2" }>
|
||||
@ -46,6 +112,22 @@ templ HostMain(navBarItems []components.NavItem) {
|
||||
|
||||
// HostInfo is meant to be an HTMX response
|
||||
templ HostInfo(h *host.Host) {
|
||||
<div class={ "flex" , "flex-col" }>
|
||||
<div
|
||||
class={ "flex" , "flex-row" , "justify-start" , "px-2" }
|
||||
hx-trigger="every 30s"
|
||||
hx-get={ fmt.Sprintf("/htmx/host/%s/stats", h.HostName) }
|
||||
hx-target="#sysInfo"
|
||||
>
|
||||
<h3>{ h.HostName }</h3>
|
||||
<img class={ "h-6" , "px-2" , "htmx-indicator" , "inline-block" } src="/static/images/grid.svg"/>
|
||||
</div>
|
||||
<div class={ "flex" , "flex-row" , "flex-wrap" } id="sysInfo">
|
||||
@SysInfo(h)
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
templ SysInfo(h *host.Host) {
|
||||
@MemChart(h)
|
||||
}
|
||||
|
@ -11,12 +11,50 @@ import "io"
|
||||
import "bytes"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"git.staur.ca/stobbsm/clustvirt/lib/host"
|
||||
"git.staur.ca/stobbsm/clustvirt/view/components"
|
||||
"git.staur.ca/stobbsm/clustvirt/view/layouts"
|
||||
bf "github.com/labstack/gommon/bytes"
|
||||
)
|
||||
|
||||
func memchart(used uint64, free uint64, buf uint64, cache uint64) templ.ComponentScript {
|
||||
return templ.ComponentScript{
|
||||
Name: `__templ_memchart_9d4c`,
|
||||
Function: `function __templ_memchart_9d4c(used, free, buf, cache){ctx = document.getElementById('memchart');
|
||||
|
||||
new Chart(ctx, {
|
||||
type: 'pie',
|
||||
data: {
|
||||
labels: [
|
||||
'Used',
|
||||
'Free',
|
||||
'Cached',
|
||||
'Buffered'
|
||||
],
|
||||
datasets: [{
|
||||
label: 'Memory Usage',
|
||||
data: [
|
||||
used,
|
||||
free,
|
||||
cache,
|
||||
buf,
|
||||
],
|
||||
backgroundColor: [
|
||||
'rgb(255,0,0)',
|
||||
'rgb(0,255,0)',
|
||||
'rgb(128,128,0)',
|
||||
'rgb(0,0,255)'
|
||||
],
|
||||
hoverOffset: 4
|
||||
}],
|
||||
}
|
||||
});
|
||||
}`,
|
||||
Call: templ.SafeScript(`__templ_memchart_9d4c`, used, free, buf, cache),
|
||||
CallInline: templ.SafeScriptInline(`__templ_memchart_9d4c`, used, free, buf, cache),
|
||||
}
|
||||
}
|
||||
|
||||
// MemChart get's the memory pi chart from the host
|
||||
func MemChart(h *host.Host) templ.Component {
|
||||
return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) {
|
||||
@ -48,7 +86,7 @@ func MemChart(h *host.Host) templ.Component {
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var3 = []any{"size-64"}
|
||||
var templ_7745c5c3_Var3 = []any{"size-40", "md:size-80"}
|
||||
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var3...)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
@ -65,63 +103,184 @@ func MemChart(h *host.Host) templ.Component {
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templ.Raw(h.ChartMemory()).Render(ctx, templ_7745c5c3_Buffer)
|
||||
var templ_7745c5c3_Var4 = []any{"size-40", "md:size-80"}
|
||||
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var4...)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div><ul><li>Free: ")
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<canvas id=\"memchart\" class=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var4 string
|
||||
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(bf.Format(int64(h.NodeMemory.Free * 1024)))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/hostinfo.templ`, Line: 16, Col: 55}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4))
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ.CSSClasses(templ_7745c5c3_Var4).String()))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</li><li>Cached: ")
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\"></canvas></div><ul><li>Free: <span id=\"memfree\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var5 string
|
||||
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(bf.Format(int64(h.NodeMemory.Cached * 1024)))
|
||||
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d Gi", h.NodeMemory.Free/1024/1024))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/hostinfo.templ`, Line: 17, Col: 59}
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/hostinfo.templ`, Line: 48, Col: 83}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</li><li>Buffers: ")
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</span></li><li>Cached: <span id=\"memcach\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var6 string
|
||||
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(bf.Format(int64(h.NodeMemory.Buffers * 1024)))
|
||||
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d Gi", h.NodeMemory.Cached/1024/1024))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/hostinfo.templ`, Line: 18, Col: 61}
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/hostinfo.templ`, Line: 49, Col: 87}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</li><li>Total: ")
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</span></li><li>Buffers: <span id=\"membuf\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var7 string
|
||||
templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(bf.Format(int64(h.NodeMemory.Total * 1024)))
|
||||
templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d Gi", h.NodeMemory.Buffers/1024/1024))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/hostinfo.templ`, Line: 19, Col: 57}
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/hostinfo.templ`, Line: 50, Col: 88}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</li></ul></div>")
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</span></li><li>Total: <span id=\"memtot\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var8 string
|
||||
templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d Gi", h.NodeMemory.Total/1024/1024))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/hostinfo.templ`, Line: 51, Col: 84}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</span></li></ul></div>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = memchart(h.NodeMemory.Total-h.NodeMemory.Free-h.NodeMemory.Buffers-h.NodeMemory.Cached, h.NodeMemory.Free,
|
||||
h.NodeMemory.Buffers, h.NodeMemory.Cached).Render(ctx, templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
if !templ_7745c5c3_IsBuffer {
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W)
|
||||
}
|
||||
return templ_7745c5c3_Err
|
||||
})
|
||||
}
|
||||
|
||||
func hostButton(hostname string) templ.Component {
|
||||
return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) {
|
||||
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer)
|
||||
if !templ_7745c5c3_IsBuffer {
|
||||
templ_7745c5c3_Buffer = templ.GetBuffer()
|
||||
defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||
}
|
||||
ctx = templ.InitializeContext(ctx)
|
||||
templ_7745c5c3_Var9 := templ.GetChildren(ctx)
|
||||
if templ_7745c5c3_Var9 == nil {
|
||||
templ_7745c5c3_Var9 = templ.NopComponent
|
||||
}
|
||||
ctx = templ.ClearChildren(ctx)
|
||||
var templ_7745c5c3_Var10 = []any{"rounded",
|
||||
"border",
|
||||
"border-solid",
|
||||
"border-uiblue-700",
|
||||
"text-uigrey-200",
|
||||
"bg-uiblue-800",
|
||||
"hover:border-uipurple-400",
|
||||
"hover:text-ui-grey-800",
|
||||
"hover:bg-uipurple-600",
|
||||
"gap-2",
|
||||
"p-1",
|
||||
"my-1",
|
||||
"w-full",
|
||||
"flex",
|
||||
"flex-row",
|
||||
"justify-between"}
|
||||
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var10...)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<button hx-target=\"#sysContent\" hx-get=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(fmt.Sprintf("/htmx/host/%s", hostname)))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" class=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ.CSSClasses(templ_7745c5c3_Var10).String()))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var11 = []any{"px-2"}
|
||||
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var11...)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<span class=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ.CSSClasses(templ_7745c5c3_Var11).String()))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var12 string
|
||||
templ_7745c5c3_Var12, templ_7745c5c3_Err = templ.JoinStringErrs(hostname)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/hostinfo.templ`, Line: 79, Col: 35}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var12))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</span> ")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var13 = []any{"htmx-indicator", "inline-block", "h-6", "px-2"}
|
||||
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var13...)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<img class=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ.CSSClasses(templ_7745c5c3_Var13).String()))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" src=\"/static/images/bars.svg\"></button>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
@ -141,19 +300,19 @@ func HostMain(navBarItems []components.NavItem) templ.Component {
|
||||
defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||
}
|
||||
ctx = templ.InitializeContext(ctx)
|
||||
templ_7745c5c3_Var8 := templ.GetChildren(ctx)
|
||||
if templ_7745c5c3_Var8 == nil {
|
||||
templ_7745c5c3_Var8 = templ.NopComponent
|
||||
templ_7745c5c3_Var14 := templ.GetChildren(ctx)
|
||||
if templ_7745c5c3_Var14 == nil {
|
||||
templ_7745c5c3_Var14 = templ.NopComponent
|
||||
}
|
||||
ctx = templ.ClearChildren(ctx)
|
||||
templ_7745c5c3_Var9 := templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) {
|
||||
templ_7745c5c3_Var15 := templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) {
|
||||
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer)
|
||||
if !templ_7745c5c3_IsBuffer {
|
||||
templ_7745c5c3_Buffer = templ.GetBuffer()
|
||||
defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||
}
|
||||
var templ_7745c5c3_Var10 = []any{"flex", "flex-row", "h-full"}
|
||||
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var10...)
|
||||
var templ_7745c5c3_Var16 = []any{"flex", "flex-row", "h-full", "mt-2"}
|
||||
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var16...)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
@ -161,7 +320,7 @@ func HostMain(navBarItems []components.NavItem) templ.Component {
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ.CSSClasses(templ_7745c5c3_Var10).String()))
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ.CSSClasses(templ_7745c5c3_Var16).String()))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
@ -169,8 +328,8 @@ func HostMain(navBarItems []components.NavItem) templ.Component {
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var11 = []any{"w-1/6", "border-uigrey-600", "border", "rounded", "border-dotted", "p-1"}
|
||||
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var11...)
|
||||
var templ_7745c5c3_Var17 = []any{"w-1/6", "border-uigrey-600", "border", "rounded", "border-dotted", "p-2"}
|
||||
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var17...)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
@ -178,16 +337,40 @@ func HostMain(navBarItems []components.NavItem) templ.Component {
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ.CSSClasses(templ_7745c5c3_Var11).String()))
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ.CSSClasses(templ_7745c5c3_Var17).String()))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\"><ul><li><a href=\"#\" hx-target=\"#sysContent\" hx-get=\"/htmx/host/venus.staur.ca\">venus.staur.ca</a></li><li><a href=\"#\" hx-target=\"#sysContent\" hx-get=\"/htmx/host/earth.staur.ca\">earth.staur.ca</a></li><li><a href=\"#\" hx-target=\"#sysContent\" hx-get=\"/htmx/host/mars.staur.ca\">mars.staur.ca</a></li></ul></div>")
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\"><ul><li>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var12 = []any{"w-3/4", "px-2"}
|
||||
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var12...)
|
||||
templ_7745c5c3_Err = hostButton("venus.staur.ca").Render(ctx, templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</li><li>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = hostButton("earth.staur.ca").Render(ctx, templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</li><li>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = hostButton("mars.staur.ca").Render(ctx, templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</li></ul></div>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var18 = []any{"w-3/4", "px-2"}
|
||||
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var18...)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
@ -195,7 +378,7 @@ func HostMain(navBarItems []components.NavItem) templ.Component {
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ.CSSClasses(templ_7745c5c3_Var12).String()))
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ.CSSClasses(templ_7745c5c3_Var18).String()))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
@ -208,7 +391,7 @@ func HostMain(navBarItems []components.NavItem) templ.Component {
|
||||
}
|
||||
return templ_7745c5c3_Err
|
||||
})
|
||||
templ_7745c5c3_Err = layouts.Manager("ClustVirt", "Cluster Manager", navBarItems).Render(templ.WithChildren(ctx, templ_7745c5c3_Var9), templ_7745c5c3_Buffer)
|
||||
templ_7745c5c3_Err = layouts.Manager("ClustVirt", "Cluster Manager", navBarItems).Render(templ.WithChildren(ctx, templ_7745c5c3_Var15), templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
@ -228,21 +411,59 @@ func HostInfo(h *host.Host) templ.Component {
|
||||
defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||
}
|
||||
ctx = templ.InitializeContext(ctx)
|
||||
templ_7745c5c3_Var13 := templ.GetChildren(ctx)
|
||||
if templ_7745c5c3_Var13 == nil {
|
||||
templ_7745c5c3_Var13 = templ.NopComponent
|
||||
templ_7745c5c3_Var19 := templ.GetChildren(ctx)
|
||||
if templ_7745c5c3_Var19 == nil {
|
||||
templ_7745c5c3_Var19 = templ.NopComponent
|
||||
}
|
||||
ctx = templ.ClearChildren(ctx)
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<h3>")
|
||||
var templ_7745c5c3_Var20 = []any{"flex", "flex-col"}
|
||||
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var20...)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var14 string
|
||||
templ_7745c5c3_Var14, templ_7745c5c3_Err = templ.JoinStringErrs(h.HostName)
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/hostinfo.templ`, Line: 48, Col: 17}
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var14))
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ.CSSClasses(templ_7745c5c3_Var20).String()))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var21 = []any{"flex", "flex-row", "justify-start", "px-2"}
|
||||
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var21...)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ.CSSClasses(templ_7745c5c3_Var21).String()))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" hx-trigger=\"every 30s\" hx-get=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(fmt.Sprintf("/htmx/host/%s/stats", h.HostName)))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" hx-target=\"#sysInfo\"><h3>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var22 string
|
||||
templ_7745c5c3_Var22, templ_7745c5c3_Err = templ.JoinStringErrs(h.HostName)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/hostinfo.templ`, Line: 121, Col: 19}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var22))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
@ -250,6 +471,68 @@ func HostInfo(h *host.Host) templ.Component {
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var23 = []any{"h-6", "px-2", "htmx-indicator", "inline-block"}
|
||||
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var23...)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<img class=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ.CSSClasses(templ_7745c5c3_Var23).String()))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" src=\"/static/images/grid.svg\"></div>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var24 = []any{"flex", "flex-row", "flex-wrap"}
|
||||
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var24...)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ.CSSClasses(templ_7745c5c3_Var24).String()))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" id=\"sysInfo\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = SysInfo(h).Render(ctx, templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div></div>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
if !templ_7745c5c3_IsBuffer {
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W)
|
||||
}
|
||||
return templ_7745c5c3_Err
|
||||
})
|
||||
}
|
||||
|
||||
func SysInfo(h *host.Host) templ.Component {
|
||||
return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) {
|
||||
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer)
|
||||
if !templ_7745c5c3_IsBuffer {
|
||||
templ_7745c5c3_Buffer = templ.GetBuffer()
|
||||
defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||
}
|
||||
ctx = templ.InitializeContext(ctx)
|
||||
templ_7745c5c3_Var25 := templ.GetChildren(ctx)
|
||||
if templ_7745c5c3_Var25 == nil {
|
||||
templ_7745c5c3_Var25 = templ.NopComponent
|
||||
}
|
||||
ctx = templ.ClearChildren(ctx)
|
||||
templ_7745c5c3_Err = MemChart(h).Render(ctx, templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
|
@ -24,6 +24,7 @@ templ Manager(title string, subtitle string, navBarItem []components.NavItem) {
|
||||
<!-- Load HTMX -->
|
||||
<script src=" https://unpkg.com/htmx.org@1.9.11" integrity="sha384-0gxUXCCR8yv9FM2b+U3FDbsKthCI66oH5IA9fHppQq9DDMHuMauqq1ZHBpJxQ0J0" crossorigin="anonymous">
|
||||
</script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.2/dist/chart.umd.min.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
}
|
||||
|
@ -134,7 +134,7 @@ func Manager(title string, subtitle string, navBarItem []components.NavItem) tem
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</footer></div><!-- Load HTMX --><script src=\" https://unpkg.com/htmx.org@1.9.11\" integrity=\"sha384-0gxUXCCR8yv9FM2b+U3FDbsKthCI66oH5IA9fHppQq9DDMHuMauqq1ZHBpJxQ0J0\" crossorigin=\"anonymous\">\n </script></body></html>")
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</footer></div><!-- Load HTMX --><script src=\" https://unpkg.com/htmx.org@1.9.11\" integrity=\"sha384-0gxUXCCR8yv9FM2b+U3FDbsKthCI66oH5IA9fHppQq9DDMHuMauqq1ZHBpJxQ0J0\" crossorigin=\"anonymous\">\n </script><script src=\"https://cdn.jsdelivr.net/npm/chart.js@4.4.2/dist/chart.umd.min.js\"></script></body></html>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user