upgrade_test.go 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371
  1. package functional
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "fmt"
  6. "io/ioutil"
  7. "net/http"
  8. "os"
  9. "os/exec"
  10. "path"
  11. "path/filepath"
  12. "testing"
  13. )
  14. var (
  15. binDir = ".versions"
  16. v1BinPath = path.Join(binDir, "1")
  17. v2BinPath = path.Join(binDir, "2")
  18. etcdctlBinPath string
  19. )
  20. func init() {
  21. os.RemoveAll(binDir)
  22. if err := os.Mkdir(binDir, 0700); err != nil {
  23. fmt.Printf("unexpected Mkdir error: %v\n", err)
  24. os.Exit(1)
  25. }
  26. if err := os.Symlink(absPathFromEnv("ETCD_V1_BIN"), v1BinPath); err != nil {
  27. fmt.Printf("unexpected Symlink error: %v\n", err)
  28. os.Exit(1)
  29. }
  30. if err := os.Symlink(absPathFromEnv("ETCD_V2_BIN"), v2BinPath); err != nil {
  31. fmt.Printf("unexpected Symlink error: %v\n", err)
  32. os.Exit(1)
  33. }
  34. etcdctlBinPath = os.Getenv("ETCDCTL_BIN")
  35. mustExist(v1BinPath)
  36. mustExist(v2BinPath)
  37. mustExist(etcdctlBinPath)
  38. }
  39. func TestStartNewMember(t *testing.T) {
  40. tests := []*Proc{
  41. NewProcWithDefaultFlags(v2BinPath),
  42. NewProcWithV1Flags(v2BinPath),
  43. NewProcWithV2Flags(v2BinPath),
  44. }
  45. for i, tt := range tests {
  46. if err := tt.Start(); err != nil {
  47. t.Fatalf("#%d: Start error: %v", i, err)
  48. }
  49. defer tt.Terminate()
  50. ver, err := checkInternalVersion(tt.URL)
  51. if err != nil {
  52. t.Fatalf("#%d: checkVersion error: %v", i, err)
  53. }
  54. if ver != "2" {
  55. t.Errorf("#%d: internal version = %s, want %s", i, ver, "2")
  56. }
  57. }
  58. }
  59. func TestStartV2Member(t *testing.T) {
  60. tests := []*Proc{
  61. NewProcWithDefaultFlags(v2BinPath),
  62. NewProcWithV1Flags(v2BinPath),
  63. NewProcWithV2Flags(v2BinPath),
  64. }
  65. for i, tt := range tests {
  66. // get v2 data dir
  67. p := NewProcWithDefaultFlags(v2BinPath)
  68. if err := p.Start(); err != nil {
  69. t.Fatalf("#%d: Start error: %v", i, err)
  70. }
  71. p.Stop()
  72. tt.SetDataDir(p.DataDir)
  73. if err := tt.Start(); err != nil {
  74. t.Fatalf("#%d: Start error: %v", i, err)
  75. }
  76. defer tt.Terminate()
  77. ver, err := checkInternalVersion(tt.URL)
  78. if err != nil {
  79. t.Fatalf("#%d: checkVersion error: %v", i, err)
  80. }
  81. if ver != "2" {
  82. t.Errorf("#%d: internal version = %s, want %s", i, ver, "2")
  83. }
  84. }
  85. }
  86. func TestStartV1Member(t *testing.T) {
  87. tests := []*Proc{
  88. NewProcWithDefaultFlags(v2BinPath),
  89. NewProcWithV1Flags(v2BinPath),
  90. NewProcWithV2Flags(v2BinPath),
  91. }
  92. for i, tt := range tests {
  93. // get v1 data dir
  94. p := NewProcWithDefaultFlags(v1BinPath)
  95. if err := p.Start(); err != nil {
  96. t.Fatalf("#%d: Start error: %v", i, err)
  97. }
  98. p.Stop()
  99. tt.SetDataDir(p.DataDir)
  100. if err := tt.Start(); err != nil {
  101. t.Fatalf("#%d: Start error: %v", i, err)
  102. }
  103. defer tt.Terminate()
  104. ver, err := checkInternalVersion(tt.URL)
  105. if err != nil {
  106. t.Fatalf("#%d: checkVersion error: %v", i, err)
  107. }
  108. if ver != "1" {
  109. t.Errorf("#%d: internal version = %s, want %s", i, ver, "1")
  110. }
  111. }
  112. }
  113. func TestUpgradeV1Cluster(t *testing.T) {
  114. // get v2-desired v1 data dir
  115. pg := NewProcGroupWithV1Flags(v1BinPath, 3)
  116. if err := pg.Start(); err != nil {
  117. t.Fatalf("Start error: %v", err)
  118. }
  119. cmd := exec.Command(etcdctlBinPath, "upgrade", "--peer-url", pg[1].PeerURL)
  120. if err := cmd.Start(); err != nil {
  121. t.Fatalf("Start error: %v", err)
  122. }
  123. if err := cmd.Wait(); err != nil {
  124. t.Fatalf("Wait error: %v", err)
  125. }
  126. t.Logf("wait until etcd exits...")
  127. if err := pg.Wait(); err != nil {
  128. t.Fatalf("Wait error: %v", err)
  129. }
  130. npg := NewProcGroupWithV1Flags(v2BinPath, 3)
  131. npg.InheritDataDir(pg)
  132. npg.CleanUnsuppportedV1Flags()
  133. if err := npg.Start(); err != nil {
  134. t.Fatalf("Start error: %v", err)
  135. }
  136. defer npg.Terminate()
  137. for _, p := range npg {
  138. ver, err := checkInternalVersion(p.URL)
  139. if err != nil {
  140. t.Fatalf("checkVersion error: %v", err)
  141. }
  142. if ver != "2" {
  143. t.Errorf("internal version = %s, want %s", ver, "2")
  144. }
  145. }
  146. }
  147. func TestUpgradeV1SnapshotedCluster(t *testing.T) {
  148. // get v2-desired v1 data dir
  149. pg := NewProcGroupWithV1Flags(v1BinPath, 3)
  150. pg.SetSnapCount(10)
  151. if err := pg.Start(); err != nil {
  152. t.Fatalf("Start error: %v", err)
  153. }
  154. cmd := exec.Command(etcdctlBinPath, "upgrade", "--peer-url", pg[1].PeerURL)
  155. if err := cmd.Start(); err != nil {
  156. t.Fatalf("Start error: %v", err)
  157. }
  158. if err := cmd.Wait(); err != nil {
  159. t.Fatalf("Wait error: %v", err)
  160. }
  161. t.Logf("wait until etcd exits...")
  162. if err := pg.Wait(); err != nil {
  163. t.Fatalf("Wait error: %v", err)
  164. }
  165. for _, p := range pg {
  166. // check it has taken snapshot
  167. fis, err := ioutil.ReadDir(path.Join(p.DataDir, "snapshot"))
  168. if err != nil {
  169. t.Fatalf("unexpected ReadDir error: %v", err)
  170. }
  171. if len(fis) == 0 {
  172. t.Fatalf("unexpected no-snapshot data dir")
  173. }
  174. }
  175. npg := NewProcGroupWithV1Flags(v2BinPath, 3)
  176. npg.InheritDataDir(pg)
  177. npg.CleanUnsuppportedV1Flags()
  178. if err := npg.Start(); err != nil {
  179. t.Fatalf("Start error: %v", err)
  180. }
  181. defer npg.Terminate()
  182. for _, p := range npg {
  183. ver, err := checkInternalVersion(p.URL)
  184. if err != nil {
  185. t.Fatalf("checkVersion error: %v", err)
  186. }
  187. if ver != "2" {
  188. t.Errorf("internal version = %s, want %s", ver, "2")
  189. }
  190. }
  191. }
  192. func TestJoinV1Cluster(t *testing.T) {
  193. pg := NewProcGroupWithV1Flags(v1BinPath, 1)
  194. if err := pg.Start(); err != nil {
  195. t.Fatalf("Start error: %v", err)
  196. }
  197. pg.Stop()
  198. npg := NewProcGroupWithV1Flags(v2BinPath, 3)
  199. npg[0].SetDataDir(pg[0].DataDir)
  200. if err := npg.Start(); err != nil {
  201. t.Fatalf("Start error: %v", err)
  202. }
  203. defer npg.Terminate()
  204. for _, p := range npg {
  205. ver, err := checkInternalVersion(p.URL)
  206. if err != nil {
  207. t.Fatalf("checkVersion error: %v", err)
  208. }
  209. if ver != "1" {
  210. t.Errorf("internal version = %s, want %s", ver, "1")
  211. }
  212. }
  213. }
  214. func TestJoinV1ClusterViaDiscovery(t *testing.T) {
  215. dp := NewProcWithDefaultFlags(v1BinPath)
  216. dp.SetV1Addr("127.0.0.1:5001")
  217. dp.SetV1PeerAddr("127.0.0.1:8001")
  218. if err := dp.Start(); err != nil {
  219. t.Fatalf("Start error: %v", err)
  220. }
  221. defer dp.Terminate()
  222. durl := "http://127.0.0.1:5001/v2/keys/cluster/"
  223. pg := NewProcGroupViaDiscoveryWithV1Flags(v1BinPath, 1, durl)
  224. if err := pg.Start(); err != nil {
  225. t.Fatalf("Start error: %v", err)
  226. }
  227. pg.Stop()
  228. npg := NewProcGroupViaDiscoveryWithV1Flags(v2BinPath, 3, durl)
  229. npg[0].SetDataDir(pg[0].DataDir)
  230. if err := npg.Start(); err != nil {
  231. t.Fatalf("Start error: %v", err)
  232. }
  233. defer npg.Terminate()
  234. for _, p := range npg {
  235. ver, err := checkInternalVersion(p.URL)
  236. if err != nil {
  237. t.Fatalf("checkVersion error: %v", err)
  238. }
  239. if ver != "1" {
  240. t.Errorf("internal version = %s, want %s", ver, "1")
  241. }
  242. }
  243. }
  244. func TestUpgradeV1Standby(t *testing.T) {
  245. // get v1 standby data dir
  246. pg := NewProcGroupWithV1Flags(v1BinPath, 3)
  247. if err := pg.Start(); err != nil {
  248. t.Fatalf("Start error: %v", err)
  249. }
  250. req, err := http.NewRequest("PUT", pg[0].PeerURL+"/v2/admin/config", bytes.NewBufferString(`{"activeSize":3,"removeDelay":1800,"syncInterval":5}`))
  251. if err != nil {
  252. t.Fatalf("NewRequest error: %v", err)
  253. }
  254. resp, err := http.DefaultClient.Do(req)
  255. if err != nil {
  256. t.Fatalf("http Do error: %v", err)
  257. }
  258. if resp.StatusCode != http.StatusOK {
  259. t.Fatalf("status = %d, want %d", resp.StatusCode, http.StatusOK)
  260. }
  261. p := NewProcInProcGroupWithV1Flags(v2BinPath, 4, 3)
  262. if err := p.Start(); err != nil {
  263. t.Fatalf("Start error: %v", err)
  264. }
  265. fmt.Println("checking new member is in standby mode...")
  266. mustExist(path.Join(p.DataDir, "standby_info"))
  267. ver, err := checkInternalVersion(p.URL)
  268. if err != nil {
  269. t.Fatalf("checkVersion error: %v", err)
  270. }
  271. if ver != "1" {
  272. t.Errorf("internal version = %s, want %s", ver, "1")
  273. }
  274. fmt.Println("upgrading the whole cluster...")
  275. cmd := exec.Command(etcdctlBinPath, "upgrade", "--peer-url", pg[0].PeerURL)
  276. if err := cmd.Start(); err != nil {
  277. t.Fatalf("Start error: %v", err)
  278. }
  279. if err := cmd.Wait(); err != nil {
  280. t.Fatalf("Wait error: %v", err)
  281. }
  282. fmt.Println("waiting until peer-mode etcd exits...")
  283. if err := pg.Wait(); err != nil {
  284. t.Fatalf("Wait error: %v", err)
  285. }
  286. fmt.Println("restarting the peer-mode etcd...")
  287. npg := NewProcGroupWithV1Flags(v2BinPath, 3)
  288. npg.InheritDataDir(pg)
  289. npg.CleanUnsuppportedV1Flags()
  290. if err := npg.Start(); err != nil {
  291. t.Fatalf("Start error: %v", err)
  292. }
  293. defer npg.Terminate()
  294. fmt.Println("waiting until standby-mode etcd exits...")
  295. if err := p.Wait(); err != nil {
  296. t.Fatalf("Wait error: %v", err)
  297. }
  298. fmt.Println("restarting the standby-mode etcd...")
  299. np := NewProcInProcGroupWithV1Flags(v2BinPath, 4, 3)
  300. np.SetDataDir(p.DataDir)
  301. np.CleanUnsuppportedV1Flags()
  302. if err := np.Start(); err != nil {
  303. t.Fatalf("Start error: %v", err)
  304. }
  305. defer np.Terminate()
  306. fmt.Println("checking the new member is in v2 proxy mode...")
  307. ver, err = checkInternalVersion(np.URL)
  308. if err != nil {
  309. t.Fatalf("checkVersion error: %v", err)
  310. }
  311. if ver != "2" {
  312. t.Errorf("internal version = %s, want %s", ver, "1")
  313. }
  314. if _, err := os.Stat(path.Join(np.DataDir, "proxy")); err != nil {
  315. t.Errorf("stat proxy dir error = %v, want nil", err)
  316. }
  317. }
  318. func absPathFromEnv(name string) string {
  319. path, err := filepath.Abs(os.Getenv(name))
  320. if err != nil {
  321. fmt.Printf("unexpected Abs error: %v\n", err)
  322. }
  323. return path
  324. }
  325. func mustExist(path string) {
  326. if _, err := os.Stat(path); err != nil {
  327. fmt.Printf("%v\n", err)
  328. os.Exit(1)
  329. }
  330. }
  331. func checkInternalVersion(url string) (string, error) {
  332. resp, err := http.Get(url + "/version")
  333. if err != nil {
  334. return "", err
  335. }
  336. b, err := ioutil.ReadAll(resp.Body)
  337. if err != nil {
  338. return "", err
  339. }
  340. var m map[string]string
  341. err = json.Unmarshal(b, &m)
  342. return m["internalVersion"], err
  343. }