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 }