LEFT | RIGHT |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 } |
LEFT | RIGHT |