Rename mounts to secrets engines and add the subcommand
This commit is contained in:
parent
d4b68970f3
commit
387cce957e
@ -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"
|
||||
)
|
||||
|
||||
func testUnmountCommand(tb testing.TB) (*cli.MockUi, *UnmountCommand) {
|
||||
func testSecretsDisableCommand(tb testing.TB) (*cli.MockUi, *SecretsDisableCommand) {
|
||||
tb.Helper()
|
||||
|
||||
ui := cli.NewMockUi()
|
||||
return ui, &UnmountCommand{
|
||||
return ui, &SecretsDisableCommand{
|
||||
BaseCommand: &BaseCommand{
|
||||
UI: ui,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnmountCommand_Run(t *testing.T) {
|
||||
func TestSecretsDisableCommand_Run(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
cases := []struct {
|
||||
@ -29,27 +29,27 @@ func TestUnmountCommand_Run(t *testing.T) {
|
||||
code int
|
||||
}{
|
||||
{
|
||||
"empty",
|
||||
nil,
|
||||
"Missing PATH!",
|
||||
"not_enough_args",
|
||||
[]string{},
|
||||
"Not enough arguments",
|
||||
1,
|
||||
},
|
||||
{
|
||||
"slash",
|
||||
[]string{"/"},
|
||||
"Missing PATH!",
|
||||
"too_many_args",
|
||||
[]string{"foo", "bar"},
|
||||
"Too many arguments",
|
||||
1,
|
||||
},
|
||||
{
|
||||
"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,
|
||||
},
|
||||
{
|
||||
"default",
|
||||
[]string{"secret"},
|
||||
"Success! Unmounted the secret backend (if it existed) at: secret/",
|
||||
"Success! Disabled the secrets engine (if it existed) at: secret/",
|
||||
0,
|
||||
},
|
||||
}
|
||||
@ -66,7 +66,7 @@ func TestUnmountCommand_Run(t *testing.T) {
|
||||
client, closer := testVaultServer(t)
|
||||
defer closer()
|
||||
|
||||
ui, cmd := testUnmountCommand(t)
|
||||
ui, cmd := testSecretsDisableCommand(t)
|
||||
cmd.client = client
|
||||
|
||||
code := cmd.Run(tc.args)
|
||||
@ -88,23 +88,23 @@ func TestUnmountCommand_Run(t *testing.T) {
|
||||
client, closer := testVaultServer(t)
|
||||
defer closer()
|
||||
|
||||
if err := client.Sys().Mount("integration_unmount/", &api.MountInput{
|
||||
if err := client.Sys().Mount("my-secret/", &api.MountInput{
|
||||
Type: "generic",
|
||||
}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
ui, cmd := testUnmountCommand(t)
|
||||
ui, cmd := testSecretsDisableCommand(t)
|
||||
cmd.client = client
|
||||
|
||||
code := cmd.Run([]string{
|
||||
"integration_unmount/",
|
||||
"my-secret/",
|
||||
})
|
||||
if exp := 0; 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()
|
||||
if !strings.Contains(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)
|
||||
defer closer()
|
||||
|
||||
ui, cmd := testUnmountCommand(t)
|
||||
ui, cmd := testSecretsDisableCommand(t)
|
||||
cmd.client = client
|
||||
|
||||
code := cmd.Run([]string{
|
||||
@ -136,7 +136,7 @@ func TestUnmountCommand_Run(t *testing.T) {
|
||||
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()
|
||||
if !strings.Contains(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.Parallel()
|
||||
|
||||
_, cmd := testUnmountCommand(t)
|
||||
_, cmd := testSecretsDisableCommand(t)
|
||||
assertNoTabs(t, cmd)
|
||||
})
|
||||
}
|
@ -10,12 +10,10 @@ import (
|
||||
"github.com/posener/complete"
|
||||
)
|
||||
|
||||
// Ensure we are implementing the right interfaces.
|
||||
var _ cli.Command = (*MountCommand)(nil)
|
||||
var _ cli.CommandAutocomplete = (*MountCommand)(nil)
|
||||
var _ cli.Command = (*SecretsEnableCommand)(nil)
|
||||
var _ cli.CommandAutocomplete = (*SecretsEnableCommand)(nil)
|
||||
|
||||
// MountCommand is a Command that mounts a new mount.
|
||||
type MountCommand struct {
|
||||
type SecretsEnableCommand struct {
|
||||
*BaseCommand
|
||||
|
||||
flagDescription string
|
||||
@ -27,45 +25,45 @@ type MountCommand struct {
|
||||
flagLocal bool
|
||||
}
|
||||
|
||||
func (c *MountCommand) Synopsis() string {
|
||||
return "Mounts a secret backend at a path"
|
||||
func (c *SecretsEnableCommand) Synopsis() string {
|
||||
return "Enable a secrets engine"
|
||||
}
|
||||
|
||||
func (c *MountCommand) Help() string {
|
||||
func (c *SecretsEnableCommand) Help() string {
|
||||
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
|
||||
mounted at the path corresponding to their "type", but users can customize
|
||||
the mount point using the -path option.
|
||||
Enables a secrets engine. By default, secrets engines are enabled at the path
|
||||
corresponding to their TYPE, but users can customize the path using the
|
||||
-path option.
|
||||
|
||||
Once mounted at a path, Vault will route all requests which begin with the
|
||||
path to the secret backend.
|
||||
Once enabled, Vault will route all requests which begin with the path to the
|
||||
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()
|
||||
|
||||
return strings.TrimSpace(helpText)
|
||||
}
|
||||
|
||||
func (c *MountCommand) Flags() *FlagSets {
|
||||
func (c *SecretsEnableCommand) Flags() *FlagSets {
|
||||
set := c.flagSet(FlagSetHTTP)
|
||||
|
||||
f := set.NewFlagSet("Command Options")
|
||||
@ -74,7 +72,7 @@ func (c *MountCommand) Flags() *FlagSets {
|
||||
Name: "description",
|
||||
Target: &c.flagDescription,
|
||||
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{
|
||||
@ -82,31 +80,34 @@ func (c *MountCommand) Flags() *FlagSets {
|
||||
Target: &c.flagPath,
|
||||
Default: "", // The default is complex, so we have to manually document
|
||||
Completion: complete.PredictAnything,
|
||||
Usage: "Place where the mount will be accessible. This must be " +
|
||||
"unique across all mounts. This defaults to the \"type\" of the mount.",
|
||||
Usage: "Place where the secrets engine will be accessible. This must be " +
|
||||
"unique cross all secrets engines. This defaults to the \"type\" of the " +
|
||||
"secrets engine.",
|
||||
})
|
||||
|
||||
f.DurationVar(&DurationVar{
|
||||
Name: "default-lease-ttl",
|
||||
Target: &c.flagDefaultLeaseTTL,
|
||||
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.",
|
||||
Usage: "The default lease TTL for this secrets engine. If unspecified, " +
|
||||
"this defaults to the Vault server's globally configured default lease " +
|
||||
"TTL.",
|
||||
})
|
||||
|
||||
f.DurationVar(&DurationVar{
|
||||
Name: "max-lease-ttl",
|
||||
Target: &c.flagMaxLeaseTTL,
|
||||
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.",
|
||||
Usage: "The maximum lease TTL for this secrets engine. If unspecified, " +
|
||||
"this defaults to the Vault server's globally configured maximum lease " +
|
||||
"TTL.",
|
||||
})
|
||||
|
||||
f.BoolVar(&BoolVar{
|
||||
Name: "force-no-cache",
|
||||
Target: &c.flagForceNoCache,
|
||||
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. " +
|
||||
"This does not affect caching of the underlying encrypted data storage.",
|
||||
})
|
||||
@ -115,30 +116,30 @@ func (c *MountCommand) Flags() *FlagSets {
|
||||
Name: "plugin-name",
|
||||
Target: &c.flagPluginName,
|
||||
Completion: complete.PredictAnything,
|
||||
Usage: "Name of the plugin to mount. This plugin name must already exist " +
|
||||
"in the Vault server's plugin catalog.",
|
||||
Usage: "Name of the secrets engine plugin. This plugin name must already " +
|
||||
"exist in Vault's plugin catalog.",
|
||||
})
|
||||
|
||||
f.BoolVar(&BoolVar{
|
||||
Name: "local",
|
||||
Target: &c.flagLocal,
|
||||
Default: false,
|
||||
Usage: "Mark the mount as a local-only mount. Local mounts are not " +
|
||||
"replicated nor removed by replication.",
|
||||
Usage: "Mark the secrets engine as local-only. Local engines are not " +
|
||||
"replicated or removed by replication.",
|
||||
})
|
||||
|
||||
return set
|
||||
}
|
||||
|
||||
func (c *MountCommand) AutocompleteArgs() complete.Predictor {
|
||||
func (c *SecretsEnableCommand) AutocompleteArgs() complete.Predictor {
|
||||
return c.PredictVaultAvailableMounts()
|
||||
}
|
||||
|
||||
func (c *MountCommand) AutocompleteFlags() complete.Flags {
|
||||
func (c *SecretsEnableCommand) AutocompleteFlags() complete.Flags {
|
||||
return c.Flags().Completions()
|
||||
}
|
||||
|
||||
func (c *MountCommand) Run(args []string) int {
|
||||
func (c *SecretsEnableCommand) Run(args []string) int {
|
||||
f := c.Flags()
|
||||
|
||||
if err := f.Parse(args); err != nil {
|
||||
@ -147,13 +148,11 @@ func (c *MountCommand) Run(args []string) int {
|
||||
}
|
||||
|
||||
args = f.Args()
|
||||
switch len(args) {
|
||||
case 0:
|
||||
c.UI.Error("Missing TYPE!")
|
||||
switch {
|
||||
case len(args) < 1:
|
||||
c.UI.Error(fmt.Sprintf("Not enough arguments (expected 1, got %d)", len(args)))
|
||||
return 1
|
||||
case 1:
|
||||
// OK
|
||||
default:
|
||||
case len(args) > 1:
|
||||
c.UI.Error(fmt.Sprintf("Too many arguments (expected 1, got %d)", len(args)))
|
||||
return 1
|
||||
}
|
||||
@ -164,17 +163,17 @@ func (c *MountCommand) Run(args []string) int {
|
||||
return 2
|
||||
}
|
||||
|
||||
// Get the mount type (first arg)
|
||||
mountType := strings.TrimSpace(args[0])
|
||||
// Get the engine type type (first arg)
|
||||
engineType := strings.TrimSpace(args[0])
|
||||
|
||||
// If no path is specified, we default the path to the backend type
|
||||
// or use the plugin name if it's a plugin backend
|
||||
mountPath := c.flagPath
|
||||
if mountPath == "" {
|
||||
if mountType == "plugin" {
|
||||
if engineType == "plugin" {
|
||||
mountPath = c.flagPluginName
|
||||
} else {
|
||||
mountPath = mountType
|
||||
mountPath = engineType
|
||||
}
|
||||
}
|
||||
|
||||
@ -183,7 +182,7 @@ func (c *MountCommand) Run(args []string) int {
|
||||
|
||||
// Build mount input
|
||||
mountInput := &api.MountInput{
|
||||
Type: mountType,
|
||||
Type: engineType,
|
||||
Description: c.flagDescription,
|
||||
Local: c.flagLocal,
|
||||
Config: api.MountConfigInput{
|
||||
@ -195,15 +194,15 @@ func (c *MountCommand) Run(args []string) int {
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
mountThing := mountType + " secret backend"
|
||||
if mountType == "plugin" {
|
||||
mountThing = c.flagPluginName + " plugin"
|
||||
thing := engineType + " secrets engine"
|
||||
if engineType == "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
|
||||
}
|
@ -7,17 +7,18 @@ import (
|
||||
"github.com/mitchellh/cli"
|
||||
)
|
||||
|
||||
func testMountCommand(tb testing.TB) (*cli.MockUi, *MountCommand) {
|
||||
func testSecretsEnableCommand(tb testing.TB) (*cli.MockUi, *SecretsEnableCommand) {
|
||||
tb.Helper()
|
||||
|
||||
ui := cli.NewMockUi()
|
||||
return ui, &MountCommand{
|
||||
return ui, &SecretsEnableCommand{
|
||||
BaseCommand: &BaseCommand{
|
||||
UI: ui,
|
||||
},
|
||||
}
|
||||
}
|
||||
func TestMountCommand_Run(t *testing.T) {
|
||||
|
||||
func TestSecretsEnableCommand_Run(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
cases := []struct {
|
||||
@ -27,9 +28,9 @@ func TestMountCommand_Run(t *testing.T) {
|
||||
code int
|
||||
}{
|
||||
{
|
||||
"empty",
|
||||
nil,
|
||||
"Missing TYPE!",
|
||||
"not_enough_args",
|
||||
[]string{},
|
||||
"Not enough arguments",
|
||||
1,
|
||||
},
|
||||
{
|
||||
@ -47,7 +48,7 @@ func TestMountCommand_Run(t *testing.T) {
|
||||
{
|
||||
"mount",
|
||||
[]string{"transit"},
|
||||
"Success! Mounted the transit secret backend at: transit/",
|
||||
"Success! Enabled the transit secrets engine at: transit/",
|
||||
0,
|
||||
},
|
||||
{
|
||||
@ -56,7 +57,7 @@ func TestMountCommand_Run(t *testing.T) {
|
||||
"-path", "transit_mount_point",
|
||||
"transit",
|
||||
},
|
||||
"Success! Mounted the transit secret backend at: transit_mount_point/",
|
||||
"Success! Enabled the transit secrets engine at: transit_mount_point/",
|
||||
0,
|
||||
},
|
||||
}
|
||||
@ -70,7 +71,7 @@ func TestMountCommand_Run(t *testing.T) {
|
||||
client, closer := testVaultServer(t)
|
||||
defer closer()
|
||||
|
||||
ui, cmd := testMountCommand(t)
|
||||
ui, cmd := testSecretsEnableCommand(t)
|
||||
cmd.client = client
|
||||
|
||||
code := cmd.Run(tc.args)
|
||||
@ -91,7 +92,7 @@ func TestMountCommand_Run(t *testing.T) {
|
||||
client, closer := testVaultServer(t)
|
||||
defer closer()
|
||||
|
||||
ui, cmd := testMountCommand(t)
|
||||
ui, cmd := testSecretsEnableCommand(t)
|
||||
cmd.client = client
|
||||
|
||||
code := cmd.Run([]string{
|
||||
@ -106,7 +107,7 @@ func TestMountCommand_Run(t *testing.T) {
|
||||
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()
|
||||
if !strings.Contains(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)
|
||||
defer closer()
|
||||
|
||||
ui, cmd := testMountCommand(t)
|
||||
ui, cmd := testSecretsEnableCommand(t)
|
||||
cmd.client = client
|
||||
|
||||
code := cmd.Run([]string{
|
||||
@ -154,7 +155,7 @@ func TestMountCommand_Run(t *testing.T) {
|
||||
t.Errorf("expected %d to be %d", code, exp)
|
||||
}
|
||||
|
||||
expected := "Error mounting: "
|
||||
expected := "Error enabling: "
|
||||
combined := ui.OutputWriter.String() + ui.ErrorWriter.String()
|
||||
if !strings.Contains(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.Parallel()
|
||||
|
||||
_, cmd := testMountCommand(t)
|
||||
_, cmd := testSecretsEnableCommand(t)
|
||||
assertNoTabs(t, cmd)
|
||||
})
|
||||
}
|
@ -11,44 +11,42 @@ import (
|
||||
"github.com/posener/complete"
|
||||
)
|
||||
|
||||
// Ensure we are implementing the right interfaces.
|
||||
var _ cli.Command = (*MountsCommand)(nil)
|
||||
var _ cli.CommandAutocomplete = (*MountsCommand)(nil)
|
||||
var _ cli.Command = (*SecretsListCommand)(nil)
|
||||
var _ cli.CommandAutocomplete = (*SecretsListCommand)(nil)
|
||||
|
||||
// MountsCommand is a Command that lists the mounts.
|
||||
type MountsCommand struct {
|
||||
type SecretsListCommand struct {
|
||||
*BaseCommand
|
||||
|
||||
flagDetailed bool
|
||||
}
|
||||
|
||||
func (c *MountsCommand) Synopsis() string {
|
||||
return "Lists mounted secret backends"
|
||||
func (c *SecretsListCommand) Synopsis() string {
|
||||
return "List enabled secrets engines"
|
||||
}
|
||||
|
||||
func (c *MountsCommand) Help() string {
|
||||
func (c *SecretsListCommand) Help() string {
|
||||
helpText := `
|
||||
Usage: vault mounts [options]
|
||||
Usage: vault secrets list [options]
|
||||
|
||||
Lists the mounted secret backends on the Vault server. This command also
|
||||
outputs information about the mount point including configured TTLs and
|
||||
Lists the enabled secret engines on the Vault server. This command also
|
||||
outputs information about the enabled path including configured TTLs and
|
||||
human-friendly descriptions. A TTL of "system" indicates that the system
|
||||
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()
|
||||
|
||||
return strings.TrimSpace(helpText)
|
||||
}
|
||||
|
||||
func (c *MountsCommand) Flags() *FlagSets {
|
||||
func (c *SecretsListCommand) Flags() *FlagSets {
|
||||
set := c.flagSet(FlagSetHTTP)
|
||||
|
||||
f := set.NewFlagSet("Command Options")
|
||||
@ -58,21 +56,21 @@ func (c *MountsCommand) Flags() *FlagSets {
|
||||
Target: &c.flagDetailed,
|
||||
Default: false,
|
||||
Usage: "Print detailed information such as TTLs and replication status " +
|
||||
"about each mount.",
|
||||
"about each secrets engine.",
|
||||
})
|
||||
|
||||
return set
|
||||
}
|
||||
|
||||
func (c *MountsCommand) AutocompleteArgs() complete.Predictor {
|
||||
func (c *SecretsListCommand) AutocompleteArgs() complete.Predictor {
|
||||
return c.PredictVaultFiles()
|
||||
}
|
||||
|
||||
func (c *MountsCommand) AutocompleteFlags() complete.Flags {
|
||||
func (c *SecretsListCommand) AutocompleteFlags() complete.Flags {
|
||||
return c.Flags().Completions()
|
||||
}
|
||||
|
||||
func (c *MountsCommand) Run(args []string) int {
|
||||
func (c *SecretsListCommand) Run(args []string) int {
|
||||
f := c.Flags()
|
||||
|
||||
if err := f.Parse(args); err != nil {
|
||||
@ -94,20 +92,20 @@ func (c *MountsCommand) Run(args []string) int {
|
||||
|
||||
mounts, err := client.Sys().ListMounts()
|
||||
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
|
||||
}
|
||||
|
||||
if c.flagDetailed {
|
||||
c.UI.Output(tableOutput(c.detailedMounts(mounts)))
|
||||
c.UI.Output(tableOutput(c.detailedMounts(mounts), nil))
|
||||
return 0
|
||||
}
|
||||
|
||||
c.UI.Output(tableOutput(c.simpleMounts(mounts)))
|
||||
c.UI.Output(tableOutput(c.simpleMounts(mounts), nil))
|
||||
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))
|
||||
for path := range mounts {
|
||||
paths = append(paths, path)
|
||||
@ -123,7 +121,7 @@ func (c *MountsCommand) simpleMounts(mounts map[string]*api.MountOutput) []strin
|
||||
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))
|
||||
for path := range mounts {
|
||||
paths = append(paths, path)
|
@ -7,18 +7,18 @@ import (
|
||||
"github.com/mitchellh/cli"
|
||||
)
|
||||
|
||||
func testMountsCommand(tb testing.TB) (*cli.MockUi, *MountsCommand) {
|
||||
func testSecretsListCommand(tb testing.TB) (*cli.MockUi, *SecretsListCommand) {
|
||||
tb.Helper()
|
||||
|
||||
ui := cli.NewMockUi()
|
||||
return ui, &MountsCommand{
|
||||
return ui, &SecretsListCommand{
|
||||
BaseCommand: &BaseCommand{
|
||||
UI: ui,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func TestMountsCommand_Run(t *testing.T) {
|
||||
func TestSecretsListCommand_Run(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
cases := []struct {
|
||||
@ -59,7 +59,7 @@ func TestMountsCommand_Run(t *testing.T) {
|
||||
client, closer := testVaultServer(t)
|
||||
defer closer()
|
||||
|
||||
ui, cmd := testMountsCommand(t)
|
||||
ui, cmd := testSecretsListCommand(t)
|
||||
cmd.client = client
|
||||
|
||||
code := cmd.Run(tc.args)
|
||||
@ -81,7 +81,7 @@ func TestMountsCommand_Run(t *testing.T) {
|
||||
client, closer := testVaultServerBad(t)
|
||||
defer closer()
|
||||
|
||||
ui, cmd := testMountsCommand(t)
|
||||
ui, cmd := testSecretsListCommand(t)
|
||||
cmd.client = client
|
||||
|
||||
code := cmd.Run([]string{})
|
||||
@ -89,7 +89,7 @@ func TestMountsCommand_Run(t *testing.T) {
|
||||
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()
|
||||
if !strings.Contains(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.Parallel()
|
||||
|
||||
_, cmd := testMountsCommand(t)
|
||||
_, cmd := testSecretsListCommand(t)
|
||||
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"
|
||||
)
|
||||
|
||||
func testRemountCommand(tb testing.TB) (*cli.MockUi, *RemountCommand) {
|
||||
func testSecretsMoveCommand(tb testing.TB) (*cli.MockUi, *SecretsMoveCommand) {
|
||||
tb.Helper()
|
||||
|
||||
ui := cli.NewMockUi()
|
||||
return ui, &RemountCommand{
|
||||
return ui, &SecretsMoveCommand{
|
||||
BaseCommand: &BaseCommand{
|
||||
UI: ui,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func TestRemountCommand_Run(t *testing.T) {
|
||||
func TestSecretsMoveCommand_Run(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
cases := []struct {
|
||||
@ -29,7 +29,7 @@ func TestRemountCommand_Run(t *testing.T) {
|
||||
}{
|
||||
{
|
||||
"not_enough_args",
|
||||
nil,
|
||||
[]string{},
|
||||
"Not enough arguments",
|
||||
1,
|
||||
},
|
||||
@ -42,7 +42,7 @@ func TestRemountCommand_Run(t *testing.T) {
|
||||
{
|
||||
"non_existent",
|
||||
[]string{"not_real", "over_here"},
|
||||
"Error remounting not_real/ to over_here/",
|
||||
"Error moving secrets engine not_real/ to over_here/",
|
||||
2,
|
||||
},
|
||||
}
|
||||
@ -56,7 +56,7 @@ func TestRemountCommand_Run(t *testing.T) {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
ui, cmd := testRemountCommand(t)
|
||||
ui, cmd := testSecretsMoveCommand(t)
|
||||
|
||||
code := cmd.Run(tc.args)
|
||||
if code != tc.code {
|
||||
@ -77,7 +77,7 @@ func TestRemountCommand_Run(t *testing.T) {
|
||||
client, closer := testVaultServer(t)
|
||||
defer closer()
|
||||
|
||||
ui, cmd := testRemountCommand(t)
|
||||
ui, cmd := testSecretsMoveCommand(t)
|
||||
cmd.client = client
|
||||
|
||||
code := cmd.Run([]string{
|
||||
@ -87,7 +87,7 @@ func TestRemountCommand_Run(t *testing.T) {
|
||||
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()
|
||||
if !strings.Contains(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)
|
||||
defer closer()
|
||||
|
||||
ui, cmd := testRemountCommand(t)
|
||||
ui, cmd := testSecretsMoveCommand(t)
|
||||
cmd.client = client
|
||||
|
||||
code := cmd.Run([]string{
|
||||
@ -119,7 +119,7 @@ func TestRemountCommand_Run(t *testing.T) {
|
||||
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()
|
||||
if !strings.Contains(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.Parallel()
|
||||
|
||||
_, cmd := testRemountCommand(t)
|
||||
_, cmd := testSecretsMoveCommand(t)
|
||||
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"
|
||||
)
|
||||
|
||||
func testMountTuneCommand(tb testing.TB) (*cli.MockUi, *MountTuneCommand) {
|
||||
func testSecretsTuneCommand(tb testing.TB) (*cli.MockUi, *SecretsTuneCommand) {
|
||||
tb.Helper()
|
||||
|
||||
ui := cli.NewMockUi()
|
||||
return ui, &MountTuneCommand{
|
||||
return ui, &SecretsTuneCommand{
|
||||
BaseCommand: &BaseCommand{
|
||||
UI: ui,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func TestMountTuneCommand_Run(t *testing.T) {
|
||||
func TestSecretsTuneCommand_Run(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
cases := []struct {
|
||||
@ -29,15 +29,9 @@ func TestMountTuneCommand_Run(t *testing.T) {
|
||||
code int
|
||||
}{
|
||||
{
|
||||
"empty",
|
||||
nil,
|
||||
"Missing PATH!",
|
||||
1,
|
||||
},
|
||||
{
|
||||
"slash",
|
||||
[]string{"/"},
|
||||
"Missing PATH!",
|
||||
"not_enough_args",
|
||||
[]string{},
|
||||
"Not enough arguments",
|
||||
1,
|
||||
},
|
||||
{
|
||||
@ -57,7 +51,7 @@ func TestMountTuneCommand_Run(t *testing.T) {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
ui, cmd := testMountTuneCommand(t)
|
||||
ui, cmd := testSecretsTuneCommand(t)
|
||||
|
||||
code := cmd.Run(tc.args)
|
||||
if code != tc.code {
|
||||
@ -78,7 +72,7 @@ func TestMountTuneCommand_Run(t *testing.T) {
|
||||
client, closer := testVaultServer(t)
|
||||
defer closer()
|
||||
|
||||
ui, cmd := testMountTuneCommand(t)
|
||||
ui, cmd := testSecretsTuneCommand(t)
|
||||
cmd.client = client
|
||||
|
||||
// Mount
|
||||
@ -97,7 +91,7 @@ func TestMountTuneCommand_Run(t *testing.T) {
|
||||
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()
|
||||
if !strings.Contains(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)
|
||||
defer closer()
|
||||
|
||||
ui, cmd := testMountTuneCommand(t)
|
||||
ui, cmd := testSecretsTuneCommand(t)
|
||||
cmd.client = client
|
||||
|
||||
code := cmd.Run([]string{
|
||||
@ -139,7 +133,7 @@ func TestMountTuneCommand_Run(t *testing.T) {
|
||||
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()
|
||||
if !strings.Contains(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.Parallel()
|
||||
|
||||
_, cmd := testMountTuneCommand(t)
|
||||
_, cmd := testSecretsTuneCommand(t)
|
||||
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
|
||||
}
|
Loading…
Reference in New Issue
Block a user