feat: debug logging

Closes coop-cloud/organising#164.
This commit is contained in:
2021-09-11 00:54:02 +02:00
parent 27d665c3be
commit 9fcdc45851
38 changed files with 305 additions and 95 deletions

View File

@ -66,13 +66,10 @@ var appBackupCommand = &cli.Command{
sourceAndExec := fmt.Sprintf("%s; %s", sourceCmd, execCmd)
cmd := exec.Command("bash", "-c", sourceAndExec)
output, err := cmd.Output()
if err != nil {
if err := internal.RunCmd(cmd); err != nil {
logrus.Fatal(err)
}
fmt.Print(string(output))
return nil
},
BashComplete: func(c *cli.Context) {

View File

@ -45,7 +45,7 @@ var appCheckCommand = &cli.Command{
logrus.Fatalf("%s is missing %s", app.Path, missingEnvVars)
}
logrus.Info("All necessary environment variables defined")
logrus.Infof("all necessary environment variables defined for '%s'", app.Name)
return nil
},

View File

@ -6,6 +6,7 @@ import (
"os"
"strings"
"coopcloud.tech/abra/cli/formatter"
"coopcloud.tech/abra/cli/internal"
"coopcloud.tech/abra/pkg/client"
"coopcloud.tech/abra/pkg/config"
@ -55,11 +56,13 @@ var appCpCommand = &cli.Command{
service = parsedSrc[0]
srcPath = parsedSrc[1]
dstPath = dst
logrus.Debugf("assuming transfer is coming FROM the container")
} else if len(parsedDst) == 2 {
service = parsedDst[0]
dstPath = parsedDst[1]
srcPath = src
isToContainer = true // <src> <container:dst>
logrus.Debugf("assuming transfer is going TO the container")
}
appFiles, err := config.LoadAppFiles("")
@ -90,6 +93,8 @@ var appCpCommand = &cli.Command{
}
container := containers[0]
logrus.Debugf("retrieved '%s' as target container on '%s'", formatter.ShortenID(container.ID), app.Server)
if isToContainer {
if _, err := os.Stat(srcPath); err != nil {
logrus.Fatalf("'%s' does not exist?", srcPath)

View File

@ -73,8 +73,10 @@ var appLogsCommand = &cli.Command{
serviceName := c.Args().Get(1)
if serviceName == "" {
logrus.Debug("tailing logs for all app services")
stackLogs(app.StackName(), cl)
}
logrus.Debugf("tailing logs for '%s'", serviceName)
service := fmt.Sprintf("%s_%s", app.StackName(), serviceName)
filters := filters.NewArgs()

View File

@ -197,6 +197,7 @@ func action(c *cli.Context) error {
if len(sanitisedAppName) > 45 {
logrus.Fatalf("'%s' cannot be longer than 45 characters", sanitisedAppName)
}
logrus.Debugf("'%s' sanitised as '%s' for new app", newAppName, sanitisedAppName)
if err := config.CopyAppEnvSample(recipe.Name, newAppName, newAppServer); err != nil {
logrus.Fatal(err)

View File

@ -37,7 +37,7 @@ var appPsCommand = &cli.Command{
logrus.Fatal(err)
}
tableCol := []string{"ID", "Image", "Command", "Created", "Status", "Ports", "Names"}
tableCol := []string{"id", "image", "command", "created", "status", "ports", "names"}
table := abraFormatter.CreateTable(tableCol)
for _, container := range containers {
@ -48,7 +48,7 @@ var appPsCommand = &cli.Command{
abraFormatter.HumanDuration(container.Created),
container.Status,
formatter.DisplayablePorts(container.Ports),
strings.Join(container.Names, ","),
strings.Join(container.Names, ", "),
}
table.Append(tableRow)
}

View File

@ -39,13 +39,13 @@ var appRemoveCommand = &cli.Command{
if !internal.Force {
response := false
prompt := &survey.Confirm{
Message: fmt.Sprintf("About to delete %s, are you sure", app.Name),
Message: fmt.Sprintf("about to delete %s, are you sure?", app.Name),
}
if err := survey.AskOne(prompt, &response); err != nil {
logrus.Fatal(err)
}
if !response {
logrus.Fatal("User aborted app removal")
logrus.Fatal("user aborted app removal")
}
}
@ -89,7 +89,7 @@ var appRemoveCommand = &cli.Command{
var secretNamesToRemove []string
if !internal.Force {
secretsPrompt := &survey.MultiSelect{
Message: "Which secrets do you want to remove?",
Message: "which secrets do you want to remove?",
Options: secretNames,
Default: secretNames,
}
@ -103,10 +103,10 @@ var appRemoveCommand = &cli.Command{
if err != nil {
logrus.Fatal(err)
}
logrus.Info(fmt.Sprintf("Secret: %s removed", name))
logrus.Info(fmt.Sprintf("secret: %s removed", name))
}
} else {
logrus.Info("No secrets to remove")
logrus.Info("no secrets to remove")
}
volumeListOKBody, err := cl.VolumeList(ctx, fs)
@ -125,7 +125,7 @@ var appRemoveCommand = &cli.Command{
var removeVols []string
if !internal.Force {
volumesPrompt := &survey.MultiSelect{
Message: "Which volumes do you want to remove?",
Message: "which volumes do you want to remove?",
Options: vols,
Default: vols,
}
@ -138,20 +138,20 @@ var appRemoveCommand = &cli.Command{
if err != nil {
logrus.Fatal(err)
}
logrus.Info(fmt.Sprintf("Volume %s removed", vol))
logrus.Info(fmt.Sprintf("volume %s removed", vol))
}
} else {
logrus.Info("No volumes were removed")
logrus.Info("no volumes were removed")
}
} else {
logrus.Info("No volumes to remove")
logrus.Info("no volumes to remove")
}
err = os.Remove(app.Path)
if err != nil {
logrus.Fatal(err)
}
logrus.Info(fmt.Sprintf("File: %s removed", app.Path))
logrus.Info(fmt.Sprintf("file: %s removed", app.Path))
return nil
},

View File

@ -70,13 +70,10 @@ var appRestoreCommand = &cli.Command{
sourceAndExec := fmt.Sprintf("%s; %s", sourceCmd, execCmd)
cmd := exec.Command("bash", "-c", sourceAndExec)
output, err := cmd.Output()
if err != nil {
if err := internal.RunCmd(cmd); err != nil {
logrus.Fatal(err)
}
fmt.Print(string(output))
return nil
},
}

View File

@ -75,6 +75,8 @@ var appRollbackCommand = &cli.Command{
// display table of existing state and expected state and prompt
// run the deployment with this target version!
logrus.Fatal("command not implemented yet, coming soon TM")
return nil
},
}

View File

@ -83,13 +83,13 @@ var appSecretGenerateCommand = &cli.Command{
os.Exit(1)
}
tableCol := []string{"Name", "Value"}
tableCol := []string{"name", "value"}
table := abraFormatter.CreateTable(tableCol)
for name, val := range secretVals {
table.Append([]string{name, val})
}
table.Render()
logrus.Warn("these secrets are not shown again, please take note of them *now*")
logrus.Warn("generated secrets are not shown again, please take note of them *now*")
return nil
},

View File

@ -25,6 +25,7 @@ func getImagePath(image string) (string, error) {
if strings.Contains(path, "library") {
path = strings.Split(path, "/")[1]
}
logrus.Debugf("parsed '%s' from '%s'", path, image)
return path, nil
}
@ -53,7 +54,7 @@ var appVersionCommand = &cli.Command{
}(app.Server, label)
}
tableCol := []string{"Name", "Image", "Version", "Digest"}
tableCol := []string{"name", "image", "version", "digest"}
table := abraFormatter.CreateTable(tableCol)
statuses := make(map[string]stack.StackStatus)

View File

@ -15,7 +15,7 @@ import (
var appVolumeListCommand = &cli.Command{
Name: "list",
Usage: "list volumes associated with an app",
Usage: "List volumes associated with an app",
Aliases: []string{"ls"},
Action: func(c *cli.Context) error {
app := internal.ValidateApp(c)
@ -26,7 +26,7 @@ var appVolumeListCommand = &cli.Command{
logrus.Fatal(err)
}
table := abraFormatter.CreateTable([]string{"DRIVER", "VOLUME NAME"})
table := abraFormatter.CreateTable([]string{"driver", "volume name"})
var volTable [][]string
for _, volume := range volumeList {
volRow := []string{
@ -45,7 +45,7 @@ var appVolumeListCommand = &cli.Command{
var appVolumeRemoveCommand = &cli.Command{
Name: "remove",
Usage: "remove volume(s) associated with an app",
Usage: "Remove volume(s) associated with an app",
Aliases: []string{"rm"},
Flags: []cli.Flag{
internal.ForceFlag,
@ -63,7 +63,7 @@ var appVolumeRemoveCommand = &cli.Command{
var volumesToRemove []string
if !internal.Force {
volumesPrompt := &survey.MultiSelect{
Message: "Which volumes do you want to remove?",
Message: "which volumes do you want to remove?",
Options: volumeNames,
Default: volumeNames,
}
@ -79,7 +79,7 @@ var appVolumeRemoveCommand = &cli.Command{
logrus.Fatal(err)
}
logrus.Info("Volumes removed successfully.")
logrus.Info("volumes removed successfully")
return nil
},

View File

@ -68,8 +68,18 @@ func RunApp(version, commit string) {
},
},
}
app.EnableBashCompletion = true
app.Before = func(c *cli.Context) error {
if Debug {
logrus.SetLevel(logrus.DebugLevel)
}
return nil
}
logrus.Debugf("Flying abra version '%s', commit '%s', enjoy the ride", version, commit)
if err := app.Run(os.Args); err != nil {
logrus.Fatal(err)
}

View File

@ -31,6 +31,7 @@ func HumanDuration(timestamp int64) string {
return units.HumanDuration(now.Sub(date)) + " ago"
}
// CreateTable prepares a table layout for output.
func CreateTable(columns []string) *tablewriter.Table {
table := tablewriter.NewWriter(os.Stdout)
table.SetHeader(columns)

View File

@ -6,6 +6,7 @@ import (
"os/exec"
)
// RunCmd runs a shell command and streams stdout/stderr in real-time.
func RunCmd(cmd *exec.Cmd) error {
r, err := cmd.StdoutPipe()
if err != nil {

View File

@ -23,6 +23,8 @@ func ValidateRecipe(c *cli.Context) recipe.Recipe {
logrus.Fatal(err)
}
logrus.Debugf("validated '%s' as recipe argument", recipeName)
return recipe
}
@ -39,6 +41,8 @@ func ValidateApp(c *cli.Context) config.App {
logrus.Fatal(err)
}
logrus.Debugf("validated '%s' as app argument", appName)
return app
}
@ -50,5 +54,7 @@ func ValidateDomain(c *cli.Context) string {
ShowSubcommandHelpAndError(c, errors.New("no domain provided"))
}
logrus.Debugf("validated '%s' as domain argument", domainName)
return domainName
}

View File

@ -77,16 +77,16 @@ var recipeLintCommand = &cli.Command{
}
}
tableCol := []string{"Rule", "Satisfied"}
tableCol := []string{"rule", "satisfied"}
table := formatter.CreateTable(tableCol)
table.Append([]string{"Compose files have the expected version", strconv.FormatBool(expectedVersion)})
table.Append([]string{"Environment configuration is provided", strconv.FormatBool(envSampleProvided)})
table.Append([]string{"Recipe contains a service named 'app'", strconv.FormatBool(serviceNamedApp)})
table.Append([]string{"Traefik routing enabled on at least one service", strconv.FormatBool(traefikEnabled)})
table.Append([]string{"All services have a healthcheck enabled", strconv.FormatBool(healthChecksForAllServices)})
table.Append([]string{"All images are using a tag", strconv.FormatBool(allImagesTagged)})
table.Append([]string{"No usage of unstable 'latest' tags", strconv.FormatBool(noUnstableTags)})
table.Append([]string{"All tags are using a semver-like format", strconv.FormatBool(semverLikeTags)})
table.Append([]string{"compose files have the expected version", strconv.FormatBool(expectedVersion)})
table.Append([]string{"environment configuration is provided", strconv.FormatBool(envSampleProvided)})
table.Append([]string{"recipe contains a service named 'app'", strconv.FormatBool(serviceNamedApp)})
table.Append([]string{"traefik routing enabled on at least one service", strconv.FormatBool(traefikEnabled)})
table.Append([]string{"all services have a healthcheck enabled", strconv.FormatBool(healthChecksForAllServices)})
table.Append([]string{"all images are using a tag", strconv.FormatBool(allImagesTagged)})
table.Append([]string{"no usage of unstable 'latest' tags", strconv.FormatBool(noUnstableTags)})
table.Append([]string{"all tags are using a semver-like format", strconv.FormatBool(semverLikeTags)})
table.Render()
return nil

View File

@ -23,7 +23,7 @@ var recipeListCommand = &cli.Command{
recipes := catl.Flatten()
sort.Sort(catalogue.ByRecipeName(recipes))
tableCol := []string{"Name", "Category", "Status"}
tableCol := []string{"name", "category", "status"}
table := formatter.CreateTable(tableCol)
for _, recipe := range recipes {

View File

@ -8,7 +8,7 @@ import (
"coopcloud.tech/abra/cli/internal"
"coopcloud.tech/abra/pkg/config"
"github.com/go-git/go-git/v5"
"coopcloud.tech/abra/pkg/git"
"github.com/sirupsen/logrus"
"github.com/urfave/cli/v2"
)
@ -28,10 +28,8 @@ var recipeNewCommand = &cli.Command{
}
url := fmt.Sprintf("%s/example.git", config.REPOS_BASE_URL)
_, err := git.PlainClone(directory, false, &git.CloneOptions{URL: url, Tags: git.AllTags})
if err != nil {
logrus.Fatal(err)
return nil
if err := git.Clone(directory, url); err != nil {
return err
}
gitRepo := path.Join(config.APPS_DIR, recipe.Name, ".git")
@ -39,6 +37,7 @@ var recipeNewCommand = &cli.Command{
logrus.Fatal(err)
return nil
}
logrus.Debugf("removed git repo in '%s'", gitRepo)
toParse := []string{
path.Join(config.APPS_DIR, recipe.Name, "README.md"),
@ -71,7 +70,7 @@ var recipeNewCommand = &cli.Command{
}
logrus.Infof(
"New recipe '%s' created in %s, happy hacking!\n",
"new recipe '%s' created in %s, happy hacking!\n",
recipe.Name, path.Join(config.APPS_DIR, recipe.Name),
)

View File

@ -36,7 +36,7 @@ the versioning metadata of up-and-running containers are.
}
if !hasAppService {
logrus.Fatal(fmt.Sprintf("No 'app' service defined in '%s', cannot proceed", recipe.Name))
logrus.Fatal(fmt.Sprintf("no 'app' service defined in '%s'", recipe.Name))
}
for _, service := range recipe.Config.Services {
@ -44,17 +44,20 @@ the versioning metadata of up-and-running containers are.
if err != nil {
logrus.Fatal(err)
}
logrus.Debugf("detected image '%s' for service '%s'", img, service.Name)
digest, err := client.GetTagDigest(img)
if err != nil {
logrus.Fatal(err)
}
logrus.Debugf("retrieved digest '%s' for '%s'", digest, img)
tag := img.(reference.NamedTagged).Tag()
label := fmt.Sprintf("coop-cloud.${STACK_NAME}.%s.version=%s-%s", service.Name, tag, digest)
if err := recipe.UpdateLabel(service.Name, label); err != nil {
logrus.Fatal(err)
}
logrus.Debugf("added label '%s' to service '%s'", label, service.Name)
}
return nil

View File

@ -40,6 +40,7 @@ This is step 1 of upgrading a recipe. Step 2 is running "abra recipe sync
if err != nil {
logrus.Fatal(err)
}
logrus.Debugf("read '%s' from the recipe catalogue for '%s'", catlVersions, service.Name)
img, err := reference.ParseNormalizedNamed(service.Image)
if err != nil {
@ -51,6 +52,7 @@ This is step 1 of upgrading a recipe. Step 2 is running "abra recipe sync
if err != nil {
logrus.Fatal(err)
}
logrus.Debugf("retrieved '%s' from remote registry for '%s'", regVersions, image)
if strings.Contains(image, "library") {
// ParseNormalizedNamed prepends 'library' to images like nginx:<tag>,
@ -61,6 +63,7 @@ This is step 1 of upgrading a recipe. Step 2 is running "abra recipe sync
semverLikeTag := true
if !tagcmp.IsParsable(img.(reference.NamedTagged).Tag()) {
logrus.Debugf("'%s' not considered semver-like", img.(reference.NamedTagged).Tag())
semverLikeTag = false
}
@ -68,6 +71,7 @@ This is step 1 of upgrading a recipe. Step 2 is running "abra recipe sync
if err != nil && semverLikeTag {
logrus.Fatal(err)
}
logrus.Debugf("parsed '%s' for '%s'", tag, service.Name)
var compatible []tagcmp.Tag
for _, regVersion := range regVersions {
@ -81,10 +85,12 @@ This is step 1 of upgrading a recipe. Step 2 is running "abra recipe sync
}
}
logrus.Debugf("detected potential upgradable tags '%s' for '%s'", compatible, service.Name)
sort.Sort(tagcmp.ByTagDesc(compatible))
if len(compatible) == 0 && semverLikeTag {
logrus.Info(fmt.Sprintf("No new versions available for '%s', '%s' is the latest", image, tag))
logrus.Info(fmt.Sprintf("no new versions available for '%s', '%s' is the latest", image, tag))
continue // skip on to the next tag and don't update any compose files
}
@ -101,11 +107,13 @@ This is step 1 of upgrading a recipe. Step 2 is running "abra recipe sync
}
}
msg := fmt.Sprintf("Which tag would you like to upgrade to? (service: %s, tag: %s)", service.Name, tag)
logrus.Debugf("detected compatible upgradable tags '%s' for '%s'", compatibleStrings, service.Name)
msg := fmt.Sprintf("upgrade to which tag? (service: %s, tag: %s)", service.Name, tag)
if !tagcmp.IsParsable(img.(reference.NamedTagged).Tag()) {
tag := img.(reference.NamedTagged).Tag()
logrus.Warning(fmt.Sprintf("Unable to determine versioning semantics of '%s', listing all tags...", tag))
msg = fmt.Sprintf("Which tag would you like to upgrade to? (service: %s, tag: %s)", service.Name, tag)
logrus.Warning(fmt.Sprintf("unable to determine versioning semantics of '%s', listing all tags", tag))
msg = fmt.Sprintf("upgrade to which tag? (service: %s, tag: %s)", service.Name, tag)
compatibleStrings = []string{}
for _, regVersion := range regVersions {
compatibleStrings = append(compatibleStrings, regVersion.Name)
@ -124,6 +132,7 @@ This is step 1 of upgrading a recipe. Step 2 is running "abra recipe sync
if err := recipe.UpdateTag(image, upgradeTag); err != nil {
logrus.Fatal(err)
}
logrus.Debugf("tag updated from '%s' to '%s' for '%s'", image, upgradeTag, recipe.Name)
}
return nil

View File

@ -62,10 +62,12 @@ All communication between Abra and the server will use this SSH connection.
for _, context := range contexts {
if context.Name == domainName {
logrus.Fatalf("Server at '%s' already exists?", domainName)
logrus.Fatalf("server at '%s' already exists?", domainName)
}
}
logrus.Debugf("creating context with domain '%s', username '%s' and port '%s'", domainName, username, port)
if err := client.CreateContext(domainName, username, port); err != nil {
logrus.Fatal(err)
}
@ -77,11 +79,12 @@ All communication between Abra and the server will use this SSH connection.
}
if _, err := cl.Info(ctx); err != nil {
logrus.Fatalf("Unable to make a connection to '%s'?", domainName)
logrus.Fatalf("unable to make a connection to '%s'?", domainName)
logrus.Debug(err)
}
logrus.Infof("Server at '%s' has been added", domainName)
logrus.Debugf("remote connection to '%s' is definitely up", domainName)
logrus.Infof("server at '%s' has been added", domainName)
return nil
},

View File

@ -21,7 +21,7 @@ var serverInitCommand = &cli.Command{
HideHelp: true,
ArgsUsage: "<domain>",
Description: `
Initialise swarm mode on the target <server>.
Initialise swarm mode on the target <domain>.
This initialisation explicitly chooses the "single host swarm" mode which uses
the default IPv4 address as the advertising address. This can be re-configured
@ -45,6 +45,7 @@ later for more advanced use cases.
return d.DialContext(ctx, "udp", "95.216.24.230:53")
},
}
logrus.Debugf("created DNS resolver via 95.216.24.230")
ctx := context.Background()
ips, err := resolver.LookupIPAddr(ctx, domainName)
@ -64,11 +65,13 @@ later for more advanced use cases.
if _, err := cl.SwarmInit(ctx, initReq); err != nil {
return err
}
logrus.Debugf("initialised swarm on '%s'", domainName)
netOpts := types.NetworkCreate{Driver: "overlay", Scope: "swarm"}
if _, err := cl.NetworkCreate(ctx, "proxy", netOpts); err != nil {
return err
}
logrus.Debug("swarm overlay network 'proxy' created")
return nil
},

View File

@ -22,6 +22,7 @@ var serverListCommand = &cli.Command{
if err != nil {
logrus.Fatal(err)
}
tableColumns := []string{"Name", "Connection"}
table := formatter.CreateTable(tableColumns)
defer table.Render()
@ -30,8 +31,8 @@ var serverListCommand = &cli.Command{
if err != nil {
logrus.Fatal(err)
}
for _, serverName := range serverNames {
for _, serverName := range serverNames {
var row []string
for _, ctx := range contexts {
endpoint, err := client.GetContextEndpoint(ctx)
@ -47,9 +48,8 @@ var serverListCommand = &cli.Command{
row = []string{serverName, "UNKNOWN"}
}
table.Append(row)
}
return nil
return nil
},
}

View File

@ -79,12 +79,14 @@ environment variable or otherwise passing the "--env/-e" flag.
}
if hetznerCloudAPIToken == "" {
logrus.Fatal("Hetzner Cloud API token is missing, cannot continue")
logrus.Fatal("Hetzner Cloud API token is missing")
}
ctx := context.Background()
client := hcloud.NewClient(hcloud.WithToken(hetznerCloudAPIToken))
logrus.Debugf("successfully created hetzner cloud API client")
var sshKeys []*hcloud.SSHKey
for _, sshKey := range c.StringSlice("ssh-keys") {
sshKey, _, err := client.SSHKey.GetByName(ctx, sshKey)
@ -106,13 +108,17 @@ environment variable or otherwise passing the "--env/-e" flag.
logrus.Fatal(err)
}
logrus.Debugf("new server '%s' created", name)
tableColumns := []string{"Name", "IPv4", "Root Password"}
table := formatter.CreateTable(tableColumns)
if len(sshKeys) > 0 {
table.Append([]string{name, res.Server.PublicNet.IPv4.IP.String(), "N/A (using SSH keys)"})
} else {
table.Append([]string{name, res.Server.PublicNet.IPv4.IP.String(), res.RootPassword})
}
table.Render()
return nil
@ -182,13 +188,14 @@ environment variable or otherwise passing the "--env/-e" flag.
}
if capsulAPIToken == "" {
logrus.Fatal("Capsul API token is missing, cannot continue")
logrus.Fatal("Capsul API token is missing")
}
// yep, the response time is quite slow, something to fix Capsul side
// yep, the response time is quite slow, something to fix on the Capsul side
client := &http.Client{Timeout: 20 * time.Second}
capsulCreateURL := fmt.Sprintf("https://%s/api/capsul/create", capsulInstance)
logrus.Debugf("using '%s' as capsul create url", capsulCreateURL)
values := map[string]string{
"name": name,
"size": capsulType,
@ -230,6 +237,7 @@ environment variable or otherwise passing the "--env/-e" flag.
if err := json.NewDecoder(res.Body).Decode(&resp); err != nil {
logrus.Fatal(err)
}
logrus.Debugf("capsul created with ID: '%s'", resp.ID)
tableColumns := []string{"Name", "ID"}
table := formatter.CreateTable(tableColumns)

View File

@ -23,7 +23,7 @@ internal bookkeeping so that it is not managed any more.
logrus.Fatal(err)
}
logrus.Infof("Server at '%s' has been forgotten", domainName)
logrus.Infof("server at '%s' has been forgotten", domainName)
return nil
},

View File

@ -14,6 +14,7 @@ var UpgradeCommand = &cli.Command{
Usage: "Upgrade abra",
Action: func(c *cli.Context) error {
cmd := exec.Command("bash", "-c", "curl -s https://install.abra.coopcloud.tech | bash")
logrus.Debugf("attempting to run '%s'", cmd)
if err := internal.RunCmd(cmd); err != nil {
logrus.Fatal(err)
}