From c14210e2aa56e7216017e2bee35bf8df759ef073 Mon Sep 17 00:00:00 2001 From: Calvin Leung Huang Date: Thu, 1 Feb 2018 12:47:46 -0500 Subject: [PATCH 01/31] Use Colored UI if stdout is a tty --- command/commands.go | 38 +++++++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/command/commands.go b/command/commands.go index d276239ac1fa..7a9973927920 100644 --- a/command/commands.go +++ b/command/commands.go @@ -11,6 +11,7 @@ import ( "github.com/hashicorp/vault/physical" "github.com/hashicorp/vault/version" "github.com/mitchellh/cli" + "golang.org/x/crypto/ssh/terminal" "github.com/hashicorp/vault/builtin/logical/aws" "github.com/hashicorp/vault/builtin/logical/cassandra" @@ -101,21 +102,32 @@ var Commands map[string]cli.CommandFactory var DeprecatedCommands map[string]cli.CommandFactory func init() { - ui := &cli.ColoredUi{ - ErrorColor: cli.UiColorRed, - WarnColor: cli.UiColorYellow, - Ui: &cli.BasicUi{ - Writer: os.Stdout, - ErrorWriter: os.Stderr, - }, + var ui cli.Ui + var serverCmdUi cli.Ui + + ui = &cli.BasicUi{ + Writer: os.Stdout, + ErrorWriter: os.Stderr, } - serverCmdUi := &cli.ColoredUi{ - ErrorColor: cli.UiColorRed, - WarnColor: cli.UiColorYellow, - Ui: &cli.BasicUi{ - Writer: os.Stdout, - }, + serverCmdUi = &cli.BasicUi{ + Writer: os.Stdout, + } + + // Attempt to detect if stdout is a tty. If so, + // Wrap BasicUi's in ColoredUi. + if terminal.IsTerminal(int(os.Stdout.Fd())) { + ui = &cli.ColoredUi{ + ErrorColor: cli.UiColorRed, + WarnColor: cli.UiColorYellow, + Ui: ui, + } + + serverCmdUi = &cli.ColoredUi{ + ErrorColor: cli.UiColorRed, + WarnColor: cli.UiColorYellow, + Ui: serverCmdUi, + } } loginHandlers := map[string]LoginHandler{ From 58be12259738c5dc425d3c29a084016b8c4de6b2 Mon Sep 17 00:00:00 2001 From: Calvin Leung Huang Date: Thu, 1 Feb 2018 12:48:29 -0500 Subject: [PATCH 02/31] Add format options to operator unseal --- command/operator_unseal.go | 37 +++++++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/command/operator_unseal.go b/command/operator_unseal.go index e2957647d1e9..b7d2c29a7bd7 100644 --- a/command/operator_unseal.go +++ b/command/operator_unseal.go @@ -1,11 +1,14 @@ package command import ( + "encoding/json" "fmt" "io" "os" "strings" + "github.com/ghodss/yaml" + "github.com/hashicorp/vault/api" "github.com/hashicorp/vault/helper/password" "github.com/mitchellh/cli" "github.com/posener/complete" @@ -50,7 +53,7 @@ Usage: vault operator unseal [options] [KEY] } func (c *OperatorUnsealCommand) Flags() *FlagSets { - set := c.flagSet(FlagSetHTTP) + set := c.flagSet(FlagSetHTTP | FlagSetOutputFormat) f := set.NewFlagSet("Command Options") @@ -141,5 +144,35 @@ func (c *OperatorUnsealCommand) Run(args []string) int { return 2 } - return OutputSealStatus(c.UI, client, status) + switch c.flagFormat { + case "yaml": + return c.unsealOutputYAML(status) + case "json": + return c.unsealOutputJSON(status) + case "table": + return OutputSealStatus(c.UI, client, status) + default: + c.UI.Error(fmt.Sprintf("Unknown format: %s", c.flagFormat)) + return 1 + } +} + +// unsealOutputYAML outputs the init output as YAML. +func (c *OperatorUnsealCommand) unsealOutputYAML(resp *api.SealStatusResponse) int { + b, err := yaml.Marshal(resp) + if err != nil { + c.UI.Error(fmt.Sprintf("Error marshaling YAML: %s", err)) + return 2 + } + return PrintRaw(c.UI, strings.TrimSpace(string(b))) +} + +// unsealOutputJSON outputs the init output as JSON. +func (c *OperatorUnsealCommand) unsealOutputJSON(resp *api.SealStatusResponse) int { + b, err := json.Marshal(resp) + if err != nil { + c.UI.Error(fmt.Sprintf("Error marshaling JSON: %s", err)) + return 2 + } + return PrintRaw(c.UI, strings.TrimSpace(string(b))) } From a1fcb87751a38aa918748c33d3571d9ddcae7ffe Mon Sep 17 00:00:00 2001 From: Calvin Leung Huang Date: Thu, 1 Feb 2018 14:16:25 -0500 Subject: [PATCH 03/31] Add format test on operator unseal --- command/operator_unseal.go | 2 +- command/operator_unseal_test.go | 30 ++++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/command/operator_unseal.go b/command/operator_unseal.go index b7d2c29a7bd7..90e337c20eb3 100644 --- a/command/operator_unseal.go +++ b/command/operator_unseal.go @@ -145,7 +145,7 @@ func (c *OperatorUnsealCommand) Run(args []string) int { } switch c.flagFormat { - case "yaml": + case "yaml", "yml": return c.unsealOutputYAML(status) case "json": return c.unsealOutputJSON(status) diff --git a/command/operator_unseal_test.go b/command/operator_unseal_test.go index e2222fc73b2d..bcc8397e6dc2 100644 --- a/command/operator_unseal_test.go +++ b/command/operator_unseal_test.go @@ -1,6 +1,7 @@ package command import ( + "encoding/json" "io/ioutil" "strings" "testing" @@ -137,4 +138,33 @@ func TestOperatorUnsealCommand_Run(t *testing.T) { _, cmd := testOperatorUnsealCommand(t) assertNoTabs(t, cmd) }) + + t.Run("format", func(t *testing.T) { + t.Parallel() + + client, keys, closer := testVaultServerUnseal(t) + defer closer() + + // Seal so we can unseal + if err := client.Sys().Seal(); err != nil { + t.Fatal(err) + } + + ui, cmd := testOperatorUnsealCommand(t) + cmd.client = client + cmd.testOutput = ioutil.Discard + + // Unseal with one key + code := cmd.Run([]string{ + "-format", "json", + keys[0], + }) + if exp := 0; code != exp { + t.Errorf("expected %d to be %d: %s", code, exp, ui.ErrorWriter.String()) + } + + if !json.Valid(ui.OutputWriter.Bytes()) { + t.Error("expected output to be valid JSON") + } + }) } From e149184b301195b0a38832daac649db12e1763b6 Mon Sep 17 00:00:00 2001 From: Calvin Leung Huang Date: Thu, 1 Feb 2018 15:59:00 -0500 Subject: [PATCH 04/31] Add -no-color output flag, and use BasicUi if no-color flag is provided --- command/audit_disable.go | 4 ++++ command/audit_enable.go | 4 ++++ command/audit_list.go | 4 ++++ command/auth_disable.go | 4 ++++ command/auth_enable.go | 4 ++++ command/auth_help.go | 4 ++++ command/auth_list.go | 4 ++++ command/auth_tune.go | 4 ++++ command/base.go | 23 ++++++++++++++++++++--- command/commands.go | 2 +- command/delete.go | 4 ++++ command/lease_renew.go | 4 ++++ command/lease_revoke.go | 4 ++++ command/list.go | 4 ++++ command/login.go | 4 ++++ command/operator_generate_root.go | 4 ++++ command/operator_init.go | 4 ++++ command/operator_key_status.go | 4 ++++ command/operator_rekey.go | 4 ++++ command/operator_seal.go | 4 ++++ command/operator_step_down.go | 4 ++++ command/operator_unseal.go | 4 ++++ command/path_help.go | 4 ++++ command/policies_deprecated.go | 5 +++++ command/policy_delete.go | 4 ++++ command/policy_fmt.go | 4 ++++ command/policy_list.go | 4 ++++ command/policy_read.go | 4 ++++ command/policy_write.go | 4 ++++ command/read.go | 4 ++++ command/rotate.go | 4 ++++ command/secrets_disable.go | 4 ++++ command/secrets_enable.go | 4 ++++ command/secrets_list.go | 4 ++++ command/secrets_move.go | 4 ++++ command/secrets_tune.go | 4 ++++ command/server.go | 4 ++++ command/ssh.go | 4 ++++ command/status.go | 4 ++++ command/token_capabilities.go | 4 ++++ command/token_create.go | 4 ++++ command/token_lookup.go | 4 ++++ command/token_renew.go | 4 ++++ command/token_revoke.go | 4 ++++ command/unwrap.go | 4 ++++ command/util.go | 13 +++++++++++++ command/write.go | 4 ++++ 47 files changed, 211 insertions(+), 4 deletions(-) diff --git a/command/audit_disable.go b/command/audit_disable.go index 1025a0ba2726..8746e595b975 100644 --- a/command/audit_disable.go +++ b/command/audit_disable.go @@ -58,6 +58,10 @@ func (c *AuditDisableCommand) Run(args []string) int { return 1 } + if c.flagNoColor { + c.UI = getBasicUI(c.UI) + } + args = f.Args() switch { case len(args) < 1: diff --git a/command/audit_enable.go b/command/audit_enable.go index 85b3bac9aa57..5c0b2090db9f 100644 --- a/command/audit_enable.go +++ b/command/audit_enable.go @@ -106,6 +106,10 @@ func (c *AuditEnableCommand) Run(args []string) int { return 1 } + if c.flagNoColor { + c.UI = getBasicUI(c.UI) + } + args = f.Args() if len(args) < 1 { c.UI.Error("Missing TYPE!") diff --git a/command/audit_list.go b/command/audit_list.go index 0012426e416b..f01a8e301a32 100644 --- a/command/audit_list.go +++ b/command/audit_list.go @@ -76,6 +76,10 @@ func (c *AuditListCommand) Run(args []string) int { return 1 } + if c.flagNoColor { + c.UI = getBasicUI(c.UI) + } + args = f.Args() if len(args) > 0 { c.UI.Error(fmt.Sprintf("Too many arguments (expected 0, got %d)", len(args))) diff --git a/command/auth_disable.go b/command/auth_disable.go index afcfe747df20..f96989b75cf3 100644 --- a/command/auth_disable.go +++ b/command/auth_disable.go @@ -59,6 +59,10 @@ func (c *AuthDisableCommand) Run(args []string) int { return 1 } + if c.flagNoColor { + c.UI = getBasicUI(c.UI) + } + args = f.Args() switch { case len(args) < 1: diff --git a/command/auth_enable.go b/command/auth_enable.go index 1cc8dbc1a7df..6bc4a036f043 100644 --- a/command/auth_enable.go +++ b/command/auth_enable.go @@ -117,6 +117,10 @@ func (c *AuthEnableCommand) Run(args []string) int { return 1 } + if c.flagNoColor { + c.UI = getBasicUI(c.UI) + } + args = f.Args() switch { case len(args) < 1: diff --git a/command/auth_help.go b/command/auth_help.go index d18d1bf0951a..bb45b2078822 100644 --- a/command/auth_help.go +++ b/command/auth_help.go @@ -73,6 +73,10 @@ func (c *AuthHelpCommand) Run(args []string) int { return 1 } + if c.flagNoColor { + c.UI = getBasicUI(c.UI) + } + args = f.Args() switch { case len(args) < 1: diff --git a/command/auth_list.go b/command/auth_list.go index ff56b8e02242..0cc1c604cbff 100644 --- a/command/auth_list.go +++ b/command/auth_list.go @@ -77,6 +77,10 @@ func (c *AuthListCommand) Run(args []string) int { return 1 } + if c.flagNoColor { + c.UI = getBasicUI(c.UI) + } + args = f.Args() if len(args) > 0 { c.UI.Error(fmt.Sprintf("Too many arguments (expected 0, got %d)", len(args))) diff --git a/command/auth_tune.go b/command/auth_tune.go index 958d11bd1fb9..4959bf311d63 100644 --- a/command/auth_tune.go +++ b/command/auth_tune.go @@ -87,6 +87,10 @@ func (c *AuthTuneCommand) Run(args []string) int { return 1 } + if c.flagNoColor { + c.UI = getBasicUI(c.UI) + } + args = f.Args() switch { case len(args) < 1: diff --git a/command/base.go b/command/base.go index 7dcca7671b5a..3d54bd5bda39 100644 --- a/command/base.go +++ b/command/base.go @@ -40,8 +40,9 @@ type BaseCommand struct { flagTLSSkipVerify bool flagWrapTTL time.Duration - flagFormat string - flagField string + flagFormat string + flagField string + flagNoColor bool tokenHelper token.TokenHelper @@ -143,6 +144,7 @@ const ( FlagSetHTTP FlagSetOutputField FlagSetOutputFormat + FlagSetOutputNoColor ) // flagSet creates the flags for this command. The result is cached on the @@ -151,6 +153,11 @@ func (c *BaseCommand) flagSet(bit FlagSetBit) *FlagSets { c.flagsOnce.Do(func() { set := NewFlagSets(c.UI) + // These flag sets will apply to all leaf subcommands. + // TODO: Optional, but FlagSetHTTP can be safely removed from the individual + // Flags() subcommands. + bit = bit | FlagSetHTTP | FlagSetOutputNoColor + if bit&FlagSetHTTP != 0 { f := set.NewFlagSet("HTTP Options") @@ -238,7 +245,7 @@ func (c *BaseCommand) flagSet(bit FlagSetBit) *FlagSets { }) } - if bit&(FlagSetOutputField|FlagSetOutputFormat) != 0 { + if bit&(FlagSetOutputField|FlagSetOutputFormat|FlagSetOutputNoColor) != 0 { f := set.NewFlagSet("Output Options") if bit&FlagSetOutputField != 0 { @@ -265,6 +272,16 @@ func (c *BaseCommand) flagSet(bit FlagSetBit) *FlagSets { "are \"table\", \"json\", or \"yaml\".", }) } + + if bit&FlagSetOutputNoColor != 0 { + f.BoolVar(&BoolVar{ + Name: "no-color", + Target: &c.flagNoColor, + Default: false, + EnvVar: "VAULT_OUTPUT_NO_COLOR", + Usage: "Print the output without ANSI color escape sequences.", + }) + } } c.flags = set diff --git a/command/commands.go b/command/commands.go index 7a9973927920..a696a98adc7f 100644 --- a/command/commands.go +++ b/command/commands.go @@ -115,7 +115,7 @@ func init() { } // Attempt to detect if stdout is a tty. If so, - // Wrap BasicUi's in ColoredUi. + // wrap BasicUi's in ColoredUi. if terminal.IsTerminal(int(os.Stdout.Fd())) { ui = &cli.ColoredUi{ ErrorColor: cli.UiColorRed, diff --git a/command/delete.go b/command/delete.go index 12c7f9611795..5ec724a9c7a0 100644 --- a/command/delete.go +++ b/command/delete.go @@ -66,6 +66,10 @@ func (c *DeleteCommand) Run(args []string) int { return 1 } + if c.flagNoColor { + c.UI = getBasicUI(c.UI) + } + args = f.Args() switch { case len(args) < 1: diff --git a/command/lease_renew.go b/command/lease_renew.go index 4dd2e1c573c0..b93b6a8ba286 100644 --- a/command/lease_renew.go +++ b/command/lease_renew.go @@ -81,6 +81,10 @@ func (c *LeaseRenewCommand) Run(args []string) int { return 1 } + if c.flagNoColor { + c.UI = getBasicUI(c.UI) + } + leaseID := "" increment := c.flagIncrement diff --git a/command/lease_revoke.go b/command/lease_revoke.go index 45f5dc3a766a..620ccfa019f6 100644 --- a/command/lease_revoke.go +++ b/command/lease_revoke.go @@ -91,6 +91,10 @@ func (c *LeaseRevokeCommand) Run(args []string) int { return 1 } + if c.flagNoColor { + c.UI = getBasicUI(c.UI) + } + args = f.Args() switch { case len(args) < 1: diff --git a/command/list.go b/command/list.go index ecfa0acb5646..31e80af3f664 100644 --- a/command/list.go +++ b/command/list.go @@ -59,6 +59,10 @@ func (c *ListCommand) Run(args []string) int { return 1 } + if c.flagNoColor { + c.UI = getBasicUI(c.UI) + } + args = f.Args() switch { case len(args) < 1: diff --git a/command/login.go b/command/login.go index 564b893bb899..2ec0bf262849 100644 --- a/command/login.go +++ b/command/login.go @@ -152,6 +152,10 @@ func (c *LoginCommand) Run(args []string) int { return 1 } + if c.flagNoColor { + c.UI = getBasicUI(c.UI) + } + args = f.Args() // Deprecations diff --git a/command/operator_generate_root.go b/command/operator_generate_root.go index 1329343b7ce4..588eb53352fd 100644 --- a/command/operator_generate_root.go +++ b/command/operator_generate_root.go @@ -206,6 +206,10 @@ func (c *OperatorGenerateRootCommand) Run(args []string) int { return 1 } + if c.flagNoColor { + c.UI = getBasicUI(c.UI) + } + args = f.Args() if len(args) > 1 { c.UI.Error(fmt.Sprintf("Too many arguments (expected 0-1, got %d)", len(args))) diff --git a/command/operator_init.go b/command/operator_init.go index 1002fa70bea2..fac83768af2e 100644 --- a/command/operator_init.go +++ b/command/operator_init.go @@ -243,6 +243,10 @@ func (c *OperatorInitCommand) Run(args []string) int { return 1 } + if c.flagNoColor { + c.UI = getBasicUI(c.UI) + } + // Deprecations // TODO: remove in 0.9.0 if c.flagAuto { diff --git a/command/operator_key_status.go b/command/operator_key_status.go index 6558290ca74c..1de1acec8457 100644 --- a/command/operator_key_status.go +++ b/command/operator_key_status.go @@ -51,6 +51,10 @@ func (c *OperatorKeyStatusCommand) Run(args []string) int { return 1 } + if c.flagNoColor { + c.UI = getBasicUI(c.UI) + } + args = f.Args() if len(args) > 0 { c.UI.Error(fmt.Sprintf("Too many arguments (expected 0, got %d)", len(args))) diff --git a/command/operator_rekey.go b/command/operator_rekey.go index dd713f157f33..9956dacf2fb0 100644 --- a/command/operator_rekey.go +++ b/command/operator_rekey.go @@ -250,6 +250,10 @@ func (c *OperatorRekeyCommand) Run(args []string) int { return 1 } + if c.flagNoColor { + c.UI = getBasicUI(c.UI) + } + args = f.Args() if len(args) > 1 { c.UI.Error(fmt.Sprintf("Too many arguments (expected 0-1, got %d)", len(args))) diff --git a/command/operator_seal.go b/command/operator_seal.go index b5fe3b8eb796..7313f13c496a 100644 --- a/command/operator_seal.go +++ b/command/operator_seal.go @@ -62,6 +62,10 @@ func (c *OperatorSealCommand) Run(args []string) int { return 1 } + if c.flagNoColor { + c.UI = getBasicUI(c.UI) + } + args = f.Args() if len(args) > 0 { c.UI.Error(fmt.Sprintf("Too many arguments (expected 0, got %d)", len(args))) diff --git a/command/operator_step_down.go b/command/operator_step_down.go index 63208faf042d..6dd2432f2d68 100644 --- a/command/operator_step_down.go +++ b/command/operator_step_down.go @@ -58,6 +58,10 @@ func (c *OperatorStepDownCommand) Run(args []string) int { return 1 } + if c.flagNoColor { + c.UI = getBasicUI(c.UI) + } + args = f.Args() if len(args) > 0 { c.UI.Error(fmt.Sprintf("Too many arguments (expected 0, got %d)", len(args))) diff --git a/command/operator_unseal.go b/command/operator_unseal.go index 90e337c20eb3..9ef89f26f345 100644 --- a/command/operator_unseal.go +++ b/command/operator_unseal.go @@ -86,6 +86,10 @@ func (c *OperatorUnsealCommand) Run(args []string) int { return 1 } + if c.flagNoColor { + c.UI = getBasicUI(c.UI) + } + unsealKey := "" args = f.Args() diff --git a/command/path_help.go b/command/path_help.go index 2ce4a38bfd42..2e2a099189df 100644 --- a/command/path_help.go +++ b/command/path_help.go @@ -69,6 +69,10 @@ func (c *PathHelpCommand) Run(args []string) int { return 1 } + if c.flagNoColor { + c.UI = getBasicUI(c.UI) + } + args = f.Args() switch { case len(args) < 1: diff --git a/command/policies_deprecated.go b/command/policies_deprecated.go index b7b5f5cf17a1..3f57572dd6f8 100644 --- a/command/policies_deprecated.go +++ b/command/policies_deprecated.go @@ -29,6 +29,11 @@ func (c *PoliciesDeprecatedCommand) Run(args []string) int { c.UI.Error(err.Error()) return 1 } + + if c.flagNoColor { + c.UI = getBasicUI(c.UI) + } + args = f.Args() // Got an arg, this is trying to read a policy diff --git a/command/policy_delete.go b/command/policy_delete.go index e74030640f69..808b458de80c 100644 --- a/command/policy_delete.go +++ b/command/policy_delete.go @@ -58,6 +58,10 @@ func (c *PolicyDeleteCommand) Run(args []string) int { return 1 } + if c.flagNoColor { + c.UI = getBasicUI(c.UI) + } + args = f.Args() switch { case len(args) < 1: diff --git a/command/policy_fmt.go b/command/policy_fmt.go index 01bde16e60b5..c12e9e904293 100644 --- a/command/policy_fmt.go +++ b/command/policy_fmt.go @@ -60,6 +60,10 @@ func (c *PolicyFmtCommand) Run(args []string) int { return 1 } + if c.flagNoColor { + c.UI = getBasicUI(c.UI) + } + args = f.Args() switch { case len(args) < 1: diff --git a/command/policy_list.go b/command/policy_list.go index 1a61136ff1ef..73a95f7c19cb 100644 --- a/command/policy_list.go +++ b/command/policy_list.go @@ -50,6 +50,10 @@ func (c *PolicyListCommand) Run(args []string) int { return 1 } + if c.flagNoColor { + c.UI = getBasicUI(c.UI) + } + args = f.Args() switch { case len(args) > 0: diff --git a/command/policy_read.go b/command/policy_read.go index 324615935a84..42b09a66b758 100644 --- a/command/policy_read.go +++ b/command/policy_read.go @@ -55,6 +55,10 @@ func (c *PolicyReadCommand) Run(args []string) int { return 1 } + if c.flagNoColor { + c.UI = getBasicUI(c.UI) + } + args = f.Args() switch { case len(args) < 1: diff --git a/command/policy_write.go b/command/policy_write.go index 9f6cb2222d56..77f3abee4e23 100644 --- a/command/policy_write.go +++ b/command/policy_write.go @@ -72,6 +72,10 @@ func (c *PolicyWriteCommand) Run(args []string) int { return 1 } + if c.flagNoColor { + c.UI = getBasicUI(c.UI) + } + args = f.Args() switch { case len(args) < 2: diff --git a/command/read.go b/command/read.go index 6dc2b5337bc7..2f43597371ee 100644 --- a/command/read.go +++ b/command/read.go @@ -58,6 +58,10 @@ func (c *ReadCommand) Run(args []string) int { return 1 } + if c.flagNoColor { + c.UI = getBasicUI(c.UI) + } + args = f.Args() switch { case len(args) < 1: diff --git a/command/rotate.go b/command/rotate.go index 77bc0602b731..789d331939d6 100644 --- a/command/rotate.go +++ b/command/rotate.go @@ -63,6 +63,10 @@ func (c *OperatorRotateCommand) Run(args []string) int { return 1 } + if c.flagNoColor { + c.UI = getBasicUI(c.UI) + } + args = f.Args() if len(args) > 0 { c.UI.Error(fmt.Sprintf("Too many arguments (expected 0, got %d)", len(args))) diff --git a/command/secrets_disable.go b/command/secrets_disable.go index 7002874409c5..d17dd8b5611e 100644 --- a/command/secrets_disable.go +++ b/command/secrets_disable.go @@ -56,6 +56,10 @@ func (c *SecretsDisableCommand) Run(args []string) int { return 1 } + if c.flagNoColor { + c.UI = getBasicUI(c.UI) + } + args = f.Args() switch { case len(args) < 1: diff --git a/command/secrets_enable.go b/command/secrets_enable.go index e31d77ec2456..c999dd91b8c4 100644 --- a/command/secrets_enable.go +++ b/command/secrets_enable.go @@ -155,6 +155,10 @@ func (c *SecretsEnableCommand) Run(args []string) int { return 1 } + if c.flagNoColor { + c.UI = getBasicUI(c.UI) + } + args = f.Args() switch { case len(args) < 1: diff --git a/command/secrets_list.go b/command/secrets_list.go index f50f61808533..f613ed3d258e 100644 --- a/command/secrets_list.go +++ b/command/secrets_list.go @@ -78,6 +78,10 @@ func (c *SecretsListCommand) Run(args []string) int { return 1 } + if c.flagNoColor { + c.UI = getBasicUI(c.UI) + } + args = f.Args() if len(args) > 0 { c.UI.Error(fmt.Sprintf("Too many arguments (expected 0, got %d)", len(args))) diff --git a/command/secrets_move.go b/command/secrets_move.go index 542b14d3d26b..04fa846ed023 100644 --- a/command/secrets_move.go +++ b/command/secrets_move.go @@ -59,6 +59,10 @@ func (c *SecretsMoveCommand) Run(args []string) int { return 1 } + if c.flagNoColor { + c.UI = getBasicUI(c.UI) + } + args = f.Args() switch { case len(args) < 2: diff --git a/command/secrets_tune.go b/command/secrets_tune.go index b2029b7507d2..8a4c5d776731 100644 --- a/command/secrets_tune.go +++ b/command/secrets_tune.go @@ -87,6 +87,10 @@ func (c *SecretsTuneCommand) Run(args []string) int { return 1 } + if c.flagNoColor { + c.UI = getBasicUI(c.UI) + } + args = f.Args() switch { case len(args) < 1: diff --git a/command/server.go b/command/server.go index 2df9b77f6141..c4e043bf98f2 100644 --- a/command/server.go +++ b/command/server.go @@ -266,6 +266,10 @@ func (c *ServerCommand) Run(args []string) int { return 1 } + if c.flagNoColor { + c.UI = getBasicUI(c.UI) + } + // Create a logger. We wrap it in a gated writer so that it doesn't // start logging too early. c.logGate = &gatedwriter.Writer{Writer: colorable.NewColorable(os.Stderr)} diff --git a/command/ssh.go b/command/ssh.go index c35fbb9cfd99..3d0ee1f1ecb9 100644 --- a/command/ssh.go +++ b/command/ssh.go @@ -220,6 +220,10 @@ func (c *SSHCommand) Run(args []string) int { return 1 } + if c.flagNoColor { + c.UI = getBasicUI(c.UI) + } + // Use homedir to expand any relative paths such as ~/.ssh c.flagUserKnownHostsFile = expandPath(c.flagUserKnownHostsFile) c.flagPublicKeyPath = expandPath(c.flagPublicKeyPath) diff --git a/command/status.go b/command/status.go index b31b093c17e9..024d379fd963 100644 --- a/command/status.go +++ b/command/status.go @@ -58,6 +58,10 @@ func (c *StatusCommand) Run(args []string) int { return 1 } + if c.flagNoColor { + c.UI = getBasicUI(c.UI) + } + args = f.Args() if len(args) > 0 { c.UI.Error(fmt.Sprintf("Too many arguments (expected 0, got %d)", len(args))) diff --git a/command/token_capabilities.go b/command/token_capabilities.go index 3212546b430b..d6a2120f8e8b 100644 --- a/command/token_capabilities.go +++ b/command/token_capabilities.go @@ -64,6 +64,10 @@ func (c *TokenCapabilitiesCommand) Run(args []string) int { return 1 } + if c.flagNoColor { + c.UI = getBasicUI(c.UI) + } + token := "" path := "" args = f.Args() diff --git a/command/token_create.go b/command/token_create.go index a75a6066ff22..75fb102d7b5d 100644 --- a/command/token_create.go +++ b/command/token_create.go @@ -199,6 +199,10 @@ func (c *TokenCreateCommand) Run(args []string) int { return 1 } + if c.flagNoColor { + c.UI = getBasicUI(c.UI) + } + args = f.Args() if len(args) > 0 { c.UI.Error(fmt.Sprintf("Too many arguments (expected 0, got %d)", len(args))) diff --git a/command/token_lookup.go b/command/token_lookup.go index 2c885eaee9bb..f418004eaffc 100644 --- a/command/token_lookup.go +++ b/command/token_lookup.go @@ -84,6 +84,10 @@ func (c *TokenLookupCommand) Run(args []string) int { return 1 } + if c.flagNoColor { + c.UI = getBasicUI(c.UI) + } + token := "" args = f.Args() diff --git a/command/token_renew.go b/command/token_renew.go index 6505ce328dab..53172012ec26 100644 --- a/command/token_renew.go +++ b/command/token_renew.go @@ -88,6 +88,10 @@ func (c *TokenRenewCommand) Run(args []string) int { return 1 } + if c.flagNoColor { + c.UI = getBasicUI(c.UI) + } + token := "" increment := c.flagIncrement diff --git a/command/token_revoke.go b/command/token_revoke.go index 351ce639c32e..7181b9c16c34 100644 --- a/command/token_revoke.go +++ b/command/token_revoke.go @@ -106,6 +106,10 @@ func (c *TokenRevokeCommand) Run(args []string) int { return 1 } + if c.flagNoColor { + c.UI = getBasicUI(c.UI) + } + args = f.Args() token := "" if len(args) > 0 { diff --git a/command/unwrap.go b/command/unwrap.go index 824676838338..b0f13f5328e0 100644 --- a/command/unwrap.go +++ b/command/unwrap.go @@ -65,6 +65,10 @@ func (c *UnwrapCommand) Run(args []string) int { return 1 } + if c.flagNoColor { + c.UI = getBasicUI(c.UI) + } + args = f.Args() token := "" switch len(args) { diff --git a/command/util.go b/command/util.go index a51999205fe9..462da78143b0 100644 --- a/command/util.go +++ b/command/util.go @@ -110,6 +110,19 @@ func PrintRaw(ui cli.Ui, str string) int { return 0 } +func getBasicUI(ui cli.Ui) cli.Ui { + switch t := ui.(type) { + case *cli.BasicUi: + return t + case *cli.ColoredUi: + return getBasicUI(t.Ui) + case *cli.ConcurrentUi: + return getBasicUI(t.Ui) + default: + return t + } +} + // getWriterFromUI accepts a cli.Ui and returns the underlying io.Writer by // unwrapping as many wrapped Uis as necessary. If there is an unknown UI // type, this falls back to os.Stdout. diff --git a/command/write.go b/command/write.go index ed25ba6ce72e..11b23e332d49 100644 --- a/command/write.go +++ b/command/write.go @@ -98,6 +98,10 @@ func (c *WriteCommand) Run(args []string) int { return 1 } + if c.flagNoColor { + c.UI = getBasicUI(c.UI) + } + args = f.Args() switch { case len(args) < 1: From 45627d6c7a0dd40ce19f47788dfff33fdbdf92d9 Mon Sep 17 00:00:00 2001 From: Calvin Leung Huang Date: Thu, 1 Feb 2018 17:27:48 -0500 Subject: [PATCH 05/31] Move seal status formatting logic to OutputSealStatus --- command/base.go | 5 +++++ command/format.go | 38 +++++++++++++++++++++++++++++++++++++- command/operator_unseal.go | 37 ++----------------------------------- command/status.go | 4 ++-- 4 files changed, 46 insertions(+), 38 deletions(-) diff --git a/command/base.go b/command/base.go index 3d54bd5bda39..bb817e60e558 100644 --- a/command/base.go +++ b/command/base.go @@ -333,6 +333,11 @@ func (f *FlagSets) Parse(args []string) error { return f.mainSet.Parse(args) } +// Parsed reports whether the command-line flags have been parsed. +func (f *FlagSets) Parsed() bool { + return f.mainSet.Parsed() +} + // Args returns the remaining args after parsing. func (f *FlagSets) Args() []string { return f.mainSet.Args() diff --git a/command/format.go b/command/format.go index c1397b3383ac..0f3bb92682e5 100644 --- a/command/format.go +++ b/command/format.go @@ -208,7 +208,19 @@ func (t TableFormatter) OutputSecret(ui cli.Ui, secret *api.Secret) error { return nil } -func OutputSealStatus(ui cli.Ui, client *api.Client, status *api.SealStatusResponse) int { +// OutputSealStatus will print *api.SealStatusResponse in the CLI according to the format provided +func OutputSealStatus(ui cli.Ui, format string, client *api.Client, status *api.SealStatusResponse) int { + switch format { + case "yaml", "yml": + return outputAsYAML(ui, status) + case "json": + return outputAsJSON(ui, status) + case "table": + default: + ui.Error(fmt.Sprintf("Unknown format: %s", format)) + return 1 + } + var sealPrefix string if status.RecoverySeal { sealPrefix = "Recovery " @@ -261,3 +273,27 @@ func OutputSealStatus(ui cli.Ui, client *api.Client, status *api.SealStatusRespo ui.Output(tableOutput(out, nil)) return 0 } + +func outputAsYAML(ui cli.Ui, data interface{}) int { + // Automatically fallback to BasicUi to avoid having ANSI color codes in the output + ui = getBasicUI(ui) + + b, err := yaml.Marshal(data) + if err != nil { + ui.Error(fmt.Sprintf("Error marshaling YAML: %s", err)) + return 2 + } + return PrintRaw(ui, strings.TrimSpace(string(b))) +} + +func outputAsJSON(ui cli.Ui, data interface{}) int { + // Automatically fallback to BasicUi to avoid having ANSI color codes in the output + ui = getBasicUI(ui) + + b, err := json.Marshal(data) + if err != nil { + ui.Error(fmt.Sprintf("Error marshaling JSON: %s", err)) + return 2 + } + return PrintRaw(ui, strings.TrimSpace(string(b))) +} diff --git a/command/operator_unseal.go b/command/operator_unseal.go index 9ef89f26f345..1342fb646828 100644 --- a/command/operator_unseal.go +++ b/command/operator_unseal.go @@ -1,14 +1,11 @@ package command import ( - "encoding/json" "fmt" "io" "os" "strings" - "github.com/ghodss/yaml" - "github.com/hashicorp/vault/api" "github.com/hashicorp/vault/helper/password" "github.com/mitchellh/cli" "github.com/posener/complete" @@ -115,7 +112,7 @@ func (c *OperatorUnsealCommand) Run(args []string) int { c.UI.Error(fmt.Sprintf("Error resetting unseal process: %s", err)) return 2 } - return OutputSealStatus(c.UI, client, status) + return OutputSealStatus(c.UI, c.flagFormat, client, status) } if unsealKey == "" { @@ -148,35 +145,5 @@ func (c *OperatorUnsealCommand) Run(args []string) int { return 2 } - switch c.flagFormat { - case "yaml", "yml": - return c.unsealOutputYAML(status) - case "json": - return c.unsealOutputJSON(status) - case "table": - return OutputSealStatus(c.UI, client, status) - default: - c.UI.Error(fmt.Sprintf("Unknown format: %s", c.flagFormat)) - return 1 - } -} - -// unsealOutputYAML outputs the init output as YAML. -func (c *OperatorUnsealCommand) unsealOutputYAML(resp *api.SealStatusResponse) int { - b, err := yaml.Marshal(resp) - if err != nil { - c.UI.Error(fmt.Sprintf("Error marshaling YAML: %s", err)) - return 2 - } - return PrintRaw(c.UI, strings.TrimSpace(string(b))) -} - -// unsealOutputJSON outputs the init output as JSON. -func (c *OperatorUnsealCommand) unsealOutputJSON(resp *api.SealStatusResponse) int { - b, err := json.Marshal(resp) - if err != nil { - c.UI.Error(fmt.Sprintf("Error marshaling JSON: %s", err)) - return 2 - } - return PrintRaw(c.UI, strings.TrimSpace(string(b))) + return OutputSealStatus(c.UI, c.flagFormat, client, status) } diff --git a/command/status.go b/command/status.go index 024d379fd963..62246f0abed7 100644 --- a/command/status.go +++ b/command/status.go @@ -39,7 +39,7 @@ Usage: vault status [options] } func (c *StatusCommand) Flags() *FlagSets { - return c.flagSet(FlagSetHTTP) + return c.flagSet(FlagSetHTTP | FlagSetOutputFormat) } func (c *StatusCommand) AutocompleteArgs() complete.Predictor { @@ -83,7 +83,7 @@ func (c *StatusCommand) Run(args []string) int { // Do not return the int here, since we want to return a custom error code // depending on the seal status. - OutputSealStatus(c.UI, client, status) + OutputSealStatus(c.UI, c.flagFormat, client, status) if status.Sealed { return 2 From ae12135da102a67fc7c4aeafc10a81f5e99fbf4e Mon Sep 17 00:00:00 2001 From: Calvin Leung Huang Date: Fri, 2 Feb 2018 13:07:56 -0500 Subject: [PATCH 06/31] Apply no-color to warnings from DeprecatedCommands as well --- command/commands.go | 7 +++++++ command/main.go | 4 ++++ 2 files changed, 11 insertions(+) diff --git a/command/commands.go b/command/commands.go index a696a98adc7f..da7d495a33ab 100644 --- a/command/commands.go +++ b/command/commands.go @@ -89,6 +89,13 @@ func (c *DeprecatedCommand) Run(args []string) int { } func (c *DeprecatedCommand) warn() { + // If we detect the env var for no-color, then get the BasicUi. + // Ideally we would want DeprecatedCommands to support flags as well, + // and do parsing here, but this will do for now. + if os.Getenv("VAULT_OUTPUT_NO_COLOR") != "" { + c.UI = getBasicUI(c.UI) + } + c.UI.Warn(wrapAtLength(fmt.Sprintf( "WARNING! The \"vault %s\" command is deprecated. Please use \"vault %s\" "+ "instead. This command will be removed in Vault 0.11 (or later).", diff --git a/command/main.go b/command/main.go index 6cc9d43da41c..b6fbfe5f32d9 100644 --- a/command/main.go +++ b/command/main.go @@ -23,6 +23,10 @@ func Run(args []string) int { args = []string{"version"} break } + + if arg == "-no-color" { + os.Setenv("VAULT_OUTPUT_NO_COLOR", "true") + } } // Calculate hidden commands from the deprecated ones From fa462a47eebef4d18417d733ff4c545f8573205f Mon Sep 17 00:00:00 2001 From: Calvin Leung Huang Date: Tue, 6 Feb 2018 12:31:12 -0500 Subject: [PATCH 07/31] Add OutputWithFormat to support arbitrary data, add format option to auth list --- command/auth_list.go | 9 +++++++-- command/format.go | 30 ++++++++++++++++++++++++++++-- 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/command/auth_list.go b/command/auth_list.go index 0cc1c604cbff..0a592b6aeb63 100644 --- a/command/auth_list.go +++ b/command/auth_list.go @@ -46,7 +46,7 @@ Usage: vault auth list [options] } func (c *AuthListCommand) Flags() *FlagSets { - set := c.flagSet(FlagSetHTTP) + set := c.flagSet(FlagSetHTTP | FlagSetOutputFormat) f := set.NewFlagSet("Command Options") @@ -55,7 +55,7 @@ func (c *AuthListCommand) Flags() *FlagSets { Target: &c.flagDetailed, Default: false, Usage: "Print detailed information such as configuration and replication " + - "status about each auth method.", + "status about each auth method. This option is only applicable to table formatted output.", }) return set @@ -99,6 +99,11 @@ func (c *AuthListCommand) Run(args []string) int { return 2 } + switch c.flagFormat { + case "json", "yaml", "yml": + return OutputWithFormat(c.UI, c.flagFormat, auths) + } + if c.flagDetailed { c.UI.Output(tableOutput(c.detailedMounts(auths), nil)) return 0 diff --git a/command/format.go b/command/format.go index 0f3bb92682e5..dfca406a694b 100644 --- a/command/format.go +++ b/command/format.go @@ -19,12 +19,38 @@ const ( hopeDelim = "♨" ) +type FormatOptions struct { + Format string +} + func OutputSecret(ui cli.Ui, format string, secret *api.Secret) int { return outputWithFormat(ui, format, secret, secret) } -func OutputList(ui cli.Ui, format string, secret *api.Secret) int { - return outputWithFormat(ui, format, secret, secret.Data["keys"]) +func OutputList(ui cli.Ui, format string, data interface{}) int { + switch data.(type) { + case *api.Secret: + secret := data.(*api.Secret) + return outputWithFormat(ui, format, secret, secret.Data["keys"]) + default: + return outputWithFormat(ui, format, nil, data) + } +} + +// OutputWithFormat supports printing arbitrary data under a specified format. +// The Formatter currently does not support table format +func OutputWithFormat(ui cli.Ui, format string, data interface{}) int { + switch data.(type) { + case *api.Secret: + secret := data.(*api.Secret) + // Best-guess effort that is this a list, so parse out the keys + if listVals, ok := secret.Data["keys"]; ok { + return outputWithFormat(ui, format, secret, listVals) + } + return outputWithFormat(ui, format, secret, secret) + default: + return outputWithFormat(ui, format, nil, data) + } } func outputWithFormat(ui cli.Ui, format string, secret *api.Secret, data interface{}) int { From 14e70ddc374cea9ef64039a6dc2a405f53b72783 Mon Sep 17 00:00:00 2001 From: Calvin Leung Huang Date: Tue, 6 Feb 2018 13:20:57 -0500 Subject: [PATCH 08/31] Add ability to output arbitrary list data on TableFormatter --- command/auth_list.go | 13 +++++-------- command/format.go | 28 +++++++++++++++++++--------- 2 files changed, 24 insertions(+), 17 deletions(-) diff --git a/command/auth_list.go b/command/auth_list.go index 0a592b6aeb63..0ffaf90e82b8 100644 --- a/command/auth_list.go +++ b/command/auth_list.go @@ -102,15 +102,12 @@ func (c *AuthListCommand) Run(args []string) int { switch c.flagFormat { case "json", "yaml", "yml": return OutputWithFormat(c.UI, c.flagFormat, auths) + default: + if c.flagDetailed { + return OutputWithFormat(c.UI, c.flagFormat, c.detailedMounts(auths)) + } + return OutputWithFormat(c.UI, c.flagFormat, c.simpleMounts(auths)) } - - if c.flagDetailed { - c.UI.Output(tableOutput(c.detailedMounts(auths), nil)) - return 0 - } - - c.UI.Output(tableOutput(c.simpleMounts(auths), nil)) - return 0 } func (c *AuthListCommand) simpleMounts(auths map[string]*api.AuthMount) []string { diff --git a/command/format.go b/command/format.go index dfca406a694b..c80dc587d42d 100644 --- a/command/format.go +++ b/command/format.go @@ -38,7 +38,6 @@ func OutputList(ui cli.Ui, format string, data interface{}) int { } // OutputWithFormat supports printing arbitrary data under a specified format. -// The Formatter currently does not support table format func OutputWithFormat(ui cli.Ui, format string, data interface{}) int { switch data.(type) { case *api.Secret: @@ -113,19 +112,30 @@ type TableFormatter struct { } func (t TableFormatter) Output(ui cli.Ui, secret *api.Secret, data interface{}) error { - // TODO: this should really use reflection like the other formatters do - if s, ok := data.(*api.Secret); ok { - return t.OutputSecret(ui, s) - } - if s, ok := data.([]interface{}); ok { - return t.OutputList(ui, secret, s) + switch data.(type) { + case *api.Secret: + return t.OutputSecret(ui, secret) + case []interface{}: + return t.OutputList(ui, secret, data) + case []string: + return t.OutputList(ui, nil, data) + default: + return errors.New("Cannot use the table formatter for this type") } - return errors.New("Cannot use the table formatter for this type") } -func (t TableFormatter) OutputList(ui cli.Ui, secret *api.Secret, list []interface{}) error { +func (t TableFormatter) OutputList(ui cli.Ui, secret *api.Secret, data interface{}) error { t.printWarnings(ui, secret) + switch data.(type) { + case []interface{}: + case []string: + ui.Output(tableOutput(data.([]string), nil)) + return nil + } + + list := data.([]interface{}) + if len(list) > 0 { keys := make([]string, len(list)) for i, v := range list { From caae214f372acd359466fc45918e6c33c4e6da2c Mon Sep 17 00:00:00 2001 From: Calvin Leung Huang Date: Tue, 6 Feb 2018 13:26:51 -0500 Subject: [PATCH 09/31] Clear up switch logic on format --- command/auth_list.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/command/auth_list.go b/command/auth_list.go index 0ffaf90e82b8..a5829e2d014f 100644 --- a/command/auth_list.go +++ b/command/auth_list.go @@ -100,14 +100,15 @@ func (c *AuthListCommand) Run(args []string) int { } switch c.flagFormat { - case "json", "yaml", "yml": - return OutputWithFormat(c.UI, c.flagFormat, auths) - default: + case "table": if c.flagDetailed { return OutputWithFormat(c.UI, c.flagFormat, c.detailedMounts(auths)) } return OutputWithFormat(c.UI, c.flagFormat, c.simpleMounts(auths)) + default: + return OutputWithFormat(c.UI, c.flagFormat, auths) } + } func (c *AuthListCommand) simpleMounts(auths map[string]*api.AuthMount) []string { From e0f96d6b0b4620a6d2b816819ead4be1148e69e8 Mon Sep 17 00:00:00 2001 From: Calvin Leung Huang Date: Tue, 6 Feb 2018 14:13:02 -0500 Subject: [PATCH 10/31] Add format option for list-related commands --- command/audit_list.go | 16 +++++++++------- command/auth_list.go | 1 - command/format.go | 15 ++++++++------- command/policy_list.go | 13 ++++++++----- command/secrets_list.go | 16 +++++++++------- 5 files changed, 34 insertions(+), 27 deletions(-) diff --git a/command/audit_list.go b/command/audit_list.go index f01a8e301a32..eb8d260f7fb9 100644 --- a/command/audit_list.go +++ b/command/audit_list.go @@ -44,7 +44,7 @@ Usage: vault audit list [options] } func (c *AuditListCommand) Flags() *FlagSets { - set := c.flagSet(FlagSetHTTP) + set := c.flagSet(FlagSetHTTP | FlagSetOutputFormat) f := set.NewFlagSet("Command Options") @@ -103,13 +103,15 @@ func (c *AuditListCommand) Run(args []string) int { return 0 } - if c.flagDetailed { - c.UI.Output(tableOutput(c.detailedAudits(audits), nil)) - return 0 + switch c.flagFormat { + case "table": + if c.flagDetailed { + return OutputWithFormat(c.UI, c.flagFormat, c.detailedAudits(audits)) + } + return OutputWithFormat(c.UI, c.flagFormat, c.simpleAudits(audits)) + default: + return OutputWithFormat(c.UI, c.flagFormat, audits) } - - c.UI.Output(tableOutput(c.simpleAudits(audits), nil)) - return 0 } func (c *AuditListCommand) simpleAudits(audits map[string]*api.Audit) []string { diff --git a/command/auth_list.go b/command/auth_list.go index a5829e2d014f..ae8d2b376a2b 100644 --- a/command/auth_list.go +++ b/command/auth_list.go @@ -108,7 +108,6 @@ func (c *AuthListCommand) Run(args []string) int { default: return OutputWithFormat(c.UI, c.flagFormat, auths) } - } func (c *AuthListCommand) simpleMounts(auths map[string]*api.AuthMount) []string { diff --git a/command/format.go b/command/format.go index c80dc587d42d..79236a3aac29 100644 --- a/command/format.go +++ b/command/format.go @@ -53,18 +53,19 @@ func OutputWithFormat(ui cli.Ui, format string, data interface{}) int { } func outputWithFormat(ui cli.Ui, format string, secret *api.Secret, data interface{}) int { - // If we had a colored UI, pull out the nested ui so we don't add escape - // sequences for outputting json, etc. - colorUI, ok := ui.(*cli.ColoredUi) - if ok { - ui = colorUI.Ui - } - formatter, ok := Formatters[strings.ToLower(format)] if !ok { ui.Error(fmt.Sprintf("Invalid output format: %s", format)) return 1 } + + // Type-check formatter, and ignore colored UI if it's a non-table output + if _, ok := formatter.(TableFormatter); !ok { + // If we had a colored UI, pull out the nested ui so we don't add escape + // sequences for outputting json, etc. + ui = getBasicUI(ui) + } + if err := formatter.Output(ui, secret, data); err != nil { ui.Error(fmt.Sprintf("Could not output secret: %s", err.Error())) return 1 diff --git a/command/policy_list.go b/command/policy_list.go index 73a95f7c19cb..4d70bfb6c2ca 100644 --- a/command/policy_list.go +++ b/command/policy_list.go @@ -31,7 +31,7 @@ Usage: vault policy list [options] } func (c *PolicyListCommand) Flags() *FlagSets { - return c.flagSet(FlagSetHTTP) + return c.flagSet(FlagSetHTTP | FlagSetOutputFormat) } func (c *PolicyListCommand) AutocompleteArgs() complete.Predictor { @@ -72,9 +72,12 @@ func (c *PolicyListCommand) Run(args []string) int { c.UI.Error(fmt.Sprintf("Error listing policies: %s", err)) return 2 } - for _, p := range policies { - c.UI.Output(p) - } - return 0 + switch c.flagFormat { + case "table": + out := append([]string{"Policies"}, policies...) + return OutputWithFormat(c.UI, c.flagFormat, out) + default: + return OutputWithFormat(c.UI, c.flagFormat, policies) + } } diff --git a/command/secrets_list.go b/command/secrets_list.go index f613ed3d258e..3a38212a930f 100644 --- a/command/secrets_list.go +++ b/command/secrets_list.go @@ -47,7 +47,7 @@ Usage: vault secrets list [options] } func (c *SecretsListCommand) Flags() *FlagSets { - set := c.flagSet(FlagSetHTTP) + set := c.flagSet(FlagSetHTTP | FlagSetOutputFormat) f := set.NewFlagSet("Command Options") @@ -100,13 +100,15 @@ func (c *SecretsListCommand) Run(args []string) int { return 2 } - if c.flagDetailed { - c.UI.Output(tableOutput(c.detailedMounts(mounts), nil)) - return 0 + switch c.flagFormat { + case "table": + if c.flagDetailed { + return OutputWithFormat(c.UI, c.flagFormat, c.detailedMounts(mounts)) + } + return OutputWithFormat(c.UI, c.flagFormat, c.simpleMounts(mounts)) + default: + return OutputWithFormat(c.UI, c.flagFormat, mounts) } - - c.UI.Output(tableOutput(c.simpleMounts(mounts), nil)) - return 0 } func (c *SecretsListCommand) simpleMounts(mounts map[string]*api.MountOutput) []string { From c8cfcb557ab9580cb726140d4b80768db7f7ba23 Mon Sep 17 00:00:00 2001 From: Calvin Leung Huang Date: Wed, 7 Feb 2018 11:14:15 -0500 Subject: [PATCH 11/31] Add format option to rest of commands that returns a client API response --- api/sys_generate_root.go | 10 +++++----- api/sys_rekey.go | 26 +++++++++++++------------- command/operator_generate_root.go | 24 ++++++++++++++++++++---- command/operator_key_status.go | 9 +++++++-- command/operator_rekey.go | 18 ++++++++++++++---- command/policy_read.go | 14 +++++++++++--- command/rotate.go | 13 +++++++++---- command/token_capabilities.go | 13 +++++++++---- 8 files changed, 88 insertions(+), 39 deletions(-) diff --git a/api/sys_generate_root.go b/api/sys_generate_root.go index 410ccf4c6078..adb5496d4e4f 100644 --- a/api/sys_generate_root.go +++ b/api/sys_generate_root.go @@ -99,11 +99,11 @@ func (c *Sys) generateRootUpdateCommon(path, shard, nonce string) (*GenerateRoot } type GenerateRootStatusResponse struct { - Nonce string - Started bool - Progress int - Required int - Complete bool + Nonce string `json:"nonce"` + Started bool `json:"started"` + Progress int `json:"progress"` + Required int `json:"required"` + Complete bool `json:"complete"` EncodedToken string `json:"encoded_token"` EncodedRootToken string `json:"encoded_root_token"` PGPFingerprint string `json:"pgp_fingerprint"` diff --git a/api/sys_rekey.go b/api/sys_rekey.go index 61002224a52a..8b2d0435d042 100644 --- a/api/sys_rekey.go +++ b/api/sys_rekey.go @@ -177,27 +177,27 @@ type RekeyInitRequest struct { } type RekeyStatusResponse struct { - Nonce string - Started bool - T int - N int - Progress int - Required int + Nonce string `json:"nonce"` + Started bool `json:"started"` + T int `json:"t"` + N int `json:"n"` + Progress int `json:"progress"` + Required int `json:"required"` PGPFingerprints []string `json:"pgp_fingerprints"` - Backup bool + Backup bool `json:"backup"` } type RekeyUpdateResponse struct { - Nonce string - Complete bool - Keys []string + Nonce string `json:"nonce"` + Complete bool `json:"complete"` + Keys []string `json:"keys"` KeysB64 []string `json:"keys_base64"` PGPFingerprints []string `json:"pgp_fingerprints"` - Backup bool + Backup bool `json:"backup"` } type RekeyRetrieveResponse struct { - Nonce string - Keys map[string][]string + Nonce string `json:"nonce"` + Keys map[string][]string `json:"keys"` KeysB64 map[string][]string `json:"keys_base64"` } diff --git a/command/operator_generate_root.go b/command/operator_generate_root.go index 588eb53352fd..a7de0a1be6c9 100644 --- a/command/operator_generate_root.go +++ b/command/operator_generate_root.go @@ -82,7 +82,7 @@ Usage: vault operator generate-root [options] [KEY] } func (c *OperatorGenerateRootCommand) Flags() *FlagSets { - set := c.flagSet(FlagSetHTTP) + set := c.flagSet(FlagSetHTTP | FlagSetOutputFormat) f := set.NewFlagSet("Command Options") @@ -341,7 +341,13 @@ func (c *OperatorGenerateRootCommand) init(client *api.Client, otp, pgpKey strin c.UI.Error(fmt.Sprintf("Error initializing root generation: %s", err)) return 2 } - return c.printStatus(status) + + switch c.flagFormat { + case "table": + return c.printStatus(status) + default: + return OutputWithFormat(c.UI, c.flagFormat, status) + } } // provide prompts the user for the seal key and posts it to the update root @@ -432,7 +438,12 @@ func (c *OperatorGenerateRootCommand) provide(client *api.Client, key string, dr c.UI.Error(fmt.Sprintf("Error posting unseal key: %s", err)) return 2 } - return c.printStatus(status) + switch c.flagFormat { + case "table": + return c.printStatus(status) + default: + return OutputWithFormat(c.UI, c.flagFormat, status) + } } // cancel cancels the root token generation @@ -460,7 +471,12 @@ func (c *OperatorGenerateRootCommand) status(client *api.Client, drToken bool) i c.UI.Error(fmt.Sprintf("Error getting root generation status: %s", err)) return 2 } - return c.printStatus(status) + switch c.flagFormat { + case "table": + return c.printStatus(status) + default: + return OutputWithFormat(c.UI, c.flagFormat, status) + } } // printStatus dumps the status to output diff --git a/command/operator_key_status.go b/command/operator_key_status.go index 1de1acec8457..812fd62d63f7 100644 --- a/command/operator_key_status.go +++ b/command/operator_key_status.go @@ -73,6 +73,11 @@ func (c *OperatorKeyStatusCommand) Run(args []string) int { return 2 } - c.UI.Output(printKeyStatus(status)) - return 0 + switch c.flagFormat { + case "table": + c.UI.Output(printKeyStatus(status)) + return 0 + default: + return OutputWithFormat(c.UI, c.flagFormat, status) + } } diff --git a/command/operator_rekey.go b/command/operator_rekey.go index 9956dacf2fb0..e33b8f73acf6 100644 --- a/command/operator_rekey.go +++ b/command/operator_rekey.go @@ -96,7 +96,7 @@ Usage: vault rekey [options] [KEY] } func (c *OperatorRekeyCommand) Flags() *FlagSets { - set := c.flagSet(FlagSetHTTP) + set := c.flagSet(FlagSetHTTP | FlagSetOutputFormat) f := set.NewFlagSet("Common Options") @@ -538,7 +538,7 @@ func (c *OperatorRekeyCommand) backupRetrieve(client *api.Client) int { Data: structs.New(storedKeys).Map(), } - return OutputSecret(c.UI, "table", secret) + return OutputSecret(c.UI, c.flagFormat, secret) } // backupDelete deletes the stored backup keys. @@ -583,11 +583,21 @@ func (c *OperatorRekeyCommand) printStatus(status *api.RekeyStatusResponse) int out = append(out, fmt.Sprintf("Backup | %t", status.Backup)) } - c.UI.Output(tableOutput(out, nil)) - return 0 + switch c.flagFormat { + case "table": + return OutputWithFormat(c.UI, c.flagFormat, out) + default: + return OutputWithFormat(c.UI, c.flagFormat, status) + } } func (c *OperatorRekeyCommand) printUnsealKeys(status *api.RekeyStatusResponse, resp *api.RekeyUpdateResponse) int { + switch c.flagFormat { + case "table": + default: + return OutputWithFormat(c.UI, c.flagFormat, resp) + } + // Space between the key prompt, if any, and the output c.UI.Output("") diff --git a/command/policy_read.go b/command/policy_read.go index 42b09a66b758..e6ad5bcf41ee 100644 --- a/command/policy_read.go +++ b/command/policy_read.go @@ -36,7 +36,7 @@ Usage: vault policy read [options] [NAME] } func (c *PolicyReadCommand) Flags() *FlagSets { - return c.flagSet(FlagSetHTTP) + return c.flagSet(FlagSetHTTP | FlagSetOutputFormat) } func (c *PolicyReadCommand) AutocompleteArgs() complete.Predictor { @@ -85,7 +85,15 @@ func (c *PolicyReadCommand) Run(args []string) int { c.UI.Error(fmt.Sprintf("No policy named: %s", name)) return 2 } - c.UI.Output(strings.TrimSpace(rules)) - return 0 + switch c.flagFormat { + case "table": + c.UI.Output(strings.TrimSpace(rules)) + return 0 + default: + resp := map[string]string{ + "policy": rules, + } + return OutputWithFormat(c.UI, c.flagFormat, &resp) + } } diff --git a/command/rotate.go b/command/rotate.go index 789d331939d6..231c5c619247 100644 --- a/command/rotate.go +++ b/command/rotate.go @@ -93,8 +93,13 @@ func (c *OperatorRotateCommand) Run(args []string) int { return 2 } - c.UI.Output("Success! Rotated key") - c.UI.Output("") - c.UI.Output(printKeyStatus(status)) - return 0 + switch c.flagFormat { + case "table": + c.UI.Output("Success! Rotated key") + c.UI.Output("") + c.UI.Output(printKeyStatus(status)) + return 0 + default: + return OutputWithFormat(c.UI, c.flagFormat, status) + } } diff --git a/command/token_capabilities.go b/command/token_capabilities.go index d6a2120f8e8b..951179f9dc84 100644 --- a/command/token_capabilities.go +++ b/command/token_capabilities.go @@ -45,7 +45,7 @@ Usage: vault token capabilities [options] [TOKEN] PATH } func (c *TokenCapabilitiesCommand) Flags() *FlagSets { - return c.flagSet(FlagSetHTTP) + return c.flagSet(FlagSetHTTP | FlagSetOutputFormat) } func (c *TokenCapabilitiesCommand) AutocompleteArgs() complete.Predictor { @@ -98,7 +98,12 @@ func (c *TokenCapabilitiesCommand) Run(args []string) int { return 2 } - sort.Strings(capabilities) - c.UI.Output(strings.Join(capabilities, ", ")) - return 0 + switch c.flagFormat { + case "table": + sort.Strings(capabilities) + c.UI.Output(strings.Join(capabilities, ", ")) + return 0 + default: + return OutputWithFormat(c.UI, c.flagFormat, capabilities) + } } From d2ba2fedab90f08265898ac0bb016691dbbb457e Mon Sep 17 00:00:00 2001 From: Calvin Leung Huang Date: Wed, 7 Feb 2018 11:51:54 -0500 Subject: [PATCH 12/31] Remove initOutputYAML and initOutputJSON, and use OutputWithFormat instead --- command/operator_init.go | 29 +---------------------------- 1 file changed, 1 insertion(+), 28 deletions(-) diff --git a/command/operator_init.go b/command/operator_init.go index fac83768af2e..adca7c7db97f 100644 --- a/command/operator_init.go +++ b/command/operator_init.go @@ -1,13 +1,11 @@ package command import ( - "encoding/json" "fmt" "net/url" "runtime" "strings" - "github.com/ghodss/yaml" "github.com/hashicorp/vault/api" "github.com/hashicorp/vault/helper/pgpkeys" "github.com/mitchellh/cli" @@ -439,14 +437,9 @@ func (c *OperatorInitCommand) init(client *api.Client, req *api.InitRequest) int } switch c.flagFormat { - case "yaml", "yml": - return c.initOutputYAML(req, resp) - case "json": - return c.initOutputJSON(req, resp) case "table": default: - c.UI.Error(fmt.Sprintf("Unknown format: %s", c.flagFormat)) - return 1 + return OutputWithFormat(c.UI, c.flagFormat, newMachineInit(req, resp)) } for i, key := range resp.Keys { @@ -507,26 +500,6 @@ func (c *OperatorInitCommand) init(client *api.Client, req *api.InitRequest) int return 0 } -// initOutputYAML outputs the init output as YAML. -func (c *OperatorInitCommand) initOutputYAML(req *api.InitRequest, resp *api.InitResponse) int { - b, err := yaml.Marshal(newMachineInit(req, resp)) - if err != nil { - c.UI.Error(fmt.Sprintf("Error marshaling YAML: %s", err)) - return 2 - } - return PrintRaw(c.UI, strings.TrimSpace(string(b))) -} - -// initOutputJSON outputs the init output as JSON. -func (c *OperatorInitCommand) initOutputJSON(req *api.InitRequest, resp *api.InitResponse) int { - b, err := json.Marshal(newMachineInit(req, resp)) - if err != nil { - c.UI.Error(fmt.Sprintf("Error marshaling JSON: %s", err)) - return 2 - } - return PrintRaw(c.UI, strings.TrimSpace(string(b))) -} - // status inspects the init status of vault and returns an appropriate error // code and message. func (c *OperatorInitCommand) status(client *api.Client) int { From 8f2a229abce992142d1c7334b98f4e2c1dd16141 Mon Sep 17 00:00:00 2001 From: Calvin Leung Huang Date: Wed, 7 Feb 2018 12:06:39 -0500 Subject: [PATCH 13/31] Remove outputAsYAML and outputAsJSON, and use OutputWithFormat instead --- command/format.go | 33 ++------------------------------- command/status.go | 8 ++++---- 2 files changed, 6 insertions(+), 35 deletions(-) diff --git a/command/format.go b/command/format.go index 79236a3aac29..c49bc8001ecd 100644 --- a/command/format.go +++ b/command/format.go @@ -67,7 +67,7 @@ func outputWithFormat(ui cli.Ui, format string, secret *api.Secret, data interfa } if err := formatter.Output(ui, secret, data); err != nil { - ui.Error(fmt.Sprintf("Could not output secret: %s", err.Error())) + ui.Error(fmt.Sprintf("Could not parse output: %s", err.Error())) return 1 } return 0 @@ -248,14 +248,9 @@ func (t TableFormatter) OutputSecret(ui cli.Ui, secret *api.Secret) error { // OutputSealStatus will print *api.SealStatusResponse in the CLI according to the format provided func OutputSealStatus(ui cli.Ui, format string, client *api.Client, status *api.SealStatusResponse) int { switch format { - case "yaml", "yml": - return outputAsYAML(ui, status) - case "json": - return outputAsJSON(ui, status) case "table": default: - ui.Error(fmt.Sprintf("Unknown format: %s", format)) - return 1 + return OutputWithFormat(ui, format, status) } var sealPrefix string @@ -310,27 +305,3 @@ func OutputSealStatus(ui cli.Ui, format string, client *api.Client, status *api. ui.Output(tableOutput(out, nil)) return 0 } - -func outputAsYAML(ui cli.Ui, data interface{}) int { - // Automatically fallback to BasicUi to avoid having ANSI color codes in the output - ui = getBasicUI(ui) - - b, err := yaml.Marshal(data) - if err != nil { - ui.Error(fmt.Sprintf("Error marshaling YAML: %s", err)) - return 2 - } - return PrintRaw(ui, strings.TrimSpace(string(b))) -} - -func outputAsJSON(ui cli.Ui, data interface{}) int { - // Automatically fallback to BasicUi to avoid having ANSI color codes in the output - ui = getBasicUI(ui) - - b, err := json.Marshal(data) - if err != nil { - ui.Error(fmt.Sprintf("Error marshaling JSON: %s", err)) - return 2 - } - return PrintRaw(ui, strings.TrimSpace(string(b))) -} diff --git a/command/status.go b/command/status.go index 62246f0abed7..9ab4a11c0def 100644 --- a/command/status.go +++ b/command/status.go @@ -81,13 +81,13 @@ func (c *StatusCommand) Run(args []string) int { return 1 } - // Do not return the int here, since we want to return a custom error code - // depending on the seal status. - OutputSealStatus(c.UI, c.flagFormat, client, status) + // Do not return the int here yet, since we may want to return a custom error + // code depending on the seal status. + code := OutputSealStatus(c.UI, c.flagFormat, client, status) if status.Sealed { return 2 } - return 0 + return code } From 204180b1af9f45fb6338158a58589cca1f547290 Mon Sep 17 00:00:00 2001 From: Calvin Leung Huang Date: Wed, 7 Feb 2018 17:09:49 -0500 Subject: [PATCH 14/31] Remove -no-color flag, use env var exclusively to toggle colored output --- command/audit_disable.go | 4 ---- command/audit_enable.go | 4 ---- command/audit_list.go | 4 ---- command/auth_disable.go | 4 ---- command/auth_enable.go | 4 ---- command/auth_help.go | 4 ---- command/auth_list.go | 4 ---- command/auth_tune.go | 4 ---- command/base.go | 13 +------------ command/commands.go | 15 +++++---------- command/delete.go | 4 ---- command/lease_renew.go | 4 ---- command/lease_revoke.go | 4 ---- command/list.go | 4 ---- command/login.go | 4 ---- command/operator_generate_root.go | 4 ---- command/operator_init.go | 4 ---- command/operator_key_status.go | 4 ---- command/operator_rekey.go | 4 ---- command/operator_seal.go | 4 ---- command/operator_step_down.go | 4 ---- command/operator_unseal.go | 4 ---- command/path_help.go | 4 ---- command/policies_deprecated.go | 4 ---- command/policy_delete.go | 4 ---- command/policy_fmt.go | 4 ---- command/policy_list.go | 4 ---- command/policy_read.go | 4 ---- command/policy_write.go | 4 ---- command/read.go | 4 ---- command/rotate.go | 4 ---- command/secrets_disable.go | 4 ---- command/secrets_enable.go | 4 ---- command/secrets_list.go | 4 ---- command/secrets_move.go | 4 ---- command/secrets_tune.go | 4 ---- command/server.go | 4 ---- command/ssh.go | 4 ---- command/status.go | 4 ---- command/token_capabilities.go | 4 ---- command/token_create.go | 4 ---- command/token_lookup.go | 4 ---- command/token_renew.go | 4 ---- command/token_revoke.go | 4 ---- command/unwrap.go | 4 ---- command/write.go | 4 ---- 46 files changed, 6 insertions(+), 198 deletions(-) diff --git a/command/audit_disable.go b/command/audit_disable.go index 8746e595b975..1025a0ba2726 100644 --- a/command/audit_disable.go +++ b/command/audit_disable.go @@ -58,10 +58,6 @@ func (c *AuditDisableCommand) Run(args []string) int { return 1 } - if c.flagNoColor { - c.UI = getBasicUI(c.UI) - } - args = f.Args() switch { case len(args) < 1: diff --git a/command/audit_enable.go b/command/audit_enable.go index 5c0b2090db9f..85b3bac9aa57 100644 --- a/command/audit_enable.go +++ b/command/audit_enable.go @@ -106,10 +106,6 @@ func (c *AuditEnableCommand) Run(args []string) int { return 1 } - if c.flagNoColor { - c.UI = getBasicUI(c.UI) - } - args = f.Args() if len(args) < 1 { c.UI.Error("Missing TYPE!") diff --git a/command/audit_list.go b/command/audit_list.go index eb8d260f7fb9..a1a70abaa6c9 100644 --- a/command/audit_list.go +++ b/command/audit_list.go @@ -76,10 +76,6 @@ func (c *AuditListCommand) Run(args []string) int { return 1 } - if c.flagNoColor { - c.UI = getBasicUI(c.UI) - } - args = f.Args() if len(args) > 0 { c.UI.Error(fmt.Sprintf("Too many arguments (expected 0, got %d)", len(args))) diff --git a/command/auth_disable.go b/command/auth_disable.go index f96989b75cf3..afcfe747df20 100644 --- a/command/auth_disable.go +++ b/command/auth_disable.go @@ -59,10 +59,6 @@ func (c *AuthDisableCommand) Run(args []string) int { return 1 } - if c.flagNoColor { - c.UI = getBasicUI(c.UI) - } - args = f.Args() switch { case len(args) < 1: diff --git a/command/auth_enable.go b/command/auth_enable.go index 6bc4a036f043..1cc8dbc1a7df 100644 --- a/command/auth_enable.go +++ b/command/auth_enable.go @@ -117,10 +117,6 @@ func (c *AuthEnableCommand) Run(args []string) int { return 1 } - if c.flagNoColor { - c.UI = getBasicUI(c.UI) - } - args = f.Args() switch { case len(args) < 1: diff --git a/command/auth_help.go b/command/auth_help.go index bb45b2078822..d18d1bf0951a 100644 --- a/command/auth_help.go +++ b/command/auth_help.go @@ -73,10 +73,6 @@ func (c *AuthHelpCommand) Run(args []string) int { return 1 } - if c.flagNoColor { - c.UI = getBasicUI(c.UI) - } - args = f.Args() switch { case len(args) < 1: diff --git a/command/auth_list.go b/command/auth_list.go index ae8d2b376a2b..75f1fc4b6463 100644 --- a/command/auth_list.go +++ b/command/auth_list.go @@ -77,10 +77,6 @@ func (c *AuthListCommand) Run(args []string) int { return 1 } - if c.flagNoColor { - c.UI = getBasicUI(c.UI) - } - args = f.Args() if len(args) > 0 { c.UI.Error(fmt.Sprintf("Too many arguments (expected 0, got %d)", len(args))) diff --git a/command/auth_tune.go b/command/auth_tune.go index 4959bf311d63..958d11bd1fb9 100644 --- a/command/auth_tune.go +++ b/command/auth_tune.go @@ -87,10 +87,6 @@ func (c *AuthTuneCommand) Run(args []string) int { return 1 } - if c.flagNoColor { - c.UI = getBasicUI(c.UI) - } - args = f.Args() switch { case len(args) < 1: diff --git a/command/base.go b/command/base.go index bb817e60e558..8caa595a7a2c 100644 --- a/command/base.go +++ b/command/base.go @@ -144,7 +144,6 @@ const ( FlagSetHTTP FlagSetOutputField FlagSetOutputFormat - FlagSetOutputNoColor ) // flagSet creates the flags for this command. The result is cached on the @@ -156,7 +155,7 @@ func (c *BaseCommand) flagSet(bit FlagSetBit) *FlagSets { // These flag sets will apply to all leaf subcommands. // TODO: Optional, but FlagSetHTTP can be safely removed from the individual // Flags() subcommands. - bit = bit | FlagSetHTTP | FlagSetOutputNoColor + bit = bit | FlagSetHTTP if bit&FlagSetHTTP != 0 { f := set.NewFlagSet("HTTP Options") @@ -272,16 +271,6 @@ func (c *BaseCommand) flagSet(bit FlagSetBit) *FlagSets { "are \"table\", \"json\", or \"yaml\".", }) } - - if bit&FlagSetOutputNoColor != 0 { - f.BoolVar(&BoolVar{ - Name: "no-color", - Target: &c.flagNoColor, - Default: false, - EnvVar: "VAULT_OUTPUT_NO_COLOR", - Usage: "Print the output without ANSI color escape sequences.", - }) - } } c.flags = set diff --git a/command/commands.go b/command/commands.go index da7d495a33ab..82a207458564 100644 --- a/command/commands.go +++ b/command/commands.go @@ -65,6 +65,9 @@ import ( physZooKeeper "github.com/hashicorp/vault/physical/zookeeper" ) +// EnvVaultCLINoColor is an env var that toggles colored UI output. +const EnvVaultCLINoColor = `VAULT_CLI_NO_COLOR` + // DeprecatedCommand is a command that wraps an existing command and prints a // deprecation notice and points the user to the new command. Deprecated // commands are always hidden from help output. @@ -89,13 +92,6 @@ func (c *DeprecatedCommand) Run(args []string) int { } func (c *DeprecatedCommand) warn() { - // If we detect the env var for no-color, then get the BasicUi. - // Ideally we would want DeprecatedCommands to support flags as well, - // and do parsing here, but this will do for now. - if os.Getenv("VAULT_OUTPUT_NO_COLOR") != "" { - c.UI = getBasicUI(c.UI) - } - c.UI.Warn(wrapAtLength(fmt.Sprintf( "WARNING! The \"vault %s\" command is deprecated. Please use \"vault %s\" "+ "instead. This command will be removed in Vault 0.11 (or later).", @@ -121,9 +117,8 @@ func init() { Writer: os.Stdout, } - // Attempt to detect if stdout is a tty. If so, - // wrap BasicUi's in ColoredUi. - if terminal.IsTerminal(int(os.Stdout.Fd())) { + // Only use colored UI if stdoout is a tty, and EnvVaultCLINoColor is not set. + if terminal.IsTerminal(int(os.Stdout.Fd())) && os.Getenv(EnvVaultCLINoColor) == "" { ui = &cli.ColoredUi{ ErrorColor: cli.UiColorRed, WarnColor: cli.UiColorYellow, diff --git a/command/delete.go b/command/delete.go index 5ec724a9c7a0..12c7f9611795 100644 --- a/command/delete.go +++ b/command/delete.go @@ -66,10 +66,6 @@ func (c *DeleteCommand) Run(args []string) int { return 1 } - if c.flagNoColor { - c.UI = getBasicUI(c.UI) - } - args = f.Args() switch { case len(args) < 1: diff --git a/command/lease_renew.go b/command/lease_renew.go index b93b6a8ba286..4dd2e1c573c0 100644 --- a/command/lease_renew.go +++ b/command/lease_renew.go @@ -81,10 +81,6 @@ func (c *LeaseRenewCommand) Run(args []string) int { return 1 } - if c.flagNoColor { - c.UI = getBasicUI(c.UI) - } - leaseID := "" increment := c.flagIncrement diff --git a/command/lease_revoke.go b/command/lease_revoke.go index 620ccfa019f6..45f5dc3a766a 100644 --- a/command/lease_revoke.go +++ b/command/lease_revoke.go @@ -91,10 +91,6 @@ func (c *LeaseRevokeCommand) Run(args []string) int { return 1 } - if c.flagNoColor { - c.UI = getBasicUI(c.UI) - } - args = f.Args() switch { case len(args) < 1: diff --git a/command/list.go b/command/list.go index 31e80af3f664..ecfa0acb5646 100644 --- a/command/list.go +++ b/command/list.go @@ -59,10 +59,6 @@ func (c *ListCommand) Run(args []string) int { return 1 } - if c.flagNoColor { - c.UI = getBasicUI(c.UI) - } - args = f.Args() switch { case len(args) < 1: diff --git a/command/login.go b/command/login.go index 2ec0bf262849..564b893bb899 100644 --- a/command/login.go +++ b/command/login.go @@ -152,10 +152,6 @@ func (c *LoginCommand) Run(args []string) int { return 1 } - if c.flagNoColor { - c.UI = getBasicUI(c.UI) - } - args = f.Args() // Deprecations diff --git a/command/operator_generate_root.go b/command/operator_generate_root.go index a7de0a1be6c9..61c8d1d7a24e 100644 --- a/command/operator_generate_root.go +++ b/command/operator_generate_root.go @@ -206,10 +206,6 @@ func (c *OperatorGenerateRootCommand) Run(args []string) int { return 1 } - if c.flagNoColor { - c.UI = getBasicUI(c.UI) - } - args = f.Args() if len(args) > 1 { c.UI.Error(fmt.Sprintf("Too many arguments (expected 0-1, got %d)", len(args))) diff --git a/command/operator_init.go b/command/operator_init.go index adca7c7db97f..4e2be88a9b3f 100644 --- a/command/operator_init.go +++ b/command/operator_init.go @@ -241,10 +241,6 @@ func (c *OperatorInitCommand) Run(args []string) int { return 1 } - if c.flagNoColor { - c.UI = getBasicUI(c.UI) - } - // Deprecations // TODO: remove in 0.9.0 if c.flagAuto { diff --git a/command/operator_key_status.go b/command/operator_key_status.go index 812fd62d63f7..3566d5e4974f 100644 --- a/command/operator_key_status.go +++ b/command/operator_key_status.go @@ -51,10 +51,6 @@ func (c *OperatorKeyStatusCommand) Run(args []string) int { return 1 } - if c.flagNoColor { - c.UI = getBasicUI(c.UI) - } - args = f.Args() if len(args) > 0 { c.UI.Error(fmt.Sprintf("Too many arguments (expected 0, got %d)", len(args))) diff --git a/command/operator_rekey.go b/command/operator_rekey.go index e33b8f73acf6..c41179a7d55e 100644 --- a/command/operator_rekey.go +++ b/command/operator_rekey.go @@ -250,10 +250,6 @@ func (c *OperatorRekeyCommand) Run(args []string) int { return 1 } - if c.flagNoColor { - c.UI = getBasicUI(c.UI) - } - args = f.Args() if len(args) > 1 { c.UI.Error(fmt.Sprintf("Too many arguments (expected 0-1, got %d)", len(args))) diff --git a/command/operator_seal.go b/command/operator_seal.go index 7313f13c496a..b5fe3b8eb796 100644 --- a/command/operator_seal.go +++ b/command/operator_seal.go @@ -62,10 +62,6 @@ func (c *OperatorSealCommand) Run(args []string) int { return 1 } - if c.flagNoColor { - c.UI = getBasicUI(c.UI) - } - args = f.Args() if len(args) > 0 { c.UI.Error(fmt.Sprintf("Too many arguments (expected 0, got %d)", len(args))) diff --git a/command/operator_step_down.go b/command/operator_step_down.go index 6dd2432f2d68..63208faf042d 100644 --- a/command/operator_step_down.go +++ b/command/operator_step_down.go @@ -58,10 +58,6 @@ func (c *OperatorStepDownCommand) Run(args []string) int { return 1 } - if c.flagNoColor { - c.UI = getBasicUI(c.UI) - } - args = f.Args() if len(args) > 0 { c.UI.Error(fmt.Sprintf("Too many arguments (expected 0, got %d)", len(args))) diff --git a/command/operator_unseal.go b/command/operator_unseal.go index 1342fb646828..120cc0f57557 100644 --- a/command/operator_unseal.go +++ b/command/operator_unseal.go @@ -83,10 +83,6 @@ func (c *OperatorUnsealCommand) Run(args []string) int { return 1 } - if c.flagNoColor { - c.UI = getBasicUI(c.UI) - } - unsealKey := "" args = f.Args() diff --git a/command/path_help.go b/command/path_help.go index 2e2a099189df..2ce4a38bfd42 100644 --- a/command/path_help.go +++ b/command/path_help.go @@ -69,10 +69,6 @@ func (c *PathHelpCommand) Run(args []string) int { return 1 } - if c.flagNoColor { - c.UI = getBasicUI(c.UI) - } - args = f.Args() switch { case len(args) < 1: diff --git a/command/policies_deprecated.go b/command/policies_deprecated.go index 3f57572dd6f8..427efa9bc04c 100644 --- a/command/policies_deprecated.go +++ b/command/policies_deprecated.go @@ -30,10 +30,6 @@ func (c *PoliciesDeprecatedCommand) Run(args []string) int { return 1 } - if c.flagNoColor { - c.UI = getBasicUI(c.UI) - } - args = f.Args() // Got an arg, this is trying to read a policy diff --git a/command/policy_delete.go b/command/policy_delete.go index 808b458de80c..e74030640f69 100644 --- a/command/policy_delete.go +++ b/command/policy_delete.go @@ -58,10 +58,6 @@ func (c *PolicyDeleteCommand) Run(args []string) int { return 1 } - if c.flagNoColor { - c.UI = getBasicUI(c.UI) - } - args = f.Args() switch { case len(args) < 1: diff --git a/command/policy_fmt.go b/command/policy_fmt.go index c12e9e904293..01bde16e60b5 100644 --- a/command/policy_fmt.go +++ b/command/policy_fmt.go @@ -60,10 +60,6 @@ func (c *PolicyFmtCommand) Run(args []string) int { return 1 } - if c.flagNoColor { - c.UI = getBasicUI(c.UI) - } - args = f.Args() switch { case len(args) < 1: diff --git a/command/policy_list.go b/command/policy_list.go index 4d70bfb6c2ca..c1412b00c5fc 100644 --- a/command/policy_list.go +++ b/command/policy_list.go @@ -50,10 +50,6 @@ func (c *PolicyListCommand) Run(args []string) int { return 1 } - if c.flagNoColor { - c.UI = getBasicUI(c.UI) - } - args = f.Args() switch { case len(args) > 0: diff --git a/command/policy_read.go b/command/policy_read.go index e6ad5bcf41ee..f32038c10660 100644 --- a/command/policy_read.go +++ b/command/policy_read.go @@ -55,10 +55,6 @@ func (c *PolicyReadCommand) Run(args []string) int { return 1 } - if c.flagNoColor { - c.UI = getBasicUI(c.UI) - } - args = f.Args() switch { case len(args) < 1: diff --git a/command/policy_write.go b/command/policy_write.go index 77f3abee4e23..9f6cb2222d56 100644 --- a/command/policy_write.go +++ b/command/policy_write.go @@ -72,10 +72,6 @@ func (c *PolicyWriteCommand) Run(args []string) int { return 1 } - if c.flagNoColor { - c.UI = getBasicUI(c.UI) - } - args = f.Args() switch { case len(args) < 2: diff --git a/command/read.go b/command/read.go index 2f43597371ee..6dc2b5337bc7 100644 --- a/command/read.go +++ b/command/read.go @@ -58,10 +58,6 @@ func (c *ReadCommand) Run(args []string) int { return 1 } - if c.flagNoColor { - c.UI = getBasicUI(c.UI) - } - args = f.Args() switch { case len(args) < 1: diff --git a/command/rotate.go b/command/rotate.go index 231c5c619247..bdc5ad8f0b6d 100644 --- a/command/rotate.go +++ b/command/rotate.go @@ -63,10 +63,6 @@ func (c *OperatorRotateCommand) Run(args []string) int { return 1 } - if c.flagNoColor { - c.UI = getBasicUI(c.UI) - } - args = f.Args() if len(args) > 0 { c.UI.Error(fmt.Sprintf("Too many arguments (expected 0, got %d)", len(args))) diff --git a/command/secrets_disable.go b/command/secrets_disable.go index d17dd8b5611e..7002874409c5 100644 --- a/command/secrets_disable.go +++ b/command/secrets_disable.go @@ -56,10 +56,6 @@ func (c *SecretsDisableCommand) Run(args []string) int { return 1 } - if c.flagNoColor { - c.UI = getBasicUI(c.UI) - } - args = f.Args() switch { case len(args) < 1: diff --git a/command/secrets_enable.go b/command/secrets_enable.go index c999dd91b8c4..e31d77ec2456 100644 --- a/command/secrets_enable.go +++ b/command/secrets_enable.go @@ -155,10 +155,6 @@ func (c *SecretsEnableCommand) Run(args []string) int { return 1 } - if c.flagNoColor { - c.UI = getBasicUI(c.UI) - } - args = f.Args() switch { case len(args) < 1: diff --git a/command/secrets_list.go b/command/secrets_list.go index 3a38212a930f..ddb954db0461 100644 --- a/command/secrets_list.go +++ b/command/secrets_list.go @@ -78,10 +78,6 @@ func (c *SecretsListCommand) Run(args []string) int { return 1 } - if c.flagNoColor { - c.UI = getBasicUI(c.UI) - } - args = f.Args() if len(args) > 0 { c.UI.Error(fmt.Sprintf("Too many arguments (expected 0, got %d)", len(args))) diff --git a/command/secrets_move.go b/command/secrets_move.go index 04fa846ed023..542b14d3d26b 100644 --- a/command/secrets_move.go +++ b/command/secrets_move.go @@ -59,10 +59,6 @@ func (c *SecretsMoveCommand) Run(args []string) int { return 1 } - if c.flagNoColor { - c.UI = getBasicUI(c.UI) - } - args = f.Args() switch { case len(args) < 2: diff --git a/command/secrets_tune.go b/command/secrets_tune.go index 8a4c5d776731..b2029b7507d2 100644 --- a/command/secrets_tune.go +++ b/command/secrets_tune.go @@ -87,10 +87,6 @@ func (c *SecretsTuneCommand) Run(args []string) int { return 1 } - if c.flagNoColor { - c.UI = getBasicUI(c.UI) - } - args = f.Args() switch { case len(args) < 1: diff --git a/command/server.go b/command/server.go index c4e043bf98f2..2df9b77f6141 100644 --- a/command/server.go +++ b/command/server.go @@ -266,10 +266,6 @@ func (c *ServerCommand) Run(args []string) int { return 1 } - if c.flagNoColor { - c.UI = getBasicUI(c.UI) - } - // Create a logger. We wrap it in a gated writer so that it doesn't // start logging too early. c.logGate = &gatedwriter.Writer{Writer: colorable.NewColorable(os.Stderr)} diff --git a/command/ssh.go b/command/ssh.go index 3d0ee1f1ecb9..c35fbb9cfd99 100644 --- a/command/ssh.go +++ b/command/ssh.go @@ -220,10 +220,6 @@ func (c *SSHCommand) Run(args []string) int { return 1 } - if c.flagNoColor { - c.UI = getBasicUI(c.UI) - } - // Use homedir to expand any relative paths such as ~/.ssh c.flagUserKnownHostsFile = expandPath(c.flagUserKnownHostsFile) c.flagPublicKeyPath = expandPath(c.flagPublicKeyPath) diff --git a/command/status.go b/command/status.go index 9ab4a11c0def..54f9b6de8513 100644 --- a/command/status.go +++ b/command/status.go @@ -58,10 +58,6 @@ func (c *StatusCommand) Run(args []string) int { return 1 } - if c.flagNoColor { - c.UI = getBasicUI(c.UI) - } - args = f.Args() if len(args) > 0 { c.UI.Error(fmt.Sprintf("Too many arguments (expected 0, got %d)", len(args))) diff --git a/command/token_capabilities.go b/command/token_capabilities.go index 951179f9dc84..ad506ce42208 100644 --- a/command/token_capabilities.go +++ b/command/token_capabilities.go @@ -64,10 +64,6 @@ func (c *TokenCapabilitiesCommand) Run(args []string) int { return 1 } - if c.flagNoColor { - c.UI = getBasicUI(c.UI) - } - token := "" path := "" args = f.Args() diff --git a/command/token_create.go b/command/token_create.go index 75fb102d7b5d..a75a6066ff22 100644 --- a/command/token_create.go +++ b/command/token_create.go @@ -199,10 +199,6 @@ func (c *TokenCreateCommand) Run(args []string) int { return 1 } - if c.flagNoColor { - c.UI = getBasicUI(c.UI) - } - args = f.Args() if len(args) > 0 { c.UI.Error(fmt.Sprintf("Too many arguments (expected 0, got %d)", len(args))) diff --git a/command/token_lookup.go b/command/token_lookup.go index f418004eaffc..2c885eaee9bb 100644 --- a/command/token_lookup.go +++ b/command/token_lookup.go @@ -84,10 +84,6 @@ func (c *TokenLookupCommand) Run(args []string) int { return 1 } - if c.flagNoColor { - c.UI = getBasicUI(c.UI) - } - token := "" args = f.Args() diff --git a/command/token_renew.go b/command/token_renew.go index 53172012ec26..6505ce328dab 100644 --- a/command/token_renew.go +++ b/command/token_renew.go @@ -88,10 +88,6 @@ func (c *TokenRenewCommand) Run(args []string) int { return 1 } - if c.flagNoColor { - c.UI = getBasicUI(c.UI) - } - token := "" increment := c.flagIncrement diff --git a/command/token_revoke.go b/command/token_revoke.go index 7181b9c16c34..351ce639c32e 100644 --- a/command/token_revoke.go +++ b/command/token_revoke.go @@ -106,10 +106,6 @@ func (c *TokenRevokeCommand) Run(args []string) int { return 1 } - if c.flagNoColor { - c.UI = getBasicUI(c.UI) - } - args = f.Args() token := "" if len(args) > 0 { diff --git a/command/unwrap.go b/command/unwrap.go index b0f13f5328e0..824676838338 100644 --- a/command/unwrap.go +++ b/command/unwrap.go @@ -65,10 +65,6 @@ func (c *UnwrapCommand) Run(args []string) int { return 1 } - if c.flagNoColor { - c.UI = getBasicUI(c.UI) - } - args = f.Args() token := "" switch len(args) { diff --git a/command/write.go b/command/write.go index 11b23e332d49..ed25ba6ce72e 100644 --- a/command/write.go +++ b/command/write.go @@ -98,10 +98,6 @@ func (c *WriteCommand) Run(args []string) int { return 1 } - if c.flagNoColor { - c.UI = getBasicUI(c.UI) - } - args = f.Args() switch { case len(args) < 1: From 2cd9e8e632d1261ae33a2d58199a3b8c1af81060 Mon Sep 17 00:00:00 2001 From: Calvin Leung Huang Date: Wed, 7 Feb 2018 17:13:20 -0500 Subject: [PATCH 15/31] Fix compile --- command/base.go | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/command/base.go b/command/base.go index 8caa595a7a2c..95ced6181548 100644 --- a/command/base.go +++ b/command/base.go @@ -40,9 +40,8 @@ type BaseCommand struct { flagTLSSkipVerify bool flagWrapTTL time.Duration - flagFormat string - flagField string - flagNoColor bool + flagFormat string + flagField string tokenHelper token.TokenHelper @@ -244,7 +243,7 @@ func (c *BaseCommand) flagSet(bit FlagSetBit) *FlagSets { }) } - if bit&(FlagSetOutputField|FlagSetOutputFormat|FlagSetOutputNoColor) != 0 { + if bit&(FlagSetOutputField|FlagSetOutputFormat) != 0 { f := set.NewFlagSet("Output Options") if bit&FlagSetOutputField != 0 { From c9573ea3ee7631ffe4d7feb80829315a98eeca7e Mon Sep 17 00:00:00 2001 From: Calvin Leung Huang Date: Wed, 7 Feb 2018 17:18:59 -0500 Subject: [PATCH 16/31] Remove -no-color flag in main.go --- command/main.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/command/main.go b/command/main.go index b6fbfe5f32d9..6cc9d43da41c 100644 --- a/command/main.go +++ b/command/main.go @@ -23,10 +23,6 @@ func Run(args []string) int { args = []string{"version"} break } - - if arg == "-no-color" { - os.Setenv("VAULT_OUTPUT_NO_COLOR", "true") - } } // Calculate hidden commands from the deprecated ones From 7ecec6408a996f13370670805a42d4930c569ade Mon Sep 17 00:00:00 2001 From: Calvin Leung Huang Date: Wed, 7 Feb 2018 18:05:00 -0500 Subject: [PATCH 17/31] Add missing FlagSetOutputFormat --- command/operator_key_status.go | 2 +- command/rotate.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/command/operator_key_status.go b/command/operator_key_status.go index 3566d5e4974f..861a5040e4e9 100644 --- a/command/operator_key_status.go +++ b/command/operator_key_status.go @@ -32,7 +32,7 @@ Usage: vault operator key-status [options] } func (c *OperatorKeyStatusCommand) Flags() *FlagSets { - return c.flagSet(FlagSetHTTP) + return c.flagSet(FlagSetHTTP | FlagSetOutputFormat) } func (c *OperatorKeyStatusCommand) AutocompleteArgs() complete.Predictor { diff --git a/command/rotate.go b/command/rotate.go index bdc5ad8f0b6d..f3e3e88536b5 100644 --- a/command/rotate.go +++ b/command/rotate.go @@ -44,7 +44,7 @@ Usage: vault rotate [options] } func (c *OperatorRotateCommand) Flags() *FlagSets { - return c.flagSet(FlagSetHTTP) + return c.flagSet(FlagSetHTTP | FlagSetOutputFormat) } func (c *OperatorRotateCommand) AutocompleteArgs() complete.Predictor { From 189f8c9b981a4e8b63a03f029c7756154ded15a9 Mon Sep 17 00:00:00 2001 From: Calvin Leung Huang Date: Thu, 8 Feb 2018 11:32:43 -0500 Subject: [PATCH 18/31] Fix generate-root/decode test --- command/operator_generate_root_test.go | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/command/operator_generate_root_test.go b/command/operator_generate_root_test.go index ad5e67e23962..e940fdda4b79 100644 --- a/command/operator_generate_root_test.go +++ b/command/operator_generate_root_test.go @@ -2,6 +2,7 @@ package command import ( "io" + "os" "regexp" "strings" "testing" @@ -129,6 +130,14 @@ func TestOperatorGenerateRootCommand_Run(t *testing.T) { ui, cmd := testOperatorGenerateRootCommand(t) + // Simulate piped output to print raw output + old := os.Stdout + _, w, err := os.Pipe() + if err != nil { + t.Fatal(err) + } + os.Stdout = w + code := cmd.Run([]string{ "-decode", encoded, "-otp", otp, @@ -137,6 +146,9 @@ func TestOperatorGenerateRootCommand_Run(t *testing.T) { t.Errorf("expected %d to be %d", code, exp) } + w.Close() + os.Stdout = old + expected := "5b54841c-c705-e59c-c6e4-a22b48e4b2cf" combined := ui.OutputWriter.String() + ui.ErrorWriter.String() if combined != expected { From a7225da2fc966b1ff483268f05c1abd70dceaacf Mon Sep 17 00:00:00 2001 From: Jeff Mitchell Date: Thu, 8 Feb 2018 16:37:38 -0500 Subject: [PATCH 19/31] Migrate init functions to main.go --- command/commands.go | 30 +---------------------- command/main.go | 59 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 29 deletions(-) diff --git a/command/commands.go b/command/commands.go index a90637f7a93c..7003e7de84de 100644 --- a/command/commands.go +++ b/command/commands.go @@ -11,7 +11,6 @@ import ( "github.com/hashicorp/vault/physical" "github.com/hashicorp/vault/version" "github.com/mitchellh/cli" - "golang.org/x/crypto/ssh/terminal" "github.com/hashicorp/vault/builtin/logical/aws" "github.com/hashicorp/vault/builtin/logical/cassandra" @@ -170,34 +169,7 @@ func (c *DeprecatedCommand) warn() { var Commands map[string]cli.CommandFactory var DeprecatedCommands map[string]cli.CommandFactory -func init() { - var ui cli.Ui - var serverCmdUi cli.Ui - - ui = &cli.BasicUi{ - Writer: os.Stdout, - ErrorWriter: os.Stderr, - } - - serverCmdUi = &cli.BasicUi{ - Writer: os.Stdout, - } - - // Only use colored UI if stdoout is a tty, and EnvVaultCLINoColor is not set. - if terminal.IsTerminal(int(os.Stdout.Fd())) && os.Getenv(EnvVaultCLINoColor) == "" { - ui = &cli.ColoredUi{ - ErrorColor: cli.UiColorRed, - WarnColor: cli.UiColorYellow, - Ui: ui, - } - - serverCmdUi = &cli.ColoredUi{ - ErrorColor: cli.UiColorRed, - WarnColor: cli.UiColorYellow, - Ui: serverCmdUi, - } - } - +func initCommands(ui, serverCmdUi cli.Ui) { loginHandlers := map[string]LoginHandler{ "aws": &credAws.CLIHandler{}, "centrify": &credCentrify.CLIHandler{}, diff --git a/command/main.go b/command/main.go index 6cc9d43da41c..82e687738170 100644 --- a/command/main.go +++ b/command/main.go @@ -10,9 +10,25 @@ import ( "text/tabwriter" "github.com/mitchellh/cli" + "golang.org/x/crypto/ssh/terminal" ) +type VaultUI struct { + cli.Ui + isTerminal bool +} + +func (u *VaultUI) Output(m string) { + if u.isTerminal { + u.Ui.Output(m) + } else { + getWriterFromUI(u.Ui).Write([]byte(m)) + } +} + func Run(args []string) int { + color := true + // Handle -v shorthand for _, arg := range args { if arg == "--" { @@ -23,8 +39,51 @@ func Run(args []string) int { args = []string{"version"} break } + + /* + if arg == "-no-color" { + color = false + } + */ + } + + if os.Getenv(EnvVaultCLINoColor) != "" { + color = false + } + + isTerminal := terminal.IsTerminal(int(os.Stdout.Fd())) + + ui := &VaultUI{ + Ui: &cli.BasicUi{ + Writer: os.Stdout, + ErrorWriter: os.Stderr, + }, + isTerminal: isTerminal, + } + serverCmdUi := &VaultUI{ + Ui: &cli.BasicUi{ + Writer: os.Stdout, + }, + isTerminal: isTerminal, + } + + // Only use colored UI if stdoout is a tty, and not disabled + if isTerminal && color { + ui.Ui = &cli.ColoredUi{ + ErrorColor: cli.UiColorRed, + WarnColor: cli.UiColorYellow, + Ui: ui.Ui, + } + + serverCmdUi.Ui = &cli.ColoredUi{ + ErrorColor: cli.UiColorRed, + WarnColor: cli.UiColorYellow, + Ui: serverCmdUi.Ui, + } } + initCommands(ui, serverCmdUi) + // Calculate hidden commands from the deprecated ones hiddenCommands := make([]string, 0, len(DeprecatedCommands)+1) for k := range DeprecatedCommands { From 2b3f18d28289a79b59db7e66b96c4703d430a4b8 Mon Sep 17 00:00:00 2001 From: Jeff Mitchell Date: Thu, 8 Feb 2018 16:54:55 -0500 Subject: [PATCH 20/31] Add no-color flag back as hidden --- command/base.go | 14 ++++++++++++-- command/main.go | 8 +++----- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/command/base.go b/command/base.go index 7b814ca5ede3..f5350210c5ed 100644 --- a/command/base.go +++ b/command/base.go @@ -40,8 +40,9 @@ type BaseCommand struct { flagTLSSkipVerify bool flagWrapTTL time.Duration - flagFormat string - flagField string + flagFormat string + flagField string + flagNoColor bool tokenHelper token.TokenHelper @@ -242,6 +243,15 @@ func (c *BaseCommand) flagSet(bit FlagSetBit) *FlagSets { "The TTL is specified as a numeric string with suffix like \"30s\" " + "or \"5m\".", }) + + f.BoolVar(&BoolVar{ + Name: "no-color", + Target: &c.flagNoColor, + Default: false, + Hidden: true, + EnvVar: EnvVaultCLINoColor, + Usage: "Print the output without ANSI color escape sequences.", + }) } if bit&(FlagSetOutputField|FlagSetOutputFormat) != 0 { diff --git a/command/main.go b/command/main.go index 82e687738170..9cde9d80aba4 100644 --- a/command/main.go +++ b/command/main.go @@ -40,11 +40,9 @@ func Run(args []string) int { break } - /* - if arg == "-no-color" { - color = false - } - */ + if arg == "-no-color" { + color = false + } } if os.Getenv(EnvVaultCLINoColor) != "" { From 63d4957ad47b45c75052c31e976512069655aa28 Mon Sep 17 00:00:00 2001 From: Calvin Leung Huang Date: Fri, 9 Feb 2018 11:10:01 -0500 Subject: [PATCH 21/31] Handle non-supported data types for TableFormatter.OutputList --- command/format.go | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/command/format.go b/command/format.go index c49bc8001ecd..feaf81e0c41a 100644 --- a/command/format.go +++ b/command/format.go @@ -42,10 +42,6 @@ func OutputWithFormat(ui cli.Ui, format string, data interface{}) int { switch data.(type) { case *api.Secret: secret := data.(*api.Secret) - // Best-guess effort that is this a list, so parse out the keys - if listVals, ok := secret.Data["keys"]; ok { - return outputWithFormat(ui, format, secret, listVals) - } return outputWithFormat(ui, format, secret, secret) default: return outputWithFormat(ui, format, nil, data) @@ -133,6 +129,8 @@ func (t TableFormatter) OutputList(ui cli.Ui, secret *api.Secret, data interface case []string: ui.Output(tableOutput(data.([]string), nil)) return nil + default: + return errors.New("Error: table formatter cannot output list for this data type") } list := data.([]interface{}) From 4ff62dd1a7b79b50953bbb0a245a31be172dd640 Mon Sep 17 00:00:00 2001 From: Jeff Mitchell Date: Fri, 9 Feb 2018 11:45:02 -0500 Subject: [PATCH 22/31] Pull formatting much further up to remove the need to use c.flagFormat (#3950) * Pull formatting much further up to remove the need to use c.flagFormat Also remove OutputWithFormat as the logic can cause issues. * Use const for env var --- command/audit_list.go | 10 ++++---- command/auth_list.go | 10 ++++---- command/base.go | 2 +- command/commands.go | 8 +++++-- command/format.go | 38 +++++++++++++++---------------- command/lease_renew.go | 2 +- command/list.go | 4 ++-- command/login.go | 8 +++---- command/main.go | 28 +++++++++++++++++++++-- command/operator_generate_root.go | 12 +++++----- command/operator_init.go | 4 ++-- command/operator_key_status.go | 4 ++-- command/operator_rekey.go | 14 +++++++----- command/operator_unseal.go | 4 ++-- command/policy_list.go | 10 ++++---- command/policy_read.go | 4 ++-- command/read.go | 2 +- command/rotate.go | 4 ++-- command/secrets_list.go | 10 ++++---- command/ssh.go | 12 +++++----- command/status.go | 2 +- command/token_capabilities.go | 4 ++-- command/token_create.go | 2 +- command/token_lookup.go | 2 +- command/token_renew.go | 2 +- command/unwrap.go | 4 ++-- command/write.go | 4 ++-- 27 files changed, 123 insertions(+), 87 deletions(-) diff --git a/command/audit_list.go b/command/audit_list.go index a1a70abaa6c9..8437dabb51c7 100644 --- a/command/audit_list.go +++ b/command/audit_list.go @@ -99,14 +99,16 @@ func (c *AuditListCommand) Run(args []string) int { return 0 } - switch c.flagFormat { + switch Format() { case "table": if c.flagDetailed { - return OutputWithFormat(c.UI, c.flagFormat, c.detailedAudits(audits)) + c.UI.Output(tableOutput(c.detailedAudits(audits), nil)) + return 0 } - return OutputWithFormat(c.UI, c.flagFormat, c.simpleAudits(audits)) + c.UI.Output(tableOutput(c.simpleAudits(audits), nil)) + return 0 default: - return OutputWithFormat(c.UI, c.flagFormat, audits) + return OutputData(c.UI, audits) } } diff --git a/command/auth_list.go b/command/auth_list.go index 75f1fc4b6463..2e4b68040332 100644 --- a/command/auth_list.go +++ b/command/auth_list.go @@ -95,14 +95,16 @@ func (c *AuthListCommand) Run(args []string) int { return 2 } - switch c.flagFormat { + switch Format() { case "table": if c.flagDetailed { - return OutputWithFormat(c.UI, c.flagFormat, c.detailedMounts(auths)) + c.UI.Output(tableOutput(c.detailedMounts(auths), nil)) + return 0 } - return OutputWithFormat(c.UI, c.flagFormat, c.simpleMounts(auths)) + c.UI.Output(tableOutput(c.simpleMounts(auths), nil)) + return 0 default: - return OutputWithFormat(c.UI, c.flagFormat, auths) + return OutputData(c.UI, auths) } } diff --git a/command/base.go b/command/base.go index f5350210c5ed..98b10394797f 100644 --- a/command/base.go +++ b/command/base.go @@ -275,7 +275,7 @@ func (c *BaseCommand) flagSet(bit FlagSetBit) *FlagSets { Name: "format", Target: &c.flagFormat, Default: "table", - EnvVar: "VAULT_FORMAT", + EnvVar: EnvVaultFormat, Completion: complete.PredictSet("table", "json", "yaml"), Usage: "Print the output in the given format. Valid formats " + "are \"table\", \"json\", or \"yaml\".", diff --git a/command/commands.go b/command/commands.go index 7003e7de84de..93f3c99d406d 100644 --- a/command/commands.go +++ b/command/commands.go @@ -64,8 +64,12 @@ import ( physZooKeeper "github.com/hashicorp/vault/physical/zookeeper" ) -// EnvVaultCLINoColor is an env var that toggles colored UI output. -const EnvVaultCLINoColor = `VAULT_CLI_NO_COLOR` +const ( + // EnvVaultCLINoColor is an env var that toggles colored UI output. + EnvVaultCLINoColor = `VAULT_CLI_NO_COLOR` + // EnvVaultFormat is the output format + EnvVaultFormat = `VAULT_FORMAT` +) var ( auditBackends = map[string]audit.Factory{ diff --git a/command/format.go b/command/format.go index feaf81e0c41a..02a6dbad8f09 100644 --- a/command/format.go +++ b/command/format.go @@ -4,6 +4,7 @@ import ( "encoding/json" "errors" "fmt" + "os" "sort" "strings" @@ -23,35 +24,28 @@ type FormatOptions struct { Format string } -func OutputSecret(ui cli.Ui, format string, secret *api.Secret) int { - return outputWithFormat(ui, format, secret, secret) +func OutputSecret(ui cli.Ui, secret *api.Secret) int { + return outputWithFormat(ui, secret, secret) } -func OutputList(ui cli.Ui, format string, data interface{}) int { +func OutputList(ui cli.Ui, data interface{}) int { switch data.(type) { case *api.Secret: secret := data.(*api.Secret) - return outputWithFormat(ui, format, secret, secret.Data["keys"]) + return outputWithFormat(ui, secret, secret.Data["keys"]) default: - return outputWithFormat(ui, format, nil, data) + return outputWithFormat(ui, nil, data) } } -// OutputWithFormat supports printing arbitrary data under a specified format. -func OutputWithFormat(ui cli.Ui, format string, data interface{}) int { - switch data.(type) { - case *api.Secret: - secret := data.(*api.Secret) - return outputWithFormat(ui, format, secret, secret) - default: - return outputWithFormat(ui, format, nil, data) - } +func OutputData(ui cli.Ui, data interface{}) int { + return outputWithFormat(ui, nil, data) } -func outputWithFormat(ui cli.Ui, format string, secret *api.Secret, data interface{}) int { - formatter, ok := Formatters[strings.ToLower(format)] +func outputWithFormat(ui cli.Ui, secret *api.Secret, data interface{}) int { + formatter, ok := Formatters[Format()] if !ok { - ui.Error(fmt.Sprintf("Invalid output format: %s", format)) + ui.Error(fmt.Sprintf("Invalid output format: %s", Format())) return 1 } @@ -80,6 +74,10 @@ var Formatters = map[string]Formatter{ "yml": YamlFormatter{}, } +func Format() string { + return os.Getenv(EnvVaultFormat) +} + // An output formatter for json output of an object type JsonFormatter struct{} @@ -244,11 +242,11 @@ func (t TableFormatter) OutputSecret(ui cli.Ui, secret *api.Secret) error { } // OutputSealStatus will print *api.SealStatusResponse in the CLI according to the format provided -func OutputSealStatus(ui cli.Ui, format string, client *api.Client, status *api.SealStatusResponse) int { - switch format { +func OutputSealStatus(ui cli.Ui, client *api.Client, status *api.SealStatusResponse) int { + switch Format() { case "table": default: - return OutputWithFormat(ui, format, status) + return OutputData(ui, status) } var sealPrefix string diff --git a/command/lease_renew.go b/command/lease_renew.go index 4dd2e1c573c0..c12f53d2e883 100644 --- a/command/lease_renew.go +++ b/command/lease_renew.go @@ -123,5 +123,5 @@ func (c *LeaseRenewCommand) Run(args []string) int { return 2 } - return OutputSecret(c.UI, c.flagFormat, secret) + return OutputSecret(c.UI, secret) } diff --git a/command/list.go b/command/list.go index ecfa0acb5646..151b46fc5b5e 100644 --- a/command/list.go +++ b/command/list.go @@ -89,7 +89,7 @@ func (c *ListCommand) Run(args []string) int { // If the secret is wrapped, return the wrapped response. if secret.WrapInfo != nil && secret.WrapInfo.TTL != 0 { - return OutputSecret(c.UI, c.flagFormat, secret) + return OutputSecret(c.UI, secret) } if _, ok := extractListData(secret); !ok { @@ -97,5 +97,5 @@ func (c *ListCommand) Run(args []string) int { return 2 } - return OutputList(c.UI, c.flagFormat, secret) + return OutputList(c.UI, secret) } diff --git a/command/login.go b/command/login.go index 564b893bb899..9272394722ae 100644 --- a/command/login.go +++ b/command/login.go @@ -274,7 +274,7 @@ func (c *LoginCommand) Run(args []string) int { return PrintRawField(c.UI, secret, "wrapping_token") } if c.flagNoStore { - return OutputSecret(c.UI, c.flagFormat, secret) + return OutputSecret(c.UI, secret) } } @@ -308,7 +308,7 @@ func (c *LoginCommand) Run(args []string) int { c.UI.Error(wrapAtLength( "Authentication was successful, but the token was not persisted. The "+ "resulting token is shown below for your records.") + "\n") - OutputSecret(c.UI, c.flagFormat, secret) + OutputSecret(c.UI, secret) return 2 } @@ -335,7 +335,7 @@ func (c *LoginCommand) Run(args []string) int { } // Print some yay! text, but only in table mode. - if c.flagFormat == "table" { + if Format() == "table" { c.UI.Output(wrapAtLength( "Success! You are now authenticated. The token information displayed "+ "below is already stored in the token helper. You do NOT need to run "+ @@ -343,7 +343,7 @@ func (c *LoginCommand) Run(args []string) int { "this token.") + "\n") } - return OutputSecret(c.UI, c.flagFormat, secret) + return OutputSecret(c.UI, secret) } // extractToken extracts the token from the given secret, automatically diff --git a/command/main.go b/command/main.go index 9cde9d80aba4..ee546a1d79bc 100644 --- a/command/main.go +++ b/command/main.go @@ -28,6 +28,7 @@ func (u *VaultUI) Output(m string) { func Run(args []string) int { color := true + var format string // Handle -v shorthand for _, arg := range args { @@ -43,9 +44,27 @@ func Run(args []string) int { if arg == "-no-color" { color = false } + + // Parse a given flag here, which overrides the env var + if strings.HasPrefix(arg, "-format=") { + format = strings.TrimPrefix(arg, "-format=") + } + } + + // If we did not parse a value, fetch the env var + if format == "" && os.Getenv(EnvVaultFormat) != "" { + format = os.Getenv(EnvVaultFormat) } + // Lowercase for consistency + format = strings.ToLower(format) + if format == "" { + format = "table" + } + // Put back into the env for later + os.Setenv(EnvVaultFormat, format) - if os.Getenv(EnvVaultCLINoColor) != "" { + // Don't use color if disabled or if the output isn't a table + if os.Getenv(EnvVaultCLINoColor) != "" || format != "table" { color = false } @@ -65,8 +84,13 @@ func Run(args []string) int { isTerminal: isTerminal, } + if _, ok := Formatters[format]; !ok { + ui.Error(fmt.Sprintf("Invalid output format: %s", format)) + return 1 + } + // Only use colored UI if stdoout is a tty, and not disabled - if isTerminal && color { + if isTerminal && color && format == "table" { ui.Ui = &cli.ColoredUi{ ErrorColor: cli.UiColorRed, WarnColor: cli.UiColorYellow, diff --git a/command/operator_generate_root.go b/command/operator_generate_root.go index 61c8d1d7a24e..e87077eae93c 100644 --- a/command/operator_generate_root.go +++ b/command/operator_generate_root.go @@ -338,11 +338,11 @@ func (c *OperatorGenerateRootCommand) init(client *api.Client, otp, pgpKey strin return 2 } - switch c.flagFormat { + switch Format() { case "table": return c.printStatus(status) default: - return OutputWithFormat(c.UI, c.flagFormat, status) + return OutputData(c.UI, status) } } @@ -434,11 +434,11 @@ func (c *OperatorGenerateRootCommand) provide(client *api.Client, key string, dr c.UI.Error(fmt.Sprintf("Error posting unseal key: %s", err)) return 2 } - switch c.flagFormat { + switch Format() { case "table": return c.printStatus(status) default: - return OutputWithFormat(c.UI, c.flagFormat, status) + return OutputData(c.UI, status) } } @@ -467,11 +467,11 @@ func (c *OperatorGenerateRootCommand) status(client *api.Client, drToken bool) i c.UI.Error(fmt.Sprintf("Error getting root generation status: %s", err)) return 2 } - switch c.flagFormat { + switch Format() { case "table": return c.printStatus(status) default: - return OutputWithFormat(c.UI, c.flagFormat, status) + return OutputData(c.UI, status) } } diff --git a/command/operator_init.go b/command/operator_init.go index 61f6ecfe2a24..a0fd3b0a3c29 100644 --- a/command/operator_init.go +++ b/command/operator_init.go @@ -432,10 +432,10 @@ func (c *OperatorInitCommand) init(client *api.Client, req *api.InitRequest) int return 2 } - switch c.flagFormat { + switch Format() { case "table": default: - return OutputWithFormat(c.UI, c.flagFormat, newMachineInit(req, resp)) + return OutputData(c.UI, newMachineInit(req, resp)) } for i, key := range resp.Keys { diff --git a/command/operator_key_status.go b/command/operator_key_status.go index 861a5040e4e9..4bb48df8842f 100644 --- a/command/operator_key_status.go +++ b/command/operator_key_status.go @@ -69,11 +69,11 @@ func (c *OperatorKeyStatusCommand) Run(args []string) int { return 2 } - switch c.flagFormat { + switch Format() { case "table": c.UI.Output(printKeyStatus(status)) return 0 default: - return OutputWithFormat(c.UI, c.flagFormat, status) + return OutputData(c.UI, status) } } diff --git a/command/operator_rekey.go b/command/operator_rekey.go index c41179a7d55e..93dbbc698098 100644 --- a/command/operator_rekey.go +++ b/command/operator_rekey.go @@ -534,7 +534,7 @@ func (c *OperatorRekeyCommand) backupRetrieve(client *api.Client) int { Data: structs.New(storedKeys).Map(), } - return OutputSecret(c.UI, c.flagFormat, secret) + return OutputSecret(c.UI, secret) } // backupDelete deletes the stored backup keys. @@ -563,6 +563,7 @@ func (c *OperatorRekeyCommand) backupDelete(client *api.Client) int { // printStatus dumps the status to output func (c *OperatorRekeyCommand) printStatus(status *api.RekeyStatusResponse) int { + // FIXME: make the table case do something more sane, possibly via stuffing these k/v into an api.Secret out := []string{} out = append(out, "Key | Value") out = append(out, fmt.Sprintf("Nonce | %s", status.Nonce)) @@ -579,19 +580,20 @@ func (c *OperatorRekeyCommand) printStatus(status *api.RekeyStatusResponse) int out = append(out, fmt.Sprintf("Backup | %t", status.Backup)) } - switch c.flagFormat { + switch Format() { case "table": - return OutputWithFormat(c.UI, c.flagFormat, out) + c.UI.Output(tableOutput(out, nil)) + return 0 default: - return OutputWithFormat(c.UI, c.flagFormat, status) + return OutputData(c.UI, status) } } func (c *OperatorRekeyCommand) printUnsealKeys(status *api.RekeyStatusResponse, resp *api.RekeyUpdateResponse) int { - switch c.flagFormat { + switch Format() { case "table": default: - return OutputWithFormat(c.UI, c.flagFormat, resp) + return OutputData(c.UI, resp) } // Space between the key prompt, if any, and the output diff --git a/command/operator_unseal.go b/command/operator_unseal.go index 120cc0f57557..c93a272ada2e 100644 --- a/command/operator_unseal.go +++ b/command/operator_unseal.go @@ -108,7 +108,7 @@ func (c *OperatorUnsealCommand) Run(args []string) int { c.UI.Error(fmt.Sprintf("Error resetting unseal process: %s", err)) return 2 } - return OutputSealStatus(c.UI, c.flagFormat, client, status) + return OutputSealStatus(c.UI, client, status) } if unsealKey == "" { @@ -141,5 +141,5 @@ func (c *OperatorUnsealCommand) Run(args []string) int { return 2 } - return OutputSealStatus(c.UI, c.flagFormat, client, status) + return OutputSealStatus(c.UI, client, status) } diff --git a/command/policy_list.go b/command/policy_list.go index c1412b00c5fc..34f53913d092 100644 --- a/command/policy_list.go +++ b/command/policy_list.go @@ -69,11 +69,13 @@ func (c *PolicyListCommand) Run(args []string) int { return 2 } - switch c.flagFormat { + switch Format() { case "table": - out := append([]string{"Policies"}, policies...) - return OutputWithFormat(c.UI, c.flagFormat, out) + for _, p := range policies { + c.UI.Output(p) + } + return 0 default: - return OutputWithFormat(c.UI, c.flagFormat, policies) + return OutputData(c.UI, policies) } } diff --git a/command/policy_read.go b/command/policy_read.go index f32038c10660..64e53f3a06ac 100644 --- a/command/policy_read.go +++ b/command/policy_read.go @@ -82,7 +82,7 @@ func (c *PolicyReadCommand) Run(args []string) int { return 2 } - switch c.flagFormat { + switch Format() { case "table": c.UI.Output(strings.TrimSpace(rules)) return 0 @@ -90,6 +90,6 @@ func (c *PolicyReadCommand) Run(args []string) int { resp := map[string]string{ "policy": rules, } - return OutputWithFormat(c.UI, c.flagFormat, &resp) + return OutputData(c.UI, &resp) } } diff --git a/command/read.go b/command/read.go index 6dc2b5337bc7..47d8e707444b 100644 --- a/command/read.go +++ b/command/read.go @@ -90,5 +90,5 @@ func (c *ReadCommand) Run(args []string) int { return PrintRawField(c.UI, secret, c.flagField) } - return OutputSecret(c.UI, c.flagFormat, secret) + return OutputSecret(c.UI, secret) } diff --git a/command/rotate.go b/command/rotate.go index f3e3e88536b5..3f2b6d12f7ff 100644 --- a/command/rotate.go +++ b/command/rotate.go @@ -89,13 +89,13 @@ func (c *OperatorRotateCommand) Run(args []string) int { return 2 } - switch c.flagFormat { + switch Format() { case "table": c.UI.Output("Success! Rotated key") c.UI.Output("") c.UI.Output(printKeyStatus(status)) return 0 default: - return OutputWithFormat(c.UI, c.flagFormat, status) + return OutputData(c.UI, status) } } diff --git a/command/secrets_list.go b/command/secrets_list.go index ddb954db0461..77b6b8d4e0e6 100644 --- a/command/secrets_list.go +++ b/command/secrets_list.go @@ -96,14 +96,16 @@ func (c *SecretsListCommand) Run(args []string) int { return 2 } - switch c.flagFormat { + switch Format() { case "table": if c.flagDetailed { - return OutputWithFormat(c.UI, c.flagFormat, c.detailedMounts(mounts)) + c.UI.Output(tableOutput(c.detailedMounts(mounts), nil)) + return 0 } - return OutputWithFormat(c.UI, c.flagFormat, c.simpleMounts(mounts)) + c.UI.Output(tableOutput(c.simpleMounts(mounts), nil)) + return 0 default: - return OutputWithFormat(c.UI, c.flagFormat, mounts) + return OutputData(c.UI, mounts) } } diff --git a/command/ssh.go b/command/ssh.go index 8d2922cecda3..7e2d99de3760 100644 --- a/command/ssh.go +++ b/command/ssh.go @@ -370,10 +370,10 @@ func (c *SSHCommand) handleTypeCA(username, ip string, sshArgs []string) int { // Handle no-exec if c.flagNoExec { - if c.flagFormat != "" { + if Format() != "table" { return PrintRawField(c.UI, secret, c.flagField) } - return OutputSecret(c.UI, c.flagFormat, secret) + return OutputSecret(c.UI, secret) } // Extract public key @@ -474,10 +474,10 @@ func (c *SSHCommand) handleTypeOTP(username, ip string, sshArgs []string) int { // Handle no-exec if c.flagNoExec { - if c.flagFormat != "" { + if Format() != "table" { return PrintRawField(c.UI, secret, c.flagField) } - return OutputSecret(c.UI, c.flagFormat, secret) + return OutputSecret(c.UI, secret) } var cmd *exec.Cmd @@ -556,10 +556,10 @@ func (c *SSHCommand) handleTypeDynamic(username, ip string, sshArgs []string) in // Handle no-exec if c.flagNoExec { - if c.flagFormat != "" { + if Format() != "table" { return PrintRawField(c.UI, secret, c.flagField) } - return OutputSecret(c.UI, c.flagFormat, secret) + return OutputSecret(c.UI, secret) } // Write the dynamic key to disk diff --git a/command/status.go b/command/status.go index 54f9b6de8513..0e6be18f75aa 100644 --- a/command/status.go +++ b/command/status.go @@ -79,7 +79,7 @@ func (c *StatusCommand) Run(args []string) int { // Do not return the int here yet, since we may want to return a custom error // code depending on the seal status. - code := OutputSealStatus(c.UI, c.flagFormat, client, status) + code := OutputSealStatus(c.UI, client, status) if status.Sealed { return 2 diff --git a/command/token_capabilities.go b/command/token_capabilities.go index ad506ce42208..9d8fa70174bd 100644 --- a/command/token_capabilities.go +++ b/command/token_capabilities.go @@ -94,12 +94,12 @@ func (c *TokenCapabilitiesCommand) Run(args []string) int { return 2 } - switch c.flagFormat { + switch Format() { case "table": sort.Strings(capabilities) c.UI.Output(strings.Join(capabilities, ", ")) return 0 default: - return OutputWithFormat(c.UI, c.flagFormat, capabilities) + return OutputData(c.UI, capabilities) } } diff --git a/command/token_create.go b/command/token_create.go index a75a6066ff22..738030406ee8 100644 --- a/command/token_create.go +++ b/command/token_create.go @@ -246,5 +246,5 @@ func (c *TokenCreateCommand) Run(args []string) int { return PrintRawField(c.UI, secret, c.flagField) } - return OutputSecret(c.UI, c.flagFormat, secret) + return OutputSecret(c.UI, secret) } diff --git a/command/token_lookup.go b/command/token_lookup.go index 2c885eaee9bb..83b65f574e5c 100644 --- a/command/token_lookup.go +++ b/command/token_lookup.go @@ -124,5 +124,5 @@ func (c *TokenLookupCommand) Run(args []string) int { return 2 } - return OutputSecret(c.UI, c.flagFormat, secret) + return OutputSecret(c.UI, secret) } diff --git a/command/token_renew.go b/command/token_renew.go index 6505ce328dab..7e7f00775bc8 100644 --- a/command/token_renew.go +++ b/command/token_renew.go @@ -132,5 +132,5 @@ func (c *TokenRenewCommand) Run(args []string) int { return 2 } - return OutputSecret(c.UI, c.flagFormat, secret) + return OutputSecret(c.UI, secret) } diff --git a/command/unwrap.go b/command/unwrap.go index 824676838338..dbb8b46d17a9 100644 --- a/command/unwrap.go +++ b/command/unwrap.go @@ -100,7 +100,7 @@ func (c *UnwrapCommand) Run(args []string) int { // Check if the original was a list response and format as a list if _, ok := extractListData(secret); ok { - return OutputList(c.UI, c.flagFormat, secret) + return OutputList(c.UI, secret) } - return OutputSecret(c.UI, c.flagFormat, secret) + return OutputSecret(c.UI, secret) } diff --git a/command/write.go b/command/write.go index ed25ba6ce72e..8d017d6faefa 100644 --- a/command/write.go +++ b/command/write.go @@ -135,7 +135,7 @@ func (c *WriteCommand) Run(args []string) int { } if secret == nil { // Don't output anything unless using the "table" format - if c.flagFormat == "table" { + if Format() == "table" { c.UI.Info(fmt.Sprintf("Success! Data written to: %s", path)) } return 0 @@ -146,5 +146,5 @@ func (c *WriteCommand) Run(args []string) int { return PrintRawField(c.UI, secret, c.flagField) } - return OutputSecret(c.UI, c.flagFormat, secret) + return OutputSecret(c.UI, secret) } From 3ff53bc57097caaa618e1030646e602545c24d6e Mon Sep 17 00:00:00 2001 From: Jeff Mitchell Date: Fri, 9 Feb 2018 11:57:33 -0500 Subject: [PATCH 23/31] Minor updates --- command/auth_list.go | 3 ++- command/commands.go | 4 +++- command/format.go | 7 ------- command/operator_rekey.go | 1 - command/util.go | 13 ------------- 5 files changed, 5 insertions(+), 23 deletions(-) diff --git a/command/auth_list.go b/command/auth_list.go index 2e4b68040332..96d650b1c303 100644 --- a/command/auth_list.go +++ b/command/auth_list.go @@ -55,7 +55,8 @@ func (c *AuthListCommand) Flags() *FlagSets { Target: &c.flagDetailed, Default: false, Usage: "Print detailed information such as configuration and replication " + - "status about each auth method. This option is only applicable to table formatted output.", + "status about each auth method. This option is only applicable to " + + "table-formatted output.", }) return set diff --git a/command/commands.go b/command/commands.go index 93f3c99d406d..59f6d95cde5e 100644 --- a/command/commands.go +++ b/command/commands.go @@ -156,7 +156,9 @@ func (c *DeprecatedCommand) Help() string { // Run wraps the embedded Run command and prints a warning about deprecation. func (c *DeprecatedCommand) Run(args []string) int { - c.warn() + if Format() == "table" { + c.warn() + } return c.Command.Run(args) } diff --git a/command/format.go b/command/format.go index 02a6dbad8f09..39f3bab8eec4 100644 --- a/command/format.go +++ b/command/format.go @@ -49,13 +49,6 @@ func outputWithFormat(ui cli.Ui, secret *api.Secret, data interface{}) int { return 1 } - // Type-check formatter, and ignore colored UI if it's a non-table output - if _, ok := formatter.(TableFormatter); !ok { - // If we had a colored UI, pull out the nested ui so we don't add escape - // sequences for outputting json, etc. - ui = getBasicUI(ui) - } - if err := formatter.Output(ui, secret, data); err != nil { ui.Error(fmt.Sprintf("Could not parse output: %s", err.Error())) return 1 diff --git a/command/operator_rekey.go b/command/operator_rekey.go index 93dbbc698098..e2bc42511b1e 100644 --- a/command/operator_rekey.go +++ b/command/operator_rekey.go @@ -563,7 +563,6 @@ func (c *OperatorRekeyCommand) backupDelete(client *api.Client) int { // printStatus dumps the status to output func (c *OperatorRekeyCommand) printStatus(status *api.RekeyStatusResponse) int { - // FIXME: make the table case do something more sane, possibly via stuffing these k/v into an api.Secret out := []string{} out = append(out, "Key | Value") out = append(out, fmt.Sprintf("Nonce | %s", status.Nonce)) diff --git a/command/util.go b/command/util.go index 462da78143b0..a51999205fe9 100644 --- a/command/util.go +++ b/command/util.go @@ -110,19 +110,6 @@ func PrintRaw(ui cli.Ui, str string) int { return 0 } -func getBasicUI(ui cli.Ui) cli.Ui { - switch t := ui.(type) { - case *cli.BasicUi: - return t - case *cli.ColoredUi: - return getBasicUI(t.Ui) - case *cli.ConcurrentUi: - return getBasicUI(t.Ui) - default: - return t - } -} - // getWriterFromUI accepts a cli.Ui and returns the underlying io.Writer by // unwrapping as many wrapped Uis as necessary. If there is an unknown UI // type, this falls back to os.Stdout. From a81c42e123e43e50ae05b36081026b0ceedc1de2 Mon Sep 17 00:00:00 2001 From: Jeff Mitchell Date: Fri, 9 Feb 2018 12:01:51 -0500 Subject: [PATCH 24/31] Remove unnecessary check --- command/main.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/command/main.go b/command/main.go index ee546a1d79bc..20a24977f2d4 100644 --- a/command/main.go +++ b/command/main.go @@ -63,8 +63,8 @@ func Run(args []string) int { // Put back into the env for later os.Setenv(EnvVaultFormat, format) - // Don't use color if disabled or if the output isn't a table - if os.Getenv(EnvVaultCLINoColor) != "" || format != "table" { + // Don't use color if disabled + if os.Getenv(EnvVaultCLINoColor) != "" { color = false } From 79992f3a6e0023c97b3b06e59c5a8940f017485e Mon Sep 17 00:00:00 2001 From: Jeff Mitchell Date: Fri, 9 Feb 2018 12:15:32 -0500 Subject: [PATCH 25/31] Fix SSH output and some tests --- command/format_test.go | 10 +++++++--- command/ssh.go | 6 +++--- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/command/format_test.go b/command/format_test.go index 44020a1aa663..fc9679b1d38e 100644 --- a/command/format_test.go +++ b/command/format_test.go @@ -1,6 +1,7 @@ package command import ( + "os" "strings" "testing" @@ -30,8 +31,9 @@ func (m mockUi) Error(s string) { m.t.Log(s) } func (m mockUi) Warn(s string) { m.t.Log(s) } func TestJsonFormatter(t *testing.T) { + os.Setenv(EnvVaultFormat, "json") ui := mockUi{t: t, SampleData: "something"} - if err := outputWithFormat(ui, "json", nil, ui); err != 0 { + if err := outputWithFormat(ui, nil, ui); err != 0 { t.Fatal(err) } var newUi mockUi @@ -46,8 +48,9 @@ func TestJsonFormatter(t *testing.T) { } func TestYamlFormatter(t *testing.T) { + os.Setenv(EnvVaultFormat, "yaml") ui := mockUi{t: t, SampleData: "something"} - if err := outputWithFormat(ui, "yaml", nil, ui); err != 0 { + if err := outputWithFormat(ui, nil, ui); err != 0 { t.Fatal(err) } var newUi mockUi @@ -63,9 +66,10 @@ func TestYamlFormatter(t *testing.T) { } func TestTableFormatter(t *testing.T) { + os.Setenv(EnvVaultFormat, "table") ui := mockUi{t: t} s := api.Secret{Data: map[string]interface{}{"k": "something"}} - if err := outputWithFormat(ui, "table", &s, &s); err != 0 { + if err := outputWithFormat(ui, &s, &s); err != 0 { t.Fatal(err) } if !strings.Contains(output, "something") { diff --git a/command/ssh.go b/command/ssh.go index 7e2d99de3760..4a9d40ee8c3e 100644 --- a/command/ssh.go +++ b/command/ssh.go @@ -370,7 +370,7 @@ func (c *SSHCommand) handleTypeCA(username, ip string, sshArgs []string) int { // Handle no-exec if c.flagNoExec { - if Format() != "table" { + if c.flagField != "" { return PrintRawField(c.UI, secret, c.flagField) } return OutputSecret(c.UI, secret) @@ -474,7 +474,7 @@ func (c *SSHCommand) handleTypeOTP(username, ip string, sshArgs []string) int { // Handle no-exec if c.flagNoExec { - if Format() != "table" { + if c.flagField != "" { return PrintRawField(c.UI, secret, c.flagField) } return OutputSecret(c.UI, secret) @@ -556,7 +556,7 @@ func (c *SSHCommand) handleTypeDynamic(username, ip string, sshArgs []string) in // Handle no-exec if c.flagNoExec { - if Format() != "table" { + if c.flagField != "" { return PrintRawField(c.UI, secret, c.flagField) } return OutputSecret(c.UI, secret) From 07cf36e76fb54790394ce0f4e743fb135e3b7bbe Mon Sep 17 00:00:00 2001 From: Jeff Mitchell Date: Fri, 9 Feb 2018 13:29:19 -0500 Subject: [PATCH 26/31] Fix tests --- command/format.go | 6 +++- command/format_test.go | 55 +++++++++++++++++++++++++++++++++ command/lease_renew_test.go | 12 ------- command/list_test.go | 18 ----------- command/main.go | 28 ++++++++++++++--- command/operator_unseal_test.go | 51 ++++++++++++++++-------------- command/read_test.go | 18 ----------- command/token_create_test.go | 16 ---------- command/token_lookup_test.go | 12 ------- command/token_renew_test.go | 12 ------- command/unwrap_test.go | 12 ------- 11 files changed, 112 insertions(+), 128 deletions(-) diff --git a/command/format.go b/command/format.go index 39f3bab8eec4..588317275d50 100644 --- a/command/format.go +++ b/command/format.go @@ -68,7 +68,11 @@ var Formatters = map[string]Formatter{ } func Format() string { - return os.Getenv(EnvVaultFormat) + format := os.Getenv(EnvVaultFormat) + if format == "" { + format = "table" + } + return format } // An output formatter for json output of an object diff --git a/command/format_test.go b/command/format_test.go index fc9679b1d38e..b97ca27315c6 100644 --- a/command/format_test.go +++ b/command/format_test.go @@ -76,3 +76,58 @@ func TestTableFormatter(t *testing.T) { t.Fatal("did not find 'something'") } } + +func Test_Format_Parsing(t *testing.T) { + defer func() { + os.Setenv(EnvVaultCLINoColor, "") + os.Setenv(EnvVaultFormat, "") + }() + + cases := []struct { + name string + args []string + out string + code int + }{ + { + "format", + []string{"-format", "json"}, + "{", + 0, + }, + { + "format_bad", + []string{"-format", "nope-not-real"}, + "Invalid output format", + 1, + }, + } + + for _, tc := range cases { + tc := tc + + t.Run(tc.name, func(t *testing.T) { + client, closer := testVaultServer(t) + defer closer() + + // Login with the token so we can renew-self. + token, _ := testTokenAndAccessor(t, client) + client.SetToken(token) + + ui, cmd := testTokenRenewCommand(t) + cmd.client = client + + tc.args = setupEnv(tc.args) + + code := cmd.Run(tc.args) + if code != tc.code { + t.Errorf("expected %d to be %d", code, tc.code) + } + + combined := ui.OutputWriter.String() + ui.ErrorWriter.String() + if !strings.Contains(combined, tc.out) { + t.Errorf("expected %q to contain %q", combined, tc.out) + } + }) + } +} diff --git a/command/lease_renew_test.go b/command/lease_renew_test.go index 166e5156be6b..aa3b32d0d8b3 100644 --- a/command/lease_renew_test.go +++ b/command/lease_renew_test.go @@ -74,18 +74,6 @@ func TestLeaseRenewCommand_Run(t *testing.T) { "foo", 0, }, - { - "format", - []string{"-format", "json"}, - "{", - 0, - }, - { - "format_bad", - []string{"-format", "nope-not-real"}, - "Invalid output format", - 1, - }, } t.Run("group", func(t *testing.T) { diff --git a/command/list_test.go b/command/list_test.go index e5a77c532bb1..375f9a82afb4 100644 --- a/command/list_test.go +++ b/command/list_test.go @@ -57,24 +57,6 @@ func TestListCommand_Run(t *testing.T) { "bar\nbaz\nfoo", 0, }, - { - "format", - []string{ - "-format", "json", - "secret/list/", - }, - "[", - 0, - }, - { - "format_bad", - []string{ - "-format", "nope-not-real", - "secret/list/", - }, - "Invalid output format", - 1, - }, } t.Run("validations", func(t *testing.T) { diff --git a/command/main.go b/command/main.go index 20a24977f2d4..e4ba19436d64 100644 --- a/command/main.go +++ b/command/main.go @@ -26,12 +26,19 @@ func (u *VaultUI) Output(m string) { } } -func Run(args []string) int { - color := true +// setupEnv parses args and may replace them and sets some env vars to known +// values based on color/format options +func setupEnv(args []string) []string { var format string + var nextArgFormat bool - // Handle -v shorthand for _, arg := range args { + if nextArgFormat { + nextArgFormat = false + format = arg + continue + } + if arg == "--" { break } @@ -42,13 +49,17 @@ func Run(args []string) int { } if arg == "-no-color" { - color = false + os.Setenv(EnvVaultCLINoColor, "true") } // Parse a given flag here, which overrides the env var if strings.HasPrefix(arg, "-format=") { format = strings.TrimPrefix(arg, "-format=") } + // For backwards compat, it could be specified without an equal sign + if arg == "-format" { + nextArgFormat = true + } } // If we did not parse a value, fetch the env var @@ -63,11 +74,20 @@ func Run(args []string) int { // Put back into the env for later os.Setenv(EnvVaultFormat, format) + return args +} + +func Run(args []string) int { + args = setupEnv(args) + // Don't use color if disabled + color := true if os.Getenv(EnvVaultCLINoColor) != "" { color = false } + format := Format() + isTerminal := terminal.IsTerminal(int(os.Stdout.Fd())) ui := &VaultUI{ diff --git a/command/operator_unseal_test.go b/command/operator_unseal_test.go index bcc8397e6dc2..aa6afe694307 100644 --- a/command/operator_unseal_test.go +++ b/command/operator_unseal_test.go @@ -3,6 +3,7 @@ package command import ( "encoding/json" "io/ioutil" + "os" "strings" "testing" @@ -138,33 +139,37 @@ func TestOperatorUnsealCommand_Run(t *testing.T) { _, cmd := testOperatorUnsealCommand(t) assertNoTabs(t, cmd) }) +} - t.Run("format", func(t *testing.T) { - t.Parallel() +func TestOperatorUnsealCommand_Format(t *testing.T) { + defer func() { + os.Setenv(EnvVaultFormat, "") + os.Setenv(EnvVaultCLINoColor, "") + }() - client, keys, closer := testVaultServerUnseal(t) - defer closer() + client, keys, closer := testVaultServerUnseal(t) + defer closer() - // Seal so we can unseal - if err := client.Sys().Seal(); err != nil { - t.Fatal(err) - } + // Seal so we can unseal + if err := client.Sys().Seal(); err != nil { + t.Fatal(err) + } - ui, cmd := testOperatorUnsealCommand(t) - cmd.client = client - cmd.testOutput = ioutil.Discard + ui, cmd := testOperatorUnsealCommand(t) + cmd.client = client + cmd.testOutput = ioutil.Discard - // Unseal with one key - code := cmd.Run([]string{ - "-format", "json", - keys[0], - }) - if exp := 0; code != exp { - t.Errorf("expected %d to be %d: %s", code, exp, ui.ErrorWriter.String()) - } + args := setupEnv([]string{"-format", "json"}) - if !json.Valid(ui.OutputWriter.Bytes()) { - t.Error("expected output to be valid JSON") - } - }) + // Unseal with one key + code := cmd.Run(append(args, []string{ + keys[0], + }...)) + if exp := 0; code != exp { + t.Errorf("expected %d to be %d: %s", code, exp, ui.ErrorWriter.String()) + } + + if !json.Valid(ui.OutputWriter.Bytes()) { + t.Error("expected output to be valid JSON") + } } diff --git a/command/read_test.go b/command/read_test.go index 1a45ed28a689..8e2c50f2d46f 100644 --- a/command/read_test.go +++ b/command/read_test.go @@ -69,24 +69,6 @@ func TestReadCommand_Run(t *testing.T) { "not present in secret", 1, }, - { - "format", - []string{ - "-format", "json", - "secret/read/foo", - }, - "{", - 0, - }, - { - "format_bad", - []string{ - "-format", "nope-not-real", - "secret/read/foo", - }, - "Invalid output format", - 1, - }, } t.Run("validations", func(t *testing.T) { diff --git a/command/token_create_test.go b/command/token_create_test.go index ec0cc79fb59a..1fd11b1e9f84 100644 --- a/command/token_create_test.go +++ b/command/token_create_test.go @@ -68,22 +68,6 @@ func TestTokenCreateCommand_Run(t *testing.T) { "not present in secret", 1, }, - { - "format", - []string{ - "-format", "json", - }, - "{", - 0, - }, - { - "format_bad", - []string{ - "-format", "nope-not-real", - }, - "Invalid output format", - 1, - }, } t.Run("validations", func(t *testing.T) { diff --git a/command/token_lookup_test.go b/command/token_lookup_test.go index eeeaefd2b335..e027b3f7c97b 100644 --- a/command/token_lookup_test.go +++ b/command/token_lookup_test.go @@ -45,18 +45,6 @@ func TestTokenLookupCommand_Run(t *testing.T) { "Too many arguments", 1, }, - { - "format", - []string{"-format", "json"}, - "{", - 0, - }, - { - "format_bad", - []string{"-format", "nope-not-real"}, - "Invalid output format", - 1, - }, } t.Run("validations", func(t *testing.T) { diff --git a/command/token_renew_test.go b/command/token_renew_test.go index 2c36412932de..4ed9a4d6dc47 100644 --- a/command/token_renew_test.go +++ b/command/token_renew_test.go @@ -53,18 +53,6 @@ func TestTokenRenewCommand_Run(t *testing.T) { "", 0, }, - { - "format", - []string{"-format", "json"}, - "{", - 0, - }, - { - "format_bad", - []string{"-format", "nope-not-real"}, - "Invalid output format", - 1, - }, } t.Run("validations", func(t *testing.T) { diff --git a/command/unwrap_test.go b/command/unwrap_test.go index 2d90d47d42d8..9da77a502639 100644 --- a/command/unwrap_test.go +++ b/command/unwrap_test.go @@ -65,18 +65,6 @@ func TestUnwrapCommand_Run(t *testing.T) { "not present in secret", 1, }, - { - "format", - []string{"-format", "json"}, - "{", - 0, - }, - { - "format_bad", - []string{"-format", "nope-not-real"}, - "Invalid output format", - 1, - }, } t.Run("validations", func(t *testing.T) { From 7982def98505ce33dc38e4e7c6f6ad2737d08042 Mon Sep 17 00:00:00 2001 From: Jeff Mitchell Date: Fri, 9 Feb 2018 16:39:27 -0500 Subject: [PATCH 27/31] Make race detector not run on generate root since it kills Travis these days --- command/operator_generate_root_test.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/command/operator_generate_root_test.go b/command/operator_generate_root_test.go index e940fdda4b79..5050218a3818 100644 --- a/command/operator_generate_root_test.go +++ b/command/operator_generate_root_test.go @@ -1,3 +1,5 @@ +// +build !race + package command import ( From 9ca29d3b3fabf69a40aa5db0068a93381447a48a Mon Sep 17 00:00:00 2001 From: Calvin Leung Huang Date: Fri, 9 Feb 2018 17:02:49 -0500 Subject: [PATCH 28/31] Update docs --- website/source/docs/commands/audit/list.html.md | 8 ++++++++ website/source/docs/commands/auth/list.html.md | 8 ++++++++ website/source/docs/commands/login.html.md | 4 ++-- .../docs/commands/operator/generate-root.html.md | 8 ++++++++ .../source/docs/commands/operator/key-status.html.md | 10 ++++++++-- website/source/docs/commands/operator/rekey.html.md | 8 +++++++- website/source/docs/commands/operator/rotate.html.md | 10 ++++++++-- website/source/docs/commands/operator/unseal.html.md | 8 ++++++++ website/source/docs/commands/policy/list.html.md | 11 +++++++++-- website/source/docs/commands/policy/read.html.md | 10 ++++++++-- website/source/docs/commands/read.html.md | 2 +- website/source/docs/commands/secrets/list.html.md | 8 ++++++++ website/source/docs/commands/ssh.html.md | 2 +- website/source/docs/commands/status.html.md | 10 ++++++++-- .../source/docs/commands/token/capabilities.html.md | 10 ++++++++-- website/source/docs/commands/token/create.html.md | 2 +- website/source/docs/commands/unwrap.html.md | 2 +- website/source/docs/commands/write.html.md | 2 +- 18 files changed, 103 insertions(+), 20 deletions(-) diff --git a/website/source/docs/commands/audit/list.html.md b/website/source/docs/commands/audit/list.html.md index cbcf0b3deb91..5b06227199e9 100644 --- a/website/source/docs/commands/audit/list.html.md +++ b/website/source/docs/commands/audit/list.html.md @@ -37,5 +37,13 @@ file/ file n/a replicated file_path=/var/log/audit.log The following flags are available in addition to the [standard set of flags](/docs/commands/index.html) included on all commands. +### Output Options + +- `-format` `(string: "table")` - Print the output in the given format. Valid + formats are "table", "json", or "yaml". This can also be specified via the + `VAULT_FORMAT` environment variable. + +### Command Options + - `-detailed` `(bool: false)` - Print detailed information such as options and replication status about each auth device. diff --git a/website/source/docs/commands/auth/list.html.md b/website/source/docs/commands/auth/list.html.md index 27d8d803639f..45b557c0fcf5 100644 --- a/website/source/docs/commands/auth/list.html.md +++ b/website/source/docs/commands/auth/list.html.md @@ -39,5 +39,13 @@ userpass/ userpass auth_userpass_eea6507e n/a system syst The following flags are available in addition to the [standard set of flags](/docs/commands/index.html) included on all commands. +### Output Options + +- `-format` `(string: "table")` - Print the output in the given format. Valid + formats are "table", "json", or "yaml". This can also be specified via the + `VAULT_FORMAT` environment variable. + +### Command Options + - `-detailed` `(bool: false)` - Print detailed information such as configuration and replication status about each auth method. diff --git a/website/source/docs/commands/login.html.md b/website/source/docs/commands/login.html.md index c3a1ddbb8fe9..800e49a37a20 100644 --- a/website/source/docs/commands/login.html.md +++ b/website/source/docs/commands/login.html.md @@ -89,13 +89,13 @@ flags](/docs/commands/index.html) included on all commands. - `-field` `(string: "")` - Print only the field with the given name. Specifying this option will take precedence over other formatting directives. The result - will not have a trailing newline making it idea for piping to other processes. + will not have a trailing newline making it ideal for piping to other processes. - `-format` `(string: "table")` - Print the output in the given format. Valid formats are "table", "json", or "yaml". This can also be specified via the `VAULT_FORMAT` environment variable. -## Command Options +### Command Options - `-method` `(string "token")` - Type of authentication to use such as "userpass" or "ldap". Note this corresponds to the TYPE, not the enabled path. diff --git a/website/source/docs/commands/operator/generate-root.html.md b/website/source/docs/commands/operator/generate-root.html.md index 70f0f6da2bd1..7965860fa531 100644 --- a/website/source/docs/commands/operator/generate-root.html.md +++ b/website/source/docs/commands/operator/generate-root.html.md @@ -55,6 +55,14 @@ $ vault operator generate-root -otp="..." The following flags are available in addition to the [standard set of flags](/docs/commands/index.html) included on all commands. +### Output Options + +- `-format` `(string: "table")` - Print the output in the given format. Valid + formats are "table", "json", or "yaml". This can also be specified via the + `VAULT_FORMAT` environment variable. + +### Command Options + - `-cancel` `(bool: false)` - Reset the root token generation progress. This will discard any submitted unseal keys or configuration. diff --git a/website/source/docs/commands/operator/key-status.html.md b/website/source/docs/commands/operator/key-status.html.md index 640235564089..7070a8227759 100644 --- a/website/source/docs/commands/operator/key-status.html.md +++ b/website/source/docs/commands/operator/key-status.html.md @@ -24,5 +24,11 @@ Install Time 01 Jan 17 12:30 UTC ## Usage -There are no flags beyond the [standard set of flags](/docs/commands/index.html) -included on all commands. +The following flags are available in addition to the [standard set of +flags](/docs/commands/index.html) included on all commands. + +### Output Options + +- `-format` `(string: "table")` - Print the output in the given format. Valid + formats are "table", "json", or "yaml". This can also be specified via the + `VAULT_FORMAT` environment variable. diff --git a/website/source/docs/commands/operator/rekey.html.md b/website/source/docs/commands/operator/rekey.html.md index 2635d0923b09..6ff0c493bd17 100644 --- a/website/source/docs/commands/operator/rekey.html.md +++ b/website/source/docs/commands/operator/rekey.html.md @@ -72,7 +72,13 @@ $ vault operator rekey -backup-delete The following flags are available in addition to the [standard set of flags](/docs/commands/index.html) included on all commands. -## Common Options +### Output Options + +- `-format` `(string: "table")` - Print the output in the given format. Valid + formats are "table", "json", or "yaml". This can also be specified via the + `VAULT_FORMAT` environment variable. + +### Command Options - `-cancel` `(bool: false)` - Reset the rekeying progress. This will discard any submitted unseal keys or configuration. The default is false. diff --git a/website/source/docs/commands/operator/rotate.html.md b/website/source/docs/commands/operator/rotate.html.md index 80f356e6559d..21b2dc4ce052 100644 --- a/website/source/docs/commands/operator/rotate.html.md +++ b/website/source/docs/commands/operator/rotate.html.md @@ -32,5 +32,11 @@ Install Time 01 May 17 10:30 UTC ## Usage -There are no flags beyond the [standard set of flags](/docs/commands/index.html) -included on all commands. +The following flags are available in addition to the [standard set of +flags](/docs/commands/index.html) included on all commands. + +### Output Options + +- `-format` `(string: "table")` - Print the output in the given format. Valid + formats are "table", "json", or "yaml". This can also be specified via the + `VAULT_FORMAT` environment variable. diff --git a/website/source/docs/commands/operator/unseal.html.md b/website/source/docs/commands/operator/unseal.html.md index ecdee34c6192..f036ac7d429d 100644 --- a/website/source/docs/commands/operator/unseal.html.md +++ b/website/source/docs/commands/operator/unseal.html.md @@ -50,5 +50,13 @@ Unseal Progress: 0 The following flags are available in addition to the [standard set of flags](/docs/commands/index.html) included on all commands. +### Output Options + +- `-format` `(string: "table")` - Print the output in the given format. Valid + formats are "table", "json", or "yaml". This can also be specified via the + `VAULT_FORMAT` environment variable. + +### Command Options + - `-reset` `(bool: false)` - Discard any previously entered keys to the unseal process. diff --git a/website/source/docs/commands/policy/list.html.md b/website/source/docs/commands/policy/list.html.md index 4ba30291f21f..b195a657e793 100644 --- a/website/source/docs/commands/policy/list.html.md +++ b/website/source/docs/commands/policy/list.html.md @@ -24,5 +24,12 @@ root ## Usage -There are no flags beyond the [standard set of flags](/docs/commands/index.html) -included on all commands. +The following flags are available in addition to the [standard set of +flags](/docs/commands/index.html) included on all commands. + +### Output Options + +- `-format` `(string: "table")` - Print the output in the given format. Valid + formats are "table", "json", or "yaml". This can also be specified via the + `VAULT_FORMAT` environment variable. + diff --git a/website/source/docs/commands/policy/read.html.md b/website/source/docs/commands/policy/read.html.md index 3f9e31956d9f..90912286275e 100644 --- a/website/source/docs/commands/policy/read.html.md +++ b/website/source/docs/commands/policy/read.html.md @@ -22,5 +22,11 @@ $ vault policy read my-policy ## Usage -There are no flags beyond the [standard set of flags](/docs/commands/index.html) -included on all commands. +The following flags are available in addition to the [standard set of +flags](/docs/commands/index.html) included on all commands. + +### Output Options + +- `-format` `(string: "table")` - Print the output in the given format. Valid + formats are "table", "json", or "yaml". This can also be specified via the + `VAULT_FORMAT` environment variable. diff --git a/website/source/docs/commands/read.html.md b/website/source/docs/commands/read.html.md index d37520ac171d..3d8ca690a61c 100644 --- a/website/source/docs/commands/read.html.md +++ b/website/source/docs/commands/read.html.md @@ -37,7 +37,7 @@ flags](/docs/commands/index.html) included on all commands. - `-field` `(string: "")` - Print only the field with the given name. Specifying this option will take precedence over other formatting directives. The result - will not have a trailing newline making it idea for piping to other processes. + will not have a trailing newline making it ideal for piping to other processes. - `-format` `(string: "table")` - Print the output in the given format. Valid formats are "table", "json", or "yaml". This can also be specified via the diff --git a/website/source/docs/commands/secrets/list.html.md b/website/source/docs/commands/secrets/list.html.md index ce8d6cb22923..4edf7fa369f8 100644 --- a/website/source/docs/commands/secrets/list.html.md +++ b/website/source/docs/commands/secrets/list.html.md @@ -45,5 +45,13 @@ sys/ system system_a9fd745d n/a n/a n/a The following flags are available in addition to the [standard set of flags](/docs/commands/index.html) included on all commands. +### Output Options + +- `-format` `(string: "table")` - Print the output in the given format. Valid + formats are "table", "json", or "yaml". This can also be specified via the + `VAULT_FORMAT` environment variable. + +### Command Options + - `-detailed` `(bool: false)` - Print detailed information such as configuration and replication status about each secrets engine. diff --git a/website/source/docs/commands/ssh.html.md b/website/source/docs/commands/ssh.html.md index 140e73146c7d..609c69f9a1f5 100644 --- a/website/source/docs/commands/ssh.html.md +++ b/website/source/docs/commands/ssh.html.md @@ -57,7 +57,7 @@ flags](/docs/commands/index.html) included on all commands. - `-field` `(string: "")` - Print only the field with the given name. Specifying this option will take precedence over other formatting directives. The result - will not have a trailing newline making it idea for piping to other processes. + will not have a trailing newline making it ideal for piping to other processes. - `-format` `(string: "table")` - Print the output in the given format. Valid formats are "table", "json", or "yaml". This can also be specified via the diff --git a/website/source/docs/commands/status.html.md b/website/source/docs/commands/status.html.md index abb2f2846a91..5ce352331ae1 100644 --- a/website/source/docs/commands/status.html.md +++ b/website/source/docs/commands/status.html.md @@ -40,5 +40,11 @@ High-Availability Enabled: false ## Usage -There are no flags beyond the [standard set of flags](/docs/commands/index.html) -included on all commands. +The following flags are available in addition to the [standard set of +flags](/docs/commands/index.html) included on all commands. + +### Output Options + +- `-format` `(string: "table")` - Print the output in the given format. Valid + formats are "table", "json", or "yaml". This can also be specified via the + `VAULT_FORMAT` environment variable. \ No newline at end of file diff --git a/website/source/docs/commands/token/capabilities.html.md b/website/source/docs/commands/token/capabilities.html.md index 393e801afb9f..9581478c3639 100644 --- a/website/source/docs/commands/token/capabilities.html.md +++ b/website/source/docs/commands/token/capabilities.html.md @@ -35,5 +35,11 @@ deny ## Usage -There are no flags beyond the [standard set of flags](/docs/commands/index.html) -included on all commands. +The following flags are available in addition to the [standard set of +flags](/docs/commands/index.html) included on all commands. + +### Output Options + +- `-format` `(string: "table")` - Print the output in the given format. Valid + formats are "table", "json", or "yaml". This can also be specified via the + `VAULT_FORMAT` environment variable. \ No newline at end of file diff --git a/website/source/docs/commands/token/create.html.md b/website/source/docs/commands/token/create.html.md index ea475ce648bd..6667cb50e6d6 100644 --- a/website/source/docs/commands/token/create.html.md +++ b/website/source/docs/commands/token/create.html.md @@ -64,7 +64,7 @@ flags](/docs/commands/index.html) included on all commands. - `-field` `(string: "")` - Print only the field with the given name. Specifying this option will take precedence over other formatting directives. The result - will not have a trailing newline making it idea for piping to other processes. + will not have a trailing newline making it ideal for piping to other processes. - `-format` `(string: "table")` - Print the output in the given format. Valid formats are "table", "json", or "yaml". This can also be specified via the diff --git a/website/source/docs/commands/unwrap.html.md b/website/source/docs/commands/unwrap.html.md index 55c3d0e29e98..2c4bea2062a9 100644 --- a/website/source/docs/commands/unwrap.html.md +++ b/website/source/docs/commands/unwrap.html.md @@ -39,7 +39,7 @@ flags](/docs/commands/index.html) included on all commands. - `-field` `(string: "")` - Print only the field with the given name. Specifying this option will take precedence over other formatting directives. The result - will not have a trailing newline making it idea for piping to other processes. + will not have a trailing newline making it ideal for piping to other processes. - `-format` `(string: "table")` - Print the output in the given format. Valid formats are "table", "json", or "yaml". This can also be specified via the diff --git a/website/source/docs/commands/write.html.md b/website/source/docs/commands/write.html.md index 1c6bb0bd60dc..c61a86a7704f 100644 --- a/website/source/docs/commands/write.html.md +++ b/website/source/docs/commands/write.html.md @@ -56,7 +56,7 @@ flags](/docs/commands/index.html) included on all commands. - `-field` `(string: "")` - Print only the field with the given name. Specifying this option will take precedence over other formatting directives. The result - will not have a trailing newline making it idea for piping to other processes. + will not have a trailing newline making it ideal for piping to other processes. - `-format` `(string: "table")` - Print the output in the given format. Valid formats are "table", "json", or "yaml". This can also be specified via the From 1583e23a7b09595311ab435ad455a724c09c5038 Mon Sep 17 00:00:00 2001 From: Calvin Leung Huang Date: Sat, 10 Feb 2018 15:33:35 -0500 Subject: [PATCH 29/31] Update docs --- website/source/docs/commands/index.html.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/website/source/docs/commands/index.html.md b/website/source/docs/commands/index.html.md index f9b218bf6553..95cf761e9ace 100644 --- a/website/source/docs/commands/index.html.md +++ b/website/source/docs/commands/index.html.md @@ -212,6 +212,10 @@ model](/docs/internals/security.html). Name to use as the SNI host when connecting via TLS. +### `VAULT_CLI_NO_COLOR` + +If provided, Vault output will not include ANSI color escape sequence characters. + ### `VAULT_MFA` **ENTERPRISE ONLY** From 9b62480eabc2531b5d0663aed4a3322b90fbaa8f Mon Sep 17 00:00:00 2001 From: Jeff Mitchell Date: Sun, 11 Feb 2018 17:07:24 -0500 Subject: [PATCH 30/31] Address review feedback --- command/audit_list.go | 2 +- command/auth_list.go | 2 +- command/base.go | 14 ++------------ command/commands.go | 4 ++-- command/format.go | 17 +++++++++++++---- command/login.go | 2 +- command/main.go | 14 +++++++------- command/operator_generate_root.go | 6 +++--- command/operator_init.go | 2 +- command/operator_key_status.go | 2 +- command/operator_rekey.go | 4 ++-- command/policy_list.go | 2 +- command/policy_read.go | 2 +- command/rotate.go | 2 +- command/secrets_list.go | 2 +- command/token_capabilities.go | 2 +- command/util.go | 2 ++ command/write.go | 2 +- 18 files changed, 42 insertions(+), 41 deletions(-) diff --git a/command/audit_list.go b/command/audit_list.go index 8437dabb51c7..3a88b908c012 100644 --- a/command/audit_list.go +++ b/command/audit_list.go @@ -99,7 +99,7 @@ func (c *AuditListCommand) Run(args []string) int { return 0 } - switch Format() { + switch Format(c.UI) { case "table": if c.flagDetailed { c.UI.Output(tableOutput(c.detailedAudits(audits), nil)) diff --git a/command/auth_list.go b/command/auth_list.go index 96d650b1c303..809540822c6e 100644 --- a/command/auth_list.go +++ b/command/auth_list.go @@ -96,7 +96,7 @@ func (c *AuthListCommand) Run(args []string) int { return 2 } - switch Format() { + switch Format(c.UI) { case "table": if c.flagDetailed { c.UI.Output(tableOutput(c.detailedMounts(auths), nil)) diff --git a/command/base.go b/command/base.go index 98b10394797f..26c62dd64fdb 100644 --- a/command/base.go +++ b/command/base.go @@ -40,9 +40,8 @@ type BaseCommand struct { flagTLSSkipVerify bool flagWrapTTL time.Duration - flagFormat string - flagField string - flagNoColor bool + flagFormat string + flagField string tokenHelper token.TokenHelper @@ -243,15 +242,6 @@ func (c *BaseCommand) flagSet(bit FlagSetBit) *FlagSets { "The TTL is specified as a numeric string with suffix like \"30s\" " + "or \"5m\".", }) - - f.BoolVar(&BoolVar{ - Name: "no-color", - Target: &c.flagNoColor, - Default: false, - Hidden: true, - EnvVar: EnvVaultCLINoColor, - Usage: "Print the output without ANSI color escape sequences.", - }) } if bit&(FlagSetOutputField|FlagSetOutputFormat) != 0 { diff --git a/command/commands.go b/command/commands.go index 59f6d95cde5e..c80c973a6348 100644 --- a/command/commands.go +++ b/command/commands.go @@ -156,7 +156,7 @@ func (c *DeprecatedCommand) Help() string { // Run wraps the embedded Run command and prints a warning about deprecation. func (c *DeprecatedCommand) Run(args []string) int { - if Format() == "table" { + if Format(c.UI) == "table" { c.warn() } return c.Command.Run(args) @@ -564,7 +564,7 @@ func initCommands(ui, serverCmdUi cli.Ui) { // Deprecated commands // - // TODO: Remove in 0.9.0 + // TODO: Remove not before 0.11.0 DeprecatedCommands = map[string]cli.CommandFactory{ "audit-disable": func() (cli.Command, error) { return &DeprecatedCommand{ diff --git a/command/format.go b/command/format.go index 588317275d50..76d018acd5ca 100644 --- a/command/format.go +++ b/command/format.go @@ -43,9 +43,10 @@ func OutputData(ui cli.Ui, data interface{}) int { } func outputWithFormat(ui cli.Ui, secret *api.Secret, data interface{}) int { - formatter, ok := Formatters[Format()] + format := Format(ui) + formatter, ok := Formatters[format] if !ok { - ui.Error(fmt.Sprintf("Invalid output format: %s", Format())) + ui.Error(fmt.Sprintf("Invalid output format: %s", format)) return 1 } @@ -67,7 +68,7 @@ var Formatters = map[string]Formatter{ "yml": YamlFormatter{}, } -func Format() string { +func format() string { format := os.Getenv(EnvVaultFormat) if format == "" { format = "table" @@ -75,6 +76,14 @@ func Format() string { return format } +func Format(ui cli.Ui) string { + switch ui.(type) { + case *VaultUI: + return ui.(*VaultUI).format + } + return format() +} + // An output formatter for json output of an object type JsonFormatter struct{} @@ -240,7 +249,7 @@ func (t TableFormatter) OutputSecret(ui cli.Ui, secret *api.Secret) error { // OutputSealStatus will print *api.SealStatusResponse in the CLI according to the format provided func OutputSealStatus(ui cli.Ui, client *api.Client, status *api.SealStatusResponse) int { - switch Format() { + switch Format(ui) { case "table": default: return OutputData(ui, status) diff --git a/command/login.go b/command/login.go index 9272394722ae..2aeb5f62e993 100644 --- a/command/login.go +++ b/command/login.go @@ -335,7 +335,7 @@ func (c *LoginCommand) Run(args []string) int { } // Print some yay! text, but only in table mode. - if Format() == "table" { + if Format(c.UI) == "table" { c.UI.Output(wrapAtLength( "Success! You are now authenticated. The token information displayed "+ "below is already stored in the token helper. You do NOT need to run "+ diff --git a/command/main.go b/command/main.go index e4ba19436d64..4226beb9a618 100644 --- a/command/main.go +++ b/command/main.go @@ -16,6 +16,7 @@ import ( type VaultUI struct { cli.Ui isTerminal bool + format string } func (u *VaultUI) Output(m string) { @@ -48,10 +49,6 @@ func setupEnv(args []string) []string { break } - if arg == "-no-color" { - os.Setenv(EnvVaultCLINoColor, "true") - } - // Parse a given flag here, which overrides the env var if strings.HasPrefix(arg, "-format=") { format = strings.TrimPrefix(arg, "-format=") @@ -62,9 +59,10 @@ func setupEnv(args []string) []string { } } + envVaultFormat := os.Getenv(EnvVaultFormat) // If we did not parse a value, fetch the env var - if format == "" && os.Getenv(EnvVaultFormat) != "" { - format = os.Getenv(EnvVaultFormat) + if format == "" && envVaultFormat != "" { + format = envVaultFormat } // Lowercase for consistency format = strings.ToLower(format) @@ -86,7 +84,7 @@ func Run(args []string) int { color = false } - format := Format() + format := format() isTerminal := terminal.IsTerminal(int(os.Stdout.Fd())) @@ -96,12 +94,14 @@ func Run(args []string) int { ErrorWriter: os.Stderr, }, isTerminal: isTerminal, + format: format, } serverCmdUi := &VaultUI{ Ui: &cli.BasicUi{ Writer: os.Stdout, }, isTerminal: isTerminal, + format: format, } if _, ok := Formatters[format]; !ok { diff --git a/command/operator_generate_root.go b/command/operator_generate_root.go index e87077eae93c..693aff3419b6 100644 --- a/command/operator_generate_root.go +++ b/command/operator_generate_root.go @@ -338,7 +338,7 @@ func (c *OperatorGenerateRootCommand) init(client *api.Client, otp, pgpKey strin return 2 } - switch Format() { + switch Format(c.UI) { case "table": return c.printStatus(status) default: @@ -434,7 +434,7 @@ func (c *OperatorGenerateRootCommand) provide(client *api.Client, key string, dr c.UI.Error(fmt.Sprintf("Error posting unseal key: %s", err)) return 2 } - switch Format() { + switch Format(c.UI) { case "table": return c.printStatus(status) default: @@ -467,7 +467,7 @@ func (c *OperatorGenerateRootCommand) status(client *api.Client, drToken bool) i c.UI.Error(fmt.Sprintf("Error getting root generation status: %s", err)) return 2 } - switch Format() { + switch Format(c.UI) { case "table": return c.printStatus(status) default: diff --git a/command/operator_init.go b/command/operator_init.go index a0fd3b0a3c29..07651148596b 100644 --- a/command/operator_init.go +++ b/command/operator_init.go @@ -432,7 +432,7 @@ func (c *OperatorInitCommand) init(client *api.Client, req *api.InitRequest) int return 2 } - switch Format() { + switch Format(c.UI) { case "table": default: return OutputData(c.UI, newMachineInit(req, resp)) diff --git a/command/operator_key_status.go b/command/operator_key_status.go index 4bb48df8842f..c5b61c8c0a8e 100644 --- a/command/operator_key_status.go +++ b/command/operator_key_status.go @@ -69,7 +69,7 @@ func (c *OperatorKeyStatusCommand) Run(args []string) int { return 2 } - switch Format() { + switch Format(c.UI) { case "table": c.UI.Output(printKeyStatus(status)) return 0 diff --git a/command/operator_rekey.go b/command/operator_rekey.go index e2bc42511b1e..972676fcf2bf 100644 --- a/command/operator_rekey.go +++ b/command/operator_rekey.go @@ -579,7 +579,7 @@ func (c *OperatorRekeyCommand) printStatus(status *api.RekeyStatusResponse) int out = append(out, fmt.Sprintf("Backup | %t", status.Backup)) } - switch Format() { + switch Format(c.UI) { case "table": c.UI.Output(tableOutput(out, nil)) return 0 @@ -589,7 +589,7 @@ func (c *OperatorRekeyCommand) printStatus(status *api.RekeyStatusResponse) int } func (c *OperatorRekeyCommand) printUnsealKeys(status *api.RekeyStatusResponse, resp *api.RekeyUpdateResponse) int { - switch Format() { + switch Format(c.UI) { case "table": default: return OutputData(c.UI, resp) diff --git a/command/policy_list.go b/command/policy_list.go index 34f53913d092..43bd5287da14 100644 --- a/command/policy_list.go +++ b/command/policy_list.go @@ -69,7 +69,7 @@ func (c *PolicyListCommand) Run(args []string) int { return 2 } - switch Format() { + switch Format(c.UI) { case "table": for _, p := range policies { c.UI.Output(p) diff --git a/command/policy_read.go b/command/policy_read.go index 64e53f3a06ac..d10a5d1027e7 100644 --- a/command/policy_read.go +++ b/command/policy_read.go @@ -82,7 +82,7 @@ func (c *PolicyReadCommand) Run(args []string) int { return 2 } - switch Format() { + switch Format(c.UI) { case "table": c.UI.Output(strings.TrimSpace(rules)) return 0 diff --git a/command/rotate.go b/command/rotate.go index 3f2b6d12f7ff..4eca04adf7c4 100644 --- a/command/rotate.go +++ b/command/rotate.go @@ -89,7 +89,7 @@ func (c *OperatorRotateCommand) Run(args []string) int { return 2 } - switch Format() { + switch Format(c.UI) { case "table": c.UI.Output("Success! Rotated key") c.UI.Output("") diff --git a/command/secrets_list.go b/command/secrets_list.go index 77b6b8d4e0e6..17f52fd9ad60 100644 --- a/command/secrets_list.go +++ b/command/secrets_list.go @@ -96,7 +96,7 @@ func (c *SecretsListCommand) Run(args []string) int { return 2 } - switch Format() { + switch Format(c.UI) { case "table": if c.flagDetailed { c.UI.Output(tableOutput(c.detailedMounts(mounts), nil)) diff --git a/command/token_capabilities.go b/command/token_capabilities.go index 9d8fa70174bd..68ec32af18a0 100644 --- a/command/token_capabilities.go +++ b/command/token_capabilities.go @@ -94,7 +94,7 @@ func (c *TokenCapabilitiesCommand) Run(args []string) int { return 2 } - switch Format() { + switch Format(c.UI) { case "table": sort.Strings(capabilities) c.UI.Output(strings.Join(capabilities, ", ")) diff --git a/command/util.go b/command/util.go index a51999205fe9..f6268d392771 100644 --- a/command/util.go +++ b/command/util.go @@ -115,6 +115,8 @@ func PrintRaw(ui cli.Ui, str string) int { // type, this falls back to os.Stdout. func getWriterFromUI(ui cli.Ui) io.Writer { switch t := ui.(type) { + case *VaultUI: + return getWriterFromUI(t.Ui) case *cli.BasicUi: return t.Writer case *cli.ColoredUi: diff --git a/command/write.go b/command/write.go index 8d017d6faefa..05766f83626f 100644 --- a/command/write.go +++ b/command/write.go @@ -135,7 +135,7 @@ func (c *WriteCommand) Run(args []string) int { } if secret == nil { // Don't output anything unless using the "table" format - if Format() == "table" { + if Format(c.UI) == "table" { c.UI.Info(fmt.Sprintf("Success! Data written to: %s", path)) } return 0 From d0e35e1e3e57ba01f5824ab666b28b654e783b96 Mon Sep 17 00:00:00 2001 From: Jeff Mitchell Date: Mon, 12 Feb 2018 18:04:42 -0500 Subject: [PATCH 31/31] Handle --format as well as -format --- command/main.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/command/main.go b/command/main.go index 4226beb9a618..824b80fa6cd2 100644 --- a/command/main.go +++ b/command/main.go @@ -28,7 +28,7 @@ func (u *VaultUI) Output(m string) { } // setupEnv parses args and may replace them and sets some env vars to known -// values based on color/format options +// values based on format options func setupEnv(args []string) []string { var format string var nextArgFormat bool @@ -50,11 +50,14 @@ func setupEnv(args []string) []string { } // Parse a given flag here, which overrides the env var + if strings.HasPrefix(arg, "--format=") { + format = strings.TrimPrefix(arg, "--format=") + } if strings.HasPrefix(arg, "-format=") { format = strings.TrimPrefix(arg, "-format=") } // For backwards compat, it could be specified without an equal sign - if arg == "-format" { + if arg == "-format" || arg == "--format" { nextArgFormat = true } }