member.go 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. // Copyright 2015 CoreOS, Inc.
  2. //
  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. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package functional
  15. import (
  16. "fmt"
  17. "io"
  18. "io/ioutil"
  19. "log"
  20. "net/http"
  21. "net/url"
  22. "os"
  23. "os/exec"
  24. "strconv"
  25. "strings"
  26. "time"
  27. )
  28. type Proc struct {
  29. *exec.Cmd
  30. Name string
  31. DataDir string
  32. URL string
  33. PeerURL string
  34. stderr io.ReadCloser
  35. }
  36. func NewProcWithDefaultFlags(path string) *Proc {
  37. var args []string
  38. dir, err := ioutil.TempDir(os.TempDir(), "etcd")
  39. if err != nil {
  40. fmt.Printf("unexpected TempDir error: %v", err)
  41. os.Exit(1)
  42. }
  43. args = append(args, "--data-dir="+dir)
  44. args = append(args, "--name=default")
  45. p := &Proc{
  46. Cmd: exec.Command(path, args...),
  47. Name: "default",
  48. DataDir: dir,
  49. URL: "http://127.0.0.1:4001",
  50. PeerURL: "http://127.0.0.1:7001",
  51. }
  52. // always expect to use start_desired_verson mode
  53. p.Env = append(p.Env,
  54. "ETCD_BINARY_DIR="+binDir,
  55. )
  56. return p
  57. }
  58. func NewProcWithV1Flags(path string) *Proc {
  59. p := NewProcWithDefaultFlags(path)
  60. p.SetV1PeerAddr("127.0.0.1:7001")
  61. return p
  62. }
  63. func NewProcWithV2Flags(path string) *Proc {
  64. p := NewProcWithDefaultFlags(path)
  65. p.SetV2PeerURL("http://127.0.0.1:7001")
  66. return p
  67. }
  68. func (p *Proc) SetV2PeerURL(url string) {
  69. p.Args = append(p.Args,
  70. "-listen-peer-urls="+url,
  71. "-initial-advertise-peer-urls="+url,
  72. "-initial-cluster",
  73. p.Name+"="+url,
  74. )
  75. p.PeerURL = url
  76. }
  77. func (p *Proc) SetV1PeerAddr(addr string) {
  78. p.Args = append(p.Args,
  79. "-peer-addr="+addr,
  80. )
  81. p.PeerURL = "http://" + addr
  82. }
  83. func (p *Proc) SetV1Addr(addr string) {
  84. p.Args = append(p.Args,
  85. "-addr="+addr,
  86. )
  87. p.URL = "http://" + addr
  88. }
  89. func (p *Proc) SetV1Peers(peers []string) {
  90. p.Args = append(p.Args,
  91. "-peers="+strings.Join(peers, ","),
  92. )
  93. }
  94. func (p *Proc) SetName(name string) {
  95. p.Args = append(p.Args,
  96. "-name="+name,
  97. )
  98. p.Name = name
  99. }
  100. func (p *Proc) SetDataDir(dataDir string) {
  101. p.Args = append(p.Args,
  102. "-data-dir="+dataDir,
  103. )
  104. p.DataDir = dataDir
  105. }
  106. func (p *Proc) SetSnapCount(cnt int) {
  107. p.Args = append(p.Args,
  108. "-snapshot-count="+strconv.Itoa(cnt),
  109. )
  110. }
  111. func (p *Proc) SetDiscovery(url string) {
  112. p.Args = append(p.Args,
  113. "-discovery="+url,
  114. )
  115. }
  116. func (p *Proc) SetPeerTLS(certFile, keyFile, caFile string) {
  117. p.Args = append(p.Args,
  118. "-peer-cert-file="+certFile,
  119. "-peer-key-file="+keyFile,
  120. "-peer-ca-file="+caFile,
  121. )
  122. u, err := url.Parse(p.PeerURL)
  123. if err != nil {
  124. log.Panicf("unexpected parse error: %v", err)
  125. }
  126. u.Scheme = "https"
  127. p.PeerURL = u.String()
  128. }
  129. func (p *Proc) CleanUnsuppportedV1Flags() {
  130. var args []string
  131. for _, arg := range p.Args {
  132. if !strings.HasPrefix(arg, "-peers=") {
  133. args = append(args, arg)
  134. }
  135. }
  136. p.Args = args
  137. }
  138. func (p *Proc) Start() error {
  139. if err := p.Cmd.Start(); err != nil {
  140. return err
  141. }
  142. for k := 0; k < 50; k++ {
  143. _, err := http.Get(p.URL)
  144. if err == nil {
  145. return nil
  146. }
  147. time.Sleep(100 * time.Millisecond)
  148. }
  149. return fmt.Errorf("instance %s failed to be available after a long time", p.Name)
  150. }
  151. func (p *Proc) Stop() {
  152. if err := p.Cmd.Process.Kill(); err != nil {
  153. fmt.Printf("Process Kill error: %v", err)
  154. return
  155. }
  156. p.Cmd.Wait()
  157. }
  158. func (p *Proc) Restart() error {
  159. p.Stop()
  160. return p.Start()
  161. }
  162. func (p *Proc) Terminate() {
  163. p.Stop()
  164. os.RemoveAll(p.DataDir)
  165. }
  166. type ProcGroup []*Proc
  167. func NewProcInProcGroupWithV1Flags(path string, num int, idx int) *Proc {
  168. pg := NewProcGroupWithV1Flags(path, num)
  169. return pg[idx]
  170. }
  171. func NewProcGroupWithV1Flags(path string, num int) ProcGroup {
  172. pg := make([]*Proc, num)
  173. for i := 0; i < num; i++ {
  174. pg[i] = NewProcWithDefaultFlags(path)
  175. pg[i].SetName(fmt.Sprintf("etcd%d", i))
  176. pg[i].SetV1PeerAddr(fmt.Sprintf("127.0.0.1:%d", 7001+i))
  177. pg[i].SetV1Addr(fmt.Sprintf("127.0.0.1:%d", 4001+i))
  178. if i > 0 {
  179. pg[i].SetV1Peers([]string{"127.0.0.1:7001"})
  180. }
  181. }
  182. return pg
  183. }
  184. func NewProcGroupViaDiscoveryWithV1Flags(path string, num int, url string) ProcGroup {
  185. pg := make([]*Proc, num)
  186. for i := range pg {
  187. pg[i] = NewProcWithDefaultFlags(path)
  188. pg[i].SetName(fmt.Sprintf("etcd%d", i))
  189. pg[i].SetDiscovery(url)
  190. pg[i].SetV1PeerAddr(fmt.Sprintf("127.0.0.1:%d", 7001+i))
  191. pg[i].SetV1Addr(fmt.Sprintf("127.0.0.1:%d", 4001+i))
  192. }
  193. return pg
  194. }
  195. func (pg ProcGroup) SetPeerTLS(certFile, keyFile, caFile string) {
  196. for i := range pg {
  197. pg[i].SetPeerTLS(certFile, keyFile, caFile)
  198. }
  199. }
  200. func (pg ProcGroup) InheritDataDir(opg ProcGroup) {
  201. for i := range pg {
  202. pg[i].SetDataDir(opg[i].DataDir)
  203. }
  204. }
  205. func (pg ProcGroup) SetSnapCount(count int) {
  206. for i := range pg {
  207. pg[i].SetSnapCount(count)
  208. }
  209. }
  210. func (pg ProcGroup) CleanUnsuppportedV1Flags() {
  211. for _, p := range pg {
  212. p.CleanUnsuppportedV1Flags()
  213. }
  214. }
  215. func (pg ProcGroup) Start() error {
  216. for _, p := range pg {
  217. if err := p.Start(); err != nil {
  218. return err
  219. }
  220. }
  221. // leave time for instances to sync and write some entries into disk
  222. // TODO: use more reliable method
  223. time.Sleep(time.Second)
  224. return nil
  225. }
  226. func (pg ProcGroup) Wait() error {
  227. for _, p := range pg {
  228. if err := p.Wait(); err != nil {
  229. return err
  230. }
  231. }
  232. return nil
  233. }
  234. func (pg ProcGroup) Stop() {
  235. for _, p := range pg {
  236. p.Stop()
  237. }
  238. }
  239. func (pg ProcGroup) Terminate() {
  240. for _, p := range pg {
  241. p.Terminate()
  242. }
  243. }