github.com/wallyworld/juju@v0.0.0-20161013125918-6cf1bc9d917a/api/agent/facade.go (about)

     1  // Copyright 2016 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package agent
     5  
     6  import (
     7  	"github.com/juju/errors"
     8  	"gopkg.in/juju/names.v2"
     9  
    10  	"github.com/juju/juju/api/base"
    11  	"github.com/juju/juju/apiserver/params"
    12  )
    13  
    14  // Life is a local representation of entity life. Should probably be
    15  // in a core/life or core/entity package; and quite probably, so
    16  // should the ConnFacade interface.
    17  type Life string
    18  
    19  const (
    20  	Alive Life = "alive"
    21  	Dying Life = "dying"
    22  	Dead  Life = "dead"
    23  )
    24  
    25  // ConnFacade exposes the parts of the Agent facade needed by the bits
    26  // that currently live in apicaller. This criterion is every bit as
    27  // terrible as it sounds -- surely there should be a new facade at the
    28  // apiserver level somewhere? -- but:
    29  //  1) this feels like a convenient/transitional method grouping, not a
    30  //     fundamental *role*; and
    31  //  2) at least it's a narrowed interface, and eschews the object-style
    32  //     sins of *State/*Entity.
    33  // Progress not perfection.
    34  type ConnFacade interface {
    35  
    36  	// Life returns Alive, Dying, Dead, ErrDenied, or some other error.
    37  	Life(names.Tag) (Life, error)
    38  
    39  	// SetPassword returns nil, ErrDenied, or some other error.
    40  	SetPassword(names.Tag, string) error
    41  }
    42  
    43  // ErrDenied is returned by Life and SetPassword to indicate that the
    44  // requested operation is impossible (and hence that the entity is
    45  // either dead or gone, and in either case that no further meaningful
    46  // interaction is possible).
    47  var ErrDenied = errors.New("entity operation impossible")
    48  
    49  // NewConnFacade returns a ConnFacade backed by the supplied APICaller.
    50  func NewConnFacade(caller base.APICaller) (ConnFacade, error) {
    51  	facadeCaller := base.NewFacadeCaller(caller, "Agent")
    52  	return &connFacade{
    53  		caller: facadeCaller,
    54  	}, nil
    55  }
    56  
    57  // connFacade implements ConnFacade.
    58  type connFacade struct {
    59  	caller base.FacadeCaller
    60  }
    61  
    62  // Life is part of the ConnFacade interface.
    63  func (facade *connFacade) Life(entity names.Tag) (Life, error) {
    64  	var results params.AgentGetEntitiesResults
    65  	args := params.Entities{
    66  		Entities: []params.Entity{{Tag: entity.String()}},
    67  	}
    68  	err := facade.caller.FacadeCall("GetEntities", args, &results)
    69  	if err != nil {
    70  		return "", errors.Trace(err)
    71  	}
    72  	if len(results.Entities) != 1 {
    73  		return "", errors.Errorf("expected 1 result, got %d", len(results.Entities))
    74  	}
    75  	if err := results.Entities[0].Error; err != nil {
    76  		if params.IsCodeNotFoundOrCodeUnauthorized(err) {
    77  			return "", ErrDenied
    78  		}
    79  		return "", errors.Trace(err)
    80  	}
    81  	life := Life(results.Entities[0].Life)
    82  	switch life {
    83  	case Alive, Dying, Dead:
    84  		return life, nil
    85  	}
    86  	return "", errors.Errorf("unknown life value %q", life)
    87  }
    88  
    89  // SetPassword is part of the ConnFacade interface.
    90  func (facade *connFacade) SetPassword(entity names.Tag, password string) error {
    91  	var results params.ErrorResults
    92  	args := params.EntityPasswords{
    93  		Changes: []params.EntityPassword{{
    94  			Tag:      entity.String(),
    95  			Password: password,
    96  		}},
    97  	}
    98  	err := facade.caller.FacadeCall("SetPasswords", args, &results)
    99  	if err != nil {
   100  		return errors.Trace(err)
   101  	}
   102  	if len(results.Results) != 1 {
   103  		return errors.Errorf("expected 1 result, got %d", len(results.Results))
   104  	}
   105  	if err := results.Results[0].Error; err != nil {
   106  		if params.IsCodeDead(err) {
   107  			return ErrDenied
   108  		} else if params.IsCodeNotFoundOrCodeUnauthorized(err) {
   109  			return ErrDenied
   110  		}
   111  		return errors.Trace(err)
   112  	}
   113  	return nil
   114  }