diff --git a/command/commands.go b/command/commands.go index a28f7d49d..416f6cb79 100644 --- a/command/commands.go +++ b/command/commands.go @@ -39,6 +39,7 @@ import ( "github.com/hashicorp/consul/command/snapshot" "github.com/hashicorp/consul/command/snapshotinspect" "github.com/hashicorp/consul/command/snapshotrestore" + "github.com/hashicorp/consul/command/snapshotsave" "github.com/hashicorp/consul/command/validate" versioncmd "github.com/hashicorp/consul/command/version" "github.com/hashicorp/consul/version" @@ -199,12 +200,7 @@ func init() { }, "snapshot save": func() (cli.Command, error) { - return &SnapshotSaveCommand{ - BaseCommand: BaseCommand{ - Flags: FlagSetHTTP, - UI: ui, - }, - }, nil + return snapshotsave.New(ui), nil }, "snapshot inspect": func() (cli.Command, error) { diff --git a/command/snapshot_save.go b/command/snapshotsave/snapshot_save.go similarity index 72% rename from command/snapshot_save.go rename to command/snapshotsave/snapshot_save.go index a628e68db..01d4ae46e 100644 --- a/command/snapshot_save.go +++ b/command/snapshotsave/snapshot_save.go @@ -1,55 +1,54 @@ -package command +package snapshotsave import ( + "flag" "fmt" "io" "os" "github.com/hashicorp/consul/api" + "github.com/hashicorp/consul/command/flags" "github.com/hashicorp/consul/snapshot" + "github.com/mitchellh/cli" ) -// SnapshotSaveCommand is a Command implementation that is used to save the -// state of the Consul servers for disaster recovery. -type SnapshotSaveCommand struct { - BaseCommand +func New(ui cli.Ui) *cmd { + c := &cmd{UI: ui} + c.init() + return c } -func (c *SnapshotSaveCommand) Help() string { - c.InitFlagSet() - return c.HelpCommand(` -Usage: consul snapshot save [options] FILE - - Retrieves an atomic, point-in-time snapshot of the state of the Consul servers - which includes key/value entries, service catalog, prepared queries, sessions, - and ACLs. - - If ACLs are enabled, a management token must be supplied in order to perform - snapshot operations. - - To create a snapshot from the leader server and save it to "backup.snap": - - $ consul snapshot save backup.snap - - To create a potentially stale snapshot from any available server (useful if no - leader is available): - - $ consul snapshot save -stale backup.snap - - For a full list of options and examples, please see the Consul documentation. - -`) +type cmd struct { + UI cli.Ui + flags *flag.FlagSet + http *flags.HTTPFlags + usage string } -func (c *SnapshotSaveCommand) Run(args []string) int { - c.InitFlagSet() - if err := c.FlagSet.Parse(args); err != nil { +func (c *cmd) init() { + c.flags = flag.NewFlagSet("", flag.ContinueOnError) + c.http = &flags.HTTPFlags{} + flags.Merge(c.flags, c.http.ClientFlags()) + flags.Merge(c.flags, c.http.ServerFlags()) + c.usage = flags.Usage(usage, c.flags, c.http.ClientFlags(), c.http.ServerFlags()) +} + +func (c *cmd) Synopsis() string { + return "Saves snapshot of Consul server state" +} + +func (c *cmd) Help() string { + return c.usage +} + +func (c *cmd) Run(args []string) int { + if err := c.flags.Parse(args); err != nil { return 1 } var file string - args = c.FlagSet.Args() + args = c.flags.Args() switch len(args) { case 0: c.UI.Error("Missing FILE argument") @@ -62,7 +61,7 @@ func (c *SnapshotSaveCommand) Run(args []string) int { } // Create and test the HTTP client - client, err := c.HTTPClient() + client, err := c.http.APIClient() if err != nil { c.UI.Error(fmt.Sprintf("Error connecting to Consul agent: %s", err)) return 1 @@ -70,7 +69,7 @@ func (c *SnapshotSaveCommand) Run(args []string) int { // Take the snapshot. snap, qm, err := client.Snapshot().Save(&api.QueryOptions{ - AllowStale: c.HTTPStale(), + AllowStale: c.http.Stale(), }) if err != nil { c.UI.Error(fmt.Sprintf("Error saving snapshot: %s", err)) @@ -114,6 +113,22 @@ func (c *SnapshotSaveCommand) Run(args []string) int { return 0 } -func (c *SnapshotSaveCommand) Synopsis() string { - return "Saves snapshot of Consul server state" -} +const usage = `Usage: consul snapshot save [options] FILE + + Retrieves an atomic, point-in-time snapshot of the state of the Consul servers + which includes key/value entries, service catalog, prepared queries, sessions, + and ACLs. + + If ACLs are enabled, a management token must be supplied in order to perform + snapshot operations. + + To create a snapshot from the leader server and save it to "backup.snap": + + $ consul snapshot save backup.snap + + To create a potentially stale snapshot from any available server (useful if no + leader is available): + + $ consul snapshot save -stale backup.snap + + For a full list of options and examples, please see the Consul documentation.` diff --git a/command/snapshot_save_test.go b/command/snapshotsave/snapshot_save_test.go similarity index 78% rename from command/snapshot_save_test.go rename to command/snapshotsave/snapshot_save_test.go index 3c905d0f1..3d8f84461 100644 --- a/command/snapshot_save_test.go +++ b/command/snapshotsave/snapshot_save_test.go @@ -1,4 +1,4 @@ -package command +package snapshotsave import ( "os" @@ -11,26 +11,12 @@ import ( "github.com/mitchellh/cli" ) -func testSnapshotSaveCommand(t *testing.T) (*cli.MockUi, *SnapshotSaveCommand) { - ui := cli.NewMockUi() - return ui, &SnapshotSaveCommand{ - BaseCommand: BaseCommand{ - UI: ui, - Flags: FlagSetHTTP, - }, - } -} - -func TestSnapshotSaveCommand_implements(t *testing.T) { - t.Parallel() - var _ cli.Command = &SnapshotSaveCommand{} -} - func TestSnapshotSaveCommand_noTabs(t *testing.T) { t.Parallel() - assertNoTabs(t, new(SnapshotSaveCommand)) + if strings.ContainsRune(New(cli.NewMockUi()).Help(), '\t') { + t.Fatal("usage has tabs") + } } - func TestSnapshotSaveCommand_Validation(t *testing.T) { t.Parallel() @@ -49,7 +35,8 @@ func TestSnapshotSaveCommand_Validation(t *testing.T) { } for name, tc := range cases { - ui, c := testSnapshotSaveCommand(t) + ui := cli.NewMockUi() + c := New(ui) // Ensure our buffer is always clear if ui.ErrorWriter != nil { @@ -77,7 +64,8 @@ func TestSnapshotSaveCommand_Run(t *testing.T) { defer a.Shutdown() client := a.Client() - ui, c := testSnapshotSaveCommand(t) + ui := cli.NewMockUi() + c := New(ui) dir := testutil.TempDir(t, "snapshot") defer os.RemoveAll(dir)