Skip to content

Commit 9bb348c

Browse files
author
s-christoff
authored
Enhance the output of consul snapshot inspect (hashicorp#8787)
1 parent 5b2833d commit 9bb348c

File tree

12 files changed

+398
-118
lines changed

12 files changed

+398
-118
lines changed

.changelog/8787.txt

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
```release-note:feature
2+
cli: update `snapshot inspect` command to provide more detailed snapshot data
3+
```

agent/consul/fsm/fsm.go

+39-23
Original file line numberDiff line numberDiff line change
@@ -159,28 +159,7 @@ func (c *FSM) Restore(old io.ReadCloser) error {
159159
restore := stateNew.Restore()
160160
defer restore.Abort()
161161

162-
// Create a decoder
163-
dec := codec.NewDecoder(old, structs.MsgpackHandle)
164-
165-
// Read in the header
166-
var header snapshotHeader
167-
if err := dec.Decode(&header); err != nil {
168-
return err
169-
}
170-
171-
// Populate the new state
172-
msgType := make([]byte, 1)
173-
for {
174-
// Read the message type
175-
_, err := old.Read(msgType)
176-
if err == io.EOF {
177-
break
178-
} else if err != nil {
179-
return err
180-
}
181-
182-
// Decode
183-
msg := structs.MessageType(msgType[0])
162+
handler := func(header *SnapshotHeader, msg structs.MessageType, dec *codec.Decoder) error {
184163
switch {
185164
case msg == structs.ChunkingStateType:
186165
chunkState := &raftchunking.State{
@@ -194,13 +173,18 @@ func (c *FSM) Restore(old io.ReadCloser) error {
194173
}
195174
case restorers[msg] != nil:
196175
fn := restorers[msg]
197-
if err := fn(&header, restore, dec); err != nil {
176+
if err := fn(header, restore, dec); err != nil {
198177
return err
199178
}
200179
default:
201180
return fmt.Errorf("Unrecognized msg type %d", msg)
202181
}
182+
return nil
183+
}
184+
if err := ReadSnapshot(old, handler); err != nil {
185+
return err
203186
}
187+
204188
if err := restore.Commit(); err != nil {
205189
return err
206190
}
@@ -218,3 +202,35 @@ func (c *FSM) Restore(old io.ReadCloser) error {
218202
stateOld.Abandon()
219203
return nil
220204
}
205+
206+
// ReadSnapshot decodes each message type and utilizes the handler function to
207+
// process each message type individually
208+
func ReadSnapshot(r io.Reader, handler func(header *SnapshotHeader, msg structs.MessageType, dec *codec.Decoder) error) error {
209+
// Create a decoder
210+
dec := codec.NewDecoder(r, structs.MsgpackHandle)
211+
212+
// Read in the header
213+
var header SnapshotHeader
214+
if err := dec.Decode(&header); err != nil {
215+
return err
216+
}
217+
218+
// Populate the new state
219+
msgType := make([]byte, 1)
220+
for {
221+
// Read the message type
222+
_, err := r.Read(msgType)
223+
if err == io.EOF {
224+
return nil
225+
} else if err != nil {
226+
return err
227+
}
228+
229+
// Decode
230+
msg := structs.MessageType(msgType[0])
231+
232+
if err := handler(&header, msg, dec); err != nil {
233+
return err
234+
}
235+
}
236+
}

agent/consul/fsm/snapshot.go

+4-4
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ type snapshot struct {
2020
chunkState *raftchunking.State
2121
}
2222

23-
// snapshotHeader is the first entry in our snapshot
24-
type snapshotHeader struct {
23+
// SnapshotHeader is the first entry in our snapshot
24+
type SnapshotHeader struct {
2525
// LastIndex is the last index that affects the data.
2626
// This is used when we do the restore for watchers.
2727
LastIndex uint64
@@ -40,7 +40,7 @@ func registerPersister(fn persister) {
4040
}
4141

4242
// restorer is a function used to load back a snapshot of the FSM state.
43-
type restorer func(header *snapshotHeader, restore *state.Restore, decoder *codec.Decoder) error
43+
type restorer func(header *SnapshotHeader, restore *state.Restore, decoder *codec.Decoder) error
4444

4545
// restorers is a map of restore functions by message type.
4646
var restorers map[structs.MessageType]restorer
@@ -62,7 +62,7 @@ func (s *snapshot) Persist(sink raft.SnapshotSink) error {
6262
defer metrics.MeasureSince([]string{"fsm", "persist"}, time.Now())
6363

6464
// Write the header
65-
header := snapshotHeader{
65+
header := SnapshotHeader{
6666
LastIndex: s.state.LastIndex(),
6767
}
6868
encoder := codec.NewEncoder(sink, structs.MsgpackHandle)

agent/consul/fsm/snapshot_oss.go

+22-22
Original file line numberDiff line numberDiff line change
@@ -506,7 +506,7 @@ func (s *snapshot) persistIndex(sink raft.SnapshotSink, encoder *codec.Encoder)
506506
return nil
507507
}
508508

509-
func restoreRegistration(header *snapshotHeader, restore *state.Restore, decoder *codec.Decoder) error {
509+
func restoreRegistration(header *SnapshotHeader, restore *state.Restore, decoder *codec.Decoder) error {
510510
var req structs.RegisterRequest
511511
if err := decoder.Decode(&req); err != nil {
512512
return err
@@ -517,7 +517,7 @@ func restoreRegistration(header *snapshotHeader, restore *state.Restore, decoder
517517
return nil
518518
}
519519

520-
func restoreKV(header *snapshotHeader, restore *state.Restore, decoder *codec.Decoder) error {
520+
func restoreKV(header *SnapshotHeader, restore *state.Restore, decoder *codec.Decoder) error {
521521
var req structs.DirEntry
522522
if err := decoder.Decode(&req); err != nil {
523523
return err
@@ -528,7 +528,7 @@ func restoreKV(header *snapshotHeader, restore *state.Restore, decoder *codec.De
528528
return nil
529529
}
530530

531-
func restoreTombstone(header *snapshotHeader, restore *state.Restore, decoder *codec.Decoder) error {
531+
func restoreTombstone(header *SnapshotHeader, restore *state.Restore, decoder *codec.Decoder) error {
532532
var req structs.DirEntry
533533
if err := decoder.Decode(&req); err != nil {
534534
return err
@@ -547,7 +547,7 @@ func restoreTombstone(header *snapshotHeader, restore *state.Restore, decoder *c
547547
return nil
548548
}
549549

550-
func restoreSession(header *snapshotHeader, restore *state.Restore, decoder *codec.Decoder) error {
550+
func restoreSession(header *SnapshotHeader, restore *state.Restore, decoder *codec.Decoder) error {
551551
var req structs.Session
552552
if err := decoder.Decode(&req); err != nil {
553553
return err
@@ -558,7 +558,7 @@ func restoreSession(header *snapshotHeader, restore *state.Restore, decoder *cod
558558
return nil
559559
}
560560

561-
func restoreACL(header *snapshotHeader, restore *state.Restore, decoder *codec.Decoder) error {
561+
func restoreACL(header *SnapshotHeader, restore *state.Restore, decoder *codec.Decoder) error {
562562
var req structs.ACL
563563
if err := decoder.Decode(&req); err != nil {
564564
return err
@@ -571,7 +571,7 @@ func restoreACL(header *snapshotHeader, restore *state.Restore, decoder *codec.D
571571
}
572572

573573
// DEPRECATED (ACL-Legacy-Compat) - remove once v1 acl compat is removed
574-
func restoreACLBootstrap(header *snapshotHeader, restore *state.Restore, decoder *codec.Decoder) error {
574+
func restoreACLBootstrap(header *SnapshotHeader, restore *state.Restore, decoder *codec.Decoder) error {
575575
var req structs.ACLBootstrap
576576
if err := decoder.Decode(&req); err != nil {
577577
return err
@@ -582,7 +582,7 @@ func restoreACLBootstrap(header *snapshotHeader, restore *state.Restore, decoder
582582
return restore.IndexRestore(&state.IndexEntry{Key: "acl-token-bootstrap", Value: req.ModifyIndex})
583583
}
584584

585-
func restoreCoordinates(header *snapshotHeader, restore *state.Restore, decoder *codec.Decoder) error {
585+
func restoreCoordinates(header *SnapshotHeader, restore *state.Restore, decoder *codec.Decoder) error {
586586
var req structs.Coordinates
587587
if err := decoder.Decode(&req); err != nil {
588588
return err
@@ -593,7 +593,7 @@ func restoreCoordinates(header *snapshotHeader, restore *state.Restore, decoder
593593
return nil
594594
}
595595

596-
func restorePreparedQuery(header *snapshotHeader, restore *state.Restore, decoder *codec.Decoder) error {
596+
func restorePreparedQuery(header *SnapshotHeader, restore *state.Restore, decoder *codec.Decoder) error {
597597
var req structs.PreparedQuery
598598
if err := decoder.Decode(&req); err != nil {
599599
return err
@@ -604,7 +604,7 @@ func restorePreparedQuery(header *snapshotHeader, restore *state.Restore, decode
604604
return nil
605605
}
606606

607-
func restoreAutopilot(header *snapshotHeader, restore *state.Restore, decoder *codec.Decoder) error {
607+
func restoreAutopilot(header *SnapshotHeader, restore *state.Restore, decoder *codec.Decoder) error {
608608
var req autopilot.Config
609609
if err := decoder.Decode(&req); err != nil {
610610
return err
@@ -615,7 +615,7 @@ func restoreAutopilot(header *snapshotHeader, restore *state.Restore, decoder *c
615615
return nil
616616
}
617617

618-
func restoreLegacyIntention(header *snapshotHeader, restore *state.Restore, decoder *codec.Decoder) error {
618+
func restoreLegacyIntention(header *SnapshotHeader, restore *state.Restore, decoder *codec.Decoder) error {
619619
var req structs.Intention
620620
if err := decoder.Decode(&req); err != nil {
621621
return err
@@ -627,7 +627,7 @@ func restoreLegacyIntention(header *snapshotHeader, restore *state.Restore, deco
627627
return nil
628628
}
629629

630-
func restoreConnectCA(header *snapshotHeader, restore *state.Restore, decoder *codec.Decoder) error {
630+
func restoreConnectCA(header *SnapshotHeader, restore *state.Restore, decoder *codec.Decoder) error {
631631
var req structs.CARoot
632632
if err := decoder.Decode(&req); err != nil {
633633
return err
@@ -638,7 +638,7 @@ func restoreConnectCA(header *snapshotHeader, restore *state.Restore, decoder *c
638638
return nil
639639
}
640640

641-
func restoreConnectCAProviderState(header *snapshotHeader, restore *state.Restore, decoder *codec.Decoder) error {
641+
func restoreConnectCAProviderState(header *SnapshotHeader, restore *state.Restore, decoder *codec.Decoder) error {
642642
var req structs.CAConsulProviderState
643643
if err := decoder.Decode(&req); err != nil {
644644
return err
@@ -649,7 +649,7 @@ func restoreConnectCAProviderState(header *snapshotHeader, restore *state.Restor
649649
return nil
650650
}
651651

652-
func restoreConnectCAConfig(header *snapshotHeader, restore *state.Restore, decoder *codec.Decoder) error {
652+
func restoreConnectCAConfig(header *SnapshotHeader, restore *state.Restore, decoder *codec.Decoder) error {
653653
var req structs.CAConfiguration
654654
if err := decoder.Decode(&req); err != nil {
655655
return err
@@ -660,15 +660,15 @@ func restoreConnectCAConfig(header *snapshotHeader, restore *state.Restore, deco
660660
return nil
661661
}
662662

663-
func restoreIndex(header *snapshotHeader, restore *state.Restore, decoder *codec.Decoder) error {
663+
func restoreIndex(header *SnapshotHeader, restore *state.Restore, decoder *codec.Decoder) error {
664664
var req state.IndexEntry
665665
if err := decoder.Decode(&req); err != nil {
666666
return err
667667
}
668668
return restore.IndexRestore(&req)
669669
}
670670

671-
func restoreToken(header *snapshotHeader, restore *state.Restore, decoder *codec.Decoder) error {
671+
func restoreToken(header *SnapshotHeader, restore *state.Restore, decoder *codec.Decoder) error {
672672
var req structs.ACLToken
673673
if err := decoder.Decode(&req); err != nil {
674674
return err
@@ -688,55 +688,55 @@ func restoreToken(header *snapshotHeader, restore *state.Restore, decoder *codec
688688
return restore.ACLToken(&req)
689689
}
690690

691-
func restorePolicy(header *snapshotHeader, restore *state.Restore, decoder *codec.Decoder) error {
691+
func restorePolicy(header *SnapshotHeader, restore *state.Restore, decoder *codec.Decoder) error {
692692
var req structs.ACLPolicy
693693
if err := decoder.Decode(&req); err != nil {
694694
return err
695695
}
696696
return restore.ACLPolicy(&req)
697697
}
698698

699-
func restoreConfigEntry(header *snapshotHeader, restore *state.Restore, decoder *codec.Decoder) error {
699+
func restoreConfigEntry(header *SnapshotHeader, restore *state.Restore, decoder *codec.Decoder) error {
700700
var req structs.ConfigEntryRequest
701701
if err := decoder.Decode(&req); err != nil {
702702
return err
703703
}
704704
return restore.ConfigEntry(req.Entry)
705705
}
706706

707-
func restoreRole(header *snapshotHeader, restore *state.Restore, decoder *codec.Decoder) error {
707+
func restoreRole(header *SnapshotHeader, restore *state.Restore, decoder *codec.Decoder) error {
708708
var req structs.ACLRole
709709
if err := decoder.Decode(&req); err != nil {
710710
return err
711711
}
712712
return restore.ACLRole(&req)
713713
}
714714

715-
func restoreBindingRule(header *snapshotHeader, restore *state.Restore, decoder *codec.Decoder) error {
715+
func restoreBindingRule(header *SnapshotHeader, restore *state.Restore, decoder *codec.Decoder) error {
716716
var req structs.ACLBindingRule
717717
if err := decoder.Decode(&req); err != nil {
718718
return err
719719
}
720720
return restore.ACLBindingRule(&req)
721721
}
722722

723-
func restoreAuthMethod(header *snapshotHeader, restore *state.Restore, decoder *codec.Decoder) error {
723+
func restoreAuthMethod(header *SnapshotHeader, restore *state.Restore, decoder *codec.Decoder) error {
724724
var req structs.ACLAuthMethod
725725
if err := decoder.Decode(&req); err != nil {
726726
return err
727727
}
728728
return restore.ACLAuthMethod(&req)
729729
}
730730

731-
func restoreFederationState(header *snapshotHeader, restore *state.Restore, decoder *codec.Decoder) error {
731+
func restoreFederationState(header *SnapshotHeader, restore *state.Restore, decoder *codec.Decoder) error {
732732
var req structs.FederationStateRequest
733733
if err := decoder.Decode(&req); err != nil {
734734
return err
735735
}
736736
return restore.FederationState(req.State)
737737
}
738738

739-
func restoreSystemMetadata(header *snapshotHeader, restore *state.Restore, decoder *codec.Decoder) error {
739+
func restoreSystemMetadata(header *SnapshotHeader, restore *state.Restore, decoder *codec.Decoder) error {
740740
var req structs.SystemMetadataEntry
741741
if err := decoder.Decode(&req); err != nil {
742742
return err

agent/structs/structs.go

+55
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,46 @@ const (
7272
SystemMetadataRequestType = 31
7373
)
7474

75+
// if a new request type is added above it must be
76+
// added to the map below
77+
78+
// requestTypeStrings is used for snapshot enhance
79+
// any new request types added must be placed here
80+
var requestTypeStrings = map[MessageType]string{
81+
RegisterRequestType: "Register",
82+
DeregisterRequestType: "Deregister",
83+
KVSRequestType: "KVS",
84+
SessionRequestType: "Session",
85+
ACLRequestType: "ACL", // DEPRECATED (ACL-Legacy-Compat)
86+
TombstoneRequestType: "Tombstone",
87+
CoordinateBatchUpdateType: "CoordinateBatchUpdate",
88+
PreparedQueryRequestType: "PreparedQuery",
89+
TxnRequestType: "Txn",
90+
AutopilotRequestType: "Autopilot",
91+
AreaRequestType: "Area",
92+
ACLBootstrapRequestType: "ACLBootstrap",
93+
IntentionRequestType: "Intention",
94+
ConnectCARequestType: "ConnectCA",
95+
ConnectCAProviderStateType: "ConnectCAProviderState",
96+
ConnectCAConfigType: "ConnectCAConfig", // FSM snapshots only.
97+
IndexRequestType: "Index", // FSM snapshots only.
98+
ACLTokenSetRequestType: "ACLToken",
99+
ACLTokenDeleteRequestType: "ACLTokenDelete",
100+
ACLPolicySetRequestType: "ACLPolicy",
101+
ACLPolicyDeleteRequestType: "ACLPolicyDelete",
102+
ConnectCALeafRequestType: "ConnectCALeaf",
103+
ConfigEntryRequestType: "ConfigEntry",
104+
ACLRoleSetRequestType: "ACLRole",
105+
ACLRoleDeleteRequestType: "ACLRoleDelete",
106+
ACLBindingRuleSetRequestType: "ACLBindingRule",
107+
ACLBindingRuleDeleteRequestType: "ACLBindingRuleDelete",
108+
ACLAuthMethodSetRequestType: "ACLAuthMethod",
109+
ACLAuthMethodDeleteRequestType: "ACLAuthMethodDelete",
110+
ChunkingStateType: "ChunkingState",
111+
FederationStateRequestType: "FederationState",
112+
SystemMetadataRequestType: "SystemMetadata",
113+
}
114+
75115
const (
76116
// IgnoreUnknownTypeFlag is set along with a MessageType
77117
// to indicate that the message type can be safely ignored
@@ -2442,6 +2482,21 @@ func (r *KeyringResponses) New() interface{} {
24422482
return new(KeyringResponses)
24432483
}
24442484

2485+
// String converts message type int to string
2486+
func (m MessageType) String() string {
2487+
s, ok := requestTypeStrings[m]
2488+
if ok {
2489+
return s
2490+
}
2491+
2492+
s, ok = enterpriseRequestType(m)
2493+
if ok {
2494+
return s
2495+
}
2496+
return "Unknown(" + strconv.Itoa(int(m)) + ")"
2497+
2498+
}
2499+
24452500
// UpstreamDownstream pairs come from individual proxy registrations, which can be updated independently.
24462501
type UpstreamDownstream struct {
24472502
Upstream ServiceName

agent/structs/structs_oss.go

+4
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,10 @@ func (_ *HealthCheck) Validate() error {
131131
return nil
132132
}
133133

134+
func enterpriseRequestType(m MessageType) (string, bool) {
135+
return "", false
136+
}
137+
134138
// CheckIDs returns the IDs for all checks associated with a session, regardless of type
135139
func (s *Session) CheckIDs() []types.CheckID {
136140
// Merge all check IDs into a single slice, since they will be handled the same way

0 commit comments

Comments
 (0)