-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add API and CLI commands to promote/demote nodes in the Raft cluster …
…(#996) (#1072) * add commands to promote and demote raft peers Building on top of the new non-voter feature, this allows controlling the voting status of individual nodes using the CLI. * document new commands and api endpoints * remove DR Token options This is not supported by OpenBao and probably never will be. * add fallback if autopilot is disabled Use the raw Raft backend functions to promote or demote a node. --------- Signed-off-by: Jan Martens <[email protected]>
- Loading branch information
Showing
9 changed files
with
559 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
// Copyright (c) 2025 OpenBao a Series of LF Projects, LLC | ||
// SPDX-License-Identifier: MPL-2.0 | ||
|
||
package command | ||
|
||
import ( | ||
"fmt" | ||
"strings" | ||
|
||
"github.com/hashicorp/cli" | ||
"github.com/posener/complete" | ||
) | ||
|
||
var ( | ||
_ cli.Command = (*OperatorRaftDemoteCommand)(nil) | ||
_ cli.CommandAutocomplete = (*OperatorRaftDemoteCommand)(nil) | ||
) | ||
|
||
type OperatorRaftDemoteCommand struct { | ||
*BaseCommand | ||
} | ||
|
||
func (c *OperatorRaftDemoteCommand) Synopsis() string { | ||
return "Demotes a voter to a permanent non-voter" | ||
} | ||
|
||
func (c *OperatorRaftDemoteCommand) Help() string { | ||
helpText := ` | ||
Usage: bao operator raft demote <server_id> | ||
Demotes voter to a permanent non-voter. | ||
$ bao operator raft demote node1 | ||
` + c.Flags().Help() | ||
|
||
return strings.TrimSpace(helpText) | ||
} | ||
|
||
func (c *OperatorRaftDemoteCommand) Flags() *FlagSets { | ||
return c.flagSet(FlagSetHTTP | FlagSetOutputFormat) | ||
} | ||
|
||
func (c *OperatorRaftDemoteCommand) AutocompleteArgs() complete.Predictor { | ||
return complete.PredictAnything | ||
} | ||
|
||
func (c *OperatorRaftDemoteCommand) AutocompleteFlags() complete.Flags { | ||
return c.Flags().Completions() | ||
} | ||
|
||
func (c *OperatorRaftDemoteCommand) Run(args []string) int { | ||
f := c.Flags() | ||
|
||
if err := f.Parse(args); err != nil { | ||
c.UI.Error(err.Error()) | ||
return 1 | ||
} | ||
|
||
serverID := "" | ||
|
||
args = f.Args() | ||
switch len(args) { | ||
case 1: | ||
serverID = strings.TrimSpace(args[0]) | ||
default: | ||
c.UI.Error(fmt.Sprintf("Incorrect arguments (expected 1, got %d)", len(args))) | ||
return 1 | ||
} | ||
|
||
if len(serverID) == 0 { | ||
c.UI.Error("Server id is required") | ||
return 1 | ||
} | ||
|
||
client, err := c.Client() | ||
if err != nil { | ||
c.UI.Error(err.Error()) | ||
return 2 | ||
} | ||
|
||
_, err = client.Logical().Write("sys/storage/raft/demote", map[string]interface{}{ | ||
"server_id": serverID, | ||
}) | ||
if err != nil { | ||
c.UI.Error(fmt.Sprintf("Error promoting server: %s", err)) | ||
return 2 | ||
} | ||
|
||
c.UI.Output("Server demoted successfully!") | ||
|
||
return 0 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
// Copyright (c) 2025 OpenBao a Series of LF Projects, LLC | ||
// SPDX-License-Identifier: MPL-2.0 | ||
|
||
package command | ||
|
||
import ( | ||
"fmt" | ||
"strings" | ||
|
||
"github.com/hashicorp/cli" | ||
"github.com/posener/complete" | ||
) | ||
|
||
var ( | ||
_ cli.Command = (*OperatorRaftPromoteCommand)(nil) | ||
_ cli.CommandAutocomplete = (*OperatorRaftPromoteCommand)(nil) | ||
) | ||
|
||
type OperatorRaftPromoteCommand struct { | ||
*BaseCommand | ||
} | ||
|
||
func (c *OperatorRaftPromoteCommand) Synopsis() string { | ||
return "Promotes a permanent non-voter to a voter" | ||
} | ||
|
||
func (c *OperatorRaftPromoteCommand) Help() string { | ||
helpText := ` | ||
Usage: bao operator raft promote <server_id> | ||
Promotes a permanent non-voter to a voter. | ||
$ bao operator raft promote node1 | ||
` + c.Flags().Help() | ||
|
||
return strings.TrimSpace(helpText) | ||
} | ||
|
||
func (c *OperatorRaftPromoteCommand) Flags() *FlagSets { | ||
return c.flagSet(FlagSetHTTP | FlagSetOutputFormat) | ||
} | ||
|
||
func (c *OperatorRaftPromoteCommand) AutocompleteArgs() complete.Predictor { | ||
return complete.PredictAnything | ||
} | ||
|
||
func (c *OperatorRaftPromoteCommand) AutocompleteFlags() complete.Flags { | ||
return c.Flags().Completions() | ||
} | ||
|
||
func (c *OperatorRaftPromoteCommand) Run(args []string) int { | ||
f := c.Flags() | ||
|
||
if err := f.Parse(args); err != nil { | ||
c.UI.Error(err.Error()) | ||
return 1 | ||
} | ||
|
||
serverID := "" | ||
|
||
args = f.Args() | ||
switch len(args) { | ||
case 1: | ||
serverID = strings.TrimSpace(args[0]) | ||
default: | ||
c.UI.Error(fmt.Sprintf("Incorrect arguments (expected 1, got %d)", len(args))) | ||
return 1 | ||
} | ||
|
||
if len(serverID) == 0 { | ||
c.UI.Error("Server id is required") | ||
return 1 | ||
} | ||
|
||
client, err := c.Client() | ||
if err != nil { | ||
c.UI.Error(err.Error()) | ||
return 2 | ||
} | ||
|
||
_, err = client.Logical().Write("sys/storage/raft/promote", map[string]interface{}{ | ||
"server_id": serverID, | ||
}) | ||
if err != nil { | ||
c.UI.Error(fmt.Sprintf("Error promoting server: %s", err)) | ||
return 2 | ||
} | ||
|
||
c.UI.Output("Server promoted successfully!") | ||
|
||
return 0 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.