Files
edubox/agent/instance.go
T

124 lines
2.8 KiB
Go

package main
import (
"encoding/json"
"fmt"
"os"
"os/exec"
"path/filepath"
"strings"
)
type InstanceInfo struct {
ID string `json:"id"`
TemplateName string `json:"templateName,omitempty"`
Port int `json:"port"`
Status string `json:"status"`
}
func instancesFile(dataDir string) string {
return filepath.Join(dataDir, "instances.json")
}
func loadInstances(dataDir string) (map[string]*InstanceInfo, error) {
f := instancesFile(dataDir)
data, err := os.ReadFile(f)
if err != nil {
if os.IsNotExist(err) {
return make(map[string]*InstanceInfo), nil
}
return nil, err
}
var list []*InstanceInfo
if err := json.Unmarshal(data, &list); err != nil {
return nil, err
}
m := make(map[string]*InstanceInfo)
for _, inst := range list {
m[inst.ID] = inst
}
return m, nil
}
func saveInstances(dataDir string, instances map[string]*InstanceInfo) error {
if err := os.MkdirAll(dataDir, 0755); err != nil {
return err
}
list := make([]*InstanceInfo, 0, len(instances))
for _, inst := range instances {
list = append(list, inst)
}
data, err := json.MarshalIndent(list, "", " ")
if err != nil {
return err
}
return os.WriteFile(instancesFile(dataDir), data, 0644)
}
func upsertInstance(dataDir string, inst *InstanceInfo) error {
instances, err := loadInstances(dataDir)
if err != nil {
return err
}
instances[inst.ID] = inst
return saveInstances(dataDir, instances)
}
func removeInstance(dataDir, instanceID string) error {
instances, err := loadInstances(dataDir)
if err != nil {
return err
}
delete(instances, instanceID)
return saveInstances(dataDir, instances)
}
func instanceURL(inst *InstanceInfo) string {
return fmt.Sprintf("http://localhost:%d", inst.Port)
}
func getInstanceStatus(dataDir, instanceID string) string {
dir := instanceDir(dataDir, instanceID)
composeFile := filepath.Join(dir, "docker-compose.yml")
if _, err := os.Stat(composeFile); err != nil {
return "stopped"
}
engine := getContainerEngine()
cmd := exec.Command(engine, "compose", "-f", composeFile, "ps", "--format", "json")
out, err := cmd.Output()
if err != nil {
return "error"
}
outStr := strings.TrimSpace(string(out))
if outStr == "" || outStr == "[]" {
return "stopped"
}
// Docker compose JSON output can be a single object or an array
if strings.HasPrefix(outStr, "[") {
var containers []map[string]interface{}
if err := json.Unmarshal(out, &containers); err != nil {
return "error"
}
for _, c := range containers {
state, _ := c["State"].(string)
if state == "running" {
return "running"
}
}
return "stopped"
}
var c map[string]interface{}
if err := json.Unmarshal(out, &c); err != nil {
return "error"
}
state, _ := c["State"].(string)
if state == "running" {
return "running"
}
return "stopped"
}