Update seal command

This commit is contained in:
Seth Vargo 2017-09-05 00:04:19 -04:00
parent 48e6460da5
commit 3f7f8b20bb
No known key found for this signature in database
GPG Key ID: C921994F9C27E0FF
2 changed files with 171 additions and 60 deletions

View File

@ -4,35 +4,17 @@ import (
"fmt"
"strings"
"github.com/hashicorp/vault/meta"
"github.com/mitchellh/cli"
"github.com/posener/complete"
)
// Ensure we are implementing the right interfaces.
var _ cli.Command = (*SealCommand)(nil)
var _ cli.CommandAutocomplete = (*SealCommand)(nil)
// SealCommand is a Command that seals the vault.
type SealCommand struct {
meta.Meta
}
func (c *SealCommand) Run(args []string) int {
flags := c.Meta.FlagSet("seal", meta.FlagSetDefault)
flags.Usage = func() { c.Ui.Error(c.Help()) }
if err := flags.Parse(args); err != nil {
return 1
}
client, err := c.Client()
if err != nil {
c.Ui.Error(fmt.Sprintf(
"Error initializing client: %s", err))
return 2
}
if err := client.Sys().Seal(); err != nil {
c.Ui.Error(fmt.Sprintf("Error sealing: %s", err))
return 1
}
c.Ui.Output("Vault is now sealed.")
return 0
*BaseCommand
}
func (c *SealCommand) Synopsis() string {
@ -43,21 +25,65 @@ func (c *SealCommand) Help() string {
helpText := `
Usage: vault seal [options]
Seal the vault.
Seals the Vault server. Sealing tells the Vault server to stop responding
to any operations until it is unsealed. When sealed, the Vault server
discards its in-memory master key to unlock the data, so it is physically
blocked from responding to operations unsealed.
Sealing a vault tells the Vault server to stop responding to any
access operations until it is unsealed again. A sealed vault throws away
its master key to unlock the data, so it is physically blocked from
responding to operations again until the vault is unsealed with
the "unseal" command or via the API.
If an unseal is in progress, sealing the Vault will reset the unsealing
process. Users will have to re-enter their portions of the master key again.
This command is idempotent, if the vault is already sealed it does nothing.
This command does nothing if the Vault server is already sealed.
If an unseal has started, sealing the vault will reset the unsealing
process. You'll have to re-enter every portion of the master key again.
This is the same as running "vault unseal -reset".
Seal the Vault server:
$ vault seal
For a full list of examples and why you might want to seal the Vault, please
see the documentation.
` + c.Flags().Help()
General Options:
` + meta.GeneralOptionsUsage()
return strings.TrimSpace(helpText)
}
func (c *SealCommand) Flags() *FlagSets {
return c.flagSet(FlagSetHTTP)
}
func (c *SealCommand) AutocompleteArgs() complete.Predictor {
return nil
}
func (c *SealCommand) AutocompleteFlags() complete.Flags {
return c.Flags().Completions()
}
func (c *SealCommand) Run(args []string) int {
f := c.Flags()
if err := f.Parse(args); err != nil {
c.UI.Error(err.Error())
return 1
}
args = f.Args()
if len(args) > 0 {
c.UI.Error(fmt.Sprintf("Too many arguments (expected 0, got %d)", len(args)))
return 1
}
client, err := c.Client()
if err != nil {
c.UI.Error(err.Error())
return 2
}
if err := client.Sys().Seal(); err != nil {
c.UI.Error(fmt.Sprintf("Error sealing: %s", err))
return 2
}
c.UI.Output("Success! Vault is sealed.")
return 0
}

View File

@ -1,37 +1,122 @@
package command
import (
"strings"
"testing"
"github.com/hashicorp/vault/http"
"github.com/hashicorp/vault/meta"
"github.com/hashicorp/vault/vault"
"github.com/mitchellh/cli"
)
func Test_Seal(t *testing.T) {
core, _, token := vault.TestCoreUnsealed(t)
ln, addr := http.TestServer(t, core)
defer ln.Close()
func testSealCommand(tb testing.TB) (*cli.MockUi, *SealCommand) {
tb.Helper()
ui := new(cli.MockUi)
c := &SealCommand{
Meta: meta.Meta{
ClientToken: token,
Ui: ui,
ui := cli.NewMockUi()
return ui, &SealCommand{
BaseCommand: &BaseCommand{
UI: ui,
},
}
}
func TestSealCommand_Run(t *testing.T) {
t.Parallel()
cases := []struct {
name string
args []string
out string
code int
}{
{
"args",
[]string{"foo"},
"Too many arguments",
1,
},
}
args := []string{"-address", addr}
if code := c.Run(args); code != 0 {
t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
}
t.Run("validations", func(t *testing.T) {
t.Parallel()
sealed, err := core.Sealed()
if err != nil {
t.Fatalf("err: %s", err)
}
if !sealed {
t.Fatal("should be sealed")
}
for _, tc := range cases {
tc := tc
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
client, closer := testVaultServer(t)
defer closer()
ui, cmd := testSealCommand(t)
cmd.client = client
code := cmd.Run(tc.args)
if code != tc.code {
t.Errorf("expected %d to be %d", code, tc.code)
}
combined := ui.OutputWriter.String() + ui.ErrorWriter.String()
if !strings.Contains(combined, tc.out) {
t.Errorf("expected %q to contain %q", combined, tc.out)
}
})
}
})
t.Run("integration", func(t *testing.T) {
t.Parallel()
client, closer := testVaultServer(t)
defer closer()
ui, cmd := testSealCommand(t)
cmd.client = client
code := cmd.Run([]string{})
if exp := 0; code != exp {
t.Errorf("expected %d to be %d", code, exp)
}
expected := "Success! Vault is sealed."
combined := ui.OutputWriter.String() + ui.ErrorWriter.String()
if !strings.Contains(combined, expected) {
t.Errorf("expected %q to contain %q", combined, expected)
}
sealStatus, err := client.Sys().SealStatus()
if err != nil {
t.Fatal(err)
}
if !sealStatus.Sealed {
t.Errorf("expected to be sealed")
}
})
t.Run("communication_failure", func(t *testing.T) {
t.Parallel()
client, closer := testVaultServerBad(t)
defer closer()
ui, cmd := testSealCommand(t)
cmd.client = client
code := cmd.Run([]string{})
if exp := 2; code != exp {
t.Errorf("expected %d to be %d", code, exp)
}
expected := "Error sealing: "
combined := ui.OutputWriter.String() + ui.ErrorWriter.String()
if !strings.Contains(combined, expected) {
t.Errorf("expected %q to contain %q", combined, expected)
}
})
t.Run("no_tabs", func(t *testing.T) {
t.Parallel()
_, cmd := testSealCommand(t)
assertNoTabs(t, cmd)
})
}