Skip to content

Commit

Permalink
Add dr-token Flag to Autopilot CLI (#21165)
Browse files Browse the repository at this point in the history
* Add dr-token flag for raft autopilot

* Add changelog

* Cleanup bad patch apply

* Set dr token explicitly
  • Loading branch information
ltcarbonell committed Jul 27, 2023
1 parent f45e9b9 commit 727c73c
Show file tree
Hide file tree
Showing 6 changed files with 84 additions and 5 deletions.
17 changes: 17 additions & 0 deletions api/sys_raft.go
Expand Up @@ -276,11 +276,19 @@ func (c *Sys) RaftAutopilotState() (*AutopilotState, error) {
return c.RaftAutopilotStateWithContext(context.Background())
}

// RaftAutopilotStateWithToken wraps RaftAutopilotStateWithContext using the given token.
func (c *Sys) RaftAutopilotStateWithDRToken(drToken string) (*AutopilotState, error) {
return c.RaftAutopilotStateWithContext(context.WithValue(context.Background(), "dr-token", drToken))
}

// RaftAutopilotStateWithContext returns the state of the raft cluster as seen by autopilot.
func (c *Sys) RaftAutopilotStateWithContext(ctx context.Context) (*AutopilotState, error) {
ctx, cancelFunc := c.c.withConfiguredTimeout(ctx)
defer cancelFunc()

if ctx.Value("dr-token") != nil {
c.c.SetToken(ctx.Value("dr-token").(string))
}
r := c.c.NewRequest(http.MethodGet, "/v1/sys/storage/raft/autopilot/state")

resp, err := c.c.rawRequestWithContext(ctx, r)
Expand Down Expand Up @@ -316,11 +324,20 @@ func (c *Sys) RaftAutopilotConfiguration() (*AutopilotConfig, error) {
return c.RaftAutopilotConfigurationWithContext(context.Background())
}

// RaftAutopilotConfigurationWithDRToken wraps RaftAutopilotConfigurationWithContext using the given token.
func (c *Sys) RaftAutopilotConfigurationWithDRToken(drToken string) (*AutopilotConfig, error) {
return c.RaftAutopilotConfigurationWithContext(context.WithValue(context.Background(), "dr-token", drToken))
}

// RaftAutopilotConfigurationWithContext fetches the autopilot config.
func (c *Sys) RaftAutopilotConfigurationWithContext(ctx context.Context) (*AutopilotConfig, error) {
ctx, cancelFunc := c.c.withConfiguredTimeout(ctx)
defer cancelFunc()

if ctx.Value("dr-token") != nil {
c.c.SetToken(ctx.Value("dr-token").(string))
}

r := c.c.NewRequest(http.MethodGet, "/v1/sys/storage/raft/autopilot/configuration")

resp, err := c.c.rawRequestWithContext(ctx, r)
Expand Down
3 changes: 3 additions & 0 deletions changelog/21165.txt
@@ -0,0 +1,3 @@
```release-note:bug
raft/autopilot: Add dr-token flag for raft autopilot cli commands
```
23 changes: 19 additions & 4 deletions command/operator_raft_autopilot_get_config.go
Expand Up @@ -7,6 +7,7 @@ import (
"fmt"
"strings"

"github.com/hashicorp/vault/api"
"github.com/mitchellh/cli"
"github.com/posener/complete"
)
Expand All @@ -18,6 +19,7 @@ var (

type OperatorRaftAutopilotGetConfigCommand struct {
*BaseCommand
flagDRToken string
}

func (c *OperatorRaftAutopilotGetConfigCommand) Synopsis() string {
Expand All @@ -37,6 +39,17 @@ Usage: vault operator raft autopilot get-config
func (c *OperatorRaftAutopilotGetConfigCommand) Flags() *FlagSets {
set := c.flagSet(FlagSetHTTP | FlagSetOutputFormat)

f := set.NewFlagSet("Command Options")

f.StringVar(&StringVar{
Name: "dr-token",
Target: &c.flagDRToken,
Default: "",
EnvVar: "",
Completion: complete.PredictAnything,
Usage: "DR operation token used to authorize this request (if a DR secondary node).",
})

return set
}

Expand Down Expand Up @@ -70,10 +83,12 @@ func (c *OperatorRaftAutopilotGetConfigCommand) Run(args []string) int {
return 2
}

config, err := client.Sys().RaftAutopilotConfiguration()
if err != nil {
c.UI.Error(err.Error())
return 2
var config *api.AutopilotConfig
switch {
case c.flagDRToken != "":
config, err = client.Sys().RaftAutopilotConfigurationWithDRToken(c.flagDRToken)
default:
config, err = client.Sys().RaftAutopilotConfiguration()
}

if config == nil {
Expand Down
20 changes: 20 additions & 0 deletions command/operator_raft_autopilot_set_config.go
Expand Up @@ -26,6 +26,7 @@ type OperatorRaftAutopilotSetConfigCommand struct {
flagMinQuorum uint
flagServerStabilizationTime time.Duration
flagDisableUpgradeMigration BoolPtr
flagDRToken string
}

func (c *OperatorRaftAutopilotSetConfigCommand) Synopsis() string {
Expand All @@ -50,36 +51,52 @@ func (c *OperatorRaftAutopilotSetConfigCommand) Flags() *FlagSets {
f.BoolPtrVar(&BoolPtrVar{
Name: "cleanup-dead-servers",
Target: &c.flagCleanupDeadServers,
Usage: "Controls whether to remove dead servers from the Raft peer list periodically or when a new server joins.",
})

f.DurationVar(&DurationVar{
Name: "last-contact-threshold",
Target: &c.flagLastContactThreshold,
Usage: "Limit on the amount of time a server can go without leader contact before being considered unhealthy.",
})

f.DurationVar(&DurationVar{
Name: "dead-server-last-contact-threshold",
Target: &c.flagDeadServerLastContactThreshold,
Usage: "Limit on the amount of time a server can go without leader contact before being considered failed. This takes effect only when cleanup_dead_servers is set.",
})

f.Uint64Var(&Uint64Var{
Name: "max-trailing-logs",
Target: &c.flagMaxTrailingLogs,
Usage: "Amount of entries in the Raft Log that a server can be behind before being considered unhealthy.",
})

f.UintVar(&UintVar{
Name: "min-quorum",
Target: &c.flagMinQuorum,
Usage: "Minimum number of servers allowed in a cluster before autopilot can prune dead servers. This should at least be 3.",
})

f.DurationVar(&DurationVar{
Name: "server-stabilization-time",
Target: &c.flagServerStabilizationTime,
Usage: "Minimum amount of time a server must be in a stable, healthy state before it can be added to the cluster.",
})

f.BoolPtrVar(&BoolPtrVar{
Name: "disable-upgrade-migration",
Target: &c.flagDisableUpgradeMigration,
Usage: "Whether or not to perform automated version upgrades.",
})

f.StringVar(&StringVar{
Name: "dr-token",
Target: &c.flagDRToken,
Default: "",
EnvVar: "",
Completion: complete.PredictAnything,
Usage: "DR operation token used to authorize this request (if a DR secondary node).",
})

return set
Expand Down Expand Up @@ -137,6 +154,9 @@ func (c *OperatorRaftAutopilotSetConfigCommand) Run(args []string) int {
if c.flagDisableUpgradeMigration.IsSet() {
data["disable_upgrade_migration"] = c.flagDisableUpgradeMigration.Get()
}
if c.flagDRToken != "" {
data["dr_operation_token"] = c.flagDRToken
}

secret, err := client.Logical().Write("sys/storage/raft/autopilot/configuration", data)
if err != nil {
Expand Down
22 changes: 21 additions & 1 deletion command/operator_raft_autopilot_state.go
Expand Up @@ -8,6 +8,7 @@ import (
"fmt"
"strings"

"github.com/hashicorp/vault/api"
"github.com/mitchellh/cli"
"github.com/posener/complete"
)
Expand All @@ -19,6 +20,7 @@ var (

type OperatorRaftAutopilotStateCommand struct {
*BaseCommand
flagDRToken string
}

func (c *OperatorRaftAutopilotStateCommand) Synopsis() string {
Expand All @@ -38,6 +40,17 @@ Usage: vault operator raft autopilot state
func (c *OperatorRaftAutopilotStateCommand) Flags() *FlagSets {
set := c.flagSet(FlagSetHTTP | FlagSetOutputFormat)

f := set.NewFlagSet("Command Options")

f.StringVar(&StringVar{
Name: "dr-token",
Target: &c.flagDRToken,
Default: "",
EnvVar: "",
Completion: complete.PredictAnything,
Usage: "DR operation token used to authorize this request (if a DR secondary node).",
})

// The output of the state endpoint contains nested values and is not fit for
// the default "table" display format. Override the default display format to
// "pretty", both in the flag and in the UI.
Expand Down Expand Up @@ -83,7 +96,14 @@ func (c *OperatorRaftAutopilotStateCommand) Run(args []string) int {
return 2
}

state, err := client.Sys().RaftAutopilotState()
var state *api.AutopilotState
switch {
case c.flagDRToken != "":
state, err = client.Sys().RaftAutopilotStateWithDRToken(c.flagDRToken)
default:
state, err = client.Sys().RaftAutopilotState()
}

if err != nil {
c.UI.Error(fmt.Sprintf("Error checking autopilot state: %s", err))
return 2
Expand Down
4 changes: 4 additions & 0 deletions vault/logical_system_raft.go
Expand Up @@ -196,6 +196,10 @@ func (b *SystemBackend) raftStoragePaths() []*framework.Path {
Type: framework.TypeBool,
Description: "Whether or not to perform automated version upgrades.",
},
"dr_operation_token": {
Type: framework.TypeString,
Description: "DR operation token used to authorize this request (if a DR secondary node).",
},
},

Operations: map[logical.Operation]framework.OperationHandler{
Expand Down

0 comments on commit 727c73c

Please sign in to comment.