// handleMaster performs one loop of master locking. // on success it returns <master>, nil // on error it returns "", err // in situations where you should try again due to concurrent state changes (e.g. another actor simultaneously acquiring the lock) // it returns "", nil func (e *etcdMasterElector) handleMaster(path, id string, ttl uint64) (string, error) { res, err := e.etcd.Get(path, false, false) // Unexpected error, bail out if err != nil && !tools.IsEtcdNotFound(err) { return "", err } // There is no master, try to become the master. if err != nil && tools.IsEtcdNotFound(err) { return e.becomeMaster(path, id, ttl) } // This should never happen. if res.Node == nil { return "", fmt.Errorf("unexpected response: %#v", res) } // We're not the master, just return the current value if res.Node.Value != id { return res.Node.Value, nil } // We are the master, try to extend out lease return e.extendMaster(path, id, ttl, res) }
// acquireOrRenewLease either races to acquire a new master lease, or update the existing master's lease // returns true if we have the lease, and an error if one occurs. // TODO: use the master election utility once it is merged in. func (c *Config) acquireOrRenewLease(etcdClient *etcd.Client) (bool, error) { result, err := etcdClient.Get(c.key, false, false) if err != nil { if tools.IsEtcdNotFound(err) { // there is no current master, try to become master, create will fail if the key already exists _, err := etcdClient.Create(c.key, c.whoami, c.ttl) if err != nil { return false, err } c.lastLease = time.Now() return true, nil } return false, err } if result.Node.Value == c.whoami { glog.Infof("key already exists, we are the master (%s)", result.Node.Value) // we extend our lease @ 1/2 of the existing TTL, this ensures the master doesn't flap around if result.Node.Expiration.Sub(time.Now()) < time.Duration(c.ttl/2)*time.Second { _, err := etcdClient.CompareAndSwap(c.key, c.whoami, c.ttl, c.whoami, result.Node.ModifiedIndex) if err != nil { return false, err } } c.lastLease = time.Now() return true, nil } glog.Infof("key already exists, the master is %s, sleeping.", result.Node.Value) return false, nil }
// InterpretDeleteError converts a generic etcd error on a delete // operation into the appropriate API error. func InterpretDeleteError(err error, kind, name string) error { switch { case tools.IsEtcdNotFound(err): return errors.NewNotFound(kind, name) default: return err } }
func (s *SchedulerServer) fetchFrameworkID(client tools.EtcdGetSet) (*mesos.FrameworkID, error) { if s.FailoverTimeout > 0 { if response, err := client.Get(meta.FrameworkIDKey, false, false); err != nil { if !tools.IsEtcdNotFound(err) { return nil, fmt.Errorf("unexpected failure attempting to load framework ID from etcd: %v", err) } log.V(1).Infof("did not find framework ID in etcd") } else if response.Node.Value != "" { log.Infof("configuring FrameworkInfo with Id found in etcd: '%s'", response.Node.Value) return mutil.NewFrameworkID(response.Node.Value), nil } } else { //TODO(jdef) this seems like a totally hackish way to clean up the framework ID if _, err := client.Delete(meta.FrameworkIDKey, true); err != nil { if !tools.IsEtcdNotFound(err) { return nil, fmt.Errorf("failed to delete framework ID from etcd: %v", err) } log.V(1).Infof("nothing to delete: did not find framework ID in etcd") } } return nil, nil }
// Refresh reloads the RangeAllocation from etcd. func (e *Etcd) Refresh() (*api.RangeAllocation, error) { e.lock.Lock() defer e.lock.Unlock() existing := &api.RangeAllocation{} if err := e.helper.ExtractObj(e.baseKey, existing, false); err != nil { if tools.IsEtcdNotFound(err) { return nil, nil } return nil, etcderr.InterpretGetError(err, e.kind, "") } return existing, nil }