abra/cli/app/list.go

265 lines
6.0 KiB
Go
Raw Normal View History

package app
import (
2021-10-14 10:02:12 +00:00
"fmt"
"sort"
"strings"
"coopcloud.tech/abra/cli/internal"
2021-09-05 19:37:03 +00:00
"coopcloud.tech/abra/pkg/config"
2021-12-28 00:24:23 +00:00
"coopcloud.tech/abra/pkg/formatter"
"coopcloud.tech/abra/pkg/recipe"
"coopcloud.tech/abra/pkg/ssh"
"coopcloud.tech/tagcmp"
"github.com/sirupsen/logrus"
"github.com/urfave/cli"
)
var status bool
var statusFlag = &cli.BoolFlag{
Name: "status, S",
Usage: "Show app deployment status",
Destination: &status,
}
2022-01-25 11:37:13 +00:00
var appRecipe string
var recipeFlag = &cli.StringFlag{
Name: "recipe, r",
Value: "",
2022-01-25 11:37:13 +00:00
Usage: "Show apps of a specific recipe",
Destination: &appRecipe,
}
var listAppServer string
var listAppServerFlag = &cli.StringFlag{
Name: "server, s",
Value: "",
Usage: "Show apps of a specific server",
Destination: &listAppServer,
}
type appStatus struct {
server string
recipe string
appName string
domain string
status string
version string
upgrade string
}
type serverStatus struct {
apps []appStatus
appCount int
versionCount int
unversionedCount int
latestCount int
upgradeCount int
}
var appListCommand = cli.Command{
Name: "list",
Aliases: []string{"ls"},
Usage: "List all managed apps",
Description: `
2022-05-13 14:44:49 +00:00
Read the local file system listing of apps and servers (e.g. ~/.abra/) to
generate a report of all your apps.
By passing the "--status/-S" flag, you can query all your servers for the
actual live deployment status. Depending on how many servers you manage, this
can take some time.
`,
Flags: []cli.Flag{
internal.DebugFlag,
statusFlag,
listAppServerFlag,
2022-01-25 11:37:13 +00:00
recipeFlag,
},
Before: internal.SubCommandBefore,
Action: func(c *cli.Context) error {
appFiles, err := config.LoadAppFiles(listAppServer)
if err != nil {
logrus.Fatal(err)
}
apps, err := config.GetApps(appFiles)
if err != nil {
logrus.Fatal(err)
}
2022-01-25 11:37:13 +00:00
sort.Sort(config.ByServerAndRecipe(apps))
statuses := make(map[string]map[string]string)
var catl recipe.RecipeCatalogue
if status {
alreadySeen := make(map[string]bool)
for _, app := range apps {
if _, ok := alreadySeen[app.Server]; !ok {
if err := ssh.EnsureHostKey(app.Server); err != nil {
logrus.Fatal(fmt.Sprintf(internal.SSHFailMsg, app.Server))
}
alreadySeen[app.Server] = true
2021-11-19 14:50:17 +00:00
}
}
statuses, err = config.GetAppStatuses(appFiles)
if err != nil {
logrus.Fatal(err)
}
2021-10-14 10:02:12 +00:00
var err error
catl, err = recipe.ReadRecipeCatalogue()
if err != nil {
logrus.Fatal(err)
}
2021-11-19 14:50:29 +00:00
}
var totalServersCount int
var totalAppsCount int
allStats := make(map[string]serverStatus)
for _, app := range apps {
var stats serverStatus
var ok bool
if stats, ok = allStats[app.Server]; !ok {
stats = serverStatus{}
2022-01-25 11:37:13 +00:00
if appRecipe == "" {
2022-01-02 15:21:22 +00:00
// count server, no filtering
totalServersCount++
}
}
2022-01-25 11:37:13 +00:00
if app.Recipe == appRecipe || appRecipe == "" {
if appRecipe != "" {
2022-01-02 15:21:22 +00:00
// only count server if matches filter
totalServersCount++
}
appStats := appStatus{}
stats.appCount++
totalAppsCount++
if status {
status := "unknown"
version := "unknown"
2022-01-01 16:22:19 +00:00
if statusMeta, ok := statuses[app.StackName()]; ok {
if currentVersion, exists := statusMeta["version"]; exists {
if currentVersion != "" {
version = currentVersion
}
}
if statusMeta["status"] != "" {
status = statusMeta["status"]
}
stats.versionCount++
} else {
stats.unversionedCount++
}
appStats.status = status
appStats.version = version
var newUpdates []string
if version != "unknown" {
2022-01-25 11:37:13 +00:00
updates, err := recipe.GetRecipeCatalogueVersions(app.Recipe, catl)
if err != nil {
logrus.Fatal(err)
}
parsedVersion, err := tagcmp.Parse(version)
if err != nil {
logrus.Fatal(err)
}
for _, update := range updates {
parsedUpdate, err := tagcmp.Parse(update)
if err != nil {
logrus.Fatal(err)
}
if update != version && parsedUpdate.IsGreaterThan(parsedVersion) {
newUpdates = append(newUpdates, update)
}
}
}
if len(newUpdates) == 0 {
if version == "unknown" {
appStats.upgrade = "unknown"
} else {
appStats.upgrade = "latest"
stats.latestCount++
}
} else {
newUpdates = internal.ReverseStringList(newUpdates)
appStats.upgrade = strings.Join(newUpdates, "\n")
stats.upgradeCount++
}
}
appStats.server = app.Server
2022-01-25 11:37:13 +00:00
appStats.recipe = app.Recipe
2022-01-01 16:22:19 +00:00
appStats.appName = app.Name
appStats.domain = app.Domain
stats.apps = append(stats.apps, appStats)
}
allStats[app.Server] = stats
}
alreadySeen := make(map[string]bool)
2021-12-30 00:07:21 +00:00
for _, app := range apps {
if _, ok := alreadySeen[app.Server]; ok {
continue
}
serverStat := allStats[app.Server]
2021-12-30 00:07:21 +00:00
2022-01-25 12:48:04 +00:00
tableCol := []string{"recipe", "domain"}
if status {
tableCol = append(tableCol, []string{"status", "version", "upgrade"}...)
}
2021-12-28 00:24:23 +00:00
table := formatter.CreateTable(tableCol)
for _, appStat := range serverStat.apps {
2022-01-25 12:48:04 +00:00
tableRow := []string{appStat.recipe, appStat.domain}
if status {
tableRow = append(tableRow, []string{appStat.status, appStat.version, appStat.upgrade}...)
}
table.Append(tableRow)
}
2022-01-02 15:21:22 +00:00
if table.NumLines() > 0 {
table.Render()
2022-01-02 15:21:22 +00:00
if status {
fmt.Println(fmt.Sprintf(
"server: %s | total apps: %v | versioned: %v | unversioned: %v | latest: %v | upgrade: %v",
app.Server,
serverStat.appCount,
serverStat.versionCount,
serverStat.unversionedCount,
serverStat.latestCount,
serverStat.upgradeCount,
))
} else {
fmt.Println(fmt.Sprintf("server: %s | total apps: %v", app.Server, serverStat.appCount))
}
}
2022-01-02 15:21:22 +00:00
if len(allStats) > 1 && table.NumLines() > 0 {
fmt.Println() // newline separator for multiple servers
}
alreadySeen[app.Server] = true
}
2021-10-14 10:02:12 +00:00
if len(allStats) > 1 {
fmt.Println(fmt.Sprintf("total servers: %v | total apps: %v ", totalServersCount, totalAppsCount))
}
return nil
},
}