2021-08-02 01:10:41 +00:00
|
|
|
package app
|
|
|
|
|
|
|
|
import (
|
2022-12-04 07:09:45 +00:00
|
|
|
"encoding/json"
|
2021-10-14 10:02:12 +00:00
|
|
|
"fmt"
|
2021-08-02 01:10:41 +00:00
|
|
|
"sort"
|
2021-10-08 07:51:47 +00:00
|
|
|
"strings"
|
2021-08-02 01:10:41 +00:00
|
|
|
|
2021-11-19 14:29:17 +00:00
|
|
|
"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"
|
2021-12-27 15:40:59 +00:00
|
|
|
"coopcloud.tech/abra/pkg/recipe"
|
2021-10-10 23:17:52 +00:00
|
|
|
"coopcloud.tech/tagcmp"
|
2021-08-02 01:10:41 +00:00
|
|
|
"github.com/sirupsen/logrus"
|
2022-01-18 13:13:20 +00:00
|
|
|
"github.com/urfave/cli"
|
2021-08-02 01:10:41 +00:00
|
|
|
)
|
|
|
|
|
2021-08-02 06:36:35 +00:00
|
|
|
var status bool
|
|
|
|
var statusFlag = &cli.BoolFlag{
|
2022-01-18 13:13:20 +00:00
|
|
|
Name: "status, S",
|
2021-08-02 06:36:35 +00:00
|
|
|
Usage: "Show app deployment status",
|
|
|
|
Destination: &status,
|
|
|
|
}
|
|
|
|
|
2023-01-22 23:54:22 +00:00
|
|
|
var recipeFilter string
|
2022-01-25 11:37:13 +00:00
|
|
|
var recipeFlag = &cli.StringFlag{
|
|
|
|
Name: "recipe, r",
|
2021-08-02 06:36:35 +00:00
|
|
|
Value: "",
|
2022-01-25 11:37:13 +00:00
|
|
|
Usage: "Show apps of a specific recipe",
|
2023-01-22 23:54:22 +00:00
|
|
|
Destination: &recipeFilter,
|
2021-08-02 06:36:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
var listAppServer string
|
|
|
|
var listAppServerFlag = &cli.StringFlag{
|
2022-01-18 13:13:20 +00:00
|
|
|
Name: "server, s",
|
2021-08-02 06:36:35 +00:00
|
|
|
Value: "",
|
|
|
|
Usage: "Show apps of a specific server",
|
|
|
|
Destination: &listAppServer,
|
|
|
|
}
|
|
|
|
|
2021-12-12 16:51:58 +00:00
|
|
|
type appStatus struct {
|
2023-03-01 11:17:23 +00:00
|
|
|
Server string `json:"server"`
|
|
|
|
Recipe string `json:"recipe"`
|
|
|
|
AppName string `json:"appName"`
|
|
|
|
Domain string `json:"domain"`
|
|
|
|
Status string `json:"status"`
|
|
|
|
Chaos string `json:"chaos"`
|
|
|
|
ChaosVersion string `json:"chaosVersion"`
|
2023-03-01 11:26:28 +00:00
|
|
|
AutoUpdate string `json:"autoUpdate"`
|
2023-03-01 11:17:23 +00:00
|
|
|
Version string `json:"version"`
|
|
|
|
Upgrade string `json:"upgrade"`
|
2021-12-12 16:51:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type serverStatus struct {
|
2022-12-04 07:09:45 +00:00
|
|
|
Apps []appStatus `json:"apps"`
|
|
|
|
AppCount int `json:"appCount"`
|
|
|
|
VersionCount int `json:"versionCount"`
|
|
|
|
UnversionedCount int `json:"unversionedCount"`
|
|
|
|
LatestCount int `json:"latestCount"`
|
|
|
|
UpgradeCount int `json:"upgradeCount"`
|
2021-12-12 16:51:58 +00:00
|
|
|
}
|
|
|
|
|
2022-01-18 13:13:20 +00:00
|
|
|
var appListCommand = cli.Command{
|
|
|
|
Name: "list",
|
|
|
|
Aliases: []string{"ls"},
|
|
|
|
Usage: "List all managed apps",
|
2021-08-02 01:10:41 +00:00
|
|
|
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.
|
2021-08-02 01:10:41 +00:00
|
|
|
|
|
|
|
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.
|
2022-03-12 09:20:37 +00:00
|
|
|
`,
|
2021-08-02 06:36:35 +00:00
|
|
|
Flags: []cli.Flag{
|
2022-01-18 13:13:20 +00:00
|
|
|
internal.DebugFlag,
|
2022-12-04 07:09:45 +00:00
|
|
|
internal.MachineReadableFlag,
|
2021-08-02 06:36:35 +00:00
|
|
|
statusFlag,
|
|
|
|
listAppServerFlag,
|
2022-01-25 11:37:13 +00:00
|
|
|
recipeFlag,
|
2021-08-02 06:36:35 +00:00
|
|
|
},
|
2022-01-18 13:13:20 +00:00
|
|
|
Before: internal.SubCommandBefore,
|
2021-08-02 01:10:41 +00:00
|
|
|
Action: func(c *cli.Context) error {
|
2021-08-02 06:36:35 +00:00
|
|
|
appFiles, err := config.LoadAppFiles(listAppServer)
|
2021-08-02 01:10:41 +00:00
|
|
|
if err != nil {
|
|
|
|
logrus.Fatal(err)
|
|
|
|
}
|
|
|
|
|
2023-01-22 23:54:22 +00:00
|
|
|
apps, err := config.GetApps(appFiles, recipeFilter)
|
2021-08-02 01:10:41 +00:00
|
|
|
if err != nil {
|
|
|
|
logrus.Fatal(err)
|
|
|
|
}
|
2021-12-12 16:51:58 +00:00
|
|
|
|
2022-01-25 11:37:13 +00:00
|
|
|
sort.Sort(config.ByServerAndRecipe(apps))
|
2021-08-02 01:10:41 +00:00
|
|
|
|
2021-12-12 16:51:58 +00:00
|
|
|
statuses := make(map[string]map[string]string)
|
2021-12-27 15:40:59 +00:00
|
|
|
var catl recipe.RecipeCatalogue
|
2021-12-12 16:51:58 +00:00
|
|
|
if status {
|
|
|
|
alreadySeen := make(map[string]bool)
|
|
|
|
for _, app := range apps {
|
|
|
|
if _, ok := alreadySeen[app.Server]; !ok {
|
|
|
|
alreadySeen[app.Server] = true
|
2021-11-19 14:50:17 +00:00
|
|
|
}
|
2021-11-09 16:43:24 +00:00
|
|
|
}
|
|
|
|
|
2023-01-22 23:54:22 +00:00
|
|
|
statuses, err = config.GetAppStatuses(apps, internal.MachineReadable)
|
2021-08-02 01:10:41 +00:00
|
|
|
if err != nil {
|
|
|
|
logrus.Fatal(err)
|
|
|
|
}
|
2021-10-14 10:02:12 +00:00
|
|
|
|
2021-12-27 15:40:59 +00:00
|
|
|
catl, err = recipe.ReadRecipeCatalogue()
|
2021-12-12 16:51:58 +00:00
|
|
|
if err != nil {
|
|
|
|
logrus.Fatal(err)
|
|
|
|
}
|
2021-11-19 14:50:29 +00:00
|
|
|
}
|
|
|
|
|
2021-12-12 16:51:58 +00:00
|
|
|
var totalServersCount int
|
|
|
|
var totalAppsCount int
|
|
|
|
allStats := make(map[string]serverStatus)
|
2021-08-02 01:10:41 +00:00
|
|
|
for _, app := range apps {
|
2021-12-12 16:51:58 +00:00
|
|
|
var stats serverStatus
|
|
|
|
var ok bool
|
|
|
|
if stats, ok = allStats[app.Server]; !ok {
|
|
|
|
stats = serverStatus{}
|
2023-01-22 23:54:22 +00:00
|
|
|
if recipeFilter == "" {
|
2022-01-02 15:21:22 +00:00
|
|
|
// count server, no filtering
|
|
|
|
totalServersCount++
|
|
|
|
}
|
2021-12-12 16:51:58 +00:00
|
|
|
}
|
|
|
|
|
2023-01-22 23:54:22 +00:00
|
|
|
if app.Recipe == recipeFilter || recipeFilter == "" {
|
|
|
|
if recipeFilter != "" {
|
2022-01-02 15:21:22 +00:00
|
|
|
// only count server if matches filter
|
|
|
|
totalServersCount++
|
|
|
|
}
|
|
|
|
|
2021-12-12 16:51:58 +00:00
|
|
|
appStats := appStatus{}
|
2022-12-04 07:09:45 +00:00
|
|
|
stats.AppCount++
|
2021-12-12 16:51:58 +00:00
|
|
|
totalAppsCount++
|
2021-11-21 12:40:23 +00:00
|
|
|
|
2021-08-02 06:36:35 +00:00
|
|
|
if status {
|
2021-10-08 08:50:48 +00:00
|
|
|
status := "unknown"
|
|
|
|
version := "unknown"
|
2023-03-01 11:17:23 +00:00
|
|
|
chaos := "unknown"
|
|
|
|
chaosVersion := "unknown"
|
2023-03-01 11:26:28 +00:00
|
|
|
autoUpdate := "unknown"
|
2022-01-01 16:22:19 +00:00
|
|
|
if statusMeta, ok := statuses[app.StackName()]; ok {
|
2021-10-08 08:50:48 +00:00
|
|
|
if currentVersion, exists := statusMeta["version"]; exists {
|
2022-01-19 11:38:41 +00:00
|
|
|
if currentVersion != "" {
|
|
|
|
version = currentVersion
|
|
|
|
}
|
2021-10-08 08:50:48 +00:00
|
|
|
}
|
2023-03-01 11:17:23 +00:00
|
|
|
if chaosDeploy, exists := statusMeta["chaos"]; exists {
|
|
|
|
chaos = chaosDeploy
|
|
|
|
}
|
|
|
|
if chaosDeployVersion, exists := statusMeta["chaosVersion"]; exists {
|
|
|
|
chaosVersion = chaosDeployVersion
|
|
|
|
}
|
2023-03-01 11:26:28 +00:00
|
|
|
if autoUpdateState, exists := statusMeta["autoUpdate"]; exists {
|
|
|
|
autoUpdate = autoUpdateState
|
|
|
|
}
|
2021-10-08 08:50:48 +00:00
|
|
|
if statusMeta["status"] != "" {
|
|
|
|
status = statusMeta["status"]
|
|
|
|
}
|
2022-12-04 07:09:45 +00:00
|
|
|
stats.VersionCount++
|
2021-08-02 01:10:41 +00:00
|
|
|
} else {
|
2022-12-04 07:09:45 +00:00
|
|
|
stats.UnversionedCount++
|
2021-08-02 01:10:41 +00:00
|
|
|
}
|
2021-10-08 07:51:47 +00:00
|
|
|
|
2022-12-04 07:09:45 +00:00
|
|
|
appStats.Status = status
|
2023-03-01 11:17:23 +00:00
|
|
|
appStats.Chaos = chaos
|
|
|
|
appStats.ChaosVersion = chaosVersion
|
2022-12-04 07:09:45 +00:00
|
|
|
appStats.Version = version
|
2023-03-01 11:26:28 +00:00
|
|
|
appStats.AutoUpdate = autoUpdate
|
2021-12-12 16:51:58 +00:00
|
|
|
|
2021-10-08 07:51:47 +00:00
|
|
|
var newUpdates []string
|
2021-10-10 23:17:52 +00:00
|
|
|
if version != "unknown" {
|
2022-01-25 11:37:13 +00:00
|
|
|
updates, err := recipe.GetRecipeCatalogueVersions(app.Recipe, catl)
|
2021-10-10 23:17:52 +00:00
|
|
|
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)
|
|
|
|
}
|
2021-10-08 08:50:48 +00:00
|
|
|
|
2021-10-10 23:17:52 +00:00
|
|
|
if update != version && parsedUpdate.IsGreaterThan(parsedVersion) {
|
|
|
|
newUpdates = append(newUpdates, update)
|
|
|
|
}
|
2021-10-08 07:51:47 +00:00
|
|
|
}
|
|
|
|
}
|
2021-10-08 08:50:48 +00:00
|
|
|
|
2021-10-08 07:51:47 +00:00
|
|
|
if len(newUpdates) == 0 {
|
2021-10-08 08:50:48 +00:00
|
|
|
if version == "unknown" {
|
2022-12-04 07:09:45 +00:00
|
|
|
appStats.Upgrade = "unknown"
|
2021-10-08 08:50:48 +00:00
|
|
|
} else {
|
2022-12-04 07:09:45 +00:00
|
|
|
appStats.Upgrade = "latest"
|
|
|
|
stats.LatestCount++
|
2021-10-08 08:50:48 +00:00
|
|
|
}
|
2021-10-08 07:51:47 +00:00
|
|
|
} else {
|
2021-12-28 01:31:06 +00:00
|
|
|
newUpdates = internal.ReverseStringList(newUpdates)
|
2022-12-04 07:09:45 +00:00
|
|
|
appStats.Upgrade = strings.Join(newUpdates, "\n")
|
|
|
|
stats.UpgradeCount++
|
2021-10-08 07:51:47 +00:00
|
|
|
}
|
2021-08-02 01:10:41 +00:00
|
|
|
}
|
2021-12-12 16:51:58 +00:00
|
|
|
|
2022-12-04 07:09:45 +00:00
|
|
|
appStats.Server = app.Server
|
|
|
|
appStats.Recipe = app.Recipe
|
|
|
|
appStats.AppName = app.Name
|
|
|
|
appStats.Domain = app.Domain
|
2021-12-12 16:51:58 +00:00
|
|
|
|
2022-12-04 07:09:45 +00:00
|
|
|
stats.Apps = append(stats.Apps, appStats)
|
2021-08-02 01:10:41 +00:00
|
|
|
}
|
2021-12-12 16:51:58 +00:00
|
|
|
allStats[app.Server] = stats
|
2021-08-02 01:10:41 +00:00
|
|
|
}
|
2023-01-31 15:09:09 +00:00
|
|
|
|
2022-12-05 00:54:20 +00:00
|
|
|
if internal.MachineReadable {
|
2022-12-04 07:09:45 +00:00
|
|
|
jsonstring, err := json.Marshal(allStats)
|
2022-12-05 00:54:20 +00:00
|
|
|
if err != nil {
|
2022-12-04 21:43:32 +00:00
|
|
|
logrus.Fatal(err)
|
2022-12-04 07:09:45 +00:00
|
|
|
} else {
|
|
|
|
fmt.Println(string(jsonstring))
|
2021-12-30 01:06:04 +00:00
|
|
|
}
|
2022-12-04 21:43:32 +00:00
|
|
|
return nil
|
|
|
|
}
|
2023-01-31 15:09:09 +00:00
|
|
|
|
2022-12-04 21:43:32 +00:00
|
|
|
alreadySeen := make(map[string]bool)
|
|
|
|
for _, app := range apps {
|
|
|
|
if _, ok := alreadySeen[app.Server]; ok {
|
|
|
|
continue
|
|
|
|
}
|
2021-12-30 01:06:04 +00:00
|
|
|
|
2022-12-04 21:43:32 +00:00
|
|
|
serverStat := allStats[app.Server]
|
2021-12-30 00:07:21 +00:00
|
|
|
|
2022-12-04 21:43:32 +00:00
|
|
|
tableCol := []string{"recipe", "domain"}
|
|
|
|
if status {
|
2023-03-01 11:26:28 +00:00
|
|
|
tableCol = append(tableCol, []string{"status", "chaos", "chaos version", "version", "upgrade", "autoupdate"}...)
|
2022-12-04 21:43:32 +00:00
|
|
|
}
|
2021-12-12 16:51:58 +00:00
|
|
|
|
2022-12-04 21:43:32 +00:00
|
|
|
table := formatter.CreateTable(tableCol)
|
2021-12-12 16:51:58 +00:00
|
|
|
|
2022-12-04 21:43:32 +00:00
|
|
|
for _, appStat := range serverStat.Apps {
|
|
|
|
tableRow := []string{appStat.Recipe, appStat.Domain}
|
|
|
|
if status {
|
2023-03-01 11:26:28 +00:00
|
|
|
tableRow = append(tableRow, []string{appStat.Status, appStat.Chaos, appStat.ChaosVersion, appStat.Version, appStat.Upgrade, appStat.AutoUpdate}...)
|
2021-12-12 16:51:58 +00:00
|
|
|
}
|
2022-12-04 21:43:32 +00:00
|
|
|
table.Append(tableRow)
|
|
|
|
}
|
2021-12-12 16:51:58 +00:00
|
|
|
|
2022-12-04 21:43:32 +00:00
|
|
|
if table.NumLines() > 0 {
|
|
|
|
table.Render()
|
2021-12-12 16:51:58 +00:00
|
|
|
|
2022-12-04 21:43:32 +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
|
|
|
}
|
2021-12-12 16:51:58 +00:00
|
|
|
}
|
2021-12-30 01:06:04 +00:00
|
|
|
|
2022-12-04 21:43:32 +00:00
|
|
|
if len(allStats) > 1 && table.NumLines() > 0 {
|
|
|
|
fmt.Println() // newline separator for multiple servers
|
2022-12-04 07:09:45 +00:00
|
|
|
}
|
2022-12-04 21:43:32 +00:00
|
|
|
|
|
|
|
alreadySeen[app.Server] = true
|
2021-12-12 16:51:58 +00:00
|
|
|
}
|
2022-12-04 21:43:32 +00:00
|
|
|
|
|
|
|
if len(allStats) > 1 {
|
|
|
|
fmt.Println(fmt.Sprintf("total servers: %v | total apps: %v ", totalServersCount, totalAppsCount))
|
|
|
|
}
|
|
|
|
|
2021-08-02 01:10:41 +00:00
|
|
|
return nil
|
|
|
|
},
|
|
|
|
}
|