github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/api/uniter/relation.go (about)

     1  // Copyright 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package uniter
     5  
     6  import (
     7  	"fmt"
     8  
     9  	"gopkg.in/juju/charm.v6"
    10  	"gopkg.in/juju/names.v2"
    11  
    12  	"github.com/juju/juju/apiserver/params"
    13  	"github.com/juju/juju/core/relation"
    14  	"github.com/juju/juju/state/multiwatcher"
    15  )
    16  
    17  // This module implements a subset of the interface provided by
    18  // state.Relation, as needed by the uniter API.
    19  
    20  // Relation represents a relation between one or two application
    21  // endpoints.
    22  type Relation struct {
    23  	st        *State
    24  	tag       names.RelationTag
    25  	id        int
    26  	life      params.Life
    27  	suspended bool
    28  	otherApp  string
    29  }
    30  
    31  // Tag returns the relation tag.
    32  func (r *Relation) Tag() names.RelationTag {
    33  	return r.tag
    34  }
    35  
    36  // String returns the relation as a string.
    37  func (r *Relation) String() string {
    38  	return r.tag.Id()
    39  }
    40  
    41  // Id returns the integer internal relation key. This is exposed
    42  // because the unit agent needs to expose a value derived from this
    43  // (as JUJU_RELATION_ID) to allow relation hooks to differentiate
    44  // between relations with different applications.
    45  func (r *Relation) Id() int {
    46  	return r.id
    47  }
    48  
    49  // Life returns the relation's current life state.
    50  func (r *Relation) Life() params.Life {
    51  	return r.life
    52  }
    53  
    54  // Suspended returns the relation's current suspended status.
    55  func (r *Relation) Suspended() bool {
    56  	return r.suspended
    57  }
    58  
    59  // UpdateSuspended updates the in memory value of the
    60  // relation's suspended attribute.
    61  func (r *Relation) UpdateSuspended(suspended bool) {
    62  	r.suspended = suspended
    63  }
    64  
    65  // OtherApplication returns the name of the application on the other
    66  // end of the relation (from this unit's perspective).
    67  func (r *Relation) OtherApplication() string {
    68  	return r.otherApp
    69  }
    70  
    71  // Refresh refreshes the contents of the relation from the underlying
    72  // state. It returns an error that satisfies errors.IsNotFound if the
    73  // relation has been removed.
    74  func (r *Relation) Refresh() error {
    75  	result, err := r.st.relation(r.tag, r.st.unitTag)
    76  	if err != nil {
    77  		return err
    78  	}
    79  	// NOTE: The status and life cycle information are the only
    80  	// things that can change - id, tag and endpoint
    81  	// information are static.
    82  	r.life = result.Life
    83  	r.suspended = result.Suspended
    84  
    85  	return nil
    86  }
    87  
    88  // SetStatus updates the status of the relation.
    89  func (r *Relation) SetStatus(status relation.Status) error {
    90  	return r.st.setRelationStatus(r.id, status)
    91  }
    92  
    93  func (r *Relation) toCharmRelation(cr multiwatcher.CharmRelation) charm.Relation {
    94  	return charm.Relation{
    95  		Name:      cr.Name,
    96  		Role:      charm.RelationRole(cr.Role),
    97  		Interface: cr.Interface,
    98  		Optional:  cr.Optional,
    99  		Limit:     cr.Limit,
   100  		Scope:     charm.RelationScope(cr.Scope),
   101  	}
   102  }
   103  
   104  // Endpoint returns the endpoint of the relation for the application the
   105  // uniter's managed unit belongs to.
   106  func (r *Relation) Endpoint() (*Endpoint, error) {
   107  	// NOTE: This differs from state.Relation.Endpoint(), because when
   108  	// talking to the API, there's already an authenticated entity - the
   109  	// unit, and we can find out its application name.
   110  	result, err := r.st.relation(r.tag, r.st.unitTag)
   111  	if err != nil {
   112  		return nil, err
   113  	}
   114  	return &Endpoint{r.toCharmRelation(result.Endpoint.Relation)}, nil
   115  }
   116  
   117  // Unit returns a RelationUnit for the supplied unit.
   118  func (r *Relation) Unit(u *Unit) (*RelationUnit, error) {
   119  	if u == nil {
   120  		return nil, fmt.Errorf("unit is nil")
   121  	}
   122  	result, err := r.st.relation(r.tag, u.tag)
   123  	if err != nil {
   124  		return nil, err
   125  	}
   126  	return &RelationUnit{
   127  		relation: r,
   128  		unit:     u,
   129  		endpoint: Endpoint{r.toCharmRelation(result.Endpoint.Relation)},
   130  		st:       r.st,
   131  	}, nil
   132  }