github.com/rochacon/deis@v1.0.2-0.20150903015341-6839b592a1ff/mesos/pkg/etcd/etcd.go (about) 1 package etcd 2 3 import ( 4 "errors" 5 "path" 6 "strconv" 7 "strings" 8 "time" 9 10 "github.com/coreos/go-etcd/etcd" 11 logger "github.com/deis/deis/mesos/pkg/log" 12 etcdlock "github.com/leeor/etcd-sync" 13 ) 14 15 // Client etcd client 16 type Client struct { 17 client *etcd.Client 18 lock *etcdlock.EtcdMutex 19 } 20 21 // Error etcd error 22 type Error struct { 23 ErrorCode int `json:"errorCode"` 24 Message string `json:"message"` 25 Cause string `json:"cause,omitempty"` 26 Index uint64 `json:"index"` 27 } 28 29 var log = logger.New() 30 31 // NewClient create a etcd client using the given machine list 32 func NewClient(machines []string) *Client { 33 log.Debugf("connecting to %v etcd server/s", machines) 34 return &Client{etcd.NewClient(machines), nil} 35 } 36 37 // SetDefault sets the value of a key without expiration 38 func SetDefault(client *Client, key, value string) { 39 Create(client, key, value, 0) 40 } 41 42 // Mkdir creates a directory only if does not exists 43 func Mkdir(c *Client, path string) { 44 _, err := c.client.CreateDir(path, 0) 45 if err != nil { 46 log.Debug(err) 47 } 48 } 49 50 // WaitForKeys wait for the required keys up to the timeout or forever if is nil 51 func WaitForKeys(c *Client, keys []string, ttl time.Duration) error { 52 start := time.Now() 53 wait := true 54 55 for { 56 for _, key := range keys { 57 _, err := c.client.Get(key, false, false) 58 if err != nil { 59 log.Debugf("key \"%s\" error %v", key, err) 60 wait = true 61 } 62 } 63 64 if !wait { 65 return nil 66 } 67 68 log.Debug("waiting for missing etcd keys...") 69 time.Sleep(1 * time.Second) 70 wait = false 71 72 if time.Since(start) > ttl { 73 return errors.New("maximum ttl reached. aborting") 74 } 75 } 76 } 77 78 // Get returns the value inside a key or an empty string 79 func Get(c *Client, key string) string { 80 result, err := c.client.Get(key, false, false) 81 if err != nil { 82 log.Debugf("%v", err) 83 return "" 84 } 85 86 return result.Node.Value 87 } 88 89 // GetList returns the list of elements inside a key or an empty list 90 func GetList(c *Client, key string) []string { 91 values, err := c.client.Get(key, true, false) 92 if err != nil { 93 log.Debugf("getlist %v", err) 94 return []string{} 95 } 96 97 result := []string{} 98 for _, node := range values.Node.Nodes { 99 result = append(result, path.Base(node.Key)) 100 } 101 102 log.Debugf("getlist %s -> %v", key, result) 103 return result 104 } 105 106 // Set sets the value of a key. 107 // If the ttl is bigger than 0 it will expire after the specified time 108 func Set(c *Client, key, value string, ttl uint64) { 109 log.Debugf("set %s -> %s", key, value) 110 _, err := c.client.Set(key, value, ttl) 111 if err != nil { 112 log.Debugf("%v", err) 113 } 114 } 115 116 // Create set the value of a key only if it does not exits 117 func Create(c *Client, key, value string, ttl uint64) { 118 log.Debugf("create %s -> %s", key, value) 119 _, err := c.client.Create(key, value, ttl) 120 if err != nil { 121 log.Debugf("%v", err) 122 } 123 } 124 125 // PublishService publish a service to etcd periodically 126 func PublishService( 127 client *Client, 128 etcdPath string, 129 host string, 130 externalPort int, 131 ttl uint64, 132 timeout time.Duration) { 133 134 for { 135 Set(client, etcdPath+"/host", host, ttl) 136 Set(client, etcdPath+"/port", strconv.Itoa(externalPort), ttl) 137 time.Sleep(timeout) 138 } 139 } 140 141 func convertEtcdError(err error) *Error { 142 etcdError := err.(*etcd.EtcdError) 143 return &Error{ 144 ErrorCode: etcdError.ErrorCode, 145 Message: etcdError.Message, 146 Cause: etcdError.Cause, 147 Index: etcdError.Index, 148 } 149 } 150 151 // GetHTTPEtcdUrls returns an array of urls that contains at least one host 152 func GetHTTPEtcdUrls(host, etcdPeers string) []string { 153 if etcdPeers != "127.0.0.1:4001" { 154 hosts := strings.Split(etcdPeers, ",") 155 result := []string{} 156 for _, _host := range hosts { 157 result = append(result, "http://"+_host+":4001") 158 } 159 return result 160 } 161 162 return []string{"http://" + host} 163 }