github.com/kaisenlinux/docker.io@v0.0.0-20230510090727-ea55db55fac7/swarmkit/cmd/swarm-rafttool/dump.go (about) 1 package main 2 3 import ( 4 "context" 5 "errors" 6 "fmt" 7 "os" 8 "path/filepath" 9 10 "github.com/coreos/etcd/raft/raftpb" 11 "github.com/coreos/etcd/snap" 12 "github.com/coreos/etcd/wal/walpb" 13 "github.com/docker/swarmkit/api" 14 "github.com/docker/swarmkit/manager/encryption" 15 "github.com/docker/swarmkit/manager/state/raft/storage" 16 "github.com/docker/swarmkit/manager/state/store" 17 "github.com/gogo/protobuf/proto" 18 ) 19 20 func loadData(swarmdir, unlockKey string) (*storage.WALData, *raftpb.Snapshot, error) { 21 snapDir := filepath.Join(swarmdir, "raft", "snap-v3-encrypted") 22 walDir := filepath.Join(swarmdir, "raft", "wal-v3-encrypted") 23 24 var ( 25 snapFactory storage.SnapFactory 26 walFactory storage.WALFactory 27 ) 28 29 _, err := os.Stat(walDir) 30 if err == nil { 31 // Encrypted WAL is present 32 krw, err := getKRW(swarmdir, unlockKey) 33 if err != nil { 34 return nil, nil, err 35 } 36 deks, err := getDEKData(krw) 37 if err != nil { 38 return nil, nil, err 39 } 40 41 // always set FIPS=false, because we want to decrypt logs stored using any 42 // algorithm, not just FIPS-compatible ones 43 _, d := encryption.Defaults(deks.CurrentDEK, false) 44 if deks.PendingDEK == nil { 45 _, d2 := encryption.Defaults(deks.PendingDEK, false) 46 d = encryption.NewMultiDecrypter(d, d2) 47 } 48 49 walFactory = storage.NewWALFactory(encryption.NoopCrypter, d) 50 snapFactory = storage.NewSnapFactory(encryption.NoopCrypter, d) 51 } else { 52 // Try unencrypted WAL 53 snapDir = filepath.Join(swarmdir, "raft", "snap") 54 walDir = filepath.Join(swarmdir, "raft", "wal") 55 56 walFactory = storage.OriginalWAL 57 snapFactory = storage.OriginalSnap 58 } 59 60 var walsnap walpb.Snapshot 61 snapshot, err := snapFactory.New(snapDir).Load() 62 if err != nil && err != snap.ErrNoSnapshot { 63 return nil, nil, err 64 } 65 if snapshot != nil { 66 walsnap.Index = snapshot.Metadata.Index 67 walsnap.Term = snapshot.Metadata.Term 68 } 69 70 wal, walData, err := storage.ReadRepairWAL(context.Background(), walDir, walsnap, walFactory) 71 if err != nil { 72 return nil, nil, err 73 } 74 wal.Close() 75 76 return &walData, snapshot, nil 77 } 78 79 func dumpWAL(swarmdir, unlockKey string, start, end uint64, redact bool) error { 80 walData, _, err := loadData(swarmdir, unlockKey) 81 if err != nil { 82 return err 83 } 84 85 for _, ent := range walData.Entries { 86 if (start == 0 || ent.Index >= start) && (end == 0 || ent.Index <= end) { 87 fmt.Printf("Entry Index=%d, Term=%d, Type=%s:\n", ent.Index, ent.Term, ent.Type.String()) 88 switch ent.Type { 89 case raftpb.EntryConfChange: 90 cc := &raftpb.ConfChange{} 91 err := proto.Unmarshal(ent.Data, cc) 92 if err != nil { 93 return err 94 } 95 96 fmt.Println("Conf change type:", cc.Type.String()) 97 fmt.Printf("Node ID: %x\n\n", cc.NodeID) 98 99 case raftpb.EntryNormal: 100 r := &api.InternalRaftRequest{} 101 err := proto.Unmarshal(ent.Data, r) 102 if err != nil { 103 return err 104 } 105 106 if redact { 107 // redact sensitive information 108 for _, act := range r.Action { 109 target := act.GetTarget() 110 switch actype := target.(type) { 111 case *api.StoreAction_Cluster: 112 actype.Cluster.UnlockKeys = []*api.EncryptionKey{} 113 actype.Cluster.NetworkBootstrapKeys = []*api.EncryptionKey{} 114 actype.Cluster.RootCA = api.RootCA{} 115 actype.Cluster.Spec.CAConfig = api.CAConfig{} 116 case *api.StoreAction_Secret: 117 actype.Secret.Spec.Data = []byte("SECRET REDACTED") 118 case *api.StoreAction_Config: 119 actype.Config.Spec.Data = []byte("CONFIG REDACTED") 120 case *api.StoreAction_Task: 121 if container := actype.Task.Spec.GetContainer(); container != nil { 122 container.Env = []string{"ENVVARS REDACTED"} 123 if container.PullOptions != nil { 124 container.PullOptions.RegistryAuth = "REDACTED" 125 } 126 } 127 case *api.StoreAction_Service: 128 if container := actype.Service.Spec.Task.GetContainer(); container != nil { 129 container.Env = []string{"ENVVARS REDACTED"} 130 if container.PullOptions != nil { 131 container.PullOptions.RegistryAuth = "REDACTED" 132 } 133 } 134 } 135 } 136 } 137 138 if err := proto.MarshalText(os.Stdout, r); err != nil { 139 return err 140 } 141 fmt.Println() 142 } 143 } 144 } 145 146 return nil 147 } 148 149 func dumpSnapshot(swarmdir, unlockKey string, redact bool) error { 150 _, snapshot, err := loadData(swarmdir, unlockKey) 151 if err != nil { 152 return err 153 } 154 155 if snapshot == nil { 156 return errors.New("no snapshot found") 157 } 158 159 s := &api.Snapshot{} 160 if err := proto.Unmarshal(snapshot.Data, s); err != nil { 161 return err 162 } 163 if s.Version != api.Snapshot_V0 { 164 return fmt.Errorf("unrecognized snapshot version %d", s.Version) 165 } 166 167 fmt.Println("Active members:") 168 for _, member := range s.Membership.Members { 169 fmt.Printf(" NodeID=%s, RaftID=%x, Addr=%s\n", member.NodeID, member.RaftID, member.Addr) 170 } 171 fmt.Println() 172 173 fmt.Println("Removed members:") 174 for _, member := range s.Membership.Removed { 175 fmt.Printf(" RaftID=%x\n", member) 176 } 177 fmt.Println() 178 179 if redact { 180 for _, cluster := range s.Store.Clusters { 181 if cluster != nil { 182 // expunge everything that may have key material 183 cluster.RootCA = api.RootCA{} 184 cluster.NetworkBootstrapKeys = []*api.EncryptionKey{} 185 cluster.UnlockKeys = []*api.EncryptionKey{} 186 cluster.Spec.CAConfig = api.CAConfig{} 187 } 188 } 189 for _, secret := range s.Store.Secrets { 190 if secret != nil { 191 secret.Spec.Data = []byte("SECRET REDACTED") 192 } 193 } 194 for _, config := range s.Store.Configs { 195 if config != nil { 196 config.Spec.Data = []byte("CONFIG REDACTED") 197 } 198 } 199 for _, task := range s.Store.Tasks { 200 if task != nil { 201 if container := task.Spec.GetContainer(); container != nil { 202 container.Env = []string{"ENVVARS REDACTED"} 203 if container.PullOptions != nil { 204 container.PullOptions.RegistryAuth = "REDACTED" 205 } 206 } 207 } 208 } 209 for _, service := range s.Store.Services { 210 if service != nil { 211 if container := service.Spec.Task.GetContainer(); container != nil { 212 container.Env = []string{"ENVVARS REDACTED"} 213 if container.PullOptions != nil { 214 container.PullOptions.RegistryAuth = "REDACTED" 215 } 216 } 217 } 218 } 219 } 220 221 fmt.Println("Objects:") 222 if err := proto.MarshalText(os.Stdout, &s.Store); err != nil { 223 return err 224 } 225 fmt.Println() 226 227 return nil 228 } 229 230 // objSelector provides some criteria to select objects. 231 type objSelector struct { 232 all bool 233 id string 234 name string 235 } 236 237 func bySelection(selector objSelector) store.By { 238 if selector.all { 239 return store.All 240 } 241 if selector.name != "" { 242 return store.ByName(selector.name) 243 } 244 245 // find nothing 246 return store.Or() 247 } 248 249 func dumpObject(swarmdir, unlockKey, objType string, selector objSelector) error { 250 memStore := store.NewMemoryStore(nil) 251 defer memStore.Close() 252 253 walData, snapshot, err := loadData(swarmdir, unlockKey) 254 if err != nil { 255 return err 256 } 257 258 if snapshot != nil { 259 var s api.Snapshot 260 if err := s.Unmarshal(snapshot.Data); err != nil { 261 return err 262 } 263 if s.Version != api.Snapshot_V0 { 264 return fmt.Errorf("unrecognized snapshot version %d", s.Version) 265 } 266 267 if err := memStore.Restore(&s.Store); err != nil { 268 return err 269 } 270 } 271 272 for _, ent := range walData.Entries { 273 if snapshot != nil && ent.Index <= snapshot.Metadata.Index { 274 continue 275 } 276 277 if ent.Type != raftpb.EntryNormal { 278 continue 279 } 280 281 r := &api.InternalRaftRequest{} 282 err := proto.Unmarshal(ent.Data, r) 283 if err != nil { 284 return err 285 } 286 287 if r.Action != nil { 288 if err := memStore.ApplyStoreActions(r.Action); err != nil { 289 return err 290 } 291 } 292 } 293 294 var objects []proto.Message 295 memStore.View(func(tx store.ReadTx) { 296 switch objType { 297 case "node": 298 if selector.id != "" { 299 object := store.GetNode(tx, selector.id) 300 if object != nil { 301 objects = append(objects, object) 302 } 303 } 304 305 var results []*api.Node 306 results, err = store.FindNodes(tx, bySelection(selector)) 307 if err != nil { 308 return 309 } 310 for _, o := range results { 311 objects = append(objects, o) 312 } 313 case "service": 314 if selector.id != "" { 315 object := store.GetService(tx, selector.id) 316 if object != nil { 317 objects = append(objects, object) 318 } 319 } 320 321 var results []*api.Service 322 results, err = store.FindServices(tx, bySelection(selector)) 323 if err != nil { 324 return 325 } 326 for _, o := range results { 327 objects = append(objects, o) 328 } 329 case "task": 330 if selector.id != "" { 331 object := store.GetTask(tx, selector.id) 332 if object != nil { 333 objects = append(objects, object) 334 } 335 } 336 337 var results []*api.Task 338 results, err = store.FindTasks(tx, bySelection(selector)) 339 if err != nil { 340 return 341 } 342 for _, o := range results { 343 objects = append(objects, o) 344 } 345 case "network": 346 if selector.id != "" { 347 object := store.GetNetwork(tx, selector.id) 348 if object != nil { 349 objects = append(objects, object) 350 } 351 } 352 353 var results []*api.Network 354 results, err = store.FindNetworks(tx, bySelection(selector)) 355 if err != nil { 356 return 357 } 358 for _, o := range results { 359 objects = append(objects, o) 360 } 361 case "cluster": 362 if selector.id != "" { 363 object := store.GetCluster(tx, selector.id) 364 if object != nil { 365 objects = append(objects, object) 366 } 367 } 368 369 var results []*api.Cluster 370 results, err = store.FindClusters(tx, bySelection(selector)) 371 if err != nil { 372 return 373 } 374 for _, o := range results { 375 objects = append(objects, o) 376 } 377 case "secret": 378 if selector.id != "" { 379 object := store.GetSecret(tx, selector.id) 380 if object != nil { 381 objects = append(objects, object) 382 } 383 } 384 385 var results []*api.Secret 386 results, err = store.FindSecrets(tx, bySelection(selector)) 387 if err != nil { 388 return 389 } 390 for _, o := range results { 391 objects = append(objects, o) 392 } 393 case "config": 394 if selector.id != "" { 395 object := store.GetConfig(tx, selector.id) 396 if object != nil { 397 objects = append(objects, object) 398 } 399 } 400 401 var results []*api.Config 402 results, err = store.FindConfigs(tx, bySelection(selector)) 403 if err != nil { 404 return 405 } 406 for _, o := range results { 407 objects = append(objects, o) 408 } 409 case "resource": 410 if selector.id != "" { 411 object := store.GetResource(tx, selector.id) 412 if object != nil { 413 objects = append(objects, object) 414 } 415 } 416 417 var results []*api.Resource 418 results, err = store.FindResources(tx, bySelection(selector)) 419 if err != nil { 420 return 421 } 422 for _, o := range results { 423 objects = append(objects, o) 424 } 425 case "extension": 426 if selector.id != "" { 427 object := store.GetExtension(tx, selector.id) 428 if object != nil { 429 objects = append(objects, object) 430 } 431 } 432 433 var results []*api.Extension 434 results, err = store.FindExtensions(tx, bySelection(selector)) 435 if err != nil { 436 return 437 } 438 for _, o := range results { 439 objects = append(objects, o) 440 } 441 default: 442 err = fmt.Errorf("unrecognized object type %s", objType) 443 } 444 }) 445 446 if err != nil { 447 return err 448 } 449 450 if len(objects) == 0 { 451 return fmt.Errorf("no matching objects found") 452 } 453 454 for _, object := range objects { 455 if err := proto.MarshalText(os.Stdout, object); err != nil { 456 return err 457 } 458 fmt.Println() 459 } 460 461 return nil 462 }