c45bdca0b3
* raft: initial work on raft ha storage support * add note on join * add todo note * raft: add support for bootstrapping and joining existing nodes * raft: gate bootstrap join by reading leader api address from storage * raft: properly check for raft-only for certain conditionals * raft: add bootstrap to api and cli * raft: fix bootstrap cli command * raft: add test for setting up new cluster with raft HA * raft: extend TestRaft_HA_NewCluster to include inmem and consul backends * raft: add test for updating an existing cluster to use raft HA * raft: remove debug log lines, clean up verifyRaftPeers * raft: minor cleanup * raft: minor cleanup * Update physical/raft/raft.go Co-authored-by: Brian Kassouf <briankassouf@users.noreply.github.com> * Update vault/ha.go Co-authored-by: Brian Kassouf <briankassouf@users.noreply.github.com> * Update vault/ha.go Co-authored-by: Brian Kassouf <briankassouf@users.noreply.github.com> * Update vault/logical_system_raft.go Co-authored-by: Brian Kassouf <briankassouf@users.noreply.github.com> * Update vault/raft.go Co-authored-by: Brian Kassouf <briankassouf@users.noreply.github.com> * Update vault/raft.go Co-authored-by: Brian Kassouf <briankassouf@users.noreply.github.com> * address feedback comments * address feedback comments * raft: refactor tls keyring logic * address feedback comments * Update vault/raft.go Co-authored-by: Alexander Bezobchuk <alexanderbez@users.noreply.github.com> * Update vault/raft.go Co-authored-by: Alexander Bezobchuk <alexanderbez@users.noreply.github.com> * address feedback comments * testing: fix import ordering * raft: rename var, cleanup comment line * docs: remove ha_storage restriction note on raft * docs: more raft HA interaction updates with migration and recovery mode * docs: update the raft join command * raft: update comments * raft: add missing isRaftHAOnly check for clearing out state set earlier * raft: update a few ha_storage config checks * Update command/operator_raft_bootstrap.go Co-authored-by: Vishal Nayak <vishalnayak@users.noreply.github.com> * raft: address feedback comments * raft: fix panic when checking for config.HAStorage.Type * Update vault/raft.go Co-authored-by: Alexander Bezobchuk <alexanderbez@users.noreply.github.com> * Update website/pages/docs/commands/operator/raft.mdx Co-authored-by: Alexander Bezobchuk <alexanderbez@users.noreply.github.com> * raft: remove bootstrap cli command * Update vault/raft.go Co-authored-by: Brian Kassouf <briankassouf@users.noreply.github.com> * Update vault/raft.go Co-authored-by: Brian Kassouf <briankassouf@users.noreply.github.com> * raft: address review feedback * raft: revert vendored sdk * raft: don't send applied index and node ID info if we're HA-only Co-authored-by: Brian Kassouf <briankassouf@users.noreply.github.com> Co-authored-by: Alexander Bezobchuk <alexanderbez@users.noreply.github.com> Co-authored-by: Vishal Nayak <vishalnayak@users.noreply.github.com>
100 lines
2.5 KiB
Go
100 lines
2.5 KiB
Go
package http
|
|
|
|
import (
|
|
"context"
|
|
"crypto/tls"
|
|
"errors"
|
|
"io"
|
|
"net/http"
|
|
|
|
"github.com/hashicorp/vault/physical/raft"
|
|
"github.com/hashicorp/vault/sdk/helper/tlsutil"
|
|
"github.com/hashicorp/vault/vault"
|
|
)
|
|
|
|
func handleSysRaftBootstrap(core *vault.Core) http.Handler {
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
switch r.Method {
|
|
case "POST", "PUT":
|
|
if core.Sealed() {
|
|
respondError(w, http.StatusBadRequest, errors.New("node must be unsealed to bootstrap"))
|
|
}
|
|
|
|
if err := core.RaftBootstrap(context.Background(), false); err != nil {
|
|
respondError(w, http.StatusInternalServerError, err)
|
|
return
|
|
}
|
|
|
|
default:
|
|
respondError(w, http.StatusBadRequest, nil)
|
|
}
|
|
})
|
|
}
|
|
|
|
func handleSysRaftJoin(core *vault.Core) http.Handler {
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
switch r.Method {
|
|
case "POST", "PUT":
|
|
handleSysRaftJoinPost(core, w, r)
|
|
default:
|
|
respondError(w, http.StatusMethodNotAllowed, nil)
|
|
}
|
|
})
|
|
}
|
|
|
|
func handleSysRaftJoinPost(core *vault.Core, w http.ResponseWriter, r *http.Request) {
|
|
// Parse the request
|
|
var req JoinRequest
|
|
if _, err := parseJSONRequest(core.PerfStandby(), r, w, &req); err != nil && err != io.EOF {
|
|
respondError(w, http.StatusBadRequest, err)
|
|
return
|
|
}
|
|
|
|
if req.NonVoter && !nonVotersAllowed {
|
|
respondError(w, http.StatusBadRequest, errors.New("non-voting nodes not allowed"))
|
|
return
|
|
}
|
|
|
|
var tlsConfig *tls.Config
|
|
var err error
|
|
if len(req.LeaderCACert) != 0 || len(req.LeaderClientCert) != 0 || len(req.LeaderClientKey) != 0 {
|
|
tlsConfig, err = tlsutil.ClientTLSConfig([]byte(req.LeaderCACert), []byte(req.LeaderClientCert), []byte(req.LeaderClientKey))
|
|
if err != nil {
|
|
respondError(w, http.StatusBadRequest, err)
|
|
return
|
|
}
|
|
}
|
|
|
|
leaderInfos := []*raft.LeaderJoinInfo{
|
|
{
|
|
LeaderAPIAddr: req.LeaderAPIAddr,
|
|
TLSConfig: tlsConfig,
|
|
Retry: req.Retry,
|
|
},
|
|
}
|
|
|
|
joined, err := core.JoinRaftCluster(context.Background(), leaderInfos, req.NonVoter)
|
|
if err != nil {
|
|
respondError(w, http.StatusInternalServerError, err)
|
|
return
|
|
}
|
|
|
|
resp := JoinResponse{
|
|
Joined: joined,
|
|
}
|
|
respondOk(w, resp)
|
|
}
|
|
|
|
type JoinResponse struct {
|
|
Joined bool `json:"joined"`
|
|
}
|
|
|
|
type JoinRequest struct {
|
|
LeaderAPIAddr string `json:"leader_api_addr"`
|
|
LeaderCACert string `json:"leader_ca_cert"`
|
|
LeaderClientCert string `json:"leader_client_cert"`
|
|
LeaderClientKey string `json:"leader_client_key"`
|
|
Retry bool `json:"retry"`
|
|
NonVoter bool `json:"non_voter"`
|
|
}
|