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