util.go 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. /*
  2. Copyright 2013 CoreOS Inc.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package test
  14. import (
  15. "fmt"
  16. "github.com/coreos/go-etcd/etcd"
  17. "io/ioutil"
  18. "net"
  19. "net/http"
  20. "os"
  21. "strconv"
  22. "time"
  23. )
  24. var client = http.Client{
  25. Transport: &http.Transport{
  26. Dial: dialTimeoutFast,
  27. },
  28. }
  29. // Sending set commands
  30. func Set(stop chan bool) {
  31. stopSet := false
  32. i := 0
  33. c := etcd.NewClient(nil)
  34. for {
  35. key := fmt.Sprintf("%s_%v", "foo", i)
  36. result, err := c.Set(key, "bar", 0)
  37. if err != nil || result.Node.Key != "/"+key || result.Node.Value != "bar" {
  38. select {
  39. case <-stop:
  40. stopSet = true
  41. default:
  42. }
  43. }
  44. select {
  45. case <-stop:
  46. stopSet = true
  47. default:
  48. }
  49. if stopSet {
  50. break
  51. }
  52. i++
  53. }
  54. stop <- true
  55. }
  56. // Create a cluster of etcd nodes
  57. func CreateCluster(size int, procAttr *os.ProcAttr, ssl bool) ([][]string, []*os.Process, error) {
  58. argGroup := make([][]string, size)
  59. sslServer1 := []string{"-peer-ca-file=../../fixtures/ca/ca.crt",
  60. "-peer-cert-file=../../fixtures/ca/server.crt",
  61. "-peer-key-file=../../fixtures/ca/server.key.insecure",
  62. }
  63. sslServer2 := []string{"-peer-ca-file=../../fixtures/ca/ca.crt",
  64. "-peer-cert-file=../../fixtures/ca/server2.crt",
  65. "-peer-key-file=../../fixtures/ca/server2.key.insecure",
  66. }
  67. for i := 0; i < size; i++ {
  68. if i == 0 {
  69. argGroup[i] = []string{"etcd", "-data-dir=/tmp/node1", "-name=node1"}
  70. if ssl {
  71. argGroup[i] = append(argGroup[i], sslServer1...)
  72. }
  73. } else {
  74. strI := strconv.Itoa(i + 1)
  75. argGroup[i] = []string{"etcd", "-name=node" + strI, "-addr=127.0.0.1:400" + strI, "-peer-addr=127.0.0.1:700" + strI, "-data-dir=/tmp/node" + strI, "-peers=127.0.0.1:7001"}
  76. if ssl {
  77. argGroup[i] = append(argGroup[i], sslServer2...)
  78. }
  79. }
  80. }
  81. etcds := make([]*os.Process, size)
  82. for i, _ := range etcds {
  83. var err error
  84. etcds[i], err = os.StartProcess(EtcdBinPath, append(argGroup[i], "-f"), procAttr)
  85. if err != nil {
  86. return nil, nil, err
  87. }
  88. // TODOBP: Change this sleep to wait until the master is up.
  89. // The problem is that if the master isn't up then the children
  90. // have to retry. This retry can take upwards of 15 seconds
  91. // which slows tests way down and some of them fail.
  92. if i == 0 {
  93. time.Sleep(time.Second * 2)
  94. }
  95. }
  96. return argGroup, etcds, nil
  97. }
  98. // Destroy all the nodes in the cluster
  99. func DestroyCluster(etcds []*os.Process) error {
  100. for _, etcd := range etcds {
  101. err := etcd.Kill()
  102. if err != nil {
  103. panic(err.Error())
  104. }
  105. etcd.Release()
  106. }
  107. return nil
  108. }
  109. //
  110. func Monitor(size int, allowDeadNum int, leaderChan chan string, all chan bool, stop chan bool) {
  111. leaderMap := make(map[int]string)
  112. baseAddrFormat := "http://0.0.0.0:400%d"
  113. for {
  114. knownLeader := "unknown"
  115. dead := 0
  116. var i int
  117. for i = 0; i < size; i++ {
  118. leader, err := getLeader(fmt.Sprintf(baseAddrFormat, i+1))
  119. if err == nil {
  120. leaderMap[i] = leader
  121. if knownLeader == "unknown" {
  122. knownLeader = leader
  123. } else {
  124. if leader != knownLeader {
  125. break
  126. }
  127. }
  128. } else {
  129. dead++
  130. if dead > allowDeadNum {
  131. break
  132. }
  133. }
  134. }
  135. if i == size {
  136. select {
  137. case <-stop:
  138. return
  139. case <-leaderChan:
  140. leaderChan <- knownLeader
  141. default:
  142. leaderChan <- knownLeader
  143. }
  144. }
  145. if dead == 0 {
  146. select {
  147. case <-all:
  148. all <- true
  149. default:
  150. all <- true
  151. }
  152. }
  153. time.Sleep(time.Millisecond * 10)
  154. }
  155. }
  156. func getLeader(addr string) (string, error) {
  157. resp, err := client.Get(addr + "/v1/leader")
  158. if err != nil {
  159. return "", err
  160. }
  161. if resp.StatusCode != http.StatusOK {
  162. resp.Body.Close()
  163. return "", fmt.Errorf("no leader")
  164. }
  165. b, err := ioutil.ReadAll(resp.Body)
  166. resp.Body.Close()
  167. if err != nil {
  168. return "", err
  169. }
  170. return string(b), nil
  171. }
  172. // Dial with timeout
  173. func dialTimeoutFast(network, addr string) (net.Conn, error) {
  174. return net.DialTimeout(network, addr, time.Millisecond*10)
  175. }