diff --git a/cli/app.go b/cli/app.go index c1c9fc7b5..bae8e45b3 100644 --- a/cli/app.go +++ b/cli/app.go @@ -59,27 +59,35 @@ var appListCommand = &cli.Command{ logrus.Fatal(err) } + apps, err := config.GetApps(appFiles) + sort.Sort(config.ByServerAndType(apps)) + + statuses := map[string]string{} tableCol := []string{"Server", "Type", "Domain"} if Status { - tableCol = []string{"Server", "Type", "Domain", "Status"} + tableCol = append(tableCol, "Status") + statuses, err = config.GetAppStatuses(appFiles) + if err != nil { + logrus.Fatal(err) + } } + table := createTable(tableCol) table.SetAutoMergeCellsByColumnIndex([]int{0}) - apps, err := config.GetApps(appFiles) - sort.Sort(config.ByServerAndType(apps)) for _, app := range apps { var tableRow []string if app.Type == Type || Type == "" { // If type flag is set, check for it, if not, Type == "" tableRow = []string{app.File.Server, app.Type, app.Domain} - } - if Status { - status, err := app.GetStatus() - if err != nil { - logrus.Fatal(err) + if Status { + stackName := strings.ReplaceAll(app.Name, ".", "_") + if status, ok := statuses[stackName]; ok { + tableRow = append(tableRow, status) + } else { + tableRow = append(tableRow, "unknown") + } } - tableRow = []string{app.File.Server, app.Type, app.Domain, status} } table.Append(tableRow) } diff --git a/config/env.go b/config/env.go index 4e3dd47c0..da3fd0272 100644 --- a/config/env.go +++ b/config/env.go @@ -1,6 +1,7 @@ package config import ( + "context" "errors" "fmt" "io/fs" @@ -10,6 +11,10 @@ import ( "path/filepath" "strings" + "coopcloud.tech/abra/client" + "github.com/docker/docker/api/types" + "github.com/docker/docker/api/types/filters" + "github.com/docker/docker/api/types/swarm" "github.com/joho/godotenv" "github.com/sirupsen/logrus" ) @@ -24,10 +29,6 @@ var REPOS_BASE_URL = "https://git.coopcloud.tech/coop-cloud" type AppEnv = map[string]string type AppName = string -type AppStatus struct { - Deployed bool -} - type App struct { Name AppName Type string @@ -139,6 +140,50 @@ func GetApps(appFiles AppFiles) ([]App, error) { return apps, nil } +func GetAppStatuses(appFiles AppFiles) (map[string]string, error) { + statuses := map[string]string{} + + servers := make(map[string]struct{}) + for _, appFile := range appFiles { + if _, ok := servers[appFile.Server]; !ok { + servers[appFile.Server] = struct{}{} + } + } + + type status struct { + services []swarm.Service + err error + } + + ch := make(chan status, len(servers)) + for server, _ := range servers { + go func(s string) { + ctx := context.Background() + cl, err := client.NewClientWithContext(s) + if err != nil { + ch <- status{services: []swarm.Service{}, err: nil} + return + } + filter := filters.NewArgs() + filter.Add("label", "com.docker.stack.namespace") + services, _ := cl.ServiceList(ctx, types.ServiceListOptions{Filters: filter}) + ch <- status{services: services, err: nil} + }(server) + } + + for range servers { + status := <-ch + for _, service := range status.services { + name := service.Spec.Labels["com.docker.stack.namespace"] + if _, ok := statuses[name]; !ok { + statuses[name] = "deployed" + } + } + } + + return statuses, nil +} + // TODO: maybe better names than read and get func readAppFile(appFile AppFile, name AppName) (App, error) {