github.com/cloud-green/juju@v0.0.0-20151002100041-a00291338d3d/api/uniter/service.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  	"github.com/juju/errors"
    10  	"github.com/juju/names"
    11  	"gopkg.in/juju/charm.v6-unstable"
    12  
    13  	"github.com/juju/juju/api/common"
    14  	"github.com/juju/juju/api/watcher"
    15  	"github.com/juju/juju/apiserver/params"
    16  )
    17  
    18  // This module implements a subset of the interface provided by
    19  // state.Service, as needed by the uniter API.
    20  
    21  // Service represents the state of a service.
    22  type Service struct {
    23  	st   *State
    24  	tag  names.ServiceTag
    25  	life params.Life
    26  }
    27  
    28  // Tag returns the service's tag.
    29  func (s *Service) Tag() names.ServiceTag {
    30  	return s.tag
    31  }
    32  
    33  // Name returns the service name.
    34  func (s *Service) Name() string {
    35  	return s.tag.Id()
    36  }
    37  
    38  // String returns the service as a string.
    39  func (s *Service) String() string {
    40  	return s.Name()
    41  }
    42  
    43  // Watch returns a watcher for observing changes to a service.
    44  func (s *Service) Watch() (watcher.NotifyWatcher, error) {
    45  	return common.Watch(s.st.facade, s.tag)
    46  }
    47  
    48  // WatchRelations returns a StringsWatcher that notifies of changes to
    49  // the lifecycles of relations involving s.
    50  func (s *Service) WatchRelations() (watcher.StringsWatcher, error) {
    51  	var results params.StringsWatchResults
    52  	args := params.Entities{
    53  		Entities: []params.Entity{{Tag: s.tag.String()}},
    54  	}
    55  	err := s.st.facade.FacadeCall("WatchServiceRelations", args, &results)
    56  	if err != nil {
    57  		return nil, err
    58  	}
    59  	if len(results.Results) != 1 {
    60  		return nil, fmt.Errorf("expected 1 result, got %d", len(results.Results))
    61  	}
    62  	result := results.Results[0]
    63  	if result.Error != nil {
    64  		return nil, result.Error
    65  	}
    66  	w := watcher.NewStringsWatcher(s.st.facade.RawAPICaller(), result)
    67  	return w, nil
    68  }
    69  
    70  // Life returns the service's current life state.
    71  func (s *Service) Life() params.Life {
    72  	return s.life
    73  }
    74  
    75  // Refresh refreshes the contents of the Service from the underlying
    76  // state.
    77  func (s *Service) Refresh() error {
    78  	life, err := s.st.life(s.tag)
    79  	if err != nil {
    80  		return err
    81  	}
    82  	s.life = life
    83  	return nil
    84  }
    85  
    86  // CharmURL returns the service's charm URL, and whether units should
    87  // upgrade to the charm with that URL even if they are in an error
    88  // state (force flag).
    89  //
    90  // NOTE: This differs from state.Service.CharmURL() by returning
    91  // an error instead as well, because it needs to make an API call.
    92  func (s *Service) CharmURL() (*charm.URL, bool, error) {
    93  	var results params.StringBoolResults
    94  	args := params.Entities{
    95  		Entities: []params.Entity{{Tag: s.tag.String()}},
    96  	}
    97  	err := s.st.facade.FacadeCall("CharmURL", args, &results)
    98  	if err != nil {
    99  		return nil, false, err
   100  	}
   101  	if len(results.Results) != 1 {
   102  		return nil, false, fmt.Errorf("expected 1 result, got %d", len(results.Results))
   103  	}
   104  	result := results.Results[0]
   105  	if result.Error != nil {
   106  		return nil, false, result.Error
   107  	}
   108  	if result.Result != "" {
   109  		curl, err := charm.ParseURL(result.Result)
   110  		if err != nil {
   111  			return nil, false, err
   112  		}
   113  		return curl, result.Ok, nil
   114  	}
   115  	return nil, false, fmt.Errorf("%q has no charm url set", s.tag)
   116  }
   117  
   118  // OwnerTag returns the service's owner user tag.
   119  func (s *Service) OwnerTag() (names.UserTag, error) {
   120  	if s.st.BestAPIVersion() > 0 {
   121  		return s.serviceOwnerTag()
   122  	}
   123  	return s.ownerTag()
   124  }
   125  
   126  func (s *Service) serviceOwnerTag() (names.UserTag, error) {
   127  	var invalidTag names.UserTag
   128  	var results params.StringResults
   129  	args := params.Entities{
   130  		Entities: []params.Entity{{Tag: s.tag.String()}},
   131  	}
   132  	err := s.st.facade.FacadeCall("ServiceOwner", args, &results)
   133  	if err != nil {
   134  		return invalidTag, err
   135  	}
   136  	if len(results.Results) != 1 {
   137  		return invalidTag, fmt.Errorf("expected 1 result, got %d", len(results.Results))
   138  	}
   139  	result := results.Results[0]
   140  	if result.Error != nil {
   141  		return invalidTag, result.Error
   142  	}
   143  	return names.ParseUserTag(result.Result)
   144  }
   145  
   146  func (s *Service) ownerTag() (names.UserTag, error) {
   147  	var invalidTag names.UserTag
   148  	var result params.StringResult
   149  	args := params.Entities{
   150  		Entities: []params.Entity{{Tag: s.tag.String()}},
   151  	}
   152  	err := s.st.facade.FacadeCall("GetOwnerTag", args, &result)
   153  	if err != nil {
   154  		return invalidTag, err
   155  	}
   156  	if result.Error != nil {
   157  		return invalidTag, result.Error
   158  	}
   159  	return names.ParseUserTag(result.Result)
   160  }
   161  
   162  // SetStatus sets the status of the service if the passed unitName,
   163  // corresponding to the calling unit, is of the leader.
   164  func (s *Service) SetStatus(unitName string, status params.Status, info string, data map[string]interface{}) error {
   165  	//TODO(perrito666) bump api version for this?
   166  	if s.st.facade.BestAPIVersion() < 2 {
   167  		return errors.NotImplementedf("SetStatus")
   168  	}
   169  	tag := names.NewUnitTag(unitName)
   170  	var result params.ErrorResults
   171  	args := params.SetStatus{
   172  		Entities: []params.EntityStatusArgs{
   173  			{
   174  				Tag:    tag.String(),
   175  				Status: status,
   176  				Info:   info,
   177  				Data:   data,
   178  			},
   179  		},
   180  	}
   181  	err := s.st.facade.FacadeCall("SetServiceStatus", args, &result)
   182  	if err != nil {
   183  		if params.IsCodeNotImplemented(err) {
   184  			return errors.NotImplementedf("SetServiceStatus")
   185  		}
   186  		return errors.Trace(err)
   187  	}
   188  	return result.OneError()
   189  }
   190  
   191  // ServiceStatus returns the status of the service if the passed unitName,
   192  // corresponding to the calling unit, is of the leader.
   193  func (s *Service) Status(unitName string) (params.ServiceStatusResult, error) {
   194  	tag := names.NewUnitTag(unitName)
   195  	var results params.ServiceStatusResults
   196  	args := params.Entities{
   197  		Entities: []params.Entity{
   198  			{
   199  				Tag: tag.String(),
   200  			},
   201  		},
   202  	}
   203  	err := s.st.facade.FacadeCall("ServiceStatus", args, &results)
   204  	if err != nil {
   205  		if params.IsCodeNotImplemented(err) {
   206  			return params.ServiceStatusResult{}, errors.NotImplementedf("ServiceStatus")
   207  		}
   208  		return params.ServiceStatusResult{}, errors.Trace(err)
   209  	}
   210  	result := results.Results[0]
   211  	if result.Error != nil {
   212  		return params.ServiceStatusResult{}, result.Error
   213  	}
   214  	return result, nil
   215  }
   216  
   217  // WatchLeadershipSettings returns a watcher which can be used to wait
   218  // for leadership settings changes to be made for the service.
   219  func (s *Service) WatchLeadershipSettings() (watcher.NotifyWatcher, error) {
   220  	return s.st.LeadershipSettings.WatchLeadershipSettings(s.tag.Id())
   221  }