upgrade_test.go 10 KB

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