forked from phc/cluster-dashboard
feat: added basic scaffolding for host executor
parent
98038e1451
commit
965467d129
@ -1,16 +1,15 @@
|
|||||||
package executor
|
package executor
|
||||||
|
|
||||||
import "time"
|
|
||||||
|
|
||||||
// Service is a service that handles executing commands on the main host and does a first processing of the raw data it gets from the system
|
// Service is a service that handles executing commands on the main host and does a first processing of the raw data it gets from the system
|
||||||
type Service interface {
|
type Service interface {
|
||||||
SlurmQueue() []string
|
SlurmQueue() ([]string, error)
|
||||||
SlurmJobs() []string
|
SlurmJobs() ([]string, error)
|
||||||
|
|
||||||
NodeUptime(hostname string) time.Time
|
NodeUptime(hostname string) (string, error)
|
||||||
|
|
||||||
Temperature(hostname string) float64
|
Temperature(hostname string) (string, error)
|
||||||
MemoryUsage(hostname string) int64
|
MemoryUsage(hostname string) (string, error)
|
||||||
StorageUsage(hostname string) int64
|
StorageUsage(hostname string) (string, error)
|
||||||
NetworkUploadDownload(hostname string) (int64, int64)
|
NetworkUpload(hostname string) (string, error)
|
||||||
|
NetworkDownload(hostname string) (string, error)
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,72 @@
|
|||||||
|
package executor
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"os/exec"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type HostRunner struct{}
|
||||||
|
|
||||||
|
func (HostRunner) SlurmQueue() ([]string, error) {
|
||||||
|
panic("todo")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (HostRunner) SlurmJobs() ([]string, error) {
|
||||||
|
panic("todo")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (HostRunner) NodeUptime(hostname string) (string, error) {
|
||||||
|
panic("todo")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (HostRunner) Temperature(hostname string) (string, error) {
|
||||||
|
panic("todo")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (HostRunner) MemoryUsage(hostname string) (string, error) {
|
||||||
|
panic("todo")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (HostRunner) StorageUsage(hostname string) (string, error) {
|
||||||
|
panic("todo")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (HostRunner) NetworkUpload(hostname string) (string, error) {
|
||||||
|
panic("todo")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (HostRunner) NetworkDownload(hostname string) (string, error) {
|
||||||
|
panic("todo")
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Internals
|
||||||
|
//
|
||||||
|
|
||||||
|
// run a shell command and returns its output as string
|
||||||
|
func run(command string) (string, error) {
|
||||||
|
buf := &bytes.Buffer{}
|
||||||
|
|
||||||
|
// ctx := context.Background()
|
||||||
|
// ctx, cancel := context.WithTimeout(ctx, 1*time.Second)
|
||||||
|
// defer cancel()
|
||||||
|
// cmd := exec.CommandContext(ctx, "sh", "-c", command)
|
||||||
|
|
||||||
|
cmd := exec.Command("sh", "-c", command)
|
||||||
|
cmd.Stdout = buf
|
||||||
|
|
||||||
|
// BUG: Al momento se questo comando ci mette troppo tutto si blocca, quindi sarebbe meglio
|
||||||
|
// usare un context per dare un timeout al comando
|
||||||
|
if err := cmd.Run(); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return buf.String(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// run a shell command on a given remote via ssh and returns its output as string, does a bit of escaping
|
||||||
|
func runOnRemote(destination, command string) (string, error) {
|
||||||
|
return run(fmt.Sprintf(`ssh %s '%s'`, destination, strings.ReplaceAll(command, `'`, `\'`)))
|
||||||
|
}
|
@ -1,43 +1,46 @@
|
|||||||
package executor
|
package executor
|
||||||
|
|
||||||
import "time"
|
|
||||||
|
|
||||||
var _ Service = &Mock{}
|
var _ Service = &Mock{}
|
||||||
|
|
||||||
type Mock struct {
|
type Mock struct {
|
||||||
SlurmQueueFunc func() []string
|
SlurmQueueFunc func() ([]string, error)
|
||||||
SlurmJobsFunc func() []string
|
SlurmJobsFunc func() ([]string, error)
|
||||||
NodeUptimeFunc func(hostname string) time.Time
|
NodeUptimeFunc func(hostname string) (string, error)
|
||||||
TemperatureFunc func(hostname string) float64
|
TemperatureFunc func(hostname string) (string, error)
|
||||||
MemoryUsageFunc func(hostname string) int64
|
MemoryUsageFunc func(hostname string) (string, error)
|
||||||
StorageUsageFunc func(hostname string) int64
|
StorageUsageFunc func(hostname string) (string, error)
|
||||||
NetworkUploadDownloadFunc func(hostname string) (int64, int64)
|
NetworkUploadFunc func(hostname string) (string, error)
|
||||||
|
NetworkDownloadFunc func(hostname string) (string, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m Mock) SlurmQueue() ([]string, error) {
|
||||||
|
return m.SlurmQueueFunc()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ex *Mock) SlurmQueue() []string {
|
func (m Mock) SlurmJobs() ([]string, error) {
|
||||||
return ex.SlurmQueueFunc()
|
return m.SlurmJobsFunc()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ex *Mock) SlurmJobs() []string {
|
func (m Mock) NodeUptime(hostname string) (string, error) {
|
||||||
return ex.SlurmJobsFunc()
|
return m.NodeUptimeFunc(hostname)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ex *Mock) NodeUptime(hostname string) time.Time {
|
func (m Mock) Temperature(hostname string) (string, error) {
|
||||||
return ex.NodeUptimeFunc(hostname)
|
return m.TemperatureFunc(hostname)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ex *Mock) Temperature(hostname string) float64 {
|
func (m Mock) MemoryUsage(hostname string) (string, error) {
|
||||||
return ex.TemperatureFunc(hostname)
|
return m.MemoryUsageFunc(hostname)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ex *Mock) MemoryUsage(hostname string) int64 {
|
func (m Mock) StorageUsage(hostname string) (string, error) {
|
||||||
return ex.MemoryUsageFunc(hostname)
|
return m.StorageUsageFunc(hostname)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ex *Mock) StorageUsage(hostname string) int64 {
|
func (m Mock) NetworkUpload(hostname string) (string, error) {
|
||||||
return ex.StorageUsageFunc(hostname)
|
return m.NetworkUploadFunc(hostname)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ex *Mock) NetworkUploadDownload(hostname string) (int64, int64) {
|
func (m Mock) NetworkDownload(hostname string) (string, error) {
|
||||||
return ex.NetworkUploadDownloadFunc(hostname)
|
return m.NetworkDownloadFunc(hostname)
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,139 @@
|
|||||||
package routes
|
package routes
|
||||||
|
|
||||||
import "github.com/gofiber/fiber/v2"
|
import (
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/gofiber/fiber/v2"
|
||||||
|
)
|
||||||
|
|
||||||
func (r *Router) Api(api fiber.Router) {
|
func (r *Router) Api(api fiber.Router) {
|
||||||
api.Get("/status", func(c *fiber.Ctx) error {
|
api.Get("/status", func(c *fiber.Ctx) error {
|
||||||
return c.JSON("ok")
|
return c.JSON("ok")
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// GetNodeStatus
|
||||||
|
api.Get("/node/:hostname", func(c *fiber.Ctx) error {
|
||||||
|
hostname := c.Params("hostname")
|
||||||
|
if hostname == "" {
|
||||||
|
return fmt.Errorf(`must provide hostname`)
|
||||||
|
}
|
||||||
|
|
||||||
|
node, err := r.Database.GetNode(hostname)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.JSON(node)
|
||||||
|
})
|
||||||
|
|
||||||
|
// GetJobStatus
|
||||||
|
api.Get("/job/:id", func(c *fiber.Ctx) error {
|
||||||
|
id := c.Params("id")
|
||||||
|
if id == "" {
|
||||||
|
return fmt.Errorf(`must provide id`)
|
||||||
|
}
|
||||||
|
|
||||||
|
job, err := r.Database.GetJob(id)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.JSON(job)
|
||||||
|
})
|
||||||
|
|
||||||
|
// AllNodes
|
||||||
|
api.Get("/nodes", func(c *fiber.Ctx) error {
|
||||||
|
nodes, err := r.Database.AllNodes()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.JSON(nodes)
|
||||||
|
})
|
||||||
|
|
||||||
|
// AllJobs
|
||||||
|
api.Get("/jobs", func(c *fiber.Ctx) error {
|
||||||
|
jobs, err := r.Database.AllJobs()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.JSON(jobs)
|
||||||
|
})
|
||||||
|
|
||||||
|
// QueryTemperatureSamples
|
||||||
|
api.Get("/stats/temperature", QueryTimeRangeMiddleware(func(c *fiber.Ctx, from, to time.Time) error {
|
||||||
|
samples, err := r.Database.QueryTemperatureSamples(from, to)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.JSON(samples)
|
||||||
|
}))
|
||||||
|
|
||||||
|
// QueryMemorySamples
|
||||||
|
api.Get("/stats/memory", QueryTimeRangeMiddleware(func(c *fiber.Ctx, from, to time.Time) error {
|
||||||
|
samples, err := r.Database.QueryMemorySamples(from, to)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.JSON(samples)
|
||||||
|
}))
|
||||||
|
|
||||||
|
// QueryStorageSamples
|
||||||
|
api.Get("/stats/storage", QueryTimeRangeMiddleware(func(c *fiber.Ctx, from, to time.Time) error {
|
||||||
|
samples, err := r.Database.QueryStorageSamples(from, to)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.JSON(samples)
|
||||||
|
}))
|
||||||
|
|
||||||
|
// QueryNetworkUploadSamples
|
||||||
|
api.Get("/stats/network-upload", QueryTimeRangeMiddleware(func(c *fiber.Ctx, from, to time.Time) error {
|
||||||
|
samples, err := r.Database.QueryNetworkUploadSamples(from, to)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.JSON(samples)
|
||||||
|
}))
|
||||||
|
|
||||||
|
// QueryNetworkDownloadSamples
|
||||||
|
api.Get("/stats/network-download", QueryTimeRangeMiddleware(func(c *fiber.Ctx, from, to time.Time) error {
|
||||||
|
samples, err := r.Database.QueryNetworkDownloadSamples(from, to)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.JSON(samples)
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
func QueryTimeRangeMiddleware(queryHandler func(c *fiber.Ctx, from, to time.Time) error) func(c *fiber.Ctx) error {
|
||||||
|
return func(c *fiber.Ctx) error {
|
||||||
|
// by default just show 1 day of data
|
||||||
|
from, err := parseTimeParam(c.Query("from"), time.Now().Add(-24*time.Hour))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
to, err := parseTimeParam(c.Query("to"), time.Now())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return queryHandler(c, from, to)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseTimeParam(s string, defaultValue time.Time) (time.Time, error) {
|
||||||
|
if s == "" {
|
||||||
|
return defaultValue, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return time.Parse(time.RFC3339, s)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue