package app import ( "context" "errors" "fmt" "strconv" abraFormatter "coopcloud.tech/abra/cli/formatter" "coopcloud.tech/abra/cli/internal" "coopcloud.tech/abra/pkg/client" "coopcloud.tech/abra/pkg/secret" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/filters" "github.com/sirupsen/logrus" "github.com/urfave/cli/v2" ) var allSecrets bool var allSecretsFlag = &cli.BoolFlag{ Name: "all", Value: false, Destination: &allSecrets, Usage: "Generate all secrets", } var appSecretGenerateCommand = &cli.Command{ Name: "generate", Aliases: []string{"g"}, Usage: "Generate secrets", ArgsUsage: " ", Flags: []cli.Flag{allSecretsFlag, internal.PassFlag}, Action: func(c *cli.Context) error { app := internal.ValidateApp(c) if c.Args().Get(1) != "" && allSecrets { internal.ShowSubcommandHelpAndError(c, errors.New("cannot use ' ' and '--all' together")) } secretsToCreate := make(map[string]string) secretEnvVars := secret.ReadSecretEnvVars(app.Env) if allSecrets { secretsToCreate = secretEnvVars } else { secretName := c.Args().Get(1) secretVersion := c.Args().Get(2) for sec := range secretEnvVars { parsed := secret.ParseSecretEnvVarName(sec) if secretName == parsed { secretsToCreate[sec] = secretVersion } } } secretVals, err := secret.GenerateSecrets(secretsToCreate, app.StackName(), app.Server) if err != nil { logrus.Fatal(err) } if internal.Pass { for name, data := range secretVals { if err := secret.PassInsertSecret(data, name, app.StackName(), app.Server); err != nil { logrus.Fatal(err) } } } tableCol := []string{"Name", "Value"} table := abraFormatter.CreateTable(tableCol) for name, val := range secretVals { table.Append([]string{name, val}) } table.Render() logrus.Warn("Warning, these secrets will not be shown again, please take note of them *now*") return nil }, } var appSecretInsertCommand = &cli.Command{ Name: "insert", Aliases: []string{"i"}, Usage: "Insert secret", Flags: []cli.Flag{internal.PassFlag}, ArgsUsage: " ", Action: func(c *cli.Context) error { app := internal.ValidateApp(c) if c.Args().Len() != 4 { internal.ShowSubcommandHelpAndError(c, errors.New("missing arguments?")) } name := c.Args().Get(1) version := c.Args().Get(2) data := c.Args().Get(3) secretName := fmt.Sprintf("%s_%s_%s", app.StackName(), name, version) if err := client.StoreSecret(secretName, data, app.Server); err != nil { logrus.Fatal(err) } if internal.Pass { if err := secret.PassInsertSecret(data, name, app.StackName(), app.Server); err != nil { logrus.Fatal(err) } } return nil }, } var appSecretRmCommand = &cli.Command{ Name: "remove", Usage: "Remove a secret", Aliases: []string{"rm"}, Flags: []cli.Flag{allSecretsFlag, internal.PassFlag}, ArgsUsage: "", Action: func(c *cli.Context) error { app := internal.ValidateApp(c) if c.Args().Get(1) != "" && allSecrets { internal.ShowSubcommandHelpAndError(c, errors.New("cannot use '' and '--all' together")) } if c.Args().Get(1) == "" && !allSecrets { internal.ShowSubcommandHelpAndError(c, errors.New("no secret(s) specified?")) } ctx := context.Background() cl, err := client.New(app.Server) if err != nil { logrus.Fatal(err) } filters := filters.NewArgs() filters.Add("name", app.StackName()) secretList, err := cl.SecretList(ctx, types.SecretListOptions{Filters: filters}) if err != nil { logrus.Fatal(err) } secretToRm := c.Args().Get(1) for _, cont := range secretList { secretName := cont.Spec.Annotations.Name parsed := secret.ParseGeneratedSecretName(secretName, app) if allSecrets { if err := cl.SecretRemove(ctx, secretName); err != nil { logrus.Fatal(err) } if internal.Pass { if err := secret.PassRmSecret(parsed, app.StackName(), app.Server); err != nil { logrus.Fatal(err) } } } else { if parsed == secretToRm { if err := cl.SecretRemove(ctx, secretName); err != nil { logrus.Fatal(err) } if internal.Pass { if err := secret.PassRmSecret(parsed, app.StackName(), app.Server); err != nil { logrus.Fatal(err) } } } } } return nil }, } var appSecretLsCommand = &cli.Command{ Name: "list", Usage: "List all secrets", Aliases: []string{"ls"}, Action: func(c *cli.Context) error { app := internal.ValidateApp(c) secrets := secret.ReadSecretEnvVars(app.Env) tableCol := []string{"Name", "Version", "Generated Name", "Created On Server"} table := abraFormatter.CreateTable(tableCol) ctx := context.Background() cl, err := client.New(app.Server) if err != nil { logrus.Fatal(err) } filters := filters.NewArgs() filters.Add("name", app.StackName()) secretList, err := cl.SecretList(ctx, types.SecretListOptions{Filters: filters}) if err != nil { logrus.Fatal(err) } remoteSecretNames := make(map[string]bool) for _, cont := range secretList { remoteSecretNames[cont.Spec.Annotations.Name] = true } for sec := range secrets { createdRemote := false secretName := secret.ParseSecretEnvVarName(sec) secVal, err := secret.ParseSecretEnvVarValue(secrets[sec]) if err != nil { logrus.Fatal(err) } secretRemoteName := fmt.Sprintf("%s_%s_%s", app.StackName(), secretName, secVal.Version) if _, ok := remoteSecretNames[secretRemoteName]; ok { createdRemote = true } tableRow := []string{secretName, secVal.Version, secretRemoteName, strconv.FormatBool(createdRemote)} table.Append(tableRow) } table.Render() return nil }, } var appSecretCommand = &cli.Command{ Name: "secret", Aliases: []string{"s"}, Usage: "Manage app secrets", ArgsUsage: "", Subcommands: []*cli.Command{ appSecretGenerateCommand, appSecretInsertCommand, appSecretRmCommand, appSecretLsCommand, }, }