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