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>
|
</clustvirt:data>
|
||||||
</metadata>
|
</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 (
|
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/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/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
|
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/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 h1:6jMIHv6wQZvdPxTuv87erW4RqN/FPU0wk7ZHN5wVuuo=
|
||||||
github.com/a-h/templ v0.2.598/go.mod h1:SA7mtYwVEajbIXFRh3vKdYm/4FYyLQAtPH1+KxzGPA8=
|
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 h1:9euLV5sTrTNTRUU9POmDUvfxyj6LAABLUcEWO+JJb4s=
|
||||||
github.com/go-chi/chi/v5 v5.0.12/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
|
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 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
|
||||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
|
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 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
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 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0=
|
||||||
github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU=
|
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 h1:2u7na789qiD5WzccZsFz4MJWOJP72G+2kUuJoSNqWnE=
|
||||||
github.com/wcharczuk/go-chart/v2 v2.1.1/go.mod h1:CyCAUt2oqvfhCl6Q5ZvAZwItgpQKZOkCJGb+VGv6l14=
|
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=
|
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-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/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 h1:ds2RoQvBvYTiJkwpSFDwCcDFNX7DqjL2WsUgTNk0Ooo=
|
||||||
golang.org/x/image v0.11.0/go.mod h1:bglhjqbqVuEb9e9+eNR45Jfu7D+T4Qan+NhQk8Ck2P8=
|
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=
|
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-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-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-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-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.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.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-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.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
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.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.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.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-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.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.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
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=
|
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 h1:lEVDNE7xfzmZXiDEGIS8NvJSuaz11OjRXw+ufbQEtPY=
|
||||||
libvirt.org/go/libvirt v1.10001.0/go.mod h1:1WiFE8EjZfq+FCVog+rvr1yatKbKZ9FaFMZgEqxEJqQ=
|
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/lib/storagevol"
|
||||||
"git.staur.ca/stobbsm/clustvirt/util"
|
"git.staur.ca/stobbsm/clustvirt/util"
|
||||||
"libvirt.org/go/libvirt"
|
"libvirt.org/go/libvirt"
|
||||||
|
"libvirt.org/go/libvirtxml"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Host holds information and acts as a connection handle for a Host
|
// Host holds information and acts as a connection handle for a Host
|
||||||
@ -80,6 +81,9 @@ type VMInfo struct {
|
|||||||
ID uint
|
ID uint
|
||||||
UUID []byte
|
UUID []byte
|
||||||
XML string
|
XML string
|
||||||
|
Active bool
|
||||||
|
VCPUs uint
|
||||||
|
Memory uint
|
||||||
// States are the current states active on the host
|
// States are the current states active on the host
|
||||||
States []guest.VMState
|
States []guest.VMState
|
||||||
}
|
}
|
||||||
@ -105,6 +109,7 @@ type StoragePoolInfo struct {
|
|||||||
Capacity uint64
|
Capacity uint64
|
||||||
Allocation uint64
|
Allocation uint64
|
||||||
Available uint64
|
Available uint64
|
||||||
|
IsNet bool
|
||||||
// HAEnabled indicates if the storage pool has High Availability
|
// HAEnabled indicates if the storage pool has High Availability
|
||||||
HAEnabled bool
|
HAEnabled bool
|
||||||
// Volumes defined in the storage pool
|
// Volumes defined in the storage pool
|
||||||
@ -134,6 +139,7 @@ type NetworkInfo struct {
|
|||||||
Name string
|
Name string
|
||||||
UUID []byte
|
UUID []byte
|
||||||
XML string
|
XML string
|
||||||
|
Active bool
|
||||||
// NetIf is the network interface this connection is applied to
|
// NetIf is the network interface this connection is applied to
|
||||||
NetIf NetIfInfo
|
NetIf NetIfInfo
|
||||||
}
|
}
|
||||||
@ -287,6 +293,19 @@ func (h *Host) getStoragePools() {
|
|||||||
h.StoragePoolList[i].Allocation = spInfo.Allocation
|
h.StoragePoolList[i].Allocation = spInfo.Allocation
|
||||||
h.StoragePoolList[i].Available = spInfo.Available
|
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)
|
svols, err := s.ListAllStorageVolumes(0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
@ -463,6 +482,15 @@ func (h *Host) getDomainInfo() {
|
|||||||
if h.VMList[i].XML, err = d.GetXMLDesc(0); err != nil {
|
if h.VMList[i].XML, err = d.GetXMLDesc(0); err != nil {
|
||||||
log.Println(err)
|
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()
|
d.Free()
|
||||||
}
|
}
|
||||||
@ -517,6 +545,9 @@ func (h *Host) getNetsInfo() {
|
|||||||
if h.NetworkList[i].XML, err = net.GetXMLDesc(0); err != nil {
|
if h.NetworkList[i].XML, err = net.GetXMLDesc(0); err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
}
|
}
|
||||||
|
if h.NetworkList[i].Active, err = net.IsActive(); err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
}
|
||||||
|
|
||||||
net.Free()
|
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
|
package network
|
||||||
|
|
||||||
|
type Network struct{}
|
||||||
|
@ -9,3 +9,38 @@ var StoragePoolStateMap = map[libvirt.StoragePoolState]string{
|
|||||||
libvirt.STORAGE_POOL_DEGRADED: "degraded",
|
libvirt.STORAGE_POOL_DEGRADED: "degraded",
|
||||||
libvirt.STORAGE_POOL_INACCESSIBLE: "inaccessible",
|
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
|
// Start webserver and serve homepage
|
||||||
|
|
||||||
defaultNavBar := []components.NavItem{
|
defaultNavBar := []components.NavItem{
|
||||||
{Name: "Home", Href: "/"},
|
{Name: "Cluster", Href: "/" },
|
||||||
{Name: "Hosts", Href: "/hostinfo"},
|
{Name: "Configuration", Href: "/config" },
|
||||||
{Name: "About", Href: "/about"},
|
{Name: "About", Href: "/about"},
|
||||||
}
|
}
|
||||||
fs := http.StripPrefix("/static/", http.FileServer(http.Dir("public")))
|
fs := http.StripPrefix("/static/", http.FileServer(http.Dir("public")))
|
||||||
@ -51,6 +51,15 @@ func main() {
|
|||||||
defer rhost.Close()
|
defer rhost.Close()
|
||||||
log.Println("Rendering HostInfo", view.HostInfo(rhost).Render(context.Background(), w))
|
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))
|
log.Println(http.ListenAndServe(":3000", r))
|
||||||
|
@ -822,10 +822,6 @@ span>a:visited {
|
|||||||
position: static;
|
position: static;
|
||||||
}
|
}
|
||||||
|
|
||||||
.absolute {
|
|
||||||
position: absolute;
|
|
||||||
}
|
|
||||||
|
|
||||||
.bottom-0 {
|
.bottom-0 {
|
||||||
bottom: 0px;
|
bottom: 0px;
|
||||||
}
|
}
|
||||||
@ -852,10 +848,31 @@ span>a:visited {
|
|||||||
margin-right: auto;
|
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 {
|
.block {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.inline-block {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.inline {
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
|
||||||
.flex {
|
.flex {
|
||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
@ -869,16 +886,9 @@ span>a:visited {
|
|||||||
height: 16rem;
|
height: 16rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.size-full {
|
.size-40 {
|
||||||
width: 100%;
|
width: 10rem;
|
||||||
height: 100%;
|
height: 10rem;
|
||||||
}
|
|
||||||
|
|
||||||
.size-max {
|
|
||||||
width: -moz-max-content;
|
|
||||||
width: max-content;
|
|
||||||
height: -moz-max-content;
|
|
||||||
height: max-content;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.h-28 {
|
.h-28 {
|
||||||
@ -893,37 +903,20 @@ span>a:visited {
|
|||||||
height: 100%;
|
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 {
|
.h-screen {
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
}
|
}
|
||||||
|
|
||||||
.min-h-80 {
|
.h-2 {
|
||||||
min-height: 20rem;
|
height: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.w-1\/4 {
|
.h-4 {
|
||||||
width: 25%;
|
height: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.w-1\/6 {
|
||||||
|
width: 16.666667%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.w-3\/4 {
|
.w-3\/4 {
|
||||||
@ -934,8 +927,13 @@ span>a:visited {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.w-1\/6 {
|
.w-16 {
|
||||||
width: 16.666667%;
|
width: 4rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.w-fit {
|
||||||
|
width: -moz-fit-content;
|
||||||
|
width: fit-content;
|
||||||
}
|
}
|
||||||
|
|
||||||
.flex-auto {
|
.flex-auto {
|
||||||
@ -990,6 +988,10 @@ span>a:visited {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.justify-start {
|
||||||
|
justify-content: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
.justify-end {
|
.justify-end {
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
}
|
}
|
||||||
@ -9032,14 +9034,6 @@ span>a:visited {
|
|||||||
border-radius: 9999px;
|
border-radius: 9999px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.rounded-none {
|
|
||||||
border-radius: 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.border-2 {
|
|
||||||
border-width: 2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.border {
|
.border {
|
||||||
border-width: 1px;
|
border-width: 1px;
|
||||||
}
|
}
|
||||||
@ -9048,19 +9042,10 @@ span>a:visited {
|
|||||||
border-style: solid;
|
border-style: solid;
|
||||||
}
|
}
|
||||||
|
|
||||||
.border-dashed {
|
|
||||||
border-style: dashed;
|
|
||||||
}
|
|
||||||
|
|
||||||
.border-dotted {
|
.border-dotted {
|
||||||
border-style: dotted;
|
border-style: dotted;
|
||||||
}
|
}
|
||||||
|
|
||||||
.border-red-500 {
|
|
||||||
--tw-border-opacity: 1;
|
|
||||||
border-color: rgb(239 68 68 / var(--tw-border-opacity));
|
|
||||||
}
|
|
||||||
|
|
||||||
.border-uiblue-100 {
|
.border-uiblue-100 {
|
||||||
--tw-border-opacity: 1;
|
--tw-border-opacity: 1;
|
||||||
border-color: rgb(221 231 248 / var(--tw-border-opacity));
|
border-color: rgb(221 231 248 / var(--tw-border-opacity));
|
||||||
@ -138666,14 +138651,14 @@ span>a:visited {
|
|||||||
stroke: rgb(51 51 30 / 0.95);
|
stroke: rgb(51 51 30 / 0.95);
|
||||||
}
|
}
|
||||||
|
|
||||||
.p-2 {
|
|
||||||
padding: 0.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.p-1 {
|
.p-1 {
|
||||||
padding: 0.25rem;
|
padding: 0.25rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.p-2 {
|
||||||
|
padding: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
.px-2 {
|
.px-2 {
|
||||||
padding-left: 0.5rem;
|
padding-left: 0.5rem;
|
||||||
padding-right: 0.5rem;
|
padding-right: 0.5rem;
|
||||||
@ -138684,6 +138669,11 @@ span>a:visited {
|
|||||||
padding-right: 1rem;
|
padding-right: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.px-1 {
|
||||||
|
padding-left: 0.25rem;
|
||||||
|
padding-right: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
.text-2xl {
|
.text-2xl {
|
||||||
font-size: 1.5rem;
|
font-size: 1.5rem;
|
||||||
line-height: 2rem;
|
line-height: 2rem;
|
||||||
@ -220262,6 +220252,16 @@ span>a:visited {
|
|||||||
--tw-ring-offset-color: rgb(51 51 30 / 0.95);
|
--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 {
|
.hover\:text-uiblue-200:hover {
|
||||||
--tw-text-opacity: 1;
|
--tw-text-opacity: 1;
|
||||||
color: rgb(187 207 241 / var(--tw-text-opacity));
|
color: rgb(187 207 241 / var(--tw-text-opacity));
|
||||||
@ -220290,6 +220290,11 @@ span>a:visited {
|
|||||||
order: 3;
|
order: 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.md\:size-80 {
|
||||||
|
width: 20rem;
|
||||||
|
height: 20rem;
|
||||||
|
}
|
||||||
|
|
||||||
.md\:h-16 {
|
.md\:h-16 {
|
||||||
height: 4rem;
|
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
|
package view
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"git.staur.ca/stobbsm/clustvirt/lib/host"
|
"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/components"
|
||||||
"git.staur.ca/stobbsm/clustvirt/view/layouts"
|
"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
|
// MemChart get's the memory pi chart from the host
|
||||||
templ MemChart(h *host.Host) {
|
templ MemChart(h *host.Host) {
|
||||||
<div class={ "flex" , "flex-row" }>
|
<div class={ "flex" , "flex-row" }>
|
||||||
<div class={ "size-64" }>
|
<div class={ "size-40" , "md:size-80" }>
|
||||||
@templ.Raw(h.ChartMemory())
|
<canvas id="memchart" class={ "size-40" , "md:size-80" }></canvas>
|
||||||
</div>
|
</div>
|
||||||
<ul>
|
<ul>
|
||||||
<li>Free: { bf.Format(int64(h.NodeMemory.Free*1024)) }</li>
|
<li>Free: <span id="memfree">{ fmt.Sprintf("%d Gi", h.NodeMemory.Free/1024/1024) }</span></li>
|
||||||
<li>Cached: { bf.Format(int64(h.NodeMemory.Cached*1024)) }</li>
|
<li>Cached: <span id="memcach">{ fmt.Sprintf("%d Gi", h.NodeMemory.Cached/1024/1024) }</span></li>
|
||||||
<li>Buffers: { bf.Format(int64(h.NodeMemory.Buffers*1024)) }</li>
|
<li>Buffers: <span id="membuf">{ fmt.Sprintf("%d Gi", h.NodeMemory.Buffers/1024/1024) }</span></li>
|
||||||
<li>Total: { bf.Format(int64(h.NodeMemory.Total*1024)) }</li>
|
<li>Total: <span id="memtot">{ fmt.Sprintf("%d Gi", h.NodeMemory.Total/1024/1024) }</span></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</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
|
// HostConnect is the page that allows us to select a host to get information from
|
||||||
templ HostMain(navBarItems []components.NavItem) {
|
templ HostMain(navBarItems []components.NavItem) {
|
||||||
@layouts.Manager("ClustVirt", "Cluster Manager", navBarItems) {
|
@layouts.Manager("ClustVirt", "Cluster Manager", navBarItems) {
|
||||||
<div class={ "flex" , "flex-row" , "h-full" }>
|
<div class={ "flex" , "flex-row" , "h-full" , "mt-2" }>
|
||||||
<div id="sysNavBar" class={ "w-1/6" , "border-uigrey-600" , "border" , "rounded" , "border-dotted" , "p-1" }>
|
<div id="sysNavBar" class={ "w-1/6" , "border-uigrey-600" , "border" , "rounded" , "border-dotted" , "p-2" }>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="#" hx-target="#sysContent" hx-get="/htmx/host/venus.staur.ca">venus.staur.ca</a></li>
|
<li>
|
||||||
<li><a href="#" hx-target="#sysContent" hx-get="/htmx/host/earth.staur.ca">earth.staur.ca</a></li>
|
@hostButton("venus.staur.ca")
|
||||||
<li><a href="#" hx-target="#sysContent" hx-get="/htmx/host/mars.staur.ca">mars.staur.ca</a></li>
|
</li>
|
||||||
|
<li>
|
||||||
|
@hostButton("earth.staur.ca")
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
@hostButton("mars.staur.ca")
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div id="sysContent" class={ "w-3/4" , "px-2" }>
|
<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
|
// HostInfo is meant to be an HTMX response
|
||||||
templ HostInfo(h *host.Host) {
|
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>
|
<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)
|
@MemChart(h)
|
||||||
}
|
}
|
||||||
|
@ -11,12 +11,50 @@ import "io"
|
|||||||
import "bytes"
|
import "bytes"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"git.staur.ca/stobbsm/clustvirt/lib/host"
|
"git.staur.ca/stobbsm/clustvirt/lib/host"
|
||||||
"git.staur.ca/stobbsm/clustvirt/view/components"
|
"git.staur.ca/stobbsm/clustvirt/view/components"
|
||||||
"git.staur.ca/stobbsm/clustvirt/view/layouts"
|
"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
|
// MemChart get's the memory pi chart from the host
|
||||||
func MemChart(h *host.Host) templ.Component {
|
func MemChart(h *host.Host) templ.Component {
|
||||||
return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) {
|
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 {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
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...)
|
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var3...)
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
@ -65,63 +103,184 @@ func MemChart(h *host.Host) templ.Component {
|
|||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
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 {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
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 {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
var templ_7745c5c3_Var4 string
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ.CSSClasses(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))
|
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
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 {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
var templ_7745c5c3_Var5 string
|
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 {
|
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))
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5))
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
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 {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
var templ_7745c5c3_Var6 string
|
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 {
|
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))
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6))
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
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 {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
var templ_7745c5c3_Var7 string
|
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 {
|
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))
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7))
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
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 {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
@ -141,19 +300,19 @@ func HostMain(navBarItems []components.NavItem) templ.Component {
|
|||||||
defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
|
defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||||
}
|
}
|
||||||
ctx = templ.InitializeContext(ctx)
|
ctx = templ.InitializeContext(ctx)
|
||||||
templ_7745c5c3_Var8 := templ.GetChildren(ctx)
|
templ_7745c5c3_Var14 := templ.GetChildren(ctx)
|
||||||
if templ_7745c5c3_Var8 == nil {
|
if templ_7745c5c3_Var14 == nil {
|
||||||
templ_7745c5c3_Var8 = templ.NopComponent
|
templ_7745c5c3_Var14 = templ.NopComponent
|
||||||
}
|
}
|
||||||
ctx = templ.ClearChildren(ctx)
|
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)
|
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer)
|
||||||
if !templ_7745c5c3_IsBuffer {
|
if !templ_7745c5c3_IsBuffer {
|
||||||
templ_7745c5c3_Buffer = templ.GetBuffer()
|
templ_7745c5c3_Buffer = templ.GetBuffer()
|
||||||
defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
|
defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||||
}
|
}
|
||||||
var templ_7745c5c3_Var10 = []any{"flex", "flex-row", "h-full"}
|
var templ_7745c5c3_Var16 = []any{"flex", "flex-row", "h-full", "mt-2"}
|
||||||
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var10...)
|
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var16...)
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
@ -161,7 +320,7 @@ func HostMain(navBarItems []components.NavItem) templ.Component {
|
|||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
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 {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
@ -169,8 +328,8 @@ func HostMain(navBarItems []components.NavItem) templ.Component {
|
|||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
var templ_7745c5c3_Var11 = []any{"w-1/6", "border-uigrey-600", "border", "rounded", "border-dotted", "p-1"}
|
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_Var11...)
|
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var17...)
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
@ -178,16 +337,40 @@ func HostMain(navBarItems []components.NavItem) templ.Component {
|
|||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
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 {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
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 {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
var templ_7745c5c3_Var12 = []any{"w-3/4", "px-2"}
|
templ_7745c5c3_Err = hostButton("venus.staur.ca").Render(ctx, templ_7745c5c3_Buffer)
|
||||||
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var12...)
|
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 {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
@ -195,7 +378,7 @@ func HostMain(navBarItems []components.NavItem) templ.Component {
|
|||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
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 {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
@ -208,7 +391,7 @@ func HostMain(navBarItems []components.NavItem) templ.Component {
|
|||||||
}
|
}
|
||||||
return templ_7745c5c3_Err
|
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 {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
@ -228,21 +411,59 @@ func HostInfo(h *host.Host) templ.Component {
|
|||||||
defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
|
defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||||
}
|
}
|
||||||
ctx = templ.InitializeContext(ctx)
|
ctx = templ.InitializeContext(ctx)
|
||||||
templ_7745c5c3_Var13 := templ.GetChildren(ctx)
|
templ_7745c5c3_Var19 := templ.GetChildren(ctx)
|
||||||
if templ_7745c5c3_Var13 == nil {
|
if templ_7745c5c3_Var19 == nil {
|
||||||
templ_7745c5c3_Var13 = templ.NopComponent
|
templ_7745c5c3_Var19 = templ.NopComponent
|
||||||
}
|
}
|
||||||
ctx = templ.ClearChildren(ctx)
|
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 {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
var templ_7745c5c3_Var14 string
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"")
|
||||||
templ_7745c5c3_Var14, templ_7745c5c3_Err = templ.JoinStringErrs(h.HostName)
|
|
||||||
if templ_7745c5c3_Err != nil {
|
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 {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
@ -250,6 +471,68 @@ func HostInfo(h *host.Host) templ.Component {
|
|||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
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)
|
templ_7745c5c3_Err = MemChart(h).Render(ctx, templ_7745c5c3_Buffer)
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
|
@ -24,6 +24,7 @@ templ Manager(title string, subtitle string, navBarItem []components.NavItem) {
|
|||||||
<!-- Load HTMX -->
|
<!-- Load HTMX -->
|
||||||
<script src=" https://unpkg.com/htmx.org@1.9.11" integrity="sha384-0gxUXCCR8yv9FM2b+U3FDbsKthCI66oH5IA9fHppQq9DDMHuMauqq1ZHBpJxQ0J0" crossorigin="anonymous">
|
<script src=" https://unpkg.com/htmx.org@1.9.11" integrity="sha384-0gxUXCCR8yv9FM2b+U3FDbsKthCI66oH5IA9fHppQq9DDMHuMauqq1ZHBpJxQ0J0" crossorigin="anonymous">
|
||||||
</script>
|
</script>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.2/dist/chart.umd.min.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
}
|
}
|
||||||
|
@ -134,7 +134,7 @@ func Manager(title string, subtitle string, navBarItem []components.NavItem) tem
|
|||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
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 {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user