etcd4.go 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. package migrate
  2. import (
  3. "fmt"
  4. "log"
  5. "os"
  6. "path"
  7. pb "github.com/coreos/etcd/etcdserver/etcdserverpb"
  8. "github.com/coreos/etcd/pkg/pbutil"
  9. raftpb "github.com/coreos/etcd/raft/raftpb"
  10. "github.com/coreos/etcd/snap"
  11. "github.com/coreos/etcd/wal"
  12. )
  13. func snapDir4(dataDir string) string {
  14. return path.Join(dataDir, "snapshot")
  15. }
  16. func logFile4(dataDir string) string {
  17. return path.Join(dataDir, "log")
  18. }
  19. func cfgFile4(dataDir string) string {
  20. return path.Join(dataDir, "conf")
  21. }
  22. func snapDir5(dataDir string) string {
  23. return path.Join(dataDir, "snap")
  24. }
  25. func walDir5(dataDir string) string {
  26. return path.Join(dataDir, "wal")
  27. }
  28. func Migrate4To5(dataDir string, name string) error {
  29. // prep new directories
  30. sd5 := snapDir5(dataDir)
  31. if err := os.MkdirAll(sd5, 0700); err != nil {
  32. return fmt.Errorf("failed creating snapshot directory %s: %v", sd5, err)
  33. }
  34. // read v0.4 data
  35. snap4, err := DecodeLatestSnapshot4FromDir(snapDir4(dataDir))
  36. if err != nil {
  37. return err
  38. }
  39. cfg4, err := DecodeConfig4FromFile(cfgFile4(dataDir))
  40. if err != nil {
  41. return err
  42. }
  43. ents4, err := DecodeLog4FromFile(logFile4(dataDir))
  44. if err != nil {
  45. return err
  46. }
  47. nodeIDs := ents4.NodeIDs()
  48. nodeID := GuessNodeID(nodeIDs, snap4, cfg4, name)
  49. if nodeID == 0 {
  50. return fmt.Errorf("Couldn't figure out the node ID from the log or flags, cannot convert")
  51. }
  52. metadata := pbutil.MustMarshal(&pb.Metadata{NodeID: nodeID, ClusterID: 0x04add5})
  53. wd5 := walDir5(dataDir)
  54. w, err := wal.Create(wd5, metadata)
  55. if err != nil {
  56. return fmt.Errorf("failed initializing wal at %s: %v", wd5, err)
  57. }
  58. defer w.Close()
  59. // transform v0.4 data
  60. var snap5 *raftpb.Snapshot
  61. if snap4 == nil {
  62. log.Printf("No snapshot found")
  63. } else {
  64. log.Printf("Found snapshot: lastIndex=%d", snap4.LastIndex)
  65. snap5 = snap4.Snapshot5()
  66. }
  67. st5 := cfg4.HardState5()
  68. // If we've got the most recent snapshot, we can use it's committed index. Still likely less than the current actual index, but worth it for the replay.
  69. if snap5 != nil {
  70. st5.Commit = snap5.Index
  71. }
  72. ents5, err := Entries4To5(ents4)
  73. if err != nil {
  74. return err
  75. }
  76. ents5Len := len(ents5)
  77. log.Printf("Found %d log entries: firstIndex=%d lastIndex=%d", ents5Len, ents5[0].Index, ents5[ents5Len-1].Index)
  78. // explicitly prepend an empty entry as the WAL code expects it
  79. ents5 = append(make([]raftpb.Entry, 1), ents5...)
  80. if err = w.Save(st5, ents5); err != nil {
  81. return err
  82. }
  83. log.Printf("Log migration successful")
  84. // migrate snapshot (if necessary) and logs
  85. if snap5 != nil {
  86. ss := snap.New(sd5)
  87. if err := ss.SaveSnap(*snap5); err != nil {
  88. return err
  89. }
  90. log.Printf("Snapshot migration successful")
  91. }
  92. return nil
  93. }
  94. func GuessNodeID(nodes map[string]uint64, snap4 *Snapshot4, cfg *Config4, name string) uint64 {
  95. var snapNodes map[string]uint64
  96. if snap4 != nil {
  97. snapNodes = snap4.GetNodesFromStore()
  98. }
  99. // First, use the flag, if set.
  100. if name != "" {
  101. log.Printf("Using suggested name %s", name)
  102. if val, ok := nodes[name]; ok {
  103. log.Printf("Found ID %d", val)
  104. return val
  105. }
  106. if snapNodes != nil {
  107. if val, ok := snapNodes[name]; ok {
  108. log.Printf("Found ID %d", val)
  109. return val
  110. }
  111. }
  112. log.Printf("Name not found, autodetecting...")
  113. }
  114. // Next, look at the snapshot peers, if that exists.
  115. if snap4 != nil {
  116. //snapNodes := make(map[string]uint64)
  117. //for _, p := range snap4.Peers {
  118. //m := generateNodeMember(p.Name, p.ConnectionString, "")
  119. //snapNodes[p.Name] = uint64(m.ID)
  120. //}
  121. for _, p := range cfg.Peers {
  122. log.Printf(p.Name)
  123. delete(snapNodes, p.Name)
  124. }
  125. if len(snapNodes) == 1 {
  126. for name, id := range nodes {
  127. log.Printf("Autodetected from snapshot: name %s", name)
  128. return id
  129. }
  130. }
  131. }
  132. // Then, try and deduce from the log.
  133. for _, p := range cfg.Peers {
  134. delete(nodes, p.Name)
  135. }
  136. if len(nodes) == 1 {
  137. for name, id := range nodes {
  138. log.Printf("Autodetected name %s", name)
  139. return id
  140. }
  141. }
  142. return 0
  143. }