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  }