Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(809)

Delta Between Two Patch Sets: state/unit.go

Issue 77820044: Add EnvironCapability to state.Policy
Left Patch Set: Add EnvironCapability to state.Policy Created 10 years ago
Right Patch Set: Add EnvironCapability to state.Policy Created 9 years, 12 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
« no previous file with change/comment | « state/policy.go ('k') | no next file » | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
1 // Copyright 2012, 2013 Canonical Ltd. 1 // Copyright 2012, 2013 Canonical Ltd.
2 // Licensed under the AGPLv3, see LICENCE file for details. 2 // Licensed under the AGPLv3, see LICENCE file for details.
3 3
4 package state 4 package state
5 5
6 import ( 6 import (
7 stderrors "errors" 7 stderrors "errors"
8 "fmt" 8 "fmt"
9 "time" 9 "time"
10 10
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after
110 // value for the associated option, and may thus be nil when no default is 110 // value for the associated option, and may thus be nil when no default is
111 // specified. 111 // specified.
112 func (u *Unit) ConfigSettings() (charm.Settings, error) { 112 func (u *Unit) ConfigSettings() (charm.Settings, error) {
113 if u.doc.CharmURL == nil { 113 if u.doc.CharmURL == nil {
114 return nil, fmt.Errorf("unit charm not set") 114 return nil, fmt.Errorf("unit charm not set")
115 } 115 }
116 settings, err := readSettings(u.st, serviceSettingsKey(u.doc.Service, u. doc.CharmURL)) 116 settings, err := readSettings(u.st, serviceSettingsKey(u.doc.Service, u. doc.CharmURL))
117 if err != nil { 117 if err != nil {
118 return nil, err 118 return nil, err
119 } 119 }
120 » charm, err := u.st.Charm(u.doc.CharmURL) 120 » chrm, err := u.st.Charm(u.doc.CharmURL)
121 if err != nil { 121 if err != nil {
122 return nil, err 122 return nil, err
123 } 123 }
124 » result := charm.Config().DefaultSettings() 124 » result := chrm.Config().DefaultSettings()
125 for name, value := range settings.Map() { 125 for name, value := range settings.Map() {
126 result[name] = value 126 result[name] = value
127 } 127 }
128 return result, nil 128 return result, nil
129 } 129 }
130 130
131 // ServiceName returns the service name. 131 // ServiceName returns the service name.
132 func (u *Unit) ServiceName() string { 132 func (u *Unit) ServiceName() string {
133 return u.doc.Service 133 return u.doc.Service
134 } 134 }
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
178 func (u *Unit) SetAgentVersion(v version.Binary) (err error) { 178 func (u *Unit) SetAgentVersion(v version.Binary) (err error) {
179 defer utils.ErrorContextf(&err, "cannot set agent version for unit %q", u) 179 defer utils.ErrorContextf(&err, "cannot set agent version for unit %q", u)
180 if err = checkVersionValidity(v); err != nil { 180 if err = checkVersionValidity(v); err != nil {
181 return err 181 return err
182 } 182 }
183 tools := &tools.Tools{Version: v} 183 tools := &tools.Tools{Version: v}
184 ops := []txn.Op{{ 184 ops := []txn.Op{{
185 C: u.st.units.Name, 185 C: u.st.units.Name,
186 Id: u.doc.Name, 186 Id: u.doc.Name,
187 Assert: notDeadDoc, 187 Assert: notDeadDoc,
188 » » Update: D{{"$set", D{{"tools", tools}}}}, 188 » » Update: bson.D{{"$set", bson.D{{"tools", tools}}}},
189 }} 189 }}
190 if err := u.st.runTransaction(ops); err != nil { 190 if err := u.st.runTransaction(ops); err != nil {
191 return onAbort(err, errDead) 191 return onAbort(err, errDead)
192 } 192 }
193 u.doc.Tools = tools 193 u.doc.Tools = tools
194 return nil 194 return nil
195 } 195 }
196 196
197 // SetMongoPassword sets the password the agent responsible for the unit 197 // SetMongoPassword sets the password the agent responsible for the unit
198 // should use to communicate with the state servers. Previous passwords 198 // should use to communicate with the state servers. Previous passwords
(...skipping 11 matching lines...) Expand all
210 } 210 }
211 211
212 // setPasswordHash sets the underlying password hash in the database directly 212 // setPasswordHash sets the underlying password hash in the database directly
213 // to the value supplied. This is split out from SetPassword to allow direct 213 // to the value supplied. This is split out from SetPassword to allow direct
214 // manipulation in tests (to check for backwards compatibility). 214 // manipulation in tests (to check for backwards compatibility).
215 func (u *Unit) setPasswordHash(passwordHash string) error { 215 func (u *Unit) setPasswordHash(passwordHash string) error {
216 ops := []txn.Op{{ 216 ops := []txn.Op{{
217 C: u.st.units.Name, 217 C: u.st.units.Name,
218 Id: u.doc.Name, 218 Id: u.doc.Name,
219 Assert: notDeadDoc, 219 Assert: notDeadDoc,
220 » » Update: D{{"$set", D{{"passwordhash", passwordHash}}}}, 220 » » Update: bson.D{{"$set", bson.D{{"passwordhash", passwordHash}}}} ,
221 }} 221 }}
222 err := u.st.runTransaction(ops) 222 err := u.st.runTransaction(ops)
223 if err != nil { 223 if err != nil {
224 return fmt.Errorf("cannot set password of unit %q: %v", u, onAbo rt(err, errDead)) 224 return fmt.Errorf("cannot set password of unit %q: %v", u, onAbo rt(err, errDead))
225 } 225 }
226 u.doc.PasswordHash = passwordHash 226 u.doc.PasswordHash = passwordHash
227 return nil 227 return nil
228 } 228 }
229 229
230 // Return the underlying PasswordHash stored in the database. Used by the test 230 // Return the underlying PasswordHash stored in the database. Used by the test
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after
316 // considered, on the basis that (1) they were created by active princip als 316 // considered, on the basis that (1) they were created by active princip als
317 // and can be expected to be deployed pretty soon afterwards, so we don' t 317 // and can be expected to be deployed pretty soon afterwards, so we don' t
318 // lose much time and (2) by maintaining this restriction, I can reduce 318 // lose much time and (2) by maintaining this restriction, I can reduce
319 // the number of tests that have to change and defer that improvement to 319 // the number of tests that have to change and defer that improvement to
320 // its own CL. 320 // its own CL.
321 minUnitsOp := minUnitsTriggerOp(u.st, u.ServiceName()) 321 minUnitsOp := minUnitsTriggerOp(u.st, u.ServiceName())
322 setDyingOps := []txn.Op{{ 322 setDyingOps := []txn.Op{{
323 C: u.st.units.Name, 323 C: u.st.units.Name,
324 Id: u.doc.Name, 324 Id: u.doc.Name,
325 Assert: isAliveDoc, 325 Assert: isAliveDoc,
326 » » Update: D{{"$set", D{{"life", Dying}}}}, 326 » » Update: bson.D{{"$set", bson.D{{"life", Dying}}}},
327 }, minUnitsOp} 327 }, minUnitsOp}
328 if u.doc.Principal != "" { 328 if u.doc.Principal != "" {
329 return setDyingOps, nil 329 return setDyingOps, nil
330 } else if len(u.doc.Subordinates) != 0 { 330 } else if len(u.doc.Subordinates) != 0 {
331 return setDyingOps, nil 331 return setDyingOps, nil
332 } 332 }
333 333
334 sdocId := u.globalKey() 334 sdocId := u.globalKey()
335 sdoc, err := getStatus(u.st, sdocId) 335 sdoc, err := getStatus(u.st, sdocId)
336 if errors.IsNotFoundError(err) { 336 if errors.IsNotFoundError(err) {
337 return nil, errAlreadyDying 337 return nil, errAlreadyDying
338 } else if err != nil { 338 } else if err != nil {
339 return nil, err 339 return nil, err
340 } 340 }
341 if sdoc.Status != params.StatusPending { 341 if sdoc.Status != params.StatusPending {
342 return setDyingOps, nil 342 return setDyingOps, nil
343 } 343 }
344 ops := []txn.Op{{ 344 ops := []txn.Op{{
345 C: u.st.statuses.Name, 345 C: u.st.statuses.Name,
346 Id: sdocId, 346 Id: sdocId,
347 » » Assert: D{{"status", params.StatusPending}}, 347 » » Assert: bson.D{{"status", params.StatusPending}},
348 }, minUnitsOp} 348 }, minUnitsOp}
349 removeAsserts := append(isAliveDoc, unitHasNoSubordinates...) 349 removeAsserts := append(isAliveDoc, unitHasNoSubordinates...)
350 removeOps, err := u.removeOps(removeAsserts) 350 removeOps, err := u.removeOps(removeAsserts)
351 if err == errAlreadyRemoved { 351 if err == errAlreadyRemoved {
352 return nil, errAlreadyDying 352 return nil, errAlreadyDying
353 } else if err != nil { 353 } else if err != nil {
354 return nil, err 354 return nil, err
355 } 355 }
356 return append(ops, removeOps...), nil 356 return append(ops, removeOps...), nil
357 } 357 }
358 358
359 var errAlreadyRemoved = stderrors.New("entity has already been removed") 359 var errAlreadyRemoved = stderrors.New("entity has already been removed")
360 360
361 // removeOps returns the operations necessary to remove the unit, assuming 361 // removeOps returns the operations necessary to remove the unit, assuming
362 // the supplied asserts apply to the unit document. 362 // the supplied asserts apply to the unit document.
363 func (u *Unit) removeOps(asserts D) ([]txn.Op, error) { 363 func (u *Unit) removeOps(asserts bson.D) ([]txn.Op, error) {
364 svc, err := u.st.Service(u.doc.Service) 364 svc, err := u.st.Service(u.doc.Service)
365 if errors.IsNotFoundError(err) { 365 if errors.IsNotFoundError(err) {
366 // If the service has been removed, the unit must already have b een. 366 // If the service has been removed, the unit must already have b een.
367 return nil, errAlreadyRemoved 367 return nil, errAlreadyRemoved
368 } else if err != nil { 368 } else if err != nil {
369 return nil, err 369 return nil, err
370 } 370 }
371 return svc.removeUnitOps(u, asserts) 371 return svc.removeUnitOps(u, asserts)
372 } 372 }
373 373
374 var ErrUnitHasSubordinates = stderrors.New("unit has subordinates") 374 var ErrUnitHasSubordinates = stderrors.New("unit has subordinates")
375 375
376 var unitHasNoSubordinates = D{{ 376 var unitHasNoSubordinates = bson.D{{
377 » "$or", []D{ 377 » "$or", []bson.D{
378 » » {{"subordinates", D{{"$size", 0}}}}, 378 » » {{"subordinates", bson.D{{"$size", 0}}}},
379 » » {{"subordinates", D{{"$exists", false}}}}, 379 » » {{"subordinates", bson.D{{"$exists", false}}}},
380 }, 380 },
381 }} 381 }}
382 382
383 // EnsureDead sets the unit lifecycle to Dead if it is Alive or Dying. 383 // EnsureDead sets the unit lifecycle to Dead if it is Alive or Dying.
384 // It does nothing otherwise. If the unit has subordinates, it will 384 // It does nothing otherwise. If the unit has subordinates, it will
385 // return ErrUnitHasSubordinates. 385 // return ErrUnitHasSubordinates.
386 func (u *Unit) EnsureDead() (err error) { 386 func (u *Unit) EnsureDead() (err error) {
387 if u.doc.Life == Dead { 387 if u.doc.Life == Dead {
388 return nil 388 return nil
389 } 389 }
390 defer func() { 390 defer func() {
391 if err == nil { 391 if err == nil {
392 u.doc.Life = Dead 392 u.doc.Life = Dead
393 } 393 }
394 }() 394 }()
395 ops := []txn.Op{{ 395 ops := []txn.Op{{
396 C: u.st.units.Name, 396 C: u.st.units.Name,
397 Id: u.doc.Name, 397 Id: u.doc.Name,
398 Assert: append(notDeadDoc, unitHasNoSubordinates...), 398 Assert: append(notDeadDoc, unitHasNoSubordinates...),
399 » » Update: D{{"$set", D{{"life", Dead}}}}, 399 » » Update: bson.D{{"$set", bson.D{{"life", Dead}}}},
400 }} 400 }}
401 if err := u.st.runTransaction(ops); err != txn.ErrAborted { 401 if err := u.st.runTransaction(ops); err != txn.ErrAborted {
402 return err 402 return err
403 } 403 }
404 if notDead, err := isNotDead(u.st.units, u.doc.Name); err != nil { 404 if notDead, err := isNotDead(u.st.units, u.doc.Name); err != nil {
405 return err 405 return err
406 } else if !notDead { 406 } else if !notDead {
407 return nil 407 return nil
408 } 408 }
409 return ErrUnitHasSubordinates 409 return ErrUnitHasSubordinates
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
491 } 491 }
492 492
493 // PrincipalName returns the name of the unit's principal. 493 // PrincipalName returns the name of the unit's principal.
494 // If the unit is not a subordinate, false is returned. 494 // If the unit is not a subordinate, false is returned.
495 func (u *Unit) PrincipalName() (string, bool) { 495 func (u *Unit) PrincipalName() (string, bool) {
496 return u.doc.Principal, u.doc.Principal != "" 496 return u.doc.Principal, u.doc.Principal != ""
497 } 497 }
498 498
499 // addressesOfMachine returns Addresses of the related machine if present. 499 // addressesOfMachine returns Addresses of the related machine if present.
500 func (u *Unit) addressesOfMachine() []instance.Address { 500 func (u *Unit) addressesOfMachine() []instance.Address {
501 » id := u.doc.MachineId 501 » if id, err := u.AssignedMachineId(); err != nil {
502 » if id != "" { 502 » » unitLogger.Errorf("unit %v cannot get assigned machine: %v", u, err)
503 » » return nil
504 » } else {
503 m, err := u.st.Machine(id) 505 m, err := u.st.Machine(id)
504 if err == nil { 506 if err == nil {
505 return m.Addresses() 507 return m.Addresses()
506 } 508 }
507 unitLogger.Errorf("unit %v misses machine id %v", u, id) 509 unitLogger.Errorf("unit %v misses machine id %v", u, id)
508 } 510 }
509 return nil 511 return nil
510 } 512 }
511 513
512 // PublicAddress returns the public address of the unit and whether it is valid. 514 // PublicAddress returns the public address of the unit and whether it is valid.
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
555 } 557 }
556 558
557 // SetStatus sets the status of the unit. The optional values 559 // SetStatus sets the status of the unit. The optional values
558 // allow to pass additional helpful status data. 560 // allow to pass additional helpful status data.
559 func (u *Unit) SetStatus(status params.Status, info string, data params.StatusDa ta) error { 561 func (u *Unit) SetStatus(status params.Status, info string, data params.StatusDa ta) error {
560 doc := statusDoc{ 562 doc := statusDoc{
561 Status: status, 563 Status: status,
562 StatusInfo: info, 564 StatusInfo: info,
563 StatusData: data, 565 StatusData: data,
564 } 566 }
565 » if err := doc.validateSet(); err != nil { 567 » if err := doc.validateSet(false); err != nil {
566 return err 568 return err
567 } 569 }
568 ops := []txn.Op{{ 570 ops := []txn.Op{{
569 C: u.st.units.Name, 571 C: u.st.units.Name,
570 Id: u.doc.Name, 572 Id: u.doc.Name,
571 Assert: notDeadDoc, 573 Assert: notDeadDoc,
572 }, 574 },
573 updateStatusOp(u.st, u.globalKey(), doc), 575 updateStatusOp(u.st, u.globalKey(), doc),
574 } 576 }
575 err := u.st.runTransaction(ops) 577 err := u.st.runTransaction(ops)
576 if err != nil { 578 if err != nil {
577 return fmt.Errorf("cannot set status of unit %q: %v", u, onAbort (err, errDead)) 579 return fmt.Errorf("cannot set status of unit %q: %v", u, onAbort (err, errDead))
578 } 580 }
579 return nil 581 return nil
580 } 582 }
581 583
582 // OpenPort sets the policy of the port with protocol and number to be opened. 584 // OpenPort sets the policy of the port with protocol and number to be opened.
583 func (u *Unit) OpenPort(protocol string, number int) (err error) { 585 func (u *Unit) OpenPort(protocol string, number int) (err error) {
584 port := instance.Port{Protocol: protocol, Number: number} 586 port := instance.Port{Protocol: protocol, Number: number}
585 defer utils.ErrorContextf(&err, "cannot open port %v for unit %q", port, u) 587 defer utils.ErrorContextf(&err, "cannot open port %v for unit %q", port, u)
586 ops := []txn.Op{{ 588 ops := []txn.Op{{
587 C: u.st.units.Name, 589 C: u.st.units.Name,
588 Id: u.doc.Name, 590 Id: u.doc.Name,
589 Assert: notDeadDoc, 591 Assert: notDeadDoc,
590 » » Update: D{{"$addToSet", D{{"ports", port}}}}, 592 » » Update: bson.D{{"$addToSet", bson.D{{"ports", port}}}},
591 }} 593 }}
592 err = u.st.runTransaction(ops) 594 err = u.st.runTransaction(ops)
593 if err != nil { 595 if err != nil {
594 return onAbort(err, errDead) 596 return onAbort(err, errDead)
595 } 597 }
596 found := false 598 found := false
597 for _, p := range u.doc.Ports { 599 for _, p := range u.doc.Ports {
598 if p == port { 600 if p == port {
599 break 601 break
600 } 602 }
601 } 603 }
602 if !found { 604 if !found {
603 u.doc.Ports = append(u.doc.Ports, port) 605 u.doc.Ports = append(u.doc.Ports, port)
604 } 606 }
605 return nil 607 return nil
606 } 608 }
607 609
608 // ClosePort sets the policy of the port with protocol and number to be closed. 610 // ClosePort sets the policy of the port with protocol and number to be closed.
609 func (u *Unit) ClosePort(protocol string, number int) (err error) { 611 func (u *Unit) ClosePort(protocol string, number int) (err error) {
610 port := instance.Port{Protocol: protocol, Number: number} 612 port := instance.Port{Protocol: protocol, Number: number}
611 defer utils.ErrorContextf(&err, "cannot close port %v for unit %q", port , u) 613 defer utils.ErrorContextf(&err, "cannot close port %v for unit %q", port , u)
612 ops := []txn.Op{{ 614 ops := []txn.Op{{
613 C: u.st.units.Name, 615 C: u.st.units.Name,
614 Id: u.doc.Name, 616 Id: u.doc.Name,
615 Assert: notDeadDoc, 617 Assert: notDeadDoc,
616 » » Update: D{{"$pull", D{{"ports", port}}}}, 618 » » Update: bson.D{{"$pull", bson.D{{"ports", port}}}},
617 }} 619 }}
618 err = u.st.runTransaction(ops) 620 err = u.st.runTransaction(ops)
619 if err != nil { 621 if err != nil {
620 return onAbort(err, errDead) 622 return onAbort(err, errDead)
621 } 623 }
622 newPorts := make([]instance.Port, 0, len(u.doc.Ports)) 624 newPorts := make([]instance.Port, 0, len(u.doc.Ports))
623 for _, p := range u.doc.Ports { 625 for _, p := range u.doc.Ports {
624 if p != port { 626 if p != port {
625 newPorts = append(newPorts, p) 627 newPorts = append(newPorts, p)
626 } 628 }
(...skipping 27 matching lines...) Expand all
654 }() 656 }()
655 if curl == nil { 657 if curl == nil {
656 return fmt.Errorf("cannot set nil charm url") 658 return fmt.Errorf("cannot set nil charm url")
657 } 659 }
658 for i := 0; i < 5; i++ { 660 for i := 0; i < 5; i++ {
659 if notDead, err := isNotDead(u.st.units, u.doc.Name); err != nil { 661 if notDead, err := isNotDead(u.st.units, u.doc.Name); err != nil {
660 return err 662 return err
661 } else if !notDead { 663 } else if !notDead {
662 return fmt.Errorf("unit %q is dead", u) 664 return fmt.Errorf("unit %q is dead", u)
663 } 665 }
664 » » sel := D{{"_id", u.doc.Name}, {"charmurl", curl}} 666 » » sel := bson.D{{"_id", u.doc.Name}, {"charmurl", curl}}
665 if count, err := u.st.units.Find(sel).Count(); err != nil { 667 if count, err := u.st.units.Find(sel).Count(); err != nil {
666 return err 668 return err
667 } else if count == 1 { 669 } else if count == 1 {
668 // Already set 670 // Already set
669 return nil 671 return nil
670 } 672 }
671 if count, err := u.st.charms.FindId(curl).Count(); err != nil { 673 if count, err := u.st.charms.FindId(curl).Count(); err != nil {
672 return err 674 return err
673 } else if count < 1 { 675 } else if count < 1 {
674 return fmt.Errorf("unknown charm url %q", curl) 676 return fmt.Errorf("unknown charm url %q", curl)
675 } 677 }
676 678
677 // Add a reference to the service settings for the new charm. 679 // Add a reference to the service settings for the new charm.
678 incOp, err := settingsIncRefOp(u.st, u.doc.Service, curl, false) 680 incOp, err := settingsIncRefOp(u.st, u.doc.Service, curl, false)
679 if err != nil { 681 if err != nil {
680 return err 682 return err
681 } 683 }
682 684
683 // Set the new charm URL. 685 // Set the new charm URL.
684 » » differentCharm := D{{"charmurl", D{{"$ne", curl}}}} 686 » » differentCharm := bson.D{{"charmurl", bson.D{{"$ne", curl}}}}
685 ops := []txn.Op{ 687 ops := []txn.Op{
686 incOp, 688 incOp,
687 { 689 {
688 C: u.st.units.Name, 690 C: u.st.units.Name,
689 Id: u.doc.Name, 691 Id: u.doc.Name,
690 Assert: append(notDeadDoc, differentCharm...), 692 Assert: append(notDeadDoc, differentCharm...),
691 » » » » Update: D{{"$set", D{{"charmurl", curl}}}}, 693 » » » » Update: bson.D{{"$set", bson.D{{"charmurl", curl }}}},
692 }} 694 }}
693 if u.doc.CharmURL != nil { 695 if u.doc.CharmURL != nil {
694 // Drop the reference to the old charm. 696 // Drop the reference to the old charm.
695 decOps, err := settingsDecRefOps(u.st, u.doc.Service, u. doc.CharmURL) 697 decOps, err := settingsDecRefOps(u.st, u.doc.Service, u. doc.CharmURL)
696 if err != nil { 698 if err != nil {
697 return err 699 return err
698 } 700 }
699 ops = append(ops, decOps...) 701 ops = append(ops, decOps...)
700 } 702 }
701 if err := u.st.runTransaction(ops); err != txn.ErrAborted { 703 if err := u.st.runTransaction(ops); err != txn.ErrAborted {
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
764 766
765 // AssignedMachineId returns the id of the assigned machine. 767 // AssignedMachineId returns the id of the assigned machine.
766 func (u *Unit) AssignedMachineId() (id string, err error) { 768 func (u *Unit) AssignedMachineId() (id string, err error) {
767 if u.IsPrincipal() { 769 if u.IsPrincipal() {
768 if u.doc.MachineId == "" { 770 if u.doc.MachineId == "" {
769 return "", &NotAssignedError{u} 771 return "", &NotAssignedError{u}
770 } 772 }
771 return u.doc.MachineId, nil 773 return u.doc.MachineId, nil
772 } 774 }
773 pudoc := unitDoc{} 775 pudoc := unitDoc{}
774 » err = u.st.units.Find(D{{"_id", u.doc.Principal}}).One(&pudoc) 776 » err = u.st.units.Find(bson.D{{"_id", u.doc.Principal}}).One(&pudoc)
775 if err == mgo.ErrNotFound { 777 if err == mgo.ErrNotFound {
776 return "", errors.NotFoundf("principal unit %q of %q", u.doc.Pri ncipal, u) 778 return "", errors.NotFoundf("principal unit %q of %q", u.doc.Pri ncipal, u)
777 } else if err != nil { 779 } else if err != nil {
778 return "", err 780 return "", err
779 } 781 }
780 if pudoc.MachineId == "" { 782 if pudoc.MachineId == "" {
781 return "", &NotAssignedError{u} 783 return "", &NotAssignedError{u}
782 } 784 }
783 return pudoc.MachineId, nil 785 return pudoc.MachineId, nil
784 } 786 }
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
819 } 821 }
820 } 822 }
821 if !canHost { 823 if !canHost {
822 return fmt.Errorf("machine %q cannot host units", m) 824 return fmt.Errorf("machine %q cannot host units", m)
823 } 825 }
824 // assignToMachine implies assignment to an existing machine, 826 // assignToMachine implies assignment to an existing machine,
825 // which is only permitted if unit placement is supported. 827 // which is only permitted if unit placement is supported.
826 if err := u.st.supportsUnitPlacement(); err != nil { 828 if err := u.st.supportsUnitPlacement(); err != nil {
827 return err 829 return err
828 } 830 }
829 » assert := append(isAliveDoc, D{ 831 » assert := append(isAliveDoc, bson.D{
830 » » {"$or", []D{ 832 » » {"$or", []bson.D{
831 {{"machineid", ""}}, 833 {{"machineid", ""}},
832 {{"machineid", m.Id()}}, 834 {{"machineid", m.Id()}},
833 }}, 835 }},
834 }...) 836 }...)
835 massert := isAliveDoc 837 massert := isAliveDoc
836 if unused { 838 if unused {
837 » » massert = append(massert, D{{"clean", D{{"$ne", false}}}}...) 839 » » massert = append(massert, bson.D{{"clean", bson.D{{"$ne", false} }}}...)
838 } 840 }
839 ops := []txn.Op{{ 841 ops := []txn.Op{{
840 C: u.st.units.Name, 842 C: u.st.units.Name,
841 Id: u.doc.Name, 843 Id: u.doc.Name,
842 Assert: assert, 844 Assert: assert,
843 » » Update: D{{"$set", D{{"machineid", m.doc.Id}}}}, 845 » » Update: bson.D{{"$set", bson.D{{"machineid", m.doc.Id}}}},
844 }, { 846 }, {
845 C: u.st.machines.Name, 847 C: u.st.machines.Name,
846 Id: m.doc.Id, 848 Id: m.doc.Id,
847 Assert: massert, 849 Assert: massert,
848 » » Update: D{{"$addToSet", D{{"principals", u.doc.Name}}}, {"$set", D{{"clean", false}}}}, 850 » » Update: bson.D{{"$addToSet", bson.D{{"principals", u.doc.Name}}} , {"$set", bson.D{{"clean", false}}}},
849 }} 851 }}
850 err = u.st.runTransaction(ops) 852 err = u.st.runTransaction(ops)
851 if err == nil { 853 if err == nil {
852 u.doc.MachineId = m.doc.Id 854 u.doc.MachineId = m.doc.Id
853 m.doc.Clean = false 855 m.doc.Clean = false
854 return nil 856 return nil
855 } 857 }
856 if err != txn.ErrAborted { 858 if err != txn.ErrAborted {
857 return err 859 return err
858 } 860 }
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
915 mdoc, ops, err = u.st.addMachineInsideMachineOps(template, paren tId, containerType) 917 mdoc, ops, err = u.st.addMachineInsideMachineOps(template, paren tId, containerType)
916 } 918 }
917 if err != nil { 919 if err != nil {
918 return err 920 return err
919 } 921 }
920 // Ensure the host machine is really clean. 922 // Ensure the host machine is really clean.
921 if parentId != "" { 923 if parentId != "" {
922 ops = append(ops, txn.Op{ 924 ops = append(ops, txn.Op{
923 C: u.st.machines.Name, 925 C: u.st.machines.Name,
924 Id: parentId, 926 Id: parentId,
925 » » » Assert: D{{"clean", true}}, 927 » » » Assert: bson.D{{"clean", true}},
926 }, txn.Op{ 928 }, txn.Op{
927 C: u.st.containerRefs.Name, 929 C: u.st.containerRefs.Name,
928 Id: parentId, 930 Id: parentId,
929 » » » Assert: D{hasNoContainersTerm}, 931 » » » Assert: bson.D{hasNoContainersTerm},
930 }) 932 })
931 } 933 }
932 » isUnassigned := D{{"machineid", ""}} 934 » isUnassigned := bson.D{{"machineid", ""}}
933 asserts := append(isAliveDoc, isUnassigned...) 935 asserts := append(isAliveDoc, isUnassigned...)
934 ops = append(ops, txn.Op{ 936 ops = append(ops, txn.Op{
935 C: u.st.units.Name, 937 C: u.st.units.Name,
936 Id: u.doc.Name, 938 Id: u.doc.Name,
937 Assert: asserts, 939 Assert: asserts,
938 » » Update: D{{"$set", D{{"machineid", mdoc.Id}}}}, 940 » » Update: bson.D{{"$set", bson.D{{"machineid", mdoc.Id}}}},
939 }) 941 })
940 942
941 err = u.st.runTransaction(ops) 943 err = u.st.runTransaction(ops)
942 if err == nil { 944 if err == nil {
943 u.doc.MachineId = mdoc.Id 945 u.doc.MachineId = mdoc.Id
944 return nil 946 return nil
945 } else if err != txn.ErrAborted { 947 } else if err != txn.ErrAborted {
946 return err 948 return err
947 } 949 }
948 950
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
989 cons, err := readConstraints(u.st, u.globalKey()) 991 cons, err := readConstraints(u.st, u.globalKey())
990 if errors.IsNotFoundError(err) { 992 if errors.IsNotFoundError(err) {
991 // Lack of constraints indicates lack of unit. 993 // Lack of constraints indicates lack of unit.
992 return nil, errors.NotFoundf("unit") 994 return nil, errors.NotFoundf("unit")
993 } else if err != nil { 995 } else if err != nil {
994 return nil, err 996 return nil, err
995 } 997 }
996 return &cons, nil 998 return &cons, nil
997 } 999 }
998 1000
999 // AssignToNewMachineOrContainer assigns the unit to a new machine, with constra ints 1001 // AssignToNewMachineOrContainer assigns the unit to a new machine,
1000 // determined according to the service and environment constraints at the time o f unit creation. 1002 // with constraints determined according to the service and
1001 // If a container is required, a clean, empty machine instance is required on wh ich to create 1003 // environment constraints at the time of unit creation. If a
1002 // the container. An existing clean, empty instance is first searched for, and i f not found, 1004 // container is required, a clean, empty machine instance is required
1003 // a new one is created. 1005 // on which to create the container. An existing clean, empty instance
1006 // is first searched for, and if not found, a new one is created.
1004 func (u *Unit) AssignToNewMachineOrContainer() (err error) { 1007 func (u *Unit) AssignToNewMachineOrContainer() (err error) {
1005 defer assignContextf(&err, u, "new machine or container") 1008 defer assignContextf(&err, u, "new machine or container")
1006 if u.doc.Principal != "" { 1009 if u.doc.Principal != "" {
1007 return fmt.Errorf("unit is a subordinate") 1010 return fmt.Errorf("unit is a subordinate")
1008 } 1011 }
1009 cons, err := u.constraints() 1012 cons, err := u.constraints()
1010 if err != nil { 1013 if err != nil {
1011 return err 1014 return err
1012 } 1015 }
1013 if !cons.HasContainer() { 1016 if !cons.HasContainer() {
(...skipping 10 matching lines...) Expand all
1024 return err 1027 return err
1025 } 1028 }
1026 err = query.One(&host) 1029 err = query.One(&host)
1027 if err == mgo.ErrNotFound { 1030 if err == mgo.ErrNotFound {
1028 // No existing clean, empty machine so create a new one. 1031 // No existing clean, empty machine so create a new one.
1029 // The container constraint will be used by AssignToNewMachine t o create the required container. 1032 // The container constraint will be used by AssignToNewMachine t o create the required container.
1030 return u.AssignToNewMachine() 1033 return u.AssignToNewMachine()
1031 } else if err != nil { 1034 } else if err != nil {
1032 return err 1035 return err
1033 } 1036 }
1037 svc, err := u.Service()
1038 if err != nil {
1039 return err
1040 }
1041 includeNetworks, excludeNetworks, err := svc.Networks()
1042 if err != nil {
1043 return err
1044 }
1034 template := MachineTemplate{ 1045 template := MachineTemplate{
1035 » » Series: u.doc.Series, 1046 » » Series: u.doc.Series,
1036 » » Constraints: *cons, 1047 » » Constraints: *cons,
1037 » » Jobs: []MachineJob{JobHostUnits}, 1048 » » Jobs: []MachineJob{JobHostUnits},
1049 » » IncludeNetworks: includeNetworks,
1050 » » ExcludeNetworks: excludeNetworks,
1038 } 1051 }
1039 err = u.assignToNewMachine(template, host.Id, *cons.Container) 1052 err = u.assignToNewMachine(template, host.Id, *cons.Container)
1040 if err == machineNotCleanErr { 1053 if err == machineNotCleanErr {
1041 // The clean machine was used before we got a chance to use it s o just 1054 // The clean machine was used before we got a chance to use it s o just
1042 // stick the unit on a new machine. 1055 // stick the unit on a new machine.
1043 return u.AssignToNewMachine() 1056 return u.AssignToNewMachine()
1044 } 1057 }
1045 return err 1058 return err
1046 } 1059 }
1047 1060
1048 // AssignToNewMachine assigns the unit to a new machine, with constraints 1061 // AssignToNewMachine assigns the unit to a new machine, with constraints
1049 // determined according to the service and environment constraints at the 1062 // determined according to the service and environment constraints at the
1050 // time of unit creation. 1063 // time of unit creation.
1051 func (u *Unit) AssignToNewMachine() (err error) { 1064 func (u *Unit) AssignToNewMachine() (err error) {
1052 defer assignContextf(&err, u, "new machine") 1065 defer assignContextf(&err, u, "new machine")
1053 if u.doc.Principal != "" { 1066 if u.doc.Principal != "" {
1054 return fmt.Errorf("unit is a subordinate") 1067 return fmt.Errorf("unit is a subordinate")
1055 } 1068 }
1056 // Get the ops necessary to create a new machine, and the machine doc th at 1069 // Get the ops necessary to create a new machine, and the machine doc th at
1057 // will be added with those operations (which includes the machine id). 1070 // will be added with those operations (which includes the machine id).
1058 cons, err := u.constraints() 1071 cons, err := u.constraints()
1059 if err != nil { 1072 if err != nil {
1060 return err 1073 return err
1061 } 1074 }
1062 var containerType instance.ContainerType 1075 var containerType instance.ContainerType
1063 // Configure to create a new container if required. 1076 // Configure to create a new container if required.
1064 if cons.HasContainer() { 1077 if cons.HasContainer() {
1065 containerType = *cons.Container 1078 containerType = *cons.Container
1066 } 1079 }
1080 svc, err := u.Service()
1081 if err != nil {
1082 return err
1083 }
1084 includeNetworks, excludeNetworks, err := svc.Networks()
1085 if err != nil {
1086 return err
1087 }
1067 template := MachineTemplate{ 1088 template := MachineTemplate{
1068 » » Series: u.doc.Series, 1089 » » Series: u.doc.Series,
1069 » » Constraints: *cons, 1090 » » Constraints: *cons,
1070 » » Jobs: []MachineJob{JobHostUnits}, 1091 » » Jobs: []MachineJob{JobHostUnits},
1092 » » IncludeNetworks: includeNetworks,
1093 » » ExcludeNetworks: excludeNetworks,
1071 } 1094 }
1072 return u.assignToNewMachine(template, "", containerType) 1095 return u.assignToNewMachine(template, "", containerType)
1073 } 1096 }
1074 1097
1075 var noCleanMachines = stderrors.New("all eligible machines in use") 1098 var noCleanMachines = stderrors.New("all eligible machines in use")
1076 1099
1077 // AssignToCleanMachine assigns u to a machine which is marked as clean. A machi ne 1100 // AssignToCleanMachine assigns u to a machine which is marked as clean. A machi ne
1078 // is clean if it has never had any principal units assigned to it. 1101 // is clean if it has never had any principal units assigned to it.
1079 // If there are no clean machines besides any machine(s) running JobHostEnviron, 1102 // If there are no clean machines besides any machine(s) running JobHostEnviron,
1080 // an error is returned. 1103 // an error is returned.
1081 // This method does not take constraints into consideration when choosing a 1104 // This method does not take constraints into consideration when choosing a
1082 // machine (lp:1161919). 1105 // machine (lp:1161919).
1083 func (u *Unit) AssignToCleanMachine() (m *Machine, err error) { 1106 func (u *Unit) AssignToCleanMachine() (m *Machine, err error) {
1084 return u.assignToCleanMaybeEmptyMachine(false) 1107 return u.assignToCleanMaybeEmptyMachine(false)
1085 } 1108 }
1086 1109
1087 // AssignToCleanMachine assigns u to a machine which is marked as clean and is a lso 1110 // AssignToCleanMachine assigns u to a machine which is marked as clean and is a lso
1088 // not hosting any containers. A machine is clean if it has never had any princi pal units 1111 // not hosting any containers. A machine is clean if it has never had any princi pal units
1089 // assigned to it. If there are no clean machines besides any machine(s) running JobHostEnviron, 1112 // assigned to it. If there are no clean machines besides any machine(s) running JobHostEnviron,
1090 // an error is returned. 1113 // an error is returned.
1091 // This method does not take constraints into consideration when choosing a 1114 // This method does not take constraints into consideration when choosing a
1092 // machine (lp:1161919). 1115 // machine (lp:1161919).
1093 func (u *Unit) AssignToCleanEmptyMachine() (m *Machine, err error) { 1116 func (u *Unit) AssignToCleanEmptyMachine() (m *Machine, err error) {
1094 return u.assignToCleanMaybeEmptyMachine(true) 1117 return u.assignToCleanMaybeEmptyMachine(true)
1095 } 1118 }
1096 1119
1097 var hasContainerTerm = bson.DocElem{ 1120 var hasContainerTerm = bson.DocElem{
1098 » "$and", []D{ 1121 » "$and", []bson.D{
1099 » » {{"children", D{{"$not", D{{"$size", 0}}}}}}, 1122 » » {{"children", bson.D{{"$not", bson.D{{"$size", 0}}}}}},
1100 » » {{"children", D{{"$exists", true}}}}, 1123 » » {{"children", bson.D{{"$exists", true}}}},
1101 }} 1124 }}
1102 1125
1103 var hasNoContainersTerm = bson.DocElem{ 1126 var hasNoContainersTerm = bson.DocElem{
1104 » "$or", []D{ 1127 » "$or", []bson.D{
1105 » » {{"children", D{{"$size", 0}}}}, 1128 » » {{"children", bson.D{{"$size", 0}}}},
1106 » » {{"children", D{{"$exists", false}}}}, 1129 » » {{"children", bson.D{{"$exists", false}}}},
1107 }} 1130 }}
1108 1131
1109 // findCleanMachineQuery returns a Mongo query to find clean (and possibly empty ) machines with 1132 // findCleanMachineQuery returns a Mongo query to find clean (and possibly empty ) machines with
1110 // characteristics matching the specified constraints. 1133 // characteristics matching the specified constraints.
1111 func (u *Unit) findCleanMachineQuery(requireEmpty bool, cons *constraints.Value) (*mgo.Query, error) { 1134 func (u *Unit) findCleanMachineQuery(requireEmpty bool, cons *constraints.Value) (*mgo.Query, error) {
1112 // Select all machines that can accept principal units and are clean. 1135 // Select all machines that can accept principal units and are clean.
1113 var containerRefs []machineContainers 1136 var containerRefs []machineContainers
1114 // If we need empty machines, first build up a list of machine ids which have containers 1137 // If we need empty machines, first build up a list of machine ids which have containers
1115 // so we can exclude those. 1138 // so we can exclude those.
1116 if requireEmpty { 1139 if requireEmpty {
1117 » » err := u.st.containerRefs.Find(D{hasContainerTerm}).All(&contain erRefs) 1140 » » err := u.st.containerRefs.Find(bson.D{hasContainerTerm}).All(&co ntainerRefs)
1118 if err != nil { 1141 if err != nil {
1119 return nil, err 1142 return nil, err
1120 } 1143 }
1121 } 1144 }
1122 var machinesWithContainers = make([]string, len(containerRefs)) 1145 var machinesWithContainers = make([]string, len(containerRefs))
1123 for i, cref := range containerRefs { 1146 for i, cref := range containerRefs {
1124 machinesWithContainers[i] = cref.Id 1147 machinesWithContainers[i] = cref.Id
1125 } 1148 }
1126 » terms := D{ 1149 » terms := bson.D{
1127 {"life", Alive}, 1150 {"life", Alive},
1128 {"series", u.doc.Series}, 1151 {"series", u.doc.Series},
1129 {"jobs", []MachineJob{JobHostUnits}}, 1152 {"jobs", []MachineJob{JobHostUnits}},
1130 {"clean", true}, 1153 {"clean", true},
1131 » » {"_id", D{{"$nin", machinesWithContainers}}}, 1154 » » {"_id", bson.D{{"$nin", machinesWithContainers}}},
1132 } 1155 }
1133 // Add the container filter term if necessary. 1156 // Add the container filter term if necessary.
1134 var containerType instance.ContainerType 1157 var containerType instance.ContainerType
1135 if cons.Container != nil { 1158 if cons.Container != nil {
1136 containerType = *cons.Container 1159 containerType = *cons.Container
1137 } 1160 }
1138 if containerType == instance.NONE { 1161 if containerType == instance.NONE {
1139 terms = append(terms, bson.DocElem{"containertype", ""}) 1162 terms = append(terms, bson.DocElem{"containertype", ""})
1140 } else if containerType != "" { 1163 } else if containerType != "" {
1141 terms = append(terms, bson.DocElem{"containertype", string(conta inerType)}) 1164 terms = append(terms, bson.DocElem{"containertype", string(conta inerType)})
1142 } 1165 }
1143 1166
1144 // Find the ids of machines which satisfy any required hardware 1167 // Find the ids of machines which satisfy any required hardware
1145 // constraints. If there is no instanceData for a machine, that 1168 // constraints. If there is no instanceData for a machine, that
1146 // machine is not considered as suitable for deploying the unit. 1169 // machine is not considered as suitable for deploying the unit.
1147 // This can happen if the machine is not yet provisioned. It may 1170 // This can happen if the machine is not yet provisioned. It may
1148 // be that when the machine is provisioned it will be found to 1171 // be that when the machine is provisioned it will be found to
1149 // be suitable, but we don't know that right now and it's best 1172 // be suitable, but we don't know that right now and it's best
1150 // to err on the side of caution and exclude such machines. 1173 // to err on the side of caution and exclude such machines.
1151 var suitableInstanceData []instanceData 1174 var suitableInstanceData []instanceData
1152 » var suitableTerms D 1175 » var suitableTerms bson.D
1153 if cons.Arch != nil && *cons.Arch != "" { 1176 if cons.Arch != nil && *cons.Arch != "" {
1154 suitableTerms = append(suitableTerms, bson.DocElem{"arch", *cons .Arch}) 1177 suitableTerms = append(suitableTerms, bson.DocElem{"arch", *cons .Arch})
1155 } 1178 }
1156 if cons.Mem != nil && *cons.Mem > 0 { 1179 if cons.Mem != nil && *cons.Mem > 0 {
1157 » » suitableTerms = append(suitableTerms, bson.DocElem{"mem", D{{"$g te", *cons.Mem}}}) 1180 » » suitableTerms = append(suitableTerms, bson.DocElem{"mem", bson.D {{"$gte", *cons.Mem}}})
1158 } 1181 }
1159 if cons.RootDisk != nil && *cons.RootDisk > 0 { 1182 if cons.RootDisk != nil && *cons.RootDisk > 0 {
1160 » » suitableTerms = append(suitableTerms, bson.DocElem{"rootdisk", D {{"$gte", *cons.RootDisk}}}) 1183 » » suitableTerms = append(suitableTerms, bson.DocElem{"rootdisk", b son.D{{"$gte", *cons.RootDisk}}})
1161 } 1184 }
1162 if cons.CpuCores != nil && *cons.CpuCores > 0 { 1185 if cons.CpuCores != nil && *cons.CpuCores > 0 {
1163 » » suitableTerms = append(suitableTerms, bson.DocElem{"cpucores", D {{"$gte", *cons.CpuCores}}}) 1186 » » suitableTerms = append(suitableTerms, bson.DocElem{"cpucores", b son.D{{"$gte", *cons.CpuCores}}})
1164 } 1187 }
1165 if cons.CpuPower != nil && *cons.CpuPower > 0 { 1188 if cons.CpuPower != nil && *cons.CpuPower > 0 {
1166 » » suitableTerms = append(suitableTerms, bson.DocElem{"cpupower", D {{"$gte", *cons.CpuPower}}}) 1189 » » suitableTerms = append(suitableTerms, bson.DocElem{"cpupower", b son.D{{"$gte", *cons.CpuPower}}})
1167 } 1190 }
1168 if cons.Tags != nil && len(*cons.Tags) > 0 { 1191 if cons.Tags != nil && len(*cons.Tags) > 0 {
1169 » » suitableTerms = append(suitableTerms, bson.DocElem{"tags", D{{"$ all", *cons.Tags}}}) 1192 » » suitableTerms = append(suitableTerms, bson.DocElem{"tags", bson. D{{"$all", *cons.Tags}}})
1170 } 1193 }
1171 if len(suitableTerms) > 0 { 1194 if len(suitableTerms) > 0 {
1172 err := u.st.instanceData.Find(suitableTerms).Select(bson.M{"_id" : 1}).All(&suitableInstanceData) 1195 err := u.st.instanceData.Find(suitableTerms).Select(bson.M{"_id" : 1}).All(&suitableInstanceData)
1173 if err != nil { 1196 if err != nil {
1174 return nil, err 1197 return nil, err
1175 } 1198 }
1176 var suitableIds = make([]string, len(suitableInstanceData)) 1199 var suitableIds = make([]string, len(suitableInstanceData))
1177 for i, m := range suitableInstanceData { 1200 for i, m := range suitableInstanceData {
1178 suitableIds[i] = m.Id 1201 suitableIds[i] = m.Id
1179 } 1202 }
1180 » » terms = append(terms, bson.DocElem{"_id", D{{"$in", suitableIds} }}) 1203 » » terms = append(terms, bson.DocElem{"_id", bson.D{{"$in", suitabl eIds}}})
1181 } 1204 }
1182 return u.st.machines.Find(terms), nil 1205 return u.st.machines.Find(terms), nil
1183 } 1206 }
1184 1207
1185 // assignToCleanMaybeEmptyMachine implements AssignToCleanMachine and AssignToCl eanEmptyMachine. 1208 // assignToCleanMaybeEmptyMachine implements AssignToCleanMachine and AssignToCl eanEmptyMachine.
1186 // A 'machine' may be a machine instance or container depending on the service c onstraints. 1209 // A 'machine' may be a machine instance or container depending on the service c onstraints.
1187 func (u *Unit) assignToCleanMaybeEmptyMachine(requireEmpty bool) (m *Machine, er r error) { 1210 func (u *Unit) assignToCleanMaybeEmptyMachine(requireEmpty bool) (m *Machine, er r error) {
1188 context := "clean" 1211 context := "clean"
1189 if requireEmpty { 1212 if requireEmpty {
1190 context += ", empty" 1213 context += ", empty"
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
1235 1258
1236 // UnassignFromMachine removes the assignment between this unit and the 1259 // UnassignFromMachine removes the assignment between this unit and the
1237 // machine it's assigned to. 1260 // machine it's assigned to.
1238 func (u *Unit) UnassignFromMachine() (err error) { 1261 func (u *Unit) UnassignFromMachine() (err error) {
1239 // TODO check local machine id and add an assert that the 1262 // TODO check local machine id and add an assert that the
1240 // machine id is as expected. 1263 // machine id is as expected.
1241 ops := []txn.Op{{ 1264 ops := []txn.Op{{
1242 C: u.st.units.Name, 1265 C: u.st.units.Name,
1243 Id: u.doc.Name, 1266 Id: u.doc.Name,
1244 Assert: txn.DocExists, 1267 Assert: txn.DocExists,
1245 » » Update: D{{"$set", D{{"machineid", ""}}}}, 1268 » » Update: bson.D{{"$set", bson.D{{"machineid", ""}}}},
1246 }} 1269 }}
1247 if u.doc.MachineId != "" { 1270 if u.doc.MachineId != "" {
1248 ops = append(ops, txn.Op{ 1271 ops = append(ops, txn.Op{
1249 C: u.st.machines.Name, 1272 C: u.st.machines.Name,
1250 Id: u.doc.MachineId, 1273 Id: u.doc.MachineId,
1251 Assert: txn.DocExists, 1274 Assert: txn.DocExists,
1252 » » » Update: D{{"$pull", D{{"principals", u.doc.Name}}}}, 1275 » » » Update: bson.D{{"$pull", bson.D{{"principals", u.doc.Nam e}}}},
1253 }) 1276 })
1254 } 1277 }
1255 err = u.st.runTransaction(ops) 1278 err = u.st.runTransaction(ops)
1256 if err != nil { 1279 if err != nil {
1257 return fmt.Errorf("cannot unassign unit %q from machine: %v", u, onAbort(err, errors.NotFoundf("machine"))) 1280 return fmt.Errorf("cannot unassign unit %q from machine: %v", u, onAbort(err, errors.NotFoundf("machine")))
1258 } 1281 }
1259 u.doc.MachineId = "" 1282 u.doc.MachineId = ""
1260 return nil 1283 return nil
1261 } 1284 }
1262 1285
1263 // SetPublicAddress sets the public address of the unit. 1286 // SetPublicAddress sets the public address of the unit.
1264 func (u *Unit) SetPublicAddress(address string) (err error) { 1287 func (u *Unit) SetPublicAddress(address string) (err error) {
1265 ops := []txn.Op{{ 1288 ops := []txn.Op{{
1266 C: u.st.units.Name, 1289 C: u.st.units.Name,
1267 Id: u.doc.Name, 1290 Id: u.doc.Name,
1268 Assert: txn.DocExists, 1291 Assert: txn.DocExists,
1269 » » Update: D{{"$set", D{{"publicaddress", address}}}}, 1292 » » Update: bson.D{{"$set", bson.D{{"publicaddress", address}}}},
1270 }} 1293 }}
1271 if err := u.st.runTransaction(ops); err != nil { 1294 if err := u.st.runTransaction(ops); err != nil {
1272 return fmt.Errorf("cannot set public address of unit %q: %v", u, onAbort(err, errors.NotFoundf("unit"))) 1295 return fmt.Errorf("cannot set public address of unit %q: %v", u, onAbort(err, errors.NotFoundf("unit")))
1273 } 1296 }
1274 u.doc.PublicAddress = address 1297 u.doc.PublicAddress = address
1275 return nil 1298 return nil
1276 } 1299 }
1277 1300
1278 // SetPrivateAddress sets the private address of the unit. 1301 // SetPrivateAddress sets the private address of the unit.
1279 func (u *Unit) SetPrivateAddress(address string) error { 1302 func (u *Unit) SetPrivateAddress(address string) error {
1280 ops := []txn.Op{{ 1303 ops := []txn.Op{{
1281 C: u.st.units.Name, 1304 C: u.st.units.Name,
1282 Id: u.doc.Name, 1305 Id: u.doc.Name,
1283 Assert: notDeadDoc, 1306 Assert: notDeadDoc,
1284 » » Update: D{{"$set", D{{"privateaddress", address}}}}, 1307 » » Update: bson.D{{"$set", bson.D{{"privateaddress", address}}}},
1285 }} 1308 }}
1286 err := u.st.runTransaction(ops) 1309 err := u.st.runTransaction(ops)
1287 if err != nil { 1310 if err != nil {
1288 return fmt.Errorf("cannot set private address of unit %q: %v", u , onAbort(err, errors.NotFoundf("unit"))) 1311 return fmt.Errorf("cannot set private address of unit %q: %v", u , onAbort(err, errors.NotFoundf("unit")))
1289 } 1312 }
1290 u.doc.PrivateAddress = address 1313 u.doc.PrivateAddress = address
1291 return nil 1314 return nil
1292 } 1315 }
1293 1316
1294 // Resolve marks the unit as having had any previous state transition 1317 // Resolve marks the unit as having had any previous state transition
(...skipping 22 matching lines...) Expand all
1317 // whether to attempt to reexecute previous failed hooks or to continue 1340 // whether to attempt to reexecute previous failed hooks or to continue
1318 // as if they had succeeded before. 1341 // as if they had succeeded before.
1319 func (u *Unit) SetResolved(mode ResolvedMode) (err error) { 1342 func (u *Unit) SetResolved(mode ResolvedMode) (err error) {
1320 defer utils.ErrorContextf(&err, "cannot set resolved mode for unit %q", u) 1343 defer utils.ErrorContextf(&err, "cannot set resolved mode for unit %q", u)
1321 switch mode { 1344 switch mode {
1322 case ResolvedRetryHooks, ResolvedNoHooks: 1345 case ResolvedRetryHooks, ResolvedNoHooks:
1323 default: 1346 default:
1324 return fmt.Errorf("invalid error resolution mode: %q", mode) 1347 return fmt.Errorf("invalid error resolution mode: %q", mode)
1325 } 1348 }
1326 // TODO(fwereade): assert unit has error status. 1349 // TODO(fwereade): assert unit has error status.
1327 » resolvedNotSet := D{{"resolved", ResolvedNone}} 1350 » resolvedNotSet := bson.D{{"resolved", ResolvedNone}}
1328 ops := []txn.Op{{ 1351 ops := []txn.Op{{
1329 C: u.st.units.Name, 1352 C: u.st.units.Name,
1330 Id: u.doc.Name, 1353 Id: u.doc.Name,
1331 Assert: append(notDeadDoc, resolvedNotSet...), 1354 Assert: append(notDeadDoc, resolvedNotSet...),
1332 » » Update: D{{"$set", D{{"resolved", mode}}}}, 1355 » » Update: bson.D{{"$set", bson.D{{"resolved", mode}}}},
1333 }} 1356 }}
1334 if err := u.st.runTransaction(ops); err == nil { 1357 if err := u.st.runTransaction(ops); err == nil {
1335 u.doc.Resolved = mode 1358 u.doc.Resolved = mode
1336 return nil 1359 return nil
1337 } else if err != txn.ErrAborted { 1360 } else if err != txn.ErrAborted {
1338 return err 1361 return err
1339 } 1362 }
1340 if ok, err := isNotDead(u.st.units, u.doc.Name); err != nil { 1363 if ok, err := isNotDead(u.st.units, u.doc.Name); err != nil {
1341 return err 1364 return err
1342 } else if !ok { 1365 } else if !ok {
1343 return errDead 1366 return errDead
1344 } 1367 }
1345 // For now, the only remaining assert is that resolved was unset. 1368 // For now, the only remaining assert is that resolved was unset.
1346 return fmt.Errorf("already resolved") 1369 return fmt.Errorf("already resolved")
1347 } 1370 }
1348 1371
1349 // ClearResolved removes any resolved setting on the unit. 1372 // ClearResolved removes any resolved setting on the unit.
1350 func (u *Unit) ClearResolved() error { 1373 func (u *Unit) ClearResolved() error {
1351 ops := []txn.Op{{ 1374 ops := []txn.Op{{
1352 C: u.st.units.Name, 1375 C: u.st.units.Name,
1353 Id: u.doc.Name, 1376 Id: u.doc.Name,
1354 Assert: txn.DocExists, 1377 Assert: txn.DocExists,
1355 » » Update: D{{"$set", D{{"resolved", ResolvedNone}}}}, 1378 » » Update: bson.D{{"$set", bson.D{{"resolved", ResolvedNone}}}},
1356 }} 1379 }}
1357 err := u.st.runTransaction(ops) 1380 err := u.st.runTransaction(ops)
1358 if err != nil { 1381 if err != nil {
1359 return fmt.Errorf("cannot clear resolved mode for unit %q: %v", u, errors.NotFoundf("unit")) 1382 return fmt.Errorf("cannot clear resolved mode for unit %q: %v", u, errors.NotFoundf("unit"))
1360 } 1383 }
1361 u.doc.Resolved = ResolvedNone 1384 u.doc.Resolved = ResolvedNone
1362 return nil 1385 return nil
1363 } 1386 }
LEFTRIGHT

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld f62528b