diff --git a/CHANGELOG.md b/CHANGELOG.md index e11145399d..18447d1180 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,6 +34,8 @@ IMPROVEMENTS: `leader_client_key_file` parameters to read and parse TLS certificate information from paths on disk. Existing non-path based parameters will continue to work, but their values will need to be provided as a single-line string with newlines delimited by `\n`. [[GH-8894](https://github.com/hashicorp/vault/pull/8894)] +* storage/raft: The `vault status` CLI command and the `sys/leader` API now contain the committed and applied + raft indexes. [[GH-9011](https://github.com/hashicorp/vault/pull/9011)] BUG FIXES: diff --git a/api/sys_leader.go b/api/sys_leader.go index 8846dcdfae..e8104b86a5 100644 --- a/api/sys_leader.go +++ b/api/sys_leader.go @@ -26,4 +26,6 @@ type LeaderResponse struct { PerfStandby bool `json:"performance_standby"` PerfStandbyLastRemoteWAL uint64 `json:"performance_standby_last_remote_wal"` LastWAL uint64 `json:"last_wal"` + RaftCommittedIndex uint64 `json:"raft_committed_index,omitempty"` + RaftAppliedIndex uint64 `json:"raft_applied_index,omitempty"` } diff --git a/command/format.go b/command/format.go index 0ba64526c6..d359901d50 100644 --- a/command/format.go +++ b/command/format.go @@ -383,6 +383,12 @@ func OutputSealStatus(ui cli.Ui, client *api.Client, status *api.SealStatusRespo } } + if leaderStatus.RaftCommittedIndex > 0 { + out = append(out, fmt.Sprintf("Raft Committed Index | %d", leaderStatus.RaftCommittedIndex)) + } + if leaderStatus.RaftAppliedIndex > 0 { + out = append(out, fmt.Sprintf("Raft Applied Index | %d", leaderStatus.RaftAppliedIndex)) + } if leaderStatus.LastWAL != 0 { out = append(out, fmt.Sprintf("Last WAL | %d", leaderStatus.LastWAL)) } diff --git a/http/sys_leader.go b/http/sys_leader.go index 76ba92b2ba..2772d98f0f 100644 --- a/http/sys_leader.go +++ b/http/sys_leader.go @@ -42,6 +42,8 @@ func handleSysLeaderGet(core *vault.Core, w http.ResponseWriter, r *http.Request resp.LastWAL = vault.LastWAL(core) } + resp.RaftCommittedIndex, resp.RaftAppliedIndex = core.GetRaftIndexes() + respondOk(w, resp) } @@ -53,4 +55,8 @@ type LeaderResponse struct { PerfStandby bool `json:"performance_standby"` PerfStandbyLastRemoteWAL uint64 `json:"performance_standby_last_remote_wal"` LastWAL uint64 `json:"last_wal,omitempty"` + + // Raft Indexes for this node + RaftCommittedIndex uint64 `json:"raft_committed_index,omitempty"` + RaftAppliedIndex uint64 `json:"raft_applied_index,omitempty"` } diff --git a/physical/raft/raft.go b/physical/raft/raft.go index 4cfc03b2c6..12afd5316b 100644 --- a/physical/raft/raft.go +++ b/physical/raft/raft.go @@ -680,6 +680,18 @@ func (b *RaftBackend) TeardownCluster(clusterListener cluster.ClusterHook) error return future.Error() } +// CommittedIndex returns the latest index committed to stable storage +func (b *RaftBackend) CommittedIndex() uint64 { + b.l.RLock() + defer b.l.RUnlock() + + if b.raft == nil { + return 0 + } + + return b.raft.LastIndex() +} + // AppliedIndex returns the latest index applied to the FSM func (b *RaftBackend) AppliedIndex() uint64 { b.l.RLock() diff --git a/vault/raft.go b/vault/raft.go index 950d510af4..2572a290fd 100644 --- a/vault/raft.go +++ b/vault/raft.go @@ -76,6 +76,18 @@ func (s *raftFollowerStates) minIndex() uint64 { return min } +func (c *Core) GetRaftIndexes() (committed uint64, applied uint64) { + c.stateLock.RLock() + defer c.stateLock.RUnlock() + + raftStorage, ok := c.underlyingPhysical.(*raft.RaftBackend) + if !ok { + return 0, 0 + } + + return raftStorage.CommittedIndex(), raftStorage.AppliedIndex() +} + // startRaftStorage will call SetupCluster in the raft backend which starts raft // up and enables the cluster handler. func (c *Core) startRaftStorage(ctx context.Context) (retErr error) { diff --git a/vendor/github.com/hashicorp/vault/api/sys_leader.go b/vendor/github.com/hashicorp/vault/api/sys_leader.go index 8846dcdfae..e8104b86a5 100644 --- a/vendor/github.com/hashicorp/vault/api/sys_leader.go +++ b/vendor/github.com/hashicorp/vault/api/sys_leader.go @@ -26,4 +26,6 @@ type LeaderResponse struct { PerfStandby bool `json:"performance_standby"` PerfStandbyLastRemoteWAL uint64 `json:"performance_standby_last_remote_wal"` LastWAL uint64 `json:"last_wal"` + RaftCommittedIndex uint64 `json:"raft_committed_index,omitempty"` + RaftAppliedIndex uint64 `json:"raft_applied_index,omitempty"` }