feat: support version/upgrade listing
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details

Closes coop-cloud/organising#130.
This commit is contained in:
decentral1se 2021-10-08 09:51:47 +02:00
parent 98ffc210e1
commit dde8afcd43
No known key found for this signature in database
GPG Key ID: 5E2EF5A63E3718CC
6 changed files with 89 additions and 34 deletions

View File

@ -2,8 +2,10 @@ package app
import ( import (
"sort" "sort"
"strings"
abraFormatter "coopcloud.tech/abra/cli/formatter" abraFormatter "coopcloud.tech/abra/cli/formatter"
"coopcloud.tech/abra/pkg/catalogue"
"coopcloud.tech/abra/pkg/config" "coopcloud.tech/abra/pkg/config"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
@ -65,10 +67,10 @@ can take some time.
} }
sort.Sort(config.ByServerAndType(apps)) sort.Sort(config.ByServerAndType(apps))
statuses := map[string]string{} statuses := make(map[string]map[string]string)
tableCol := []string{"Server", "Type", "Domain"} tableCol := []string{"Server", "Type", "Domain"}
if status { if status {
tableCol = append(tableCol, "Status") tableCol = append(tableCol, "Status", "Version", "Updates")
statuses, err = config.GetAppStatuses(appFiles) statuses, err = config.GetAppStatuses(appFiles)
if err != nil { if err != nil {
logrus.Fatal(err) logrus.Fatal(err)
@ -84,11 +86,38 @@ can take some time.
// 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.Server, app.Type, app.Domain} tableRow = []string{app.Server, app.Type, app.Domain}
if status { if status {
if status, ok := statuses[app.StackName()]; ok { stackName := app.StackName()
tableRow = append(tableRow, status) if app.Env["STACK_NAME"] != "" {
stackName = app.Env["STACK_NAME"]
}
var version string
if status, ok := statuses[stackName]; ok {
version = status["version"]
tableRow = append(tableRow, status["status"], version)
} else { } else {
tableRow = append(tableRow, "unknown") tableRow = append(tableRow, "unknown")
} }
var newUpdates []string
updates, err := catalogue.GetRecipeCatalogueVersions(app.Type)
if err != nil {
logrus.Fatal(err)
}
for _, update := range updates {
if update != version {
newUpdates = append(newUpdates, update)
}
}
if len(newUpdates) == 0 {
tableRow = append(tableRow, "none, on latest")
} else {
// FIXME: jeezus golang why do you not have a list reverse function
for i, j := 0, len(newUpdates)-1; i < j; i, j = i+1, j-1 {
newUpdates[i], newUpdates[j] = newUpdates[j], newUpdates[i]
}
tableRow = append(tableRow, strings.Join(newUpdates, "\n"))
}
} }
} }
table.Append(tableRow) table.Append(tableRow)

View File

@ -63,7 +63,7 @@ var appRemoveCommand = &cli.Command{
if err != nil { if err != nil {
logrus.Fatal(err) logrus.Fatal(err)
} }
if statuses[app.Name] == "deployed" { if statuses[app.Name]["status"] == "deployed" {
logrus.Fatalf("'%s' is still deployed. Run \"abra app %s undeploy\" or pass --force", app.Name, app.Name) logrus.Fatalf("'%s' is still deployed. Run \"abra app %s undeploy\" or pass --force", app.Name, app.Name)
} }
} }

View File

@ -1,6 +1,7 @@
package recipe package recipe
import ( import (
"errors"
"fmt" "fmt"
"coopcloud.tech/abra/cli/internal" "coopcloud.tech/abra/cli/internal"
@ -11,20 +12,21 @@ import (
) )
var recipeSyncCommand = &cli.Command{ var recipeSyncCommand = &cli.Command{
Name: "sync", Name: "sync",
Usage: "Ensure recipe version labels are up-to-date", Usage: "Ensure recipe version labels are up-to-date",
Aliases: []string{"s"}, Aliases: []string{"s"},
ArgsUsage: "<recipe> <version>",
Description: ` Description: `
This command will generate labels for the main recipe service (i.e. the service This command will generate labels for the main recipe service (i.e. by
named "app", by convention) which corresponds to the following format: convention, typically the service named "app") which corresponds to the
following format:
coop-cloud.${STACK_NAME}.version=${RECIPE_TAG} coop-cloud.${STACK_NAME}.version=<version>
The ${RECIPE_TAG} is determined by the recipe maintainer and is retrieved by The <version> is determined by the recipe maintainer and is specified on the
this command by asking for the list of git tags on the local git repository. command-line. The <recipe> configuration will be updated on the local file
The <recipe> configuration will be updated on the local file system. system.
`, `,
ArgsUsage: "<recipe>",
BashComplete: func(c *cli.Context) { BashComplete: func(c *cli.Context) {
catl, err := catalogue.ReadRecipeCatalogue() catl, err := catalogue.ReadRecipeCatalogue()
if err != nil { if err != nil {
@ -38,10 +40,17 @@ The <recipe> configuration will be updated on the local file system.
} }
}, },
Action: func(c *cli.Context) error { Action: func(c *cli.Context) error {
if c.Args().Len() != 2 {
internal.ShowSubcommandHelpAndError(c, errors.New("missing <recipe>/<version> arguments?"))
}
recipe := internal.ValidateRecipe(c) recipe := internal.ValidateRecipe(c)
mainService := "app" // TODO: validate with tagcmp when new commits come in
// See https://git.coopcloud.tech/coop-cloud/abra/pulls/109
nextTag := c.Args().Get(1)
mainService := "app"
var services []string var services []string
hasAppService := false hasAppService := false
for _, service := range recipe.Config.Services { for _, service := range recipe.Config.Services {
@ -67,24 +76,12 @@ The <recipe> configuration will be updated on the local file system.
logrus.Debugf("selecting '%s' as the service to sync version labels", mainService) logrus.Debugf("selecting '%s' as the service to sync version labels", mainService)
tags, err := recipe.Tags() label := fmt.Sprintf("coop-cloud.${STACK_NAME}.version=%s", nextTag)
if err != nil {
logrus.Fatal(err)
}
if len(tags) == 0 {
logrus.Fatalf("no tags detected for '%s'", recipe.Name)
}
latestTag := tags[len(tags)-1]
logrus.Infof("choosing '%s' as latest tag for recipe '%s'", latestTag, recipe.Name)
label := fmt.Sprintf("coop-cloud.${STACK_NAME}.version=%s", latestTag)
if err := recipe.UpdateLabel(mainService, label); err != nil { if err := recipe.UpdateLabel(mainService, label); err != nil {
logrus.Fatal(err) logrus.Fatal(err)
} }
logrus.Infof("added label '%s' to service '%s'", label, mainService) logrus.Infof("synced label '%s' to service '%s'", label, mainService)
return nil return nil
}, },

View File

@ -480,3 +480,23 @@ func GetRecipeVersions(recipeName string) (RecipeVersions, error) {
return versions, nil return versions, nil
} }
// GetRecipeCatalogueVersions list the recipe versions listed in the recipe catalogue.
func GetRecipeCatalogueVersions(recipeName string) ([]string, error) {
var versions []string
catl, err := ReadRecipeCatalogue()
if err != nil {
return versions, err
}
if recipeMeta, exists := catl[recipeName]; exists {
for _, versionMeta := range recipeMeta.Versions {
for tag := range versionMeta {
versions = append(versions, tag)
}
}
}
return versions, nil
}

View File

@ -124,7 +124,7 @@ func UpdateLabel(pattern, serviceName, label, recipeName string) error {
return err return err
} }
old := fmt.Sprintf("coop-cloud.${STACK_NAME}.%s.version=%s", service.Name, value) old := fmt.Sprintf("coop-cloud.${STACK_NAME}.version=%s", value)
replacedBytes := strings.Replace(string(bytes), old, label, -1) replacedBytes := strings.Replace(string(bytes), old, label, -1)
logrus.Debugf("updating '%s' to '%s' in '%s'", old, label, compose.Filename) logrus.Debugf("updating '%s' to '%s' in '%s'", old, label, compose.Filename)

View File

@ -276,8 +276,8 @@ func SanitiseAppName(name string) string {
} }
// GetAppStatuses queries servers to check the deployment status of given apps // GetAppStatuses queries servers to check the deployment status of given apps
func GetAppStatuses(appFiles AppFiles) (map[string]string, error) { func GetAppStatuses(appFiles AppFiles) (map[string]map[string]string, error) {
statuses := map[string]string{} statuses := make(map[string]map[string]string)
var unique []string var unique []string
servers := make(map[string]struct{}) servers := make(map[string]struct{})
@ -299,11 +299,20 @@ func GetAppStatuses(appFiles AppFiles) (map[string]string, error) {
for range servers { for range servers {
status := <-ch status := <-ch
result := make(map[string]string)
for _, service := range status.Services { for _, service := range status.Services {
name := service.Spec.Labels[convert.LabelNamespace] name := service.Spec.Labels[convert.LabelNamespace]
if _, ok := statuses[name]; !ok { if _, ok := statuses[name]; !ok {
statuses[name] = "deployed" result["status"] = "deployed"
} }
labelKey := fmt.Sprintf("coop-cloud.%s.version", name)
if version, ok := service.Spec.Labels[labelKey]; ok {
result["version"] = version
}
statuses[name] = result
} }
} }