launchpad.net/~rogpeppe/juju-core/500-errgo-fix@v0.0.0-20140213181702-000000002356/state/api/uniter/unit.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 "launchpad.net/errgo/errors" 9 10 "launchpad.net/juju-core/charm" 11 "launchpad.net/juju-core/names" 12 "launchpad.net/juju-core/state/api/base" 13 "launchpad.net/juju-core/state/api/params" 14 "launchpad.net/juju-core/state/api/watcher" 15 ) 16 17 // Unit represents a juju unit as seen by a uniter worker. 18 type Unit struct { 19 st *State 20 tag string 21 life params.Life 22 } 23 24 // Tag returns the unit's tag. 25 func (u *Unit) Tag() string { 26 return u.tag 27 } 28 29 // Name returns the name of the unit. 30 func (u *Unit) Name() string { 31 _, unitName, err := names.ParseTag(u.tag, names.UnitTagKind) 32 if err != nil { 33 panic(fmt.Sprintf("%q is not a valid unit tag", u.tag)) 34 } 35 return unitName 36 } 37 38 // String returns the unit as a string. 39 func (u *Unit) String() string { 40 return u.Name() 41 } 42 43 // Life returns the unit's lifecycle value. 44 func (u *Unit) Life() params.Life { 45 return u.life 46 } 47 48 // Refresh updates the cached local copy of the unit's data. 49 func (u *Unit) Refresh() error { 50 life, err := u.st.life(u.tag) 51 if err != nil { 52 return base.WrapError(err) 53 } 54 u.life = life 55 return nil 56 } 57 58 // SetStatus sets the status of the unit. 59 func (u *Unit) SetStatus(status params.Status, info string, data params.StatusData) error { 60 var result params.ErrorResults 61 args := params.SetStatus{ 62 Entities: []params.SetEntityStatus{ 63 {Tag: u.tag, Status: status, Info: info, Data: data}, 64 }, 65 } 66 err := u.st.caller.Call("Uniter", "", "SetStatus", args, &result) 67 if err != nil { 68 return base.WrapError(err) 69 } 70 return result.OneError() 71 } 72 73 // EnsureDead sets the unit lifecycle to Dead if it is Alive or 74 // Dying. It does nothing otherwise. 75 func (u *Unit) EnsureDead() error { 76 var result params.ErrorResults 77 args := params.Entities{ 78 Entities: []params.Entity{{Tag: u.tag}}, 79 } 80 err := u.st.caller.Call("Uniter", "", "EnsureDead", args, &result) 81 if err != nil { 82 return base.WrapError(err) 83 } 84 return result.OneError() 85 } 86 87 // Watch returns a watcher for observing changes to the unit. 88 func (u *Unit) Watch() (watcher.NotifyWatcher, error) { 89 var results params.NotifyWatchResults 90 args := params.Entities{ 91 Entities: []params.Entity{{Tag: u.tag}}, 92 } 93 err := u.st.caller.Call("Uniter", "", "Watch", args, &results) 94 if err != nil { 95 return nil, base.WrapError(err) 96 } 97 if len(results.Results) != 1 { 98 return nil, errors.Newf("expected one result, got %d", len(results.Results)) 99 } 100 result := results.Results[0] 101 if result.Error != nil { 102 return nil, result.Error 103 } 104 w := watcher.NewNotifyWatcher(u.st.caller, result) 105 return w, nil 106 } 107 108 // Service returns the service. 109 func (u *Unit) Service() (*Service, error) { 110 serviceTag := names.ServiceTag(u.ServiceName()) 111 service := &Service{ 112 st: u.st, 113 tag: serviceTag, 114 } 115 // Call Refresh() immediately to get the up-to-date 116 // life and other needed locally cached fields. 117 err := service.Refresh() 118 if err != nil { 119 return nil, base.WrapError(err) 120 } 121 return service, nil 122 } 123 124 // ConfigSettings returns the complete set of service charm config settings 125 // available to the unit. Unset values will be replaced with the default 126 // value for the associated option, and may thus be nil when no default is 127 // specified. 128 func (u *Unit) ConfigSettings() (charm.Settings, error) { 129 var results params.ConfigSettingsResults 130 args := params.Entities{ 131 Entities: []params.Entity{{Tag: u.tag}}, 132 } 133 err := u.st.caller.Call("Uniter", "", "ConfigSettings", args, &results) 134 if err != nil { 135 return nil, base.WrapError(err) 136 } 137 if len(results.Results) != 1 { 138 return nil, errors.Newf("expected one result, got %d", len(results.Results)) 139 } 140 result := results.Results[0] 141 if result.Error != nil { 142 return nil, result.Error 143 } 144 return charm.Settings(result.Settings), nil 145 } 146 147 // ServiceName returns the service name. 148 func (u *Unit) ServiceName() string { 149 return names.UnitService(u.Name()) 150 } 151 152 // ServiceTag returns the service tag. 153 func (u *Unit) ServiceTag() string { 154 return names.ServiceTag(u.ServiceName()) 155 } 156 157 // Destroy, when called on a Alive unit, advances its lifecycle as far as 158 // possible; it otherwise has no effect. In most situations, the unit's 159 // life is just set to Dying; but if a principal unit that is not assigned 160 // to a provisioned machine is Destroyed, it will be removed from state 161 // directly. 162 func (u *Unit) Destroy() error { 163 var result params.ErrorResults 164 args := params.Entities{ 165 Entities: []params.Entity{{Tag: u.tag}}, 166 } 167 err := u.st.caller.Call("Uniter", "", "Destroy", args, &result) 168 if err != nil { 169 return base.WrapError(err) 170 } 171 return result.OneError() 172 } 173 174 // DestroyAllSubordinates destroys all subordinates of the unit. 175 func (u *Unit) DestroyAllSubordinates() error { 176 var result params.ErrorResults 177 args := params.Entities{ 178 Entities: []params.Entity{{Tag: u.tag}}, 179 } 180 err := u.st.caller.Call("Uniter", "", "DestroyAllSubordinates", args, &result) 181 if err != nil { 182 return base.WrapError(err) 183 } 184 return result.OneError() 185 } 186 187 // Resolved returns the resolved mode for the unit. 188 // 189 // NOTE: This differs from state.Unit.Resolved() by returning an 190 // error as well, because it needs to make an API call 191 func (u *Unit) Resolved() (params.ResolvedMode, error) { 192 var results params.ResolvedModeResults 193 args := params.Entities{ 194 Entities: []params.Entity{{Tag: u.tag}}, 195 } 196 err := u.st.caller.Call("Uniter", "", "Resolved", args, &results) 197 if err != nil { 198 return "", base.WrapError(err) 199 } 200 if len(results.Results) != 1 { 201 return "", errors.Newf("expected one result, got %d", len(results.Results)) 202 } 203 result := results.Results[0] 204 if result.Error != nil { 205 return "", result.Error 206 } 207 return result.Mode, nil 208 } 209 210 // IsPrincipal returns whether the unit is deployed in its own container, 211 // and can therefore have subordinate services deployed alongside it. 212 // 213 // NOTE: This differs from state.Unit.IsPrincipal() by returning an 214 // error as well, because it needs to make an API call. 215 func (u *Unit) IsPrincipal() (bool, error) { 216 var results params.StringBoolResults 217 args := params.Entities{ 218 Entities: []params.Entity{{Tag: u.tag}}, 219 } 220 err := u.st.caller.Call("Uniter", "", "GetPrincipal", args, &results) 221 if err != nil { 222 return false, base.WrapError(err) 223 } 224 if len(results.Results) != 1 { 225 return false, errors.Newf("expected one result, got %d", len(results.Results)) 226 } 227 result := results.Results[0] 228 if result.Error != nil { 229 return false, result.Error 230 } 231 // GetPrincipal returns false when the unit is subordinate. 232 return !result.Ok, nil 233 } 234 235 // HasSubordinates returns the tags of any subordinate units. 236 func (u *Unit) HasSubordinates() (bool, error) { 237 var results params.BoolResults 238 args := params.Entities{ 239 Entities: []params.Entity{{Tag: u.tag}}, 240 } 241 err := u.st.caller.Call("Uniter", "", "HasSubordinates", args, &results) 242 if err != nil { 243 return false, base.WrapError(err) 244 } 245 if len(results.Results) != 1 { 246 return false, errors.Newf("expected one result, got %d", len(results.Results)) 247 } 248 result := results.Results[0] 249 if result.Error != nil { 250 return false, result.Error 251 } 252 return result.Result, nil 253 } 254 255 // PublicAddress returns the public address of the unit and whether it 256 // is valid. 257 // 258 // NOTE: This differs from state.Unit.PublicAddres() by returning 259 // an error instead of a bool, because it needs to make an API call. 260 // 261 // TODO(dimitern): We might be able to drop this, once we have machine 262 // addresses implemented fully. See also LP bug 1221798. 263 func (u *Unit) PublicAddress() (string, error) { 264 var results params.StringResults 265 args := params.Entities{ 266 Entities: []params.Entity{{Tag: u.tag}}, 267 } 268 err := u.st.caller.Call("Uniter", "", "PublicAddress", args, &results) 269 if err != nil { 270 return "", base.WrapError(err) 271 } 272 if len(results.Results) != 1 { 273 return "", errors.Newf("expected one result, got %d", len(results.Results)) 274 } 275 result := results.Results[0] 276 if result.Error != nil { 277 return "", result.Error 278 } 279 return result.Result, nil 280 } 281 282 // SetPublicAddress sets the public address of the unit. 283 // 284 // TODO(dimitern): We might be able to drop this, once we have machine 285 // addresses implemented fully. See also LP bug 1221798. 286 func (u *Unit) SetPublicAddress(address string) error { 287 var result params.ErrorResults 288 args := params.SetEntityAddresses{ 289 Entities: []params.SetEntityAddress{ 290 {Tag: u.tag, Address: address}, 291 }, 292 } 293 err := u.st.caller.Call("Uniter", "", "SetPublicAddress", args, &result) 294 if err != nil { 295 return base.WrapError(err) 296 } 297 return result.OneError() 298 } 299 300 // PrivateAddress returns the private address of the unit and whether 301 // it is valid. 302 // 303 // NOTE: This differs from state.Unit.PrivateAddress() by returning 304 // an error instead of a bool, because it needs to make an API call. 305 // 306 // TODO(dimitern): We might be able to drop this, once we have machine 307 // addresses implemented fully. See also LP bug 1221798. 308 func (u *Unit) PrivateAddress() (string, error) { 309 var results params.StringResults 310 args := params.Entities{ 311 Entities: []params.Entity{{Tag: u.tag}}, 312 } 313 err := u.st.caller.Call("Uniter", "", "PrivateAddress", args, &results) 314 if err != nil { 315 return "", base.WrapError(err) 316 } 317 if len(results.Results) != 1 { 318 return "", errors.Newf("expected one result, got %d", len(results.Results)) 319 } 320 result := results.Results[0] 321 if result.Error != nil { 322 return "", result.Error 323 } 324 return result.Result, nil 325 } 326 327 // SetPrivateAddress sets the private address of the unit. 328 // 329 // TODO(dimitern): We might be able to drop this, once we have machine 330 // addresses implemented fully. See also LP bug 1221798. 331 func (u *Unit) SetPrivateAddress(address string) error { 332 var result params.ErrorResults 333 args := params.SetEntityAddresses{ 334 Entities: []params.SetEntityAddress{ 335 {Tag: u.tag, Address: address}, 336 }, 337 } 338 err := u.st.caller.Call("Uniter", "", "SetPrivateAddress", args, &result) 339 if err != nil { 340 return base.WrapError(err) 341 } 342 return result.OneError() 343 } 344 345 // OpenPort sets the policy of the port with protocol and number to be 346 // opened. 347 // 348 // TODO: We should really be opening and closing ports on machines, 349 // rather than units. 350 func (u *Unit) OpenPort(protocol string, number int) error { 351 var result params.ErrorResults 352 args := params.EntitiesPorts{ 353 Entities: []params.EntityPort{ 354 {Tag: u.tag, Protocol: protocol, Port: number}, 355 }, 356 } 357 err := u.st.caller.Call("Uniter", "", "OpenPort", args, &result) 358 if err != nil { 359 return base.WrapError(err) 360 } 361 return result.OneError() 362 } 363 364 // ClosePort sets the policy of the port with protocol and number to 365 // be closed. 366 // 367 // TODO: We should really be opening and closing ports on machines, 368 // rather than units. 369 func (u *Unit) ClosePort(protocol string, number int) error { 370 var result params.ErrorResults 371 args := params.EntitiesPorts{ 372 Entities: []params.EntityPort{ 373 {Tag: u.tag, Protocol: protocol, Port: number}, 374 }, 375 } 376 err := u.st.caller.Call("Uniter", "", "ClosePort", args, &result) 377 if err != nil { 378 return base.WrapError(err) 379 } 380 return result.OneError() 381 } 382 383 var ErrNoCharmURLSet = errors.New("unit has no charm url set") 384 385 // CharmURL returns the charm URL this unit is currently using. 386 // 387 // NOTE: This differs from state.Unit.CharmURL() by returning 388 // an error instead of a bool, because it needs to make an API call. 389 func (u *Unit) CharmURL() (*charm.URL, error) { 390 var results params.StringBoolResults 391 args := params.Entities{ 392 Entities: []params.Entity{{Tag: u.tag}}, 393 } 394 err := u.st.caller.Call("Uniter", "", "CharmURL", args, &results) 395 if err != nil { 396 return nil, base.WrapError(err) 397 } 398 if len(results.Results) != 1 { 399 return nil, errors.Newf("expected one result, got %d", len(results.Results)) 400 } 401 result := results.Results[0] 402 if result.Error != nil { 403 return nil, result.Error 404 } 405 if result.Result != "" { 406 curl, err := charm.ParseURL(result.Result) 407 if err != nil { 408 return nil, base.WrapError(err) 409 } 410 return curl, nil 411 } 412 return nil, ErrNoCharmURLSet 413 } 414 415 // SetCharmURL marks the unit as currently using the supplied charm URL. 416 // An error will be returned if the unit is dead, or the charm URL not known. 417 func (u *Unit) SetCharmURL(curl *charm.URL) error { 418 if curl == nil { 419 return errors.Newf("charm URL cannot be nil") 420 } 421 var result params.ErrorResults 422 args := params.EntitiesCharmURL{ 423 Entities: []params.EntityCharmURL{ 424 {Tag: u.tag, CharmURL: curl.String()}, 425 }, 426 } 427 err := u.st.caller.Call("Uniter", "", "SetCharmURL", args, &result) 428 if err != nil { 429 return base.WrapError(err) 430 } 431 return result.OneError() 432 } 433 434 // ClearResolved removes any resolved setting on the unit. 435 func (u *Unit) ClearResolved() error { 436 var result params.ErrorResults 437 args := params.Entities{ 438 Entities: []params.Entity{{Tag: u.tag}}, 439 } 440 err := u.st.caller.Call("Uniter", "", "ClearResolved", args, &result) 441 if err != nil { 442 return base.WrapError(err) 443 } 444 return result.OneError() 445 } 446 447 // WatchConfigSettings returns a watcher for observing changes to the 448 // unit's service configuration settings. The unit must have a charm URL 449 // set before this method is called, and the returned watcher will be 450 // valid only while the unit's charm URL is not changed. 451 func (u *Unit) WatchConfigSettings() (watcher.NotifyWatcher, error) { 452 var results params.NotifyWatchResults 453 args := params.Entities{ 454 Entities: []params.Entity{{Tag: u.tag}}, 455 } 456 err := u.st.caller.Call("Uniter", "", "WatchConfigSettings", args, &results) 457 if err != nil { 458 return nil, base.WrapError(err) 459 } 460 if len(results.Results) != 1 { 461 return nil, errors.Newf("expected one result, got %d", len(results.Results)) 462 } 463 result := results.Results[0] 464 if result.Error != nil { 465 return nil, result.Error 466 } 467 w := watcher.NewNotifyWatcher(u.st.caller, result) 468 return w, nil 469 }