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