// Update is part of the Relations interface. func (r *relations) Update(ids []int) error { for _, id := range ids { if relationer, found := r.relationers[id]; found { rel := relationer.ru.Relation() if err := rel.Refresh(); err != nil { return errors.Annotatef(err, "cannot update relation %q", rel) } if rel.Life() == params.Dying { if err := r.setDying(id); err != nil { return errors.Trace(err) } } continue } // Relations that are not alive are simply skipped, because they // were not previously known anyway. rel, err := r.st.RelationById(id) if err != nil { if params.IsCodeNotFoundOrCodeUnauthorized(err) { continue } return errors.Trace(err) } if rel.Life() != params.Alive { continue } // Make sure we ignore relations not implemented by the unit's charm. ch, err := corecharm.ReadCharmDir(r.charmDir) if err != nil { return errors.Trace(err) } if ep, err := rel.Endpoint(); err != nil { return errors.Trace(err) } else if !ep.ImplementedBy(ch) { logger.Warningf("skipping relation with unknown endpoint %q", ep.Name) continue } dir, err := relation.ReadStateDir(r.relationsDir, id) if err != nil { return errors.Trace(err) } err = r.add(rel, dir) if err == nil { r.relationers[id].StartHooks() continue } e := dir.Remove() if !params.IsCodeCannotEnterScope(err) { return errors.Trace(err) } if e != nil { return errors.Trace(e) } } if ok, err := r.unit.IsPrincipal(); err != nil { return errors.Trace(err) } else if ok { return nil } // If no Alive relations remain between a subordinate unit's service // and its principal's service, the subordinate must become Dying. for _, relationer := range r.relationers { scope := relationer.ru.Endpoint().Scope if scope == corecharm.ScopeContainer && !relationer.dying { return nil } } return r.unit.Destroy() }
func (r *relations) update(remote map[int]remotestate.RelationSnapshot) error { for id, relationSnapshot := range remote { if _, found := r.relationers[id]; found { // We've seen this relation before. The only changes // we care about are to the lifecycle state, and to // the member settings versions. We handle differences // in settings in nextRelationHook. if relationSnapshot.Life == params.Dying { if err := r.setDying(id); err != nil { return errors.Trace(err) } } continue } // Relations that are not alive are simply skipped, because they // were not previously known anyway. if relationSnapshot.Life != params.Alive { continue } rel, err := r.st.RelationById(id) if err != nil { if params.IsCodeNotFoundOrCodeUnauthorized(err) { continue } return errors.Trace(err) } // Make sure we ignore relations not implemented by the unit's charm. ch, err := corecharm.ReadCharmDir(r.charmDir) if err != nil { return errors.Trace(err) } if ep, err := rel.Endpoint(); err != nil { return errors.Trace(err) } else if !ep.ImplementedBy(ch) { logger.Warningf("skipping relation with unknown endpoint %q", ep.Name) continue } dir, err := ReadStateDir(r.relationsDir, id) if err != nil { return errors.Trace(err) } addErr := r.add(rel, dir) if addErr == nil { continue } removeErr := dir.Remove() if !params.IsCodeCannotEnterScope(addErr) { return errors.Trace(addErr) } if removeErr != nil { return errors.Trace(removeErr) } } if ok, err := r.unit.IsPrincipal(); err != nil { return errors.Trace(err) } else if ok { return nil } // If no Alive relations remain between a subordinate unit's service // and its principal's service, the subordinate must become Dying. for _, relationer := range r.relationers { scope := relationer.ru.Endpoint().Scope if scope == corecharm.ScopeContainer && !relationer.dying { return nil } } return r.unit.Destroy() }
// updateRelations responds to changes in the life states of the relations // with the supplied ids. If any id corresponds to an alive relation not // known to the unit, the uniter will join that relation and return its // relationer in the added list. func (u *Uniter) updateRelations(ids []int) (added []*Relationer, err error) { for _, id := range ids { if r, found := u.relationers[id]; found { rel := r.ru.Relation() if err := rel.Refresh(); err != nil { return nil, fmt.Errorf("cannot update relation %q: %v", rel, err) } if rel.Life() == params.Dying { if err := r.SetDying(); err != nil { return nil, err } else if r.IsImplicit() { delete(u.relationers, id) } } continue } // Relations that are not alive are simply skipped, because they // were not previously known anyway. rel, err := u.st.RelationById(id) if err != nil { if params.IsCodeNotFoundOrCodeUnauthorized(err) { continue } return nil, err } if rel.Life() != params.Alive { continue } // Make sure we ignore relations not implemented by the unit's charm. ch, err := corecharm.ReadCharmDir(u.charmPath) if err != nil { return nil, err } if ep, err := rel.Endpoint(); err != nil { return nil, err } else if !ep.ImplementedBy(ch) { logger.Warningf("skipping relation with unknown endpoint %q", ep.Name) continue } dir, err := relation.ReadStateDir(u.relationsDir, id) if err != nil { return nil, err } err = u.addRelation(rel, dir) if err == nil { added = append(added, u.relationers[id]) continue } e := dir.Remove() if !params.IsCodeCannotEnterScope(err) { return nil, err } if e != nil { return nil, e } } if ok, err := u.unit.IsPrincipal(); err != nil { return nil, err } else if ok { return added, nil } // If no Alive relations remain between a subordinate unit's service // and its principal's service, the subordinate must become Dying. keepAlive := false for _, r := range u.relationers { scope := r.ru.Endpoint().Scope if scope == corecharm.ScopeContainer && !r.dying { keepAlive = true break } } if !keepAlive { if err := u.unit.Destroy(); err != nil { return nil, err } } return added, nil }