github.com/macb/etcd@v0.3.1-0.20140227003422-a60481c6b1a0/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 "errors" 21 "fmt" 22 "github.com/coreos/etcd/third_party/github.com/coreos/go-etcd/etcd" 23 "io/ioutil" 24 "net" 25 "net/http" 26 "os" 27 "strconv" 28 "time" 29 ) 30 31 var client = http.Client{ 32 Transport: &http.Transport{ 33 Dial: dialTimeoutFast, 34 }, 35 } 36 37 // Sending set commands 38 func Set(stop chan bool) { 39 40 stopSet := false 41 i := 0 42 c := etcd.NewClient(nil) 43 for { 44 key := fmt.Sprintf("%s_%v", "foo", i) 45 46 result, err := c.Set(key, "bar", 0) 47 48 if err != nil || result.Node.Key != "/"+key || result.Node.Value != "bar" { 49 select { 50 case <-stop: 51 stopSet = true 52 53 default: 54 } 55 } 56 57 select { 58 case <-stop: 59 stopSet = true 60 61 default: 62 } 63 64 if stopSet { 65 break 66 } 67 68 i++ 69 } 70 stop <- true 71 } 72 73 func WaitForServer(host string, client http.Client, scheme string) error { 74 path := fmt.Sprintf("%s://%s/v2/keys/", scheme, host) 75 76 var resp *http.Response 77 var err error 78 for i := 0; i < 10; i++ { 79 time.Sleep(1 * time.Second) 80 81 resp, err = client.Get(path) 82 if err == nil && resp.StatusCode == 200 { 83 return nil 84 } 85 } 86 87 return errors.New(fmt.Sprintf("etcd server was not reachable in a long time, last-time response and error: %v; %v", resp, err)) 88 } 89 90 // Create a cluster of etcd nodes 91 func CreateCluster(size int, procAttr *os.ProcAttr, ssl bool) ([][]string, []*os.Process, error) { 92 argGroup := make([][]string, size) 93 94 sslServer1 := []string{"-peer-ca-file=../../fixtures/ca/ca.crt", 95 "-peer-cert-file=../../fixtures/ca/server.crt", 96 "-peer-key-file=../../fixtures/ca/server.key.insecure", 97 } 98 99 sslServer2 := []string{"-peer-ca-file=../../fixtures/ca/ca.crt", 100 "-peer-cert-file=../../fixtures/ca/server2.crt", 101 "-peer-key-file=../../fixtures/ca/server2.key.insecure", 102 } 103 104 for i := 0; i < size; i++ { 105 if i == 0 { 106 argGroup[i] = []string{"etcd", "-data-dir=/tmp/node1", "-name=node1"} 107 if ssl { 108 argGroup[i] = append(argGroup[i], sslServer1...) 109 } 110 } else { 111 strI := strconv.Itoa(i + 1) 112 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"} 113 if ssl { 114 argGroup[i] = append(argGroup[i], sslServer2...) 115 } 116 } 117 } 118 119 etcds := make([]*os.Process, size) 120 121 for i := range etcds { 122 var err error 123 etcds[i], err = os.StartProcess(EtcdBinPath, append(argGroup[i], "-f"), procAttr) 124 if err != nil { 125 return nil, nil, err 126 } 127 128 // The problem is that if the master isn't up then the children 129 // have to retry. This retry can take upwards of 15 seconds 130 // which slows tests way down and some of them fail. 131 if i == 0 { 132 client := buildClient() 133 err = WaitForServer("127.0.0.1:4001", client, "http") 134 if err != nil { 135 return nil, nil, err 136 } 137 } 138 } 139 140 return argGroup, etcds, nil 141 } 142 143 // Destroy all the nodes in the cluster 144 func DestroyCluster(etcds []*os.Process) error { 145 for _, etcd := range etcds { 146 err := etcd.Kill() 147 if err != nil { 148 panic(err.Error()) 149 } 150 etcd.Release() 151 } 152 return nil 153 } 154 155 // 156 func Monitor(size int, allowDeadNum int, leaderChan chan string, all chan bool, stop chan bool) { 157 leaderMap := make(map[int]string) 158 baseAddrFormat := "http://0.0.0.0:400%d" 159 160 for { 161 knownLeader := "unknown" 162 dead := 0 163 var i int 164 165 for i = 0; i < size; i++ { 166 leader, err := getLeader(fmt.Sprintf(baseAddrFormat, i+1)) 167 168 if err == nil { 169 leaderMap[i] = leader 170 171 if knownLeader == "unknown" { 172 knownLeader = leader 173 } else { 174 if leader != knownLeader { 175 break 176 } 177 178 } 179 180 } else { 181 dead++ 182 if dead > allowDeadNum { 183 break 184 } 185 } 186 187 } 188 189 if i == size { 190 select { 191 case <-stop: 192 return 193 case <-leaderChan: 194 leaderChan <- knownLeader 195 default: 196 leaderChan <- knownLeader 197 } 198 199 } 200 if dead == 0 { 201 select { 202 case <-all: 203 all <- true 204 default: 205 all <- true 206 } 207 } 208 209 time.Sleep(time.Millisecond * 10) 210 } 211 212 } 213 214 func getLeader(addr string) (string, error) { 215 216 resp, err := client.Get(addr + "/v1/leader") 217 218 if err != nil { 219 return "", err 220 } 221 222 if resp.StatusCode != http.StatusOK { 223 resp.Body.Close() 224 return "", fmt.Errorf("no leader") 225 } 226 227 b, err := ioutil.ReadAll(resp.Body) 228 229 resp.Body.Close() 230 231 if err != nil { 232 return "", err 233 } 234 235 return string(b), nil 236 237 } 238 239 // Dial with timeout 240 func dialTimeoutFast(network, addr string) (net.Conn, error) { 241 return net.DialTimeout(network, addr, time.Millisecond*10) 242 }