Handle inactive VM and Docker services
This commit is contained in:
@@ -22,6 +22,12 @@ type Workload struct {
|
||||
Status string `json:"status"`
|
||||
}
|
||||
|
||||
type WorkloadDiscovery struct {
|
||||
Available bool `json:"available"`
|
||||
Message string `json:"message,omitempty"`
|
||||
Items []Workload `json:"items"`
|
||||
}
|
||||
|
||||
type Prepared struct {
|
||||
Sources []string
|
||||
Stopped []model.Source
|
||||
@@ -29,12 +35,15 @@ type Prepared struct {
|
||||
Kind model.JobType
|
||||
}
|
||||
|
||||
func (w *WorkloadManager) Discover(ctx context.Context, kind model.JobType) ([]Workload, error) {
|
||||
func (w *WorkloadManager) Discover(ctx context.Context, kind model.JobType) (WorkloadDiscovery, error) {
|
||||
switch kind {
|
||||
case model.JobDocker:
|
||||
if _, err := os.Stat("/var/run/docker.sock"); err != nil {
|
||||
return WorkloadDiscovery{Available: false, Message: "Docker is not enabled or is not running on this Unraid server.", Items: []Workload{}}, nil
|
||||
}
|
||||
output, err := exec.CommandContext(ctx, "docker", "ps", "-a", "--format", "{{json .}}").Output()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("environment: list Docker containers: %w", err)
|
||||
return WorkloadDiscovery{}, fmt.Errorf("environment: list Docker containers: %w", err)
|
||||
}
|
||||
var result []Workload
|
||||
for _, line := range strings.Split(strings.TrimSpace(string(output)), "\n") {
|
||||
@@ -47,15 +56,22 @@ func (w *WorkloadManager) Discover(ctx context.Context, kind model.JobType) ([]W
|
||||
Status string `json:"Status"`
|
||||
}
|
||||
if err := json.Unmarshal([]byte(line), &item); err != nil {
|
||||
return nil, fmt.Errorf("environment: decode Docker container list: %w", err)
|
||||
return WorkloadDiscovery{}, fmt.Errorf("environment: decode Docker container list: %w", err)
|
||||
}
|
||||
result = append(result, Workload{ID: item.Names, Name: item.Names, Status: item.Status})
|
||||
}
|
||||
return result, nil
|
||||
message := ""
|
||||
if len(result) == 0 {
|
||||
message = "Docker is active, but no containers are configured."
|
||||
}
|
||||
return WorkloadDiscovery{Available: true, Message: message, Items: result}, nil
|
||||
case model.JobVM:
|
||||
if !unraidServiceEnabled("/boot/config/domain.cfg") {
|
||||
return WorkloadDiscovery{Available: false, Message: "The Unraid VM Manager is not enabled. Enable VMs under Settings > VM Manager to select virtual machines.", Items: []Workload{}}, nil
|
||||
}
|
||||
output, err := exec.CommandContext(ctx, "virsh", "list", "--all", "--name").Output()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("environment: list virtual machines: %w", err)
|
||||
return WorkloadDiscovery{}, fmt.Errorf("environment: VM Manager is enabled but virtual machines could not be listed: %w", err)
|
||||
}
|
||||
var result []Workload
|
||||
for _, name := range strings.Split(strings.TrimSpace(string(output)), "\n") {
|
||||
@@ -66,12 +82,30 @@ func (w *WorkloadManager) Discover(ctx context.Context, kind model.JobType) ([]W
|
||||
state, _ := exec.CommandContext(ctx, "virsh", "domstate", name).Output()
|
||||
result = append(result, Workload{ID: name, Name: name, Status: strings.TrimSpace(string(state))})
|
||||
}
|
||||
return result, nil
|
||||
message := ""
|
||||
if len(result) == 0 {
|
||||
message = "The VM Manager is active, but no virtual machines are configured."
|
||||
}
|
||||
return WorkloadDiscovery{Available: true, Message: message, Items: result}, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("validation: unsupported workload type %q", kind)
|
||||
return WorkloadDiscovery{}, fmt.Errorf("validation: unsupported workload type %q", kind)
|
||||
}
|
||||
}
|
||||
|
||||
func unraidServiceEnabled(path string) bool {
|
||||
data, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
for _, line := range strings.Split(string(data), "\n") {
|
||||
parts := strings.SplitN(strings.TrimSpace(line), "=", 2)
|
||||
if len(parts) == 2 && parts[0] == "SERVICE" {
|
||||
return strings.Trim(strings.TrimSpace(parts[1]), "\"'") == "enable"
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (w *WorkloadManager) Prepare(ctx context.Context, job model.Job) (Prepared, error) {
|
||||
prepared := Prepared{Kind: job.Type}
|
||||
for _, source := range job.Sources {
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
package platform
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestUnraidServiceEnabled(t *testing.T) {
|
||||
path := filepath.Join(t.TempDir(), "domain.cfg")
|
||||
for _, test := range []struct {
|
||||
content string
|
||||
want bool
|
||||
}{
|
||||
{content: "SERVICE=\"enable\"\n", want: true},
|
||||
{content: "SERVICE=disable\n", want: false},
|
||||
{content: "OTHER=value\n", want: false},
|
||||
} {
|
||||
if err := os.WriteFile(path, []byte(test.content), 0600); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if got := unraidServiceEnabled(path); got != test.want {
|
||||
t.Fatalf("content %q: got %v, want %v", test.content, got, test.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -70,7 +70,7 @@ func (s *Service) BrowseDirectories(path string) ([]platform.DirectoryEntry, err
|
||||
return platform.BrowseDirectories(path)
|
||||
}
|
||||
|
||||
func (s *Service) DiscoverWorkloads(ctx context.Context, kind model.JobType) ([]platform.Workload, error) {
|
||||
func (s *Service) DiscoverWorkloads(ctx context.Context, kind model.JobType) (platform.WorkloadDiscovery, error) {
|
||||
return s.workloads.Discover(ctx, kind)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user