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