WIP: app status listing using concurrency
This being my first time using goroutines, it is pretty messy but the idea has been shown to be workable! We can concurrently look up multiple contexts for a much faster response time especially when using multiple servers. Remaining TODOs are: - [ ] Get proper status reporting (deployed/inactive/unknown) - [ ] Error handling (especially when missing contexts) - [ ] Refactor and tidy
This commit is contained in:
parent
429c7e4e50
commit
ef1591d596
24
cli/app.go
24
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)
|
||||
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)
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in New Issue