// addRelation causes the unit agent to join the supplied relation, and to // store persistent state in the supplied dir. func (u *Uniter) addRelation(rel *uniter.Relation, dir *relation.StateDir) error { logger.Infof("joining relation %q", rel) ru, err := rel.Unit(u.unit) if err != nil { return err } r := NewRelationer(ru, dir, u.relationHooks) w, err := u.unit.Watch() if err != nil { return err } defer watcher.Stop(w, &u.tomb) for { select { case <-u.tomb.Dying(): return tomb.ErrDying case _, ok := <-w.Changes(): if !ok { return watcher.MustErr(w) } err := r.Join() if params.IsCodeCannotEnterScopeYet(err) { logger.Infof("cannot enter scope for relation %q; waiting for subordinate to be removed", rel) continue } else if err != nil { return err } logger.Infof("joined relation %q", rel) u.relationers[rel.Id()] = r return nil } } }
// add causes the unit agent to join the supplied relation, and to // store persistent state in the supplied dir. It will block until the // operation succeeds or fails; or until the abort chan is closed, in // which case it will return resolver.ErrLoopAborted. func (r *relations) add(rel *uniter.Relation, dir *StateDir) (err error) { logger.Infof("joining relation %q", rel) ru, err := rel.Unit(r.unit) if err != nil { return errors.Trace(err) } relationer := NewRelationer(ru, dir) unitWatcher, err := r.unit.Watch() if err != nil { return errors.Trace(err) } defer func() { if e := worker.Stop(unitWatcher); e != nil { if err == nil { err = e } else { logger.Errorf("while stopping unit watcher: %v", e) } } }() for { select { case <-r.abort: // Should this be a different error? e.g. resolver.ErrAborted, that // Loop translates into ErrLoopAborted? return resolver.ErrLoopAborted case _, ok := <-unitWatcher.Changes(): if !ok { return errors.New("unit watcher closed") } err := relationer.Join() if params.IsCodeCannotEnterScopeYet(err) { logger.Infof("cannot enter scope for relation %q; waiting for subordinate to be removed", rel) continue } else if err != nil { return errors.Trace(err) } logger.Infof("joined relation %q", rel) r.relationers[rel.Id()] = relationer return nil } } }
// add causes the unit agent to join the supplied relation, and to // store persistent state in the supplied dir. func (r *relations) add(rel *uniter.Relation, dir *StateDir) (err error) { logger.Infof("joining relation %q", rel) ru, err := rel.Unit(r.unit) if err != nil { return errors.Trace(err) } relationer := NewRelationer(ru, dir) w, err := r.unit.Watch() if err != nil { return errors.Trace(err) } defer func() { if e := w.Stop(); e != nil { if err == nil { err = e } else { logger.Errorf("error stopping unit watcher: %v", e) } } }() for { select { case <-r.abort: return tomb.ErrDying case _, ok := <-w.Changes(): if !ok { return watcher.EnsureErr(w) } err := relationer.Join() if params.IsCodeCannotEnterScopeYet(err) { logger.Infof("cannot enter scope for relation %q; waiting for subordinate to be removed", rel) continue } else if err != nil { return errors.Trace(err) } logger.Infof("joined relation %q", rel) r.relationers[rel.Id()] = relationer return nil } } }