// becomeMaster attempts to become the master for this lock. // returns "", nil if the attempt failed // returns id, nil if the attempt succeeded // returns "", err if an error occurred func (e *etcdMasterElector) becomeMaster(path, id string, ttl uint64) (string, error) { _, err := e.etcd.Create(path, id, ttl) if err != nil && !etcdstorage.IsEtcdNodeExist(err) { // unexpected error return "", err } if err != nil && etcdstorage.IsEtcdNodeExist(err) { return "", nil } return id, nil }
// InterpretUpdateError converts a generic etcd error on a update // operation into the appropriate API error. func InterpretUpdateError(err error, kind, name string) error { switch { case etcdstorage.IsEtcdTestFailed(err), etcdstorage.IsEtcdNodeExist(err): return errors.NewConflict(kind, name, err) default: return err } }
// InterpretCreateError converts a generic etcd error on a create // operation into the appropriate API error. func InterpretCreateError(err error, kind, name string) error { switch { case etcdstorage.IsEtcdNodeExist(err): return errors.NewAlreadyExists(kind, name) default: return err } }
// InterpretUpdateError converts a generic etcd error on a update // operation into the appropriate API error. func InterpretUpdateError(err error, kind, name string) error { switch { case etcdstorage.IsEtcdTestFailed(err), etcdstorage.IsEtcdNodeExist(err): return errors.NewConflict(kind, name, err) case etcdstorage.IsEtcdUnreachable(err): return errors.NewServerTimeout(kind, "update", 2) // TODO: make configurable or handled at a higher level default: return err } }
// InterpretCreateError converts a generic etcd error on a create // operation into the appropriate API error. func InterpretCreateError(err error, kind, name string) error { switch { case etcdstorage.IsEtcdNodeExist(err): return errors.NewAlreadyExists(kind, name) case etcdstorage.IsEtcdUnreachable(err): return errors.NewServerTimeout(kind, "create", 2) // TODO: make configurable or handled at a higher level default: return err } }
// tryAcquire tries to create the lease key in etcd, or if it already exists // and belongs to another user, to wait until the lease expires or is deleted. // It returns true if the lease was acquired, the current TTL, the nextIndex // to watch from, or an error. func (e *Etcd) tryAcquire() (ok bool, ttl uint64, nextIndex uint64, err error) { ttl = e.ttl resp, err := e.client.Create(e.key, e.value, ttl) if err == nil { // we hold the lease index := resp.EtcdIndex glog.V(4).Infof("Lease %s acquired at %d, ttl %d seconds", e.key, index, e.ttl) return true, ttl, index + 1, nil } if !storage.IsEtcdNodeExist(err) { return false, 0, 0, fmt.Errorf("unable to check lease %s: %v", e.key, err) } latest, err := e.client.Get(e.key, false, false) if err != nil { return false, 0, 0, fmt.Errorf("unable to retrieve lease %s: %v", e.key, err) } nextIndex = eventIndexFor(latest) if latest.Node.TTL > 0 { ttl = uint64(latest.Node.TTL) } if latest.Node.Value != e.value { glog.V(4).Infof("Lease %s owned by %s at %d ttl %d seconds, waiting for expiration", e.key, latest.Node.Value, nextIndex-1, ttl) // waits until the lease expires or changes to us. // TODO: it's possible we were given the lease during the watch, but we just expect to go // through this loop again and let this condition check if _, err := e.waitForExpiration(false, nextIndex, nil); err != nil { return false, 0, 0, fmt.Errorf("unable to wait for lease expiration %s: %v", e.key, err) } return false, 0, 0, nil } glog.V(4).Infof("Lease %s already held, expires in %d seconds", e.key, ttl) return true, ttl, nextIndex, nil }