mirror of
https://github.com/optim-enterprises-bv/vault.git
synced 2025-11-01 02:57:59 +00:00
Rename mounts to secrets engines and add the subcommand
This commit is contained in:
@@ -1,128 +0,0 @@
|
|||||||
package command
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/hashicorp/vault/api"
|
|
||||||
"github.com/mitchellh/cli"
|
|
||||||
"github.com/posener/complete"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Ensure we are implementing the right interfaces.
|
|
||||||
var _ cli.Command = (*MountTuneCommand)(nil)
|
|
||||||
var _ cli.CommandAutocomplete = (*MountTuneCommand)(nil)
|
|
||||||
|
|
||||||
// MountTuneCommand is a Command that remounts a mounted secret backend
|
|
||||||
// to a new endpoint.
|
|
||||||
type MountTuneCommand struct {
|
|
||||||
*BaseCommand
|
|
||||||
|
|
||||||
flagDefaultLeaseTTL time.Duration
|
|
||||||
flagMaxLeaseTTL time.Duration
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *MountTuneCommand) Synopsis() string {
|
|
||||||
return "Tunes an existing mount's configuration"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *MountTuneCommand) Help() string {
|
|
||||||
helpText := `
|
|
||||||
Usage: vault mount-tune [options] PATH
|
|
||||||
|
|
||||||
Tune the configuration options for a mounted secret backend at the given
|
|
||||||
path. The argument corresponds to the PATH of the mount, not the TYPE!
|
|
||||||
|
|
||||||
Tune the default lease for the PKI secret backend:
|
|
||||||
|
|
||||||
$ vault mount-tune -default-lease-ttl=72h pki/
|
|
||||||
|
|
||||||
For a full list of examples and paths, please see the documentation that
|
|
||||||
corresponds to the secret backend in use.
|
|
||||||
|
|
||||||
` + c.Flags().Help()
|
|
||||||
|
|
||||||
return strings.TrimSpace(helpText)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *MountTuneCommand) Flags() *FlagSets {
|
|
||||||
set := c.flagSet(FlagSetHTTP)
|
|
||||||
|
|
||||||
f := set.NewFlagSet("Command Options")
|
|
||||||
|
|
||||||
f.DurationVar(&DurationVar{
|
|
||||||
Name: "default-lease-ttl",
|
|
||||||
Target: &c.flagDefaultLeaseTTL,
|
|
||||||
Default: 0,
|
|
||||||
EnvVar: "",
|
|
||||||
Completion: complete.PredictAnything,
|
|
||||||
Usage: "The default lease TTL for this backend. If unspecified, this " +
|
|
||||||
"defaults to the Vault server's globally configured default lease TTL, " +
|
|
||||||
"or a previously configured value for the backend.",
|
|
||||||
})
|
|
||||||
|
|
||||||
f.DurationVar(&DurationVar{
|
|
||||||
Name: "max-lease-ttl",
|
|
||||||
Target: &c.flagMaxLeaseTTL,
|
|
||||||
Default: 0,
|
|
||||||
EnvVar: "",
|
|
||||||
Completion: complete.PredictAnything,
|
|
||||||
Usage: "The maximum lease TTL for this backend. If unspecified, this " +
|
|
||||||
"defaults to the Vault server's globally configured maximum lease TTL, " +
|
|
||||||
"or a previously configured value for the backend.",
|
|
||||||
})
|
|
||||||
|
|
||||||
return set
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *MountTuneCommand) AutocompleteArgs() complete.Predictor {
|
|
||||||
return c.PredictVaultMounts()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *MountTuneCommand) AutocompleteFlags() complete.Flags {
|
|
||||||
return c.Flags().Completions()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *MountTuneCommand) Run(args []string) int {
|
|
||||||
f := c.Flags()
|
|
||||||
|
|
||||||
if err := f.Parse(args); err != nil {
|
|
||||||
c.UI.Error(err.Error())
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
args = f.Args()
|
|
||||||
mountPath, remaining, err := extractPath(args)
|
|
||||||
if err != nil {
|
|
||||||
c.UI.Error(err.Error())
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(remaining) > 0 {
|
|
||||||
c.UI.Error(fmt.Sprintf("Too many arguments (expected 1, got %d)", len(args)))
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
client, err := c.Client()
|
|
||||||
if err != nil {
|
|
||||||
c.UI.Error(err.Error())
|
|
||||||
return 2
|
|
||||||
}
|
|
||||||
|
|
||||||
// Append a trailing slash to indicate it's a path in output
|
|
||||||
mountPath = ensureTrailingSlash(mountPath)
|
|
||||||
|
|
||||||
mountConfig := api.MountConfigInput{
|
|
||||||
DefaultLeaseTTL: c.flagDefaultLeaseTTL.String(),
|
|
||||||
MaxLeaseTTL: c.flagMaxLeaseTTL.String(),
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := client.Sys().TuneMount(mountPath, mountConfig); err != nil {
|
|
||||||
c.UI.Error(fmt.Sprintf("Error tuning mount %s: %s", mountPath, err))
|
|
||||||
return 2
|
|
||||||
}
|
|
||||||
|
|
||||||
c.UI.Output(fmt.Sprintf("Success! Tuned the mount at: %s", mountPath))
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
43
command/secrets.go
Normal file
43
command/secrets.go
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
package command
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/mitchellh/cli"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ cli.Command = (*SecretsCommand)(nil)
|
||||||
|
|
||||||
|
type SecretsCommand struct {
|
||||||
|
*BaseCommand
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *SecretsCommand) Synopsis() string {
|
||||||
|
return "Interact with secrets engines"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *SecretsCommand) Help() string {
|
||||||
|
helpText := `
|
||||||
|
Usage: vault secrets <subcommand> [options] [args]
|
||||||
|
|
||||||
|
This command groups subcommands for interacting with Vault's secrets engines.
|
||||||
|
Each secret engine behaves differently. Please see the documentation for
|
||||||
|
more information.
|
||||||
|
|
||||||
|
List all enabled secrets engines:
|
||||||
|
|
||||||
|
$ vault secrets list
|
||||||
|
|
||||||
|
Enable a new secrets engine:
|
||||||
|
|
||||||
|
$ vault secrets enable database
|
||||||
|
|
||||||
|
Please see the individual subcommand help for detailed usage information.
|
||||||
|
`
|
||||||
|
|
||||||
|
return strings.TrimSpace(helpText)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *SecretsCommand) Run(args []string) int {
|
||||||
|
return cli.RunResultHelp
|
||||||
|
}
|
||||||
84
command/secrets_disable.go
Normal file
84
command/secrets_disable.go
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
package command
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/mitchellh/cli"
|
||||||
|
"github.com/posener/complete"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ cli.Command = (*SecretsDisableCommand)(nil)
|
||||||
|
var _ cli.CommandAutocomplete = (*SecretsDisableCommand)(nil)
|
||||||
|
|
||||||
|
type SecretsDisableCommand struct {
|
||||||
|
*BaseCommand
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *SecretsDisableCommand) Synopsis() string {
|
||||||
|
return "Disable a secret engine"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *SecretsDisableCommand) Help() string {
|
||||||
|
helpText := `
|
||||||
|
Usage: vault secrets disable [options] PATH
|
||||||
|
|
||||||
|
Disables a secrets engine at the given PATH. The argument corresponds to
|
||||||
|
the enabled PATH of the engine, not the TYPE! All secrets created by this
|
||||||
|
engine are revoked and its Vault data is removed.
|
||||||
|
|
||||||
|
Disable the secrets engine enabled at aws/:
|
||||||
|
|
||||||
|
$ vault secrets disable aws/
|
||||||
|
|
||||||
|
` + c.Flags().Help()
|
||||||
|
|
||||||
|
return strings.TrimSpace(helpText)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *SecretsDisableCommand) Flags() *FlagSets {
|
||||||
|
return c.flagSet(FlagSetHTTP)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *SecretsDisableCommand) AutocompleteArgs() complete.Predictor {
|
||||||
|
return c.PredictVaultMounts()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *SecretsDisableCommand) AutocompleteFlags() complete.Flags {
|
||||||
|
return c.Flags().Completions()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *SecretsDisableCommand) Run(args []string) int {
|
||||||
|
f := c.Flags()
|
||||||
|
|
||||||
|
if err := f.Parse(args); err != nil {
|
||||||
|
c.UI.Error(err.Error())
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
args = f.Args()
|
||||||
|
switch {
|
||||||
|
case len(args) < 1:
|
||||||
|
c.UI.Error(fmt.Sprintf("Not enough arguments (expected 1, got %d)", len(args)))
|
||||||
|
return 1
|
||||||
|
case len(args) > 1:
|
||||||
|
c.UI.Error(fmt.Sprintf("Too many arguments (expected 1, got %d)", len(args)))
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
client, err := c.Client()
|
||||||
|
if err != nil {
|
||||||
|
c.UI.Error(err.Error())
|
||||||
|
return 2
|
||||||
|
}
|
||||||
|
|
||||||
|
path := ensureTrailingSlash(sanitizePath(args[0]))
|
||||||
|
|
||||||
|
if err := client.Sys().Unmount(path); err != nil {
|
||||||
|
c.UI.Error(fmt.Sprintf("Error disabling secrets engine at %s: %s", path, err))
|
||||||
|
return 2
|
||||||
|
}
|
||||||
|
|
||||||
|
c.UI.Output(fmt.Sprintf("Success! Disabled the secrets engine (if it existed) at: %s", path))
|
||||||
|
return 0
|
||||||
|
}
|
||||||
@@ -8,18 +8,18 @@ import (
|
|||||||
"github.com/mitchellh/cli"
|
"github.com/mitchellh/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
func testUnmountCommand(tb testing.TB) (*cli.MockUi, *UnmountCommand) {
|
func testSecretsDisableCommand(tb testing.TB) (*cli.MockUi, *SecretsDisableCommand) {
|
||||||
tb.Helper()
|
tb.Helper()
|
||||||
|
|
||||||
ui := cli.NewMockUi()
|
ui := cli.NewMockUi()
|
||||||
return ui, &UnmountCommand{
|
return ui, &SecretsDisableCommand{
|
||||||
BaseCommand: &BaseCommand{
|
BaseCommand: &BaseCommand{
|
||||||
UI: ui,
|
UI: ui,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUnmountCommand_Run(t *testing.T) {
|
func TestSecretsDisableCommand_Run(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
cases := []struct {
|
cases := []struct {
|
||||||
@@ -29,27 +29,27 @@ func TestUnmountCommand_Run(t *testing.T) {
|
|||||||
code int
|
code int
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
"empty",
|
"not_enough_args",
|
||||||
nil,
|
[]string{},
|
||||||
"Missing PATH!",
|
"Not enough arguments",
|
||||||
1,
|
1,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"slash",
|
"too_many_args",
|
||||||
[]string{"/"},
|
[]string{"foo", "bar"},
|
||||||
"Missing PATH!",
|
"Too many arguments",
|
||||||
1,
|
1,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"not_real",
|
"not_real",
|
||||||
[]string{"not_real"},
|
[]string{"not_real"},
|
||||||
"Success! Unmounted the secret backend (if it existed) at: not_real/",
|
"Success! Disabled the secrets engine (if it existed) at: not_real/",
|
||||||
0,
|
0,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"default",
|
"default",
|
||||||
[]string{"secret"},
|
[]string{"secret"},
|
||||||
"Success! Unmounted the secret backend (if it existed) at: secret/",
|
"Success! Disabled the secrets engine (if it existed) at: secret/",
|
||||||
0,
|
0,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -66,7 +66,7 @@ func TestUnmountCommand_Run(t *testing.T) {
|
|||||||
client, closer := testVaultServer(t)
|
client, closer := testVaultServer(t)
|
||||||
defer closer()
|
defer closer()
|
||||||
|
|
||||||
ui, cmd := testUnmountCommand(t)
|
ui, cmd := testSecretsDisableCommand(t)
|
||||||
cmd.client = client
|
cmd.client = client
|
||||||
|
|
||||||
code := cmd.Run(tc.args)
|
code := cmd.Run(tc.args)
|
||||||
@@ -88,23 +88,23 @@ func TestUnmountCommand_Run(t *testing.T) {
|
|||||||
client, closer := testVaultServer(t)
|
client, closer := testVaultServer(t)
|
||||||
defer closer()
|
defer closer()
|
||||||
|
|
||||||
if err := client.Sys().Mount("integration_unmount/", &api.MountInput{
|
if err := client.Sys().Mount("my-secret/", &api.MountInput{
|
||||||
Type: "generic",
|
Type: "generic",
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
ui, cmd := testUnmountCommand(t)
|
ui, cmd := testSecretsDisableCommand(t)
|
||||||
cmd.client = client
|
cmd.client = client
|
||||||
|
|
||||||
code := cmd.Run([]string{
|
code := cmd.Run([]string{
|
||||||
"integration_unmount/",
|
"my-secret/",
|
||||||
})
|
})
|
||||||
if exp := 0; code != exp {
|
if exp := 0; code != exp {
|
||||||
t.Errorf("expected %d to be %d", code, exp)
|
t.Errorf("expected %d to be %d", code, exp)
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := "Success! Unmounted the secret backend (if it existed) at: integration_unmount/"
|
expected := "Success! Disabled the secrets engine (if it existed) at: my-secret/"
|
||||||
combined := ui.OutputWriter.String() + ui.ErrorWriter.String()
|
combined := ui.OutputWriter.String() + ui.ErrorWriter.String()
|
||||||
if !strings.Contains(combined, expected) {
|
if !strings.Contains(combined, expected) {
|
||||||
t.Errorf("expected %q to contain %q", combined, expected)
|
t.Errorf("expected %q to contain %q", combined, expected)
|
||||||
@@ -126,7 +126,7 @@ func TestUnmountCommand_Run(t *testing.T) {
|
|||||||
client, closer := testVaultServerBad(t)
|
client, closer := testVaultServerBad(t)
|
||||||
defer closer()
|
defer closer()
|
||||||
|
|
||||||
ui, cmd := testUnmountCommand(t)
|
ui, cmd := testSecretsDisableCommand(t)
|
||||||
cmd.client = client
|
cmd.client = client
|
||||||
|
|
||||||
code := cmd.Run([]string{
|
code := cmd.Run([]string{
|
||||||
@@ -136,7 +136,7 @@ func TestUnmountCommand_Run(t *testing.T) {
|
|||||||
t.Errorf("expected %d to be %d", code, exp)
|
t.Errorf("expected %d to be %d", code, exp)
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := "Error unmounting pki/: "
|
expected := "Error disabling secrets engine at pki/: "
|
||||||
combined := ui.OutputWriter.String() + ui.ErrorWriter.String()
|
combined := ui.OutputWriter.String() + ui.ErrorWriter.String()
|
||||||
if !strings.Contains(combined, expected) {
|
if !strings.Contains(combined, expected) {
|
||||||
t.Errorf("expected %q to contain %q", combined, expected)
|
t.Errorf("expected %q to contain %q", combined, expected)
|
||||||
@@ -146,7 +146,7 @@ func TestUnmountCommand_Run(t *testing.T) {
|
|||||||
t.Run("no_tabs", func(t *testing.T) {
|
t.Run("no_tabs", func(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
_, cmd := testUnmountCommand(t)
|
_, cmd := testSecretsDisableCommand(t)
|
||||||
assertNoTabs(t, cmd)
|
assertNoTabs(t, cmd)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -10,12 +10,10 @@ import (
|
|||||||
"github.com/posener/complete"
|
"github.com/posener/complete"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Ensure we are implementing the right interfaces.
|
var _ cli.Command = (*SecretsEnableCommand)(nil)
|
||||||
var _ cli.Command = (*MountCommand)(nil)
|
var _ cli.CommandAutocomplete = (*SecretsEnableCommand)(nil)
|
||||||
var _ cli.CommandAutocomplete = (*MountCommand)(nil)
|
|
||||||
|
|
||||||
// MountCommand is a Command that mounts a new mount.
|
type SecretsEnableCommand struct {
|
||||||
type MountCommand struct {
|
|
||||||
*BaseCommand
|
*BaseCommand
|
||||||
|
|
||||||
flagDescription string
|
flagDescription string
|
||||||
@@ -27,45 +25,45 @@ type MountCommand struct {
|
|||||||
flagLocal bool
|
flagLocal bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *MountCommand) Synopsis() string {
|
func (c *SecretsEnableCommand) Synopsis() string {
|
||||||
return "Mounts a secret backend at a path"
|
return "Enable a secrets engine"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *MountCommand) Help() string {
|
func (c *SecretsEnableCommand) Help() string {
|
||||||
helpText := `
|
helpText := `
|
||||||
Usage: vault mount [options] TYPE
|
Usage: vault secrets enable [options] TYPE
|
||||||
|
|
||||||
Mount a secret backend at a particular path. By default, secret backends are
|
Enables a secrets engine. By default, secrets engines are enabled at the path
|
||||||
mounted at the path corresponding to their "type", but users can customize
|
corresponding to their TYPE, but users can customize the path using the
|
||||||
the mount point using the -path option.
|
-path option.
|
||||||
|
|
||||||
Once mounted at a path, Vault will route all requests which begin with the
|
Once enabled, Vault will route all requests which begin with the path to the
|
||||||
path to the secret backend.
|
secrets engine.
|
||||||
|
|
||||||
Mount the AWS backend at aws/:
|
Enable the AWS secrets engine at aws/:
|
||||||
|
|
||||||
$ vault mount aws
|
$ vault secrets enable aws
|
||||||
|
|
||||||
Mount the SSH backend at ssh-prod/:
|
Enable the SSH secrets engine at ssh-prod/:
|
||||||
|
|
||||||
$ vault mount -path=ssh-prod ssh
|
$ vault secrets enable -path=ssh-prod ssh
|
||||||
|
|
||||||
Mount the database backend with an explicit maximum TTL of 30m:
|
Enable the database secrets engine with an explicit maximum TTL of 30m:
|
||||||
|
|
||||||
$ vault mount -max-lease-ttl=30m database
|
$ vault secrets enable -max-lease-ttl=30m database
|
||||||
|
|
||||||
Mount a custom plugin (after it is registered in the plugin registry):
|
Enable a custom plugin (after it is registered in the plugin registry):
|
||||||
|
|
||||||
$ vault mount -path=my-secrets -plugin-name=my-custom-plugin plugin
|
$ vault secrets enable -path=my-secrets -plugin-name=my-plugin plugin
|
||||||
|
|
||||||
For a full list of secret backends and examples, please see the documentation.
|
For a full list of secrets engines and examples, please see the documentation.
|
||||||
|
|
||||||
` + c.Flags().Help()
|
` + c.Flags().Help()
|
||||||
|
|
||||||
return strings.TrimSpace(helpText)
|
return strings.TrimSpace(helpText)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *MountCommand) Flags() *FlagSets {
|
func (c *SecretsEnableCommand) Flags() *FlagSets {
|
||||||
set := c.flagSet(FlagSetHTTP)
|
set := c.flagSet(FlagSetHTTP)
|
||||||
|
|
||||||
f := set.NewFlagSet("Command Options")
|
f := set.NewFlagSet("Command Options")
|
||||||
@@ -74,7 +72,7 @@ func (c *MountCommand) Flags() *FlagSets {
|
|||||||
Name: "description",
|
Name: "description",
|
||||||
Target: &c.flagDescription,
|
Target: &c.flagDescription,
|
||||||
Completion: complete.PredictAnything,
|
Completion: complete.PredictAnything,
|
||||||
Usage: "Human-friendly description for the purpose of this mount.",
|
Usage: "Human-friendly description for the purpose of this engine.",
|
||||||
})
|
})
|
||||||
|
|
||||||
f.StringVar(&StringVar{
|
f.StringVar(&StringVar{
|
||||||
@@ -82,31 +80,34 @@ func (c *MountCommand) Flags() *FlagSets {
|
|||||||
Target: &c.flagPath,
|
Target: &c.flagPath,
|
||||||
Default: "", // The default is complex, so we have to manually document
|
Default: "", // The default is complex, so we have to manually document
|
||||||
Completion: complete.PredictAnything,
|
Completion: complete.PredictAnything,
|
||||||
Usage: "Place where the mount will be accessible. This must be " +
|
Usage: "Place where the secrets engine will be accessible. This must be " +
|
||||||
"unique across all mounts. This defaults to the \"type\" of the mount.",
|
"unique cross all secrets engines. This defaults to the \"type\" of the " +
|
||||||
|
"secrets engine.",
|
||||||
})
|
})
|
||||||
|
|
||||||
f.DurationVar(&DurationVar{
|
f.DurationVar(&DurationVar{
|
||||||
Name: "default-lease-ttl",
|
Name: "default-lease-ttl",
|
||||||
Target: &c.flagDefaultLeaseTTL,
|
Target: &c.flagDefaultLeaseTTL,
|
||||||
Completion: complete.PredictAnything,
|
Completion: complete.PredictAnything,
|
||||||
Usage: "The default lease TTL for this backend. If unspecified, this " +
|
Usage: "The default lease TTL for this secrets engine. If unspecified, " +
|
||||||
"defaults to the Vault server's globally configured default lease TTL.",
|
"this defaults to the Vault server's globally configured default lease " +
|
||||||
|
"TTL.",
|
||||||
})
|
})
|
||||||
|
|
||||||
f.DurationVar(&DurationVar{
|
f.DurationVar(&DurationVar{
|
||||||
Name: "max-lease-ttl",
|
Name: "max-lease-ttl",
|
||||||
Target: &c.flagMaxLeaseTTL,
|
Target: &c.flagMaxLeaseTTL,
|
||||||
Completion: complete.PredictAnything,
|
Completion: complete.PredictAnything,
|
||||||
Usage: "The maximum lease TTL for this backend. If unspecified, this " +
|
Usage: "The maximum lease TTL for this secrets engine. If unspecified, " +
|
||||||
"defaults to the Vault server's globally configured maximum lease TTL.",
|
"this defaults to the Vault server's globally configured maximum lease " +
|
||||||
|
"TTL.",
|
||||||
})
|
})
|
||||||
|
|
||||||
f.BoolVar(&BoolVar{
|
f.BoolVar(&BoolVar{
|
||||||
Name: "force-no-cache",
|
Name: "force-no-cache",
|
||||||
Target: &c.flagForceNoCache,
|
Target: &c.flagForceNoCache,
|
||||||
Default: false,
|
Default: false,
|
||||||
Usage: "Force the backend to disable caching. If unspecified, this " +
|
Usage: "Force the secrets engine to disable caching. If unspecified, this " +
|
||||||
"defaults to the Vault server's globally configured cache settings. " +
|
"defaults to the Vault server's globally configured cache settings. " +
|
||||||
"This does not affect caching of the underlying encrypted data storage.",
|
"This does not affect caching of the underlying encrypted data storage.",
|
||||||
})
|
})
|
||||||
@@ -115,30 +116,30 @@ func (c *MountCommand) Flags() *FlagSets {
|
|||||||
Name: "plugin-name",
|
Name: "plugin-name",
|
||||||
Target: &c.flagPluginName,
|
Target: &c.flagPluginName,
|
||||||
Completion: complete.PredictAnything,
|
Completion: complete.PredictAnything,
|
||||||
Usage: "Name of the plugin to mount. This plugin name must already exist " +
|
Usage: "Name of the secrets engine plugin. This plugin name must already " +
|
||||||
"in the Vault server's plugin catalog.",
|
"exist in Vault's plugin catalog.",
|
||||||
})
|
})
|
||||||
|
|
||||||
f.BoolVar(&BoolVar{
|
f.BoolVar(&BoolVar{
|
||||||
Name: "local",
|
Name: "local",
|
||||||
Target: &c.flagLocal,
|
Target: &c.flagLocal,
|
||||||
Default: false,
|
Default: false,
|
||||||
Usage: "Mark the mount as a local-only mount. Local mounts are not " +
|
Usage: "Mark the secrets engine as local-only. Local engines are not " +
|
||||||
"replicated nor removed by replication.",
|
"replicated or removed by replication.",
|
||||||
})
|
})
|
||||||
|
|
||||||
return set
|
return set
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *MountCommand) AutocompleteArgs() complete.Predictor {
|
func (c *SecretsEnableCommand) AutocompleteArgs() complete.Predictor {
|
||||||
return c.PredictVaultAvailableMounts()
|
return c.PredictVaultAvailableMounts()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *MountCommand) AutocompleteFlags() complete.Flags {
|
func (c *SecretsEnableCommand) AutocompleteFlags() complete.Flags {
|
||||||
return c.Flags().Completions()
|
return c.Flags().Completions()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *MountCommand) Run(args []string) int {
|
func (c *SecretsEnableCommand) Run(args []string) int {
|
||||||
f := c.Flags()
|
f := c.Flags()
|
||||||
|
|
||||||
if err := f.Parse(args); err != nil {
|
if err := f.Parse(args); err != nil {
|
||||||
@@ -147,13 +148,11 @@ func (c *MountCommand) Run(args []string) int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
args = f.Args()
|
args = f.Args()
|
||||||
switch len(args) {
|
switch {
|
||||||
case 0:
|
case len(args) < 1:
|
||||||
c.UI.Error("Missing TYPE!")
|
c.UI.Error(fmt.Sprintf("Not enough arguments (expected 1, got %d)", len(args)))
|
||||||
return 1
|
return 1
|
||||||
case 1:
|
case len(args) > 1:
|
||||||
// OK
|
|
||||||
default:
|
|
||||||
c.UI.Error(fmt.Sprintf("Too many arguments (expected 1, got %d)", len(args)))
|
c.UI.Error(fmt.Sprintf("Too many arguments (expected 1, got %d)", len(args)))
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
@@ -164,17 +163,17 @@ func (c *MountCommand) Run(args []string) int {
|
|||||||
return 2
|
return 2
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the mount type (first arg)
|
// Get the engine type type (first arg)
|
||||||
mountType := strings.TrimSpace(args[0])
|
engineType := strings.TrimSpace(args[0])
|
||||||
|
|
||||||
// If no path is specified, we default the path to the backend type
|
// If no path is specified, we default the path to the backend type
|
||||||
// or use the plugin name if it's a plugin backend
|
// or use the plugin name if it's a plugin backend
|
||||||
mountPath := c.flagPath
|
mountPath := c.flagPath
|
||||||
if mountPath == "" {
|
if mountPath == "" {
|
||||||
if mountType == "plugin" {
|
if engineType == "plugin" {
|
||||||
mountPath = c.flagPluginName
|
mountPath = c.flagPluginName
|
||||||
} else {
|
} else {
|
||||||
mountPath = mountType
|
mountPath = engineType
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -183,7 +182,7 @@ func (c *MountCommand) Run(args []string) int {
|
|||||||
|
|
||||||
// Build mount input
|
// Build mount input
|
||||||
mountInput := &api.MountInput{
|
mountInput := &api.MountInput{
|
||||||
Type: mountType,
|
Type: engineType,
|
||||||
Description: c.flagDescription,
|
Description: c.flagDescription,
|
||||||
Local: c.flagLocal,
|
Local: c.flagLocal,
|
||||||
Config: api.MountConfigInput{
|
Config: api.MountConfigInput{
|
||||||
@@ -195,15 +194,15 @@ func (c *MountCommand) Run(args []string) int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if err := client.Sys().Mount(mountPath, mountInput); err != nil {
|
if err := client.Sys().Mount(mountPath, mountInput); err != nil {
|
||||||
c.UI.Error(fmt.Sprintf("Error mounting: %s", err))
|
c.UI.Error(fmt.Sprintf("Error enabling: %s", err))
|
||||||
return 2
|
return 2
|
||||||
}
|
}
|
||||||
|
|
||||||
mountThing := mountType + " secret backend"
|
thing := engineType + " secrets engine"
|
||||||
if mountType == "plugin" {
|
if engineType == "plugin" {
|
||||||
mountThing = c.flagPluginName + " plugin"
|
thing = c.flagPluginName + " plugin"
|
||||||
}
|
}
|
||||||
|
|
||||||
c.UI.Output(fmt.Sprintf("Success! Mounted the %s at: %s", mountThing, mountPath))
|
c.UI.Output(fmt.Sprintf("Success! Enabled the %s at: %s", thing, mountPath))
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
@@ -7,17 +7,18 @@ import (
|
|||||||
"github.com/mitchellh/cli"
|
"github.com/mitchellh/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
func testMountCommand(tb testing.TB) (*cli.MockUi, *MountCommand) {
|
func testSecretsEnableCommand(tb testing.TB) (*cli.MockUi, *SecretsEnableCommand) {
|
||||||
tb.Helper()
|
tb.Helper()
|
||||||
|
|
||||||
ui := cli.NewMockUi()
|
ui := cli.NewMockUi()
|
||||||
return ui, &MountCommand{
|
return ui, &SecretsEnableCommand{
|
||||||
BaseCommand: &BaseCommand{
|
BaseCommand: &BaseCommand{
|
||||||
UI: ui,
|
UI: ui,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
func TestMountCommand_Run(t *testing.T) {
|
|
||||||
|
func TestSecretsEnableCommand_Run(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
cases := []struct {
|
cases := []struct {
|
||||||
@@ -27,9 +28,9 @@ func TestMountCommand_Run(t *testing.T) {
|
|||||||
code int
|
code int
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
"empty",
|
"not_enough_args",
|
||||||
nil,
|
[]string{},
|
||||||
"Missing TYPE!",
|
"Not enough arguments",
|
||||||
1,
|
1,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -47,7 +48,7 @@ func TestMountCommand_Run(t *testing.T) {
|
|||||||
{
|
{
|
||||||
"mount",
|
"mount",
|
||||||
[]string{"transit"},
|
[]string{"transit"},
|
||||||
"Success! Mounted the transit secret backend at: transit/",
|
"Success! Enabled the transit secrets engine at: transit/",
|
||||||
0,
|
0,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -56,7 +57,7 @@ func TestMountCommand_Run(t *testing.T) {
|
|||||||
"-path", "transit_mount_point",
|
"-path", "transit_mount_point",
|
||||||
"transit",
|
"transit",
|
||||||
},
|
},
|
||||||
"Success! Mounted the transit secret backend at: transit_mount_point/",
|
"Success! Enabled the transit secrets engine at: transit_mount_point/",
|
||||||
0,
|
0,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -70,7 +71,7 @@ func TestMountCommand_Run(t *testing.T) {
|
|||||||
client, closer := testVaultServer(t)
|
client, closer := testVaultServer(t)
|
||||||
defer closer()
|
defer closer()
|
||||||
|
|
||||||
ui, cmd := testMountCommand(t)
|
ui, cmd := testSecretsEnableCommand(t)
|
||||||
cmd.client = client
|
cmd.client = client
|
||||||
|
|
||||||
code := cmd.Run(tc.args)
|
code := cmd.Run(tc.args)
|
||||||
@@ -91,7 +92,7 @@ func TestMountCommand_Run(t *testing.T) {
|
|||||||
client, closer := testVaultServer(t)
|
client, closer := testVaultServer(t)
|
||||||
defer closer()
|
defer closer()
|
||||||
|
|
||||||
ui, cmd := testMountCommand(t)
|
ui, cmd := testSecretsEnableCommand(t)
|
||||||
cmd.client = client
|
cmd.client = client
|
||||||
|
|
||||||
code := cmd.Run([]string{
|
code := cmd.Run([]string{
|
||||||
@@ -106,7 +107,7 @@ func TestMountCommand_Run(t *testing.T) {
|
|||||||
t.Errorf("expected %d to be %d", code, exp)
|
t.Errorf("expected %d to be %d", code, exp)
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := "Success! Mounted the pki secret backend at: mount_integration/"
|
expected := "Success! Enabled the pki secrets engine at: mount_integration/"
|
||||||
combined := ui.OutputWriter.String() + ui.ErrorWriter.String()
|
combined := ui.OutputWriter.String() + ui.ErrorWriter.String()
|
||||||
if !strings.Contains(combined, expected) {
|
if !strings.Contains(combined, expected) {
|
||||||
t.Errorf("expected %q to contain %q", combined, expected)
|
t.Errorf("expected %q to contain %q", combined, expected)
|
||||||
@@ -144,7 +145,7 @@ func TestMountCommand_Run(t *testing.T) {
|
|||||||
client, closer := testVaultServerBad(t)
|
client, closer := testVaultServerBad(t)
|
||||||
defer closer()
|
defer closer()
|
||||||
|
|
||||||
ui, cmd := testMountCommand(t)
|
ui, cmd := testSecretsEnableCommand(t)
|
||||||
cmd.client = client
|
cmd.client = client
|
||||||
|
|
||||||
code := cmd.Run([]string{
|
code := cmd.Run([]string{
|
||||||
@@ -154,7 +155,7 @@ func TestMountCommand_Run(t *testing.T) {
|
|||||||
t.Errorf("expected %d to be %d", code, exp)
|
t.Errorf("expected %d to be %d", code, exp)
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := "Error mounting: "
|
expected := "Error enabling: "
|
||||||
combined := ui.OutputWriter.String() + ui.ErrorWriter.String()
|
combined := ui.OutputWriter.String() + ui.ErrorWriter.String()
|
||||||
if !strings.Contains(combined, expected) {
|
if !strings.Contains(combined, expected) {
|
||||||
t.Errorf("expected %q to contain %q", combined, expected)
|
t.Errorf("expected %q to contain %q", combined, expected)
|
||||||
@@ -164,7 +165,7 @@ func TestMountCommand_Run(t *testing.T) {
|
|||||||
t.Run("no_tabs", func(t *testing.T) {
|
t.Run("no_tabs", func(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
_, cmd := testMountCommand(t)
|
_, cmd := testSecretsEnableCommand(t)
|
||||||
assertNoTabs(t, cmd)
|
assertNoTabs(t, cmd)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -11,44 +11,42 @@ import (
|
|||||||
"github.com/posener/complete"
|
"github.com/posener/complete"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Ensure we are implementing the right interfaces.
|
var _ cli.Command = (*SecretsListCommand)(nil)
|
||||||
var _ cli.Command = (*MountsCommand)(nil)
|
var _ cli.CommandAutocomplete = (*SecretsListCommand)(nil)
|
||||||
var _ cli.CommandAutocomplete = (*MountsCommand)(nil)
|
|
||||||
|
|
||||||
// MountsCommand is a Command that lists the mounts.
|
type SecretsListCommand struct {
|
||||||
type MountsCommand struct {
|
|
||||||
*BaseCommand
|
*BaseCommand
|
||||||
|
|
||||||
flagDetailed bool
|
flagDetailed bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *MountsCommand) Synopsis() string {
|
func (c *SecretsListCommand) Synopsis() string {
|
||||||
return "Lists mounted secret backends"
|
return "List enabled secrets engines"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *MountsCommand) Help() string {
|
func (c *SecretsListCommand) Help() string {
|
||||||
helpText := `
|
helpText := `
|
||||||
Usage: vault mounts [options]
|
Usage: vault secrets list [options]
|
||||||
|
|
||||||
Lists the mounted secret backends on the Vault server. This command also
|
Lists the enabled secret engines on the Vault server. This command also
|
||||||
outputs information about the mount point including configured TTLs and
|
outputs information about the enabled path including configured TTLs and
|
||||||
human-friendly descriptions. A TTL of "system" indicates that the system
|
human-friendly descriptions. A TTL of "system" indicates that the system
|
||||||
default is in use.
|
default is in use.
|
||||||
|
|
||||||
List all mounts:
|
List all enabled secrets engines:
|
||||||
|
|
||||||
$ vault mounts
|
$ vault secrets list
|
||||||
|
|
||||||
List all mounts with detailed output:
|
List all enabled secrets engines with detailed output:
|
||||||
|
|
||||||
$ vault mounts -detailed
|
$ vault secrets list -detailed
|
||||||
|
|
||||||
` + c.Flags().Help()
|
` + c.Flags().Help()
|
||||||
|
|
||||||
return strings.TrimSpace(helpText)
|
return strings.TrimSpace(helpText)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *MountsCommand) Flags() *FlagSets {
|
func (c *SecretsListCommand) Flags() *FlagSets {
|
||||||
set := c.flagSet(FlagSetHTTP)
|
set := c.flagSet(FlagSetHTTP)
|
||||||
|
|
||||||
f := set.NewFlagSet("Command Options")
|
f := set.NewFlagSet("Command Options")
|
||||||
@@ -58,21 +56,21 @@ func (c *MountsCommand) Flags() *FlagSets {
|
|||||||
Target: &c.flagDetailed,
|
Target: &c.flagDetailed,
|
||||||
Default: false,
|
Default: false,
|
||||||
Usage: "Print detailed information such as TTLs and replication status " +
|
Usage: "Print detailed information such as TTLs and replication status " +
|
||||||
"about each mount.",
|
"about each secrets engine.",
|
||||||
})
|
})
|
||||||
|
|
||||||
return set
|
return set
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *MountsCommand) AutocompleteArgs() complete.Predictor {
|
func (c *SecretsListCommand) AutocompleteArgs() complete.Predictor {
|
||||||
return c.PredictVaultFiles()
|
return c.PredictVaultFiles()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *MountsCommand) AutocompleteFlags() complete.Flags {
|
func (c *SecretsListCommand) AutocompleteFlags() complete.Flags {
|
||||||
return c.Flags().Completions()
|
return c.Flags().Completions()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *MountsCommand) Run(args []string) int {
|
func (c *SecretsListCommand) Run(args []string) int {
|
||||||
f := c.Flags()
|
f := c.Flags()
|
||||||
|
|
||||||
if err := f.Parse(args); err != nil {
|
if err := f.Parse(args); err != nil {
|
||||||
@@ -94,20 +92,20 @@ func (c *MountsCommand) Run(args []string) int {
|
|||||||
|
|
||||||
mounts, err := client.Sys().ListMounts()
|
mounts, err := client.Sys().ListMounts()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.UI.Error(fmt.Sprintf("Error listing mounts: %s", err))
|
c.UI.Error(fmt.Sprintf("Error listing secrets engines: %s", err))
|
||||||
return 2
|
return 2
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.flagDetailed {
|
if c.flagDetailed {
|
||||||
c.UI.Output(tableOutput(c.detailedMounts(mounts)))
|
c.UI.Output(tableOutput(c.detailedMounts(mounts), nil))
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
c.UI.Output(tableOutput(c.simpleMounts(mounts)))
|
c.UI.Output(tableOutput(c.simpleMounts(mounts), nil))
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *MountsCommand) simpleMounts(mounts map[string]*api.MountOutput) []string {
|
func (c *SecretsListCommand) simpleMounts(mounts map[string]*api.MountOutput) []string {
|
||||||
paths := make([]string, 0, len(mounts))
|
paths := make([]string, 0, len(mounts))
|
||||||
for path := range mounts {
|
for path := range mounts {
|
||||||
paths = append(paths, path)
|
paths = append(paths, path)
|
||||||
@@ -123,7 +121,7 @@ func (c *MountsCommand) simpleMounts(mounts map[string]*api.MountOutput) []strin
|
|||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *MountsCommand) detailedMounts(mounts map[string]*api.MountOutput) []string {
|
func (c *SecretsListCommand) detailedMounts(mounts map[string]*api.MountOutput) []string {
|
||||||
paths := make([]string, 0, len(mounts))
|
paths := make([]string, 0, len(mounts))
|
||||||
for path := range mounts {
|
for path := range mounts {
|
||||||
paths = append(paths, path)
|
paths = append(paths, path)
|
||||||
@@ -7,18 +7,18 @@ import (
|
|||||||
"github.com/mitchellh/cli"
|
"github.com/mitchellh/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
func testMountsCommand(tb testing.TB) (*cli.MockUi, *MountsCommand) {
|
func testSecretsListCommand(tb testing.TB) (*cli.MockUi, *SecretsListCommand) {
|
||||||
tb.Helper()
|
tb.Helper()
|
||||||
|
|
||||||
ui := cli.NewMockUi()
|
ui := cli.NewMockUi()
|
||||||
return ui, &MountsCommand{
|
return ui, &SecretsListCommand{
|
||||||
BaseCommand: &BaseCommand{
|
BaseCommand: &BaseCommand{
|
||||||
UI: ui,
|
UI: ui,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMountsCommand_Run(t *testing.T) {
|
func TestSecretsListCommand_Run(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
cases := []struct {
|
cases := []struct {
|
||||||
@@ -59,7 +59,7 @@ func TestMountsCommand_Run(t *testing.T) {
|
|||||||
client, closer := testVaultServer(t)
|
client, closer := testVaultServer(t)
|
||||||
defer closer()
|
defer closer()
|
||||||
|
|
||||||
ui, cmd := testMountsCommand(t)
|
ui, cmd := testSecretsListCommand(t)
|
||||||
cmd.client = client
|
cmd.client = client
|
||||||
|
|
||||||
code := cmd.Run(tc.args)
|
code := cmd.Run(tc.args)
|
||||||
@@ -81,7 +81,7 @@ func TestMountsCommand_Run(t *testing.T) {
|
|||||||
client, closer := testVaultServerBad(t)
|
client, closer := testVaultServerBad(t)
|
||||||
defer closer()
|
defer closer()
|
||||||
|
|
||||||
ui, cmd := testMountsCommand(t)
|
ui, cmd := testSecretsListCommand(t)
|
||||||
cmd.client = client
|
cmd.client = client
|
||||||
|
|
||||||
code := cmd.Run([]string{})
|
code := cmd.Run([]string{})
|
||||||
@@ -89,7 +89,7 @@ func TestMountsCommand_Run(t *testing.T) {
|
|||||||
t.Errorf("expected %d to be %d", code, exp)
|
t.Errorf("expected %d to be %d", code, exp)
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := "Error listing mounts: "
|
expected := "Error listing secrets engines: "
|
||||||
combined := ui.OutputWriter.String() + ui.ErrorWriter.String()
|
combined := ui.OutputWriter.String() + ui.ErrorWriter.String()
|
||||||
if !strings.Contains(combined, expected) {
|
if !strings.Contains(combined, expected) {
|
||||||
t.Errorf("expected %q to contain %q", combined, expected)
|
t.Errorf("expected %q to contain %q", combined, expected)
|
||||||
@@ -99,7 +99,7 @@ func TestMountsCommand_Run(t *testing.T) {
|
|||||||
t.Run("no_tabs", func(t *testing.T) {
|
t.Run("no_tabs", func(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
_, cmd := testMountsCommand(t)
|
_, cmd := testSecretsListCommand(t)
|
||||||
assertNoTabs(t, cmd)
|
assertNoTabs(t, cmd)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
89
command/secrets_move.go
Normal file
89
command/secrets_move.go
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
package command
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/mitchellh/cli"
|
||||||
|
"github.com/posener/complete"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ cli.Command = (*SecretsMoveCommand)(nil)
|
||||||
|
var _ cli.CommandAutocomplete = (*SecretsMoveCommand)(nil)
|
||||||
|
|
||||||
|
type SecretsMoveCommand struct {
|
||||||
|
*BaseCommand
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *SecretsMoveCommand) Synopsis() string {
|
||||||
|
return "Move a secrets engine to a new path"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *SecretsMoveCommand) Help() string {
|
||||||
|
helpText := `
|
||||||
|
Usage: vault secrets move [options] SOURCE DESTINATION
|
||||||
|
|
||||||
|
Moves an existing secrets engine to a new path. Any leases from the old
|
||||||
|
secrets engine are revoked, but all configuration associated with the engine
|
||||||
|
is preserved.
|
||||||
|
|
||||||
|
WARNING! Moving an existing secrets engine will revoke any leases from the
|
||||||
|
old engine.
|
||||||
|
|
||||||
|
Move the existing secrets engine at secret/ to generic/:
|
||||||
|
|
||||||
|
$ vault secrets move secret/ generic/
|
||||||
|
|
||||||
|
` + c.Flags().Help()
|
||||||
|
|
||||||
|
return strings.TrimSpace(helpText)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *SecretsMoveCommand) Flags() *FlagSets {
|
||||||
|
return c.flagSet(FlagSetHTTP)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *SecretsMoveCommand) AutocompleteArgs() complete.Predictor {
|
||||||
|
return c.PredictVaultMounts()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *SecretsMoveCommand) AutocompleteFlags() complete.Flags {
|
||||||
|
return c.Flags().Completions()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *SecretsMoveCommand) Run(args []string) int {
|
||||||
|
f := c.Flags()
|
||||||
|
|
||||||
|
if err := f.Parse(args); err != nil {
|
||||||
|
c.UI.Error(err.Error())
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
args = f.Args()
|
||||||
|
switch {
|
||||||
|
case len(args) < 2:
|
||||||
|
c.UI.Error(fmt.Sprintf("Not enough arguments (expected 2, got %d)", len(args)))
|
||||||
|
return 1
|
||||||
|
case len(args) > 2:
|
||||||
|
c.UI.Error(fmt.Sprintf("Too many arguments (expected 2, got %d)", len(args)))
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// Grab the source and destination
|
||||||
|
source := ensureTrailingSlash(args[0])
|
||||||
|
destination := ensureTrailingSlash(args[1])
|
||||||
|
|
||||||
|
client, err := c.Client()
|
||||||
|
if err != nil {
|
||||||
|
c.UI.Error(err.Error())
|
||||||
|
return 2
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := client.Sys().Remount(source, destination); err != nil {
|
||||||
|
c.UI.Error(fmt.Sprintf("Error moving secrets engine %s to %s: %s", source, destination, err))
|
||||||
|
return 2
|
||||||
|
}
|
||||||
|
|
||||||
|
c.UI.Output(fmt.Sprintf("Success! Moved secrets engine %s to: %s", source, destination))
|
||||||
|
return 0
|
||||||
|
}
|
||||||
@@ -7,18 +7,18 @@ import (
|
|||||||
"github.com/mitchellh/cli"
|
"github.com/mitchellh/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
func testRemountCommand(tb testing.TB) (*cli.MockUi, *RemountCommand) {
|
func testSecretsMoveCommand(tb testing.TB) (*cli.MockUi, *SecretsMoveCommand) {
|
||||||
tb.Helper()
|
tb.Helper()
|
||||||
|
|
||||||
ui := cli.NewMockUi()
|
ui := cli.NewMockUi()
|
||||||
return ui, &RemountCommand{
|
return ui, &SecretsMoveCommand{
|
||||||
BaseCommand: &BaseCommand{
|
BaseCommand: &BaseCommand{
|
||||||
UI: ui,
|
UI: ui,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRemountCommand_Run(t *testing.T) {
|
func TestSecretsMoveCommand_Run(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
cases := []struct {
|
cases := []struct {
|
||||||
@@ -29,7 +29,7 @@ func TestRemountCommand_Run(t *testing.T) {
|
|||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
"not_enough_args",
|
"not_enough_args",
|
||||||
nil,
|
[]string{},
|
||||||
"Not enough arguments",
|
"Not enough arguments",
|
||||||
1,
|
1,
|
||||||
},
|
},
|
||||||
@@ -42,7 +42,7 @@ func TestRemountCommand_Run(t *testing.T) {
|
|||||||
{
|
{
|
||||||
"non_existent",
|
"non_existent",
|
||||||
[]string{"not_real", "over_here"},
|
[]string{"not_real", "over_here"},
|
||||||
"Error remounting not_real/ to over_here/",
|
"Error moving secrets engine not_real/ to over_here/",
|
||||||
2,
|
2,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -56,7 +56,7 @@ func TestRemountCommand_Run(t *testing.T) {
|
|||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
ui, cmd := testRemountCommand(t)
|
ui, cmd := testSecretsMoveCommand(t)
|
||||||
|
|
||||||
code := cmd.Run(tc.args)
|
code := cmd.Run(tc.args)
|
||||||
if code != tc.code {
|
if code != tc.code {
|
||||||
@@ -77,7 +77,7 @@ func TestRemountCommand_Run(t *testing.T) {
|
|||||||
client, closer := testVaultServer(t)
|
client, closer := testVaultServer(t)
|
||||||
defer closer()
|
defer closer()
|
||||||
|
|
||||||
ui, cmd := testRemountCommand(t)
|
ui, cmd := testSecretsMoveCommand(t)
|
||||||
cmd.client = client
|
cmd.client = client
|
||||||
|
|
||||||
code := cmd.Run([]string{
|
code := cmd.Run([]string{
|
||||||
@@ -87,7 +87,7 @@ func TestRemountCommand_Run(t *testing.T) {
|
|||||||
t.Errorf("expected %d to be %d", code, exp)
|
t.Errorf("expected %d to be %d", code, exp)
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := "Success! Remounted secret/ to: generic/"
|
expected := "Success! Moved secrets engine secret/ to: generic/"
|
||||||
combined := ui.OutputWriter.String() + ui.ErrorWriter.String()
|
combined := ui.OutputWriter.String() + ui.ErrorWriter.String()
|
||||||
if !strings.Contains(combined, expected) {
|
if !strings.Contains(combined, expected) {
|
||||||
t.Errorf("expected %q to contain %q", combined, expected)
|
t.Errorf("expected %q to contain %q", combined, expected)
|
||||||
@@ -109,7 +109,7 @@ func TestRemountCommand_Run(t *testing.T) {
|
|||||||
client, closer := testVaultServerBad(t)
|
client, closer := testVaultServerBad(t)
|
||||||
defer closer()
|
defer closer()
|
||||||
|
|
||||||
ui, cmd := testRemountCommand(t)
|
ui, cmd := testSecretsMoveCommand(t)
|
||||||
cmd.client = client
|
cmd.client = client
|
||||||
|
|
||||||
code := cmd.Run([]string{
|
code := cmd.Run([]string{
|
||||||
@@ -119,7 +119,7 @@ func TestRemountCommand_Run(t *testing.T) {
|
|||||||
t.Errorf("expected %d to be %d", code, exp)
|
t.Errorf("expected %d to be %d", code, exp)
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := "Error remounting secret/ to generic/: "
|
expected := "Error moving secrets engine secret/ to generic/:"
|
||||||
combined := ui.OutputWriter.String() + ui.ErrorWriter.String()
|
combined := ui.OutputWriter.String() + ui.ErrorWriter.String()
|
||||||
if !strings.Contains(combined, expected) {
|
if !strings.Contains(combined, expected) {
|
||||||
t.Errorf("expected %q to contain %q", combined, expected)
|
t.Errorf("expected %q to contain %q", combined, expected)
|
||||||
@@ -129,7 +129,7 @@ func TestRemountCommand_Run(t *testing.T) {
|
|||||||
t.Run("no_tabs", func(t *testing.T) {
|
t.Run("no_tabs", func(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
_, cmd := testRemountCommand(t)
|
_, cmd := testSecretsMoveCommand(t)
|
||||||
assertNoTabs(t, cmd)
|
assertNoTabs(t, cmd)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
119
command/secrets_tune.go
Normal file
119
command/secrets_tune.go
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
package command
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/hashicorp/vault/api"
|
||||||
|
"github.com/mitchellh/cli"
|
||||||
|
"github.com/posener/complete"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ cli.Command = (*SecretsTuneCommand)(nil)
|
||||||
|
var _ cli.CommandAutocomplete = (*SecretsTuneCommand)(nil)
|
||||||
|
|
||||||
|
type SecretsTuneCommand struct {
|
||||||
|
*BaseCommand
|
||||||
|
|
||||||
|
flagDefaultLeaseTTL time.Duration
|
||||||
|
flagMaxLeaseTTL time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *SecretsTuneCommand) Synopsis() string {
|
||||||
|
return "Tune a secrets engine configuration"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *SecretsTuneCommand) Help() string {
|
||||||
|
helpText := `
|
||||||
|
Usage: vault secrets tune [options] PATH
|
||||||
|
|
||||||
|
Tunes the configuration options for the secrets engine at the given PATH.
|
||||||
|
The argument corresponds to the PATH where the secrets engine is enabled,
|
||||||
|
not the TYPE!
|
||||||
|
|
||||||
|
Tune the default lease for the PKI secrets engine:
|
||||||
|
|
||||||
|
$ vault secrets tune -default-lease-ttl=72h pki/
|
||||||
|
|
||||||
|
` + c.Flags().Help()
|
||||||
|
|
||||||
|
return strings.TrimSpace(helpText)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *SecretsTuneCommand) Flags() *FlagSets {
|
||||||
|
set := c.flagSet(FlagSetHTTP)
|
||||||
|
|
||||||
|
f := set.NewFlagSet("Command Options")
|
||||||
|
|
||||||
|
f.DurationVar(&DurationVar{
|
||||||
|
Name: "default-lease-ttl",
|
||||||
|
Target: &c.flagDefaultLeaseTTL,
|
||||||
|
Default: 0,
|
||||||
|
EnvVar: "",
|
||||||
|
Completion: complete.PredictAnything,
|
||||||
|
Usage: "The default lease TTL for this secrets engine. If unspecified, " +
|
||||||
|
"this defaults to the Vault server's globally configured default lease " +
|
||||||
|
"TTL, or a previously configured value for the secrets engine.",
|
||||||
|
})
|
||||||
|
|
||||||
|
f.DurationVar(&DurationVar{
|
||||||
|
Name: "max-lease-ttl",
|
||||||
|
Target: &c.flagMaxLeaseTTL,
|
||||||
|
Default: 0,
|
||||||
|
EnvVar: "",
|
||||||
|
Completion: complete.PredictAnything,
|
||||||
|
Usage: "The maximum lease TTL for this secrets engine. If unspecified, " +
|
||||||
|
"this defaults to the Vault server's globally configured maximum lease " +
|
||||||
|
"TTL, or a previously configured value for the secrets engine.",
|
||||||
|
})
|
||||||
|
|
||||||
|
return set
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *SecretsTuneCommand) AutocompleteArgs() complete.Predictor {
|
||||||
|
return c.PredictVaultMounts()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *SecretsTuneCommand) AutocompleteFlags() complete.Flags {
|
||||||
|
return c.Flags().Completions()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *SecretsTuneCommand) Run(args []string) int {
|
||||||
|
f := c.Flags()
|
||||||
|
|
||||||
|
if err := f.Parse(args); err != nil {
|
||||||
|
c.UI.Error(err.Error())
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
args = f.Args()
|
||||||
|
switch {
|
||||||
|
case len(args) < 1:
|
||||||
|
c.UI.Error(fmt.Sprintf("Not enough arguments (expected 1, got %d)", len(args)))
|
||||||
|
return 1
|
||||||
|
case len(args) > 1:
|
||||||
|
c.UI.Error(fmt.Sprintf("Too many arguments (expected 1, got %d)", len(args)))
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
client, err := c.Client()
|
||||||
|
if err != nil {
|
||||||
|
c.UI.Error(err.Error())
|
||||||
|
return 2
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append a trailing slash to indicate it's a path in output
|
||||||
|
mountPath := ensureTrailingSlash(sanitizePath(args[0]))
|
||||||
|
|
||||||
|
if err := client.Sys().TuneMount(mountPath, api.MountConfigInput{
|
||||||
|
DefaultLeaseTTL: ttlToAPI(c.flagDefaultLeaseTTL),
|
||||||
|
MaxLeaseTTL: ttlToAPI(c.flagMaxLeaseTTL),
|
||||||
|
}); err != nil {
|
||||||
|
c.UI.Error(fmt.Sprintf("Error tuning secrets engine %s: %s", mountPath, err))
|
||||||
|
return 2
|
||||||
|
}
|
||||||
|
|
||||||
|
c.UI.Output(fmt.Sprintf("Success! Tuned the secrets engine at: %s", mountPath))
|
||||||
|
return 0
|
||||||
|
}
|
||||||
@@ -8,18 +8,18 @@ import (
|
|||||||
"github.com/mitchellh/cli"
|
"github.com/mitchellh/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
func testMountTuneCommand(tb testing.TB) (*cli.MockUi, *MountTuneCommand) {
|
func testSecretsTuneCommand(tb testing.TB) (*cli.MockUi, *SecretsTuneCommand) {
|
||||||
tb.Helper()
|
tb.Helper()
|
||||||
|
|
||||||
ui := cli.NewMockUi()
|
ui := cli.NewMockUi()
|
||||||
return ui, &MountTuneCommand{
|
return ui, &SecretsTuneCommand{
|
||||||
BaseCommand: &BaseCommand{
|
BaseCommand: &BaseCommand{
|
||||||
UI: ui,
|
UI: ui,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMountTuneCommand_Run(t *testing.T) {
|
func TestSecretsTuneCommand_Run(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
cases := []struct {
|
cases := []struct {
|
||||||
@@ -29,15 +29,9 @@ func TestMountTuneCommand_Run(t *testing.T) {
|
|||||||
code int
|
code int
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
"empty",
|
"not_enough_args",
|
||||||
nil,
|
[]string{},
|
||||||
"Missing PATH!",
|
"Not enough arguments",
|
||||||
1,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"slash",
|
|
||||||
[]string{"/"},
|
|
||||||
"Missing PATH!",
|
|
||||||
1,
|
1,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -57,7 +51,7 @@ func TestMountTuneCommand_Run(t *testing.T) {
|
|||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
ui, cmd := testMountTuneCommand(t)
|
ui, cmd := testSecretsTuneCommand(t)
|
||||||
|
|
||||||
code := cmd.Run(tc.args)
|
code := cmd.Run(tc.args)
|
||||||
if code != tc.code {
|
if code != tc.code {
|
||||||
@@ -78,7 +72,7 @@ func TestMountTuneCommand_Run(t *testing.T) {
|
|||||||
client, closer := testVaultServer(t)
|
client, closer := testVaultServer(t)
|
||||||
defer closer()
|
defer closer()
|
||||||
|
|
||||||
ui, cmd := testMountTuneCommand(t)
|
ui, cmd := testSecretsTuneCommand(t)
|
||||||
cmd.client = client
|
cmd.client = client
|
||||||
|
|
||||||
// Mount
|
// Mount
|
||||||
@@ -97,7 +91,7 @@ func TestMountTuneCommand_Run(t *testing.T) {
|
|||||||
t.Errorf("expected %d to be %d", code, exp)
|
t.Errorf("expected %d to be %d", code, exp)
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := "Success! Tuned the mount at: mount_tune_integration/"
|
expected := "Success! Tuned the secrets engine at: mount_tune_integration/"
|
||||||
combined := ui.OutputWriter.String() + ui.ErrorWriter.String()
|
combined := ui.OutputWriter.String() + ui.ErrorWriter.String()
|
||||||
if !strings.Contains(combined, expected) {
|
if !strings.Contains(combined, expected) {
|
||||||
t.Errorf("expected %q to contain %q", combined, expected)
|
t.Errorf("expected %q to contain %q", combined, expected)
|
||||||
@@ -129,7 +123,7 @@ func TestMountTuneCommand_Run(t *testing.T) {
|
|||||||
client, closer := testVaultServerBad(t)
|
client, closer := testVaultServerBad(t)
|
||||||
defer closer()
|
defer closer()
|
||||||
|
|
||||||
ui, cmd := testMountTuneCommand(t)
|
ui, cmd := testSecretsTuneCommand(t)
|
||||||
cmd.client = client
|
cmd.client = client
|
||||||
|
|
||||||
code := cmd.Run([]string{
|
code := cmd.Run([]string{
|
||||||
@@ -139,7 +133,7 @@ func TestMountTuneCommand_Run(t *testing.T) {
|
|||||||
t.Errorf("expected %d to be %d", code, exp)
|
t.Errorf("expected %d to be %d", code, exp)
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := "Error tuning mount pki/: "
|
expected := "Error tuning secrets engine pki/: "
|
||||||
combined := ui.OutputWriter.String() + ui.ErrorWriter.String()
|
combined := ui.OutputWriter.String() + ui.ErrorWriter.String()
|
||||||
if !strings.Contains(combined, expected) {
|
if !strings.Contains(combined, expected) {
|
||||||
t.Errorf("expected %q to contain %q", combined, expected)
|
t.Errorf("expected %q to contain %q", combined, expected)
|
||||||
@@ -149,7 +143,7 @@ func TestMountTuneCommand_Run(t *testing.T) {
|
|||||||
t.Run("no_tabs", func(t *testing.T) {
|
t.Run("no_tabs", func(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
_, cmd := testMountTuneCommand(t)
|
_, cmd := testSecretsTuneCommand(t)
|
||||||
assertNoTabs(t, cmd)
|
assertNoTabs(t, cmd)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -1,94 +0,0 @@
|
|||||||
package command
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/mitchellh/cli"
|
|
||||||
"github.com/posener/complete"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Ensure we are implementing the right interfaces.
|
|
||||||
var _ cli.Command = (*UnmountCommand)(nil)
|
|
||||||
var _ cli.CommandAutocomplete = (*UnmountCommand)(nil)
|
|
||||||
|
|
||||||
// UnmountCommand is a Command that mounts a new mount.
|
|
||||||
type UnmountCommand struct {
|
|
||||||
*BaseCommand
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *UnmountCommand) Synopsis() string {
|
|
||||||
return "Unmounts a secret backend"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *UnmountCommand) Help() string {
|
|
||||||
helpText := `
|
|
||||||
Usage: vault unmount [options] PATH
|
|
||||||
|
|
||||||
Unmounts a secret backend at the given PATH. The argument corresponds to
|
|
||||||
the PATH of the mount, not the TYPE! All secrets created by this backend
|
|
||||||
are revoked and its Vault data is removed.
|
|
||||||
|
|
||||||
If no mount exists at the given path, the command will still return as
|
|
||||||
successful because unmounting is an idempotent operation.
|
|
||||||
|
|
||||||
Unmount the secret backend mounted at aws/:
|
|
||||||
|
|
||||||
$ vault unmount aws/
|
|
||||||
|
|
||||||
For a full list of examples, please see the documentation.
|
|
||||||
|
|
||||||
` + c.Flags().Help()
|
|
||||||
|
|
||||||
return strings.TrimSpace(helpText)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *UnmountCommand) Flags() *FlagSets {
|
|
||||||
return c.flagSet(FlagSetHTTP)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *UnmountCommand) AutocompleteArgs() complete.Predictor {
|
|
||||||
return c.PredictVaultMounts()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *UnmountCommand) AutocompleteFlags() complete.Flags {
|
|
||||||
return c.Flags().Completions()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *UnmountCommand) Run(args []string) int {
|
|
||||||
f := c.Flags()
|
|
||||||
|
|
||||||
if err := f.Parse(args); err != nil {
|
|
||||||
c.UI.Error(err.Error())
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
args = f.Args()
|
|
||||||
mountPath, remaining, err := extractPath(args)
|
|
||||||
if err != nil {
|
|
||||||
c.UI.Error(err.Error())
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(remaining) > 0 {
|
|
||||||
c.UI.Error(fmt.Sprintf("Too many arguments (expected 1, got %d)", len(args)))
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
client, err := c.Client()
|
|
||||||
if err != nil {
|
|
||||||
c.UI.Error(err.Error())
|
|
||||||
return 2
|
|
||||||
}
|
|
||||||
|
|
||||||
// Append a trailing slash to indicate it's a path in output
|
|
||||||
mountPath = ensureTrailingSlash(mountPath)
|
|
||||||
|
|
||||||
if err := client.Sys().Unmount(mountPath); err != nil {
|
|
||||||
c.UI.Error(fmt.Sprintf("Error unmounting %s: %s", mountPath, err))
|
|
||||||
return 2
|
|
||||||
}
|
|
||||||
|
|
||||||
c.UI.Output(fmt.Sprintf("Success! Unmounted the secret backend (if it existed) at: %s", mountPath))
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user