github.com/coreos/mantle@v0.13.0/kola/tests/etcd/util.go (about) 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 15 package etcd 16 17 import ( 18 "bytes" 19 "encoding/json" 20 "fmt" 21 "math/rand" 22 "strconv" 23 "strings" 24 "time" 25 26 "github.com/coreos/mantle/kola/cluster" 27 "github.com/coreos/mantle/platform" 28 "github.com/coreos/mantle/util" 29 ) 30 31 // GetClusterHealth polls etcdctl cluster-health command until success 32 // or maximum retries have been reached. Can be effectively used to 33 // block a test until the etcd cluster is up and running. 34 func GetClusterHealth(c cluster.TestCluster, m platform.Machine, csize int) error { 35 var err error 36 var b []byte 37 38 checker := func() error { 39 b, err := c.SSH(m, "etcdctl cluster-health") 40 if err != nil { 41 return err 42 } 43 44 // repsonse should include "healthy" for each machine and for cluster 45 if strings.Count(string(b), "healthy") != (csize*2)+1 { 46 return fmt.Errorf("unexpected etcdctl output") 47 } 48 49 plog.Infof("cluster healthy") 50 return nil 51 } 52 53 err = util.Retry(15, 10*time.Second, checker) 54 if err != nil { 55 return fmt.Errorf("health polling failed: %v: %s", err, b) 56 } 57 58 return nil 59 } 60 61 // setKeys sets n random keys and values across each machine in a 62 // cluster and returns these values to later be checked with checkKeys. 63 // If all the values don't get set due to a machine that is down and 64 // error is NOT returned. An error is returned if no keys are able to be 65 // set. 66 func setKeys(c cluster.TestCluster, n int) (map[string]string, error) { 67 var written = map[string]string{} 68 for _, m := range c.Machines() { 69 for i := 0; i < n; i++ { 70 // random key and value, may overwrwite previous sets if 71 // collision which is fine 72 key := strconv.Itoa(rand.Int())[0:3] 73 value := strconv.Itoa(rand.Int())[0:3] 74 75 b, err := c.SSH(m, fmt.Sprintf("curl -s -w %%{http_code} -s http://127.0.0.1:2379/v2/keys/%v -XPUT -d value=%v", key, value)) 76 if err != nil { 77 return nil, err 78 } 79 80 // check for 201 or 200 resp header 81 if !bytes.HasSuffix(b, []byte("200")) && !bytes.HasSuffix(b, []byte("201")) { 82 continue 83 } 84 85 written[key] = value 86 } 87 } 88 if len(written) == 0 { 89 return nil, fmt.Errorf("failed to write any keys") 90 } 91 92 plog.Infof("wrote %v keys", len(written)) 93 return written, nil 94 } 95 96 // checkKeys tests that each node in the cluster has the full provided 97 // key set in keyMap. Quorum get must be used. 98 func checkKeys(c cluster.TestCluster, keyMap map[string]string) error { 99 for i, m := range c.Machines() { 100 for k, v := range keyMap { 101 cmd := fmt.Sprintf("curl -s http://127.0.0.1:2379/v2/keys/%v?quorum=true", k) 102 103 b, err := c.SSH(m, cmd) 104 if err != nil { 105 return fmt.Errorf("error curling key: %v", err) 106 } 107 108 var jsonMap map[string]interface{} 109 err = json.Unmarshal(b, &jsonMap) 110 if err != nil { 111 return err 112 } 113 114 // error code? 115 errorCode, ok := jsonMap["errorCode"] 116 if ok { 117 msg := jsonMap["message"] 118 return fmt.Errorf("machine %v errorCode %v: %v: %s", i, errorCode, msg, b) 119 } 120 121 node, ok := jsonMap["node"] 122 if !ok { 123 return fmt.Errorf("retrieving key in CheckKeys, no node in resp") 124 } 125 126 n := node.(map[string]interface{}) 127 value, ok := n["value"] 128 if !ok { 129 return fmt.Errorf("retrieving key in CheckKeys, no value in resp") 130 } 131 132 if value != v { 133 return fmt.Errorf("checkKeys got incorrect value! expected:%v got: %v", v, value) 134 } 135 } 136 } 137 plog.Infof("checked %v keys", len(keyMap)) 138 return nil 139 }