From 892ba52c56db7c3f1a17cbe5f158c1492c9673b3 Mon Sep 17 00:00:00 2001 From: Jared Kirschner <85913323+jkirschner-hashicorp@users.noreply.github.com> Date: Thu, 31 Aug 2023 15:05:08 -0400 Subject: [PATCH 1/3] docs: admin partition and DNS clarification (#18613) --- website/content/docs/enterprise/admin-partitions.mdx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/website/content/docs/enterprise/admin-partitions.mdx b/website/content/docs/enterprise/admin-partitions.mdx index 023e38ee31e7..74f7d64f0186 100644 --- a/website/content/docs/enterprise/admin-partitions.mdx +++ b/website/content/docs/enterprise/admin-partitions.mdx @@ -53,7 +53,12 @@ Only resources in the `default` admin partition will be replicated to secondary ### DNS Queries -Client agents will be configured to operate within a specific admin partition. The DNS interface will only return results for the admin partition within the scope of the client. +When queried, the DNS interface returns results for a single admin partition. +The query may explicitly specify the admin partition to use in the lookup. +If you do not specify an admin partition in the query, +the lookup uses the admin partition of the Consul agent that received the query. +Server agents always exist within the `default` admin partition. +Client agents are configured to operate within a specific admin partition. ### Service Mesh Configurations From 699aa4741693956a9e6f1c34fae2d90626dbf5f8 Mon Sep 17 00:00:00 2001 From: Michael Zalimeni Date: Thu, 31 Aug 2023 15:59:29 -0400 Subject: [PATCH 2/3] fix: make UNSPECIFIED protocol pass validation (#18634) We explicitly enumerate the allowed protocols in validation, so this change is necessary to use the new enum value. Also add tests for enum validators to ensure they stay aligned to protos unless we explicitly want them to diverge. --- internal/catalog/internal/types/validators.go | 4 +++- .../catalog/internal/types/validators_test.go | 20 +++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/internal/catalog/internal/types/validators.go b/internal/catalog/internal/types/validators.go index 94691107f934..a9934156e298 100644 --- a/internal/catalog/internal/types/validators.go +++ b/internal/catalog/internal/types/validators.go @@ -139,7 +139,9 @@ func validatePortName(name string) error { func validateProtocol(protocol pbcatalog.Protocol) error { switch protocol { - case pbcatalog.Protocol_PROTOCOL_TCP, + case pbcatalog.Protocol_PROTOCOL_UNSPECIFIED, + // means pbcatalog.FailoverMode_FAILOVER_MODE_TCP + pbcatalog.Protocol_PROTOCOL_TCP, pbcatalog.Protocol_PROTOCOL_HTTP, pbcatalog.Protocol_PROTOCOL_HTTP2, pbcatalog.Protocol_PROTOCOL_GRPC, diff --git a/internal/catalog/internal/types/validators_test.go b/internal/catalog/internal/types/validators_test.go index a3790e9f9e05..d62c675cf927 100644 --- a/internal/catalog/internal/types/validators_test.go +++ b/internal/catalog/internal/types/validators_test.go @@ -334,6 +334,26 @@ func TestValidatePortName(t *testing.T) { }) } +func TestValidateProtocol(t *testing.T) { + // this test simply verifies that we accept all enum values specified in our proto + // in order to avoid validator drift. + for name, value := range pbcatalog.Protocol_value { + t.Run(name, func(t *testing.T) { + require.NoError(t, validateProtocol(pbcatalog.Protocol(value))) + }) + } +} + +func TestValidateHealth(t *testing.T) { + // this test simply verifies that we accept all enum values specified in our proto + // in order to avoid validator drift. + for name, value := range pbcatalog.Health_value { + t.Run(name, func(t *testing.T) { + require.NoError(t, validateHealth(pbcatalog.Health(value))) + }) + } +} + func TestValidateWorkloadAddress(t *testing.T) { type testCase struct { addr *pbcatalog.WorkloadAddress From 78e3cbe1562165f891f56c93047031d608ac4ed4 Mon Sep 17 00:00:00 2001 From: Ashesh Vidyut <134911583+absolutelightning@users.noreply.github.com> Date: Fri, 1 Sep 2023 10:23:44 +0530 Subject: [PATCH 3/3] NET 1594 - Snapshot Agent Filename Should Include Consul Version / Datacenter (#18625) * init * tests added and few fixes * revert arg message * changelog added * removed var declaration * fix CI * fix test * added node name and status * updated save.mdx * added example * fix tense * fix description --- .changelog/18625.txt | 5 ++ command/snapshot/save/snapshot_save.go | 76 +++++++++++++++++++-- command/snapshot/save/snapshot_save_test.go | 52 ++++++++++++++ website/content/commands/snapshot/save.mdx | 15 ++++ 4 files changed, 144 insertions(+), 4 deletions(-) create mode 100644 .changelog/18625.txt diff --git a/.changelog/18625.txt b/.changelog/18625.txt new file mode 100644 index 000000000000..8474cac8dc1d --- /dev/null +++ b/.changelog/18625.txt @@ -0,0 +1,5 @@ +```release-note:improvement +Adds flag -append-filename (which works on values version, dc, node and status) to consul snapshot save command. +Adding the flag -append-filename version,dc,node,status will add consul version, consul datacenter, node name and leader/follower +(status) in the file name given in the snapshot save command before the file extension. +``` diff --git a/command/snapshot/save/snapshot_save.go b/command/snapshot/save/snapshot_save.go index 2395a4f3a038..c774e6d89e1d 100644 --- a/command/snapshot/save/snapshot_save.go +++ b/command/snapshot/save/snapshot_save.go @@ -6,7 +6,10 @@ package save import ( "flag" "fmt" + "golang.org/x/exp/slices" "os" + "path/filepath" + "strings" "github.com/mitchellh/cli" "github.com/rboyer/safeio" @@ -23,10 +26,18 @@ func New(ui cli.Ui) *cmd { } type cmd struct { - UI cli.Ui - flags *flag.FlagSet - http *flags.HTTPFlags - help string + UI cli.Ui + flags *flag.FlagSet + http *flags.HTTPFlags + help string + appendFileNameFlag flags.StringValue +} + +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") + return fs } func (c *cmd) init() { @@ -34,6 +45,7 @@ func (c *cmd) init() { c.http = &flags.HTTPFlags{} flags.Merge(c.flags, c.http.ClientFlags()) flags.Merge(c.flags, c.http.ServerFlags()) + flags.Merge(c.flags, c.getAppendFileNameFlag()) c.help = flags.Usage(help, c.flags) } @@ -58,6 +70,62 @@ func (c *cmd) Run(args []string) int { // Create and test the HTTP client client, err := c.http.APIClient() + + 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) + } + } + } + + if slices.Contains(appendFileNameFlags, "dc") { + if config, ok := agentSelfResponse["Config"]; ok { + if datacenter, ok := config["Datacenter"]; ok { + fileNameWithoutExt = fileNameWithoutExt + "-" + datacenter.(string) + } + } + } + + 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" + } + } + } + } + } + + //adding extension back + file = fileNameWithoutExt + fileExt + } + if err != nil { c.UI.Error(fmt.Sprintf("Error connecting to Consul agent: %s", err)) return 1 diff --git a/command/snapshot/save/snapshot_save_test.go b/command/snapshot/save/snapshot_save_test.go index a95b537e9475..8e339cd51f5b 100644 --- a/command/snapshot/save/snapshot_save_test.go +++ b/command/snapshot/save/snapshot_save_test.go @@ -72,6 +72,58 @@ func TestSnapshotSaveCommand_Validation(t *testing.T) { } } +func TestSnapshotSaveCommandWithAppendFileNameFlag(t *testing.T) { + if testing.Short() { + t.Skip("too slow for testing.Short") + } + + t.Parallel() + a := agent.NewTestAgent(t, ``) + defer a.Shutdown() + client := a.Client() + + ui := cli.NewMockUi() + c := New(ui) + + dir := testutil.TempDir(t, "snapshot") + file := filepath.Join(dir, "backup.tgz") + args := []string{ + "-append-filename=version,dc,node,status", + "-http-addr=" + a.HTTPAddr(), + file, + } + + stats := a.Stats() + + status := "follower" + + if stats["consul"]["leader"] == "true" { + status = "leader" + } + + newFilePath := filepath.Join(dir, "backup"+"-"+a.Config.Version+"-"+a.Config.Datacenter+ + "-"+a.Config.NodeName+"-"+status+".tgz") + + code := c.Run(args) + if code != 0 { + t.Fatalf("bad: %d. %#v", code, ui.ErrorWriter.String()) + } + + fi, err := os.Stat(newFilePath) + require.NoError(t, err) + require.Equal(t, fi.Mode(), os.FileMode(0600)) + + f, err := os.Open(newFilePath) + if err != nil { + t.Fatalf("err: %v", err) + } + defer f.Close() + + if err := client.Snapshot().Restore(nil, f); err != nil { + t.Fatalf("err: %v", err) + } +} + func TestSnapshotSaveCommand(t *testing.T) { if testing.Short() { t.Skip("too slow for testing.Short") diff --git a/website/content/commands/snapshot/save.mdx b/website/content/commands/snapshot/save.mdx index 18ffc50150ab..dfd4d4086d45 100644 --- a/website/content/commands/snapshot/save.mdx +++ b/website/content/commands/snapshot/save.mdx @@ -49,6 +49,10 @@ Usage: `consul snapshot save [options] FILE` @include 'http_api_options_server.mdx' +- `-append-filename=` - Value can be - version,dc,node,status +Adds consul version, datacenter name, node name, and status (leader/follower) +to the file name before the extension separated by `-` + ## Examples To create a snapshot from the leader server and save it to "backup.snap": @@ -73,6 +77,17 @@ $ consul snapshot save -stale backup.snap # ... ``` +To create snapshot file with consul version, datacenter, node name and leader/follower info, +run + +```shell-session +$ consul snapshot save -append-filename node,status,version,dc backup.snap +#... +``` + +File name created will be like backup-%CONSUL_VERSION%-%DC_NAME%-%NODE_NAME%-%STATUS.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.