Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 18 additions & 33 deletions command/snapshot/save/snapshot_save.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ type cmd struct {
func (c *cmd) getAppendFileNameFlag() *flag.FlagSet {
fs := flag.NewFlagSet("", flag.ContinueOnError)
fs.Var(&c.appendFileNameFlag, "append-filename", "Append filename flag supports the following "+
"comma-separated arguments. 1. version, 2. dc. 3. node 4. status. It appends these values to the filename provided in the command")
"comma-separated arguments. 1. version, 2. dc. It appends these values to the filename provided in the command")
return fs
}

Expand Down Expand Up @@ -74,50 +74,35 @@ func (c *cmd) Run(args []string) int {
appendFileNameFlags := strings.Split(c.appendFileNameFlag.String(), ",")

if len(appendFileNameFlags) != 0 && len(c.appendFileNameFlag.String()) > 0 {
agentSelfResponse, err := client.Agent().Self()
if err != nil {
c.UI.Error(fmt.Sprintf("Error connecting to Consul agent and fetching datacenter/version: %s", err))
return 1
}

fileExt := filepath.Ext(file)
fileNameWithoutExt := strings.TrimSuffix(file, fileExt)

if slices.Contains(appendFileNameFlags, "version") {
if config, ok := agentSelfResponse["Config"]; ok {
if version, ok := config["Version"]; ok {
fileNameWithoutExt = fileNameWithoutExt + "-" + version.(string)
operatorHealthResponse, err := client.Operator().AutopilotServerHealth(nil)
if err != nil {
c.UI.Error(fmt.Sprintf("Error fetching version of Consul agent Leader: %s", err))
return 1
}
version := ""

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Prefer using

var version string

for zero valued initialization

for _, server := range operatorHealthResponse.Servers {
if server.Leader {
version = server.Version
break
}
}
fileNameWithoutExt = fileNameWithoutExt + "-" + version
}

if slices.Contains(appendFileNameFlags, "dc") {
if config, ok := agentSelfResponse["Config"]; ok {
if datacenter, ok := config["Datacenter"]; ok {
fileNameWithoutExt = fileNameWithoutExt + "-" + datacenter.(string)
}
agentSelfResponse, err := client.Agent().Self()
if err != nil {
c.UI.Error(fmt.Sprintf("Error connecting to Consul agent and fetching datacenter/version: %s", err))
return 1
}
}

if slices.Contains(appendFileNameFlags, "node") {
if config, ok := agentSelfResponse["Config"]; ok {
if nodeName, ok := config["NodeName"]; ok {
fileNameWithoutExt = fileNameWithoutExt + "-" + nodeName.(string)
}
}
}

if slices.Contains(appendFileNameFlags, "status") {
if status, ok := agentSelfResponse["Stats"]; ok {
if config, ok := status["consul"]; ok {
configMap := config.(map[string]interface{})
if leader, ok := configMap["leader"]; ok {
if leader == "true" {
fileNameWithoutExt = fileNameWithoutExt + "-" + "leader"
} else {
fileNameWithoutExt = fileNameWithoutExt + "-" + "follower"
}
}
if datacenter, ok := config["Datacenter"]; ok {
fileNameWithoutExt = fileNameWithoutExt + "-" + datacenter.(string)
}
}
}
Expand Down
27 changes: 13 additions & 14 deletions command/snapshot/save/snapshot_save_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,34 +88,33 @@ func TestSnapshotSaveCommandWithAppendFileNameFlag(t *testing.T) {
dir := testutil.TempDir(t, "snapshot")
file := filepath.Join(dir, "backup.tgz")
args := []string{
"-append-filename=version,dc,node,status",
"-append-filename=version,dc",
"-http-addr=" + a.HTTPAddr(),
file,
}

stats := a.Stats()

status := "follower"

if stats["consul"]["leader"] == "true" {
status = "leader"
}

// We need to use the self endpoint here for ENT, which returns the product suffix (+ent)
self, err := client.Agent().Self()
require.NoError(t, err)

cfg, ok := self["Config"]
require.True(t, ok)

versionAny, ok := cfg["Version"]
dc, ok := cfg["Datacenter"]
require.True(t, ok)

version, ok := versionAny.(string)
require.True(t, ok)
datacenter := dc.(string)

operatorHealth, _ := client.Operator().AutopilotServerHealth(nil)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be good to add a err check here.


version := ""
for _, server := range operatorHealth.Servers {
if server.Leader {
version = server.Version
}
}

newFilePath := filepath.Join(dir, "backup"+"-"+version+"-"+a.Config.Datacenter+
"-"+a.Config.NodeName+"-"+status+".tgz")
newFilePath := filepath.Join(dir, "backup"+"-"+version+"-"+datacenter+".tgz")

code := c.Run(args)
if code != 0 {
Expand Down
16 changes: 8 additions & 8 deletions website/content/commands/snapshot/save.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -77,20 +77,20 @@ $ consul snapshot save -stale backup.snap
# ...
```

To create snapshot file with consul version, datacenter, node name and leader/follower info,
run
This is useful for situations where a cluster is in a degraded state and no
leader is available. To target a specific server for a snapshot, you can run
the `consul snapshot save` command on that specific server.

To create snapshot file with consul version and datacenter run

```shell-session
$ consul snapshot save -append-filename node,status,version,dc backup.snap
$ consul snapshot save -append-filename version,dc backup.snap
#...
```

File name created will be like backup-%CONSUL_VERSION%-%DC_NAME%-%NODE_NAME%-%STATUS.snap
File name created will be like backup-%CONSUL_VERSION%-%DC_NAME%.snap
example - backup-1.17.0-dc1-local-machine-leader.tgz

This is useful for situations where a cluster is in a degraded state and no
leader is available. To target a specific server for a snapshot, you can run
the `consul snapshot save` command on that specific server.
Note Version is always the leader's consul version

Please see the [HTTP API](/consul/api-docs/snapshot) documentation for
more details about snapshot internals.