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
26
cli/app.go
26
cli/app.go
|
@ -59,27 +59,35 @@ var appListCommand = &cli.Command{
|
||||||
logrus.Fatal(err)
|
logrus.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
apps, err := config.GetApps(appFiles)
|
||||||
|
sort.Sort(config.ByServerAndType(apps))
|
||||||
|
|
||||||
|
statuses := map[string]string{}
|
||||||
tableCol := []string{"Server", "Type", "Domain"}
|
tableCol := []string{"Server", "Type", "Domain"}
|
||||||
if Status {
|
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 := createTable(tableCol)
|
||||||
table.SetAutoMergeCellsByColumnIndex([]int{0})
|
table.SetAutoMergeCellsByColumnIndex([]int{0})
|
||||||
|
|
||||||
apps, err := config.GetApps(appFiles)
|
|
||||||
sort.Sort(config.ByServerAndType(apps))
|
|
||||||
for _, app := range apps {
|
for _, app := range apps {
|
||||||
var tableRow []string
|
var tableRow []string
|
||||||
if app.Type == Type || Type == "" {
|
if app.Type == Type || Type == "" {
|
||||||
// If type flag is set, check for it, if not, Type == ""
|
// If type flag is set, check for it, if not, Type == ""
|
||||||
tableRow = []string{app.File.Server, app.Type, app.Domain}
|
tableRow = []string{app.File.Server, app.Type, app.Domain}
|
||||||
}
|
if Status {
|
||||||
if Status {
|
stackName := strings.ReplaceAll(app.Name, ".", "_")
|
||||||
status, err := app.GetStatus()
|
if status, ok := statuses[stackName]; ok {
|
||||||
if err != nil {
|
tableRow = append(tableRow, status)
|
||||||
logrus.Fatal(err)
|
} else {
|
||||||
|
tableRow = append(tableRow, "unknown")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
tableRow = []string{app.File.Server, app.Type, app.Domain, status}
|
|
||||||
}
|
}
|
||||||
table.Append(tableRow)
|
table.Append(tableRow)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package config
|
package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
|
@ -10,6 +11,10 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"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/joho/godotenv"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
@ -24,10 +29,6 @@ var REPOS_BASE_URL = "https://git.coopcloud.tech/coop-cloud"
|
||||||
type AppEnv = map[string]string
|
type AppEnv = map[string]string
|
||||||
type AppName = string
|
type AppName = string
|
||||||
|
|
||||||
type AppStatus struct {
|
|
||||||
Deployed bool
|
|
||||||
}
|
|
||||||
|
|
||||||
type App struct {
|
type App struct {
|
||||||
Name AppName
|
Name AppName
|
||||||
Type string
|
Type string
|
||||||
|
@ -139,6 +140,50 @@ func GetApps(appFiles AppFiles) ([]App, error) {
|
||||||
return apps, nil
|
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
|
// TODO: maybe better names than read and get
|
||||||
|
|
||||||
func readAppFile(appFile AppFile, name AppName) (App, error) {
|
func readAppFile(appFile AppFile, name AppName) (App, error) {
|
||||||
|
|
Loading…
Reference in New Issue