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 }