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

Delta Between Two Patch Sets: state/unit.go

Issue 10447045: Add machine instance metadata to state (Closed)
Left Patch Set: Created 11 years, 9 months ago
Right Patch Set: Add machine instance metadata to state Created 11 years, 9 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
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 "labix.org/v2/mgo" 9 "labix.org/v2/mgo"
10 "labix.org/v2/mgo/txn" 10 "labix.org/v2/mgo/txn"
(...skipping 208 matching lines...) Expand 10 before | Expand all | Expand 10 after
219 // directly. 219 // directly.
220 func (u *Unit) Destroy() (err error) { 220 func (u *Unit) Destroy() (err error) {
221 defer func() { 221 defer func() {
222 if err == nil { 222 if err == nil {
223 // This is a white lie; the document might actually be r emoved. 223 // This is a white lie; the document might actually be r emoved.
224 u.doc.Life = Dying 224 u.doc.Life = Dying
225 } 225 }
226 }() 226 }()
227 unit := &Unit{st: u.st, doc: u.doc} 227 unit := &Unit{st: u.st, doc: u.doc}
228 for i := 0; i < 5; i++ { 228 for i := 0; i < 5; i++ {
229 » » ops, err := unit.destroyOps() 229 » » switch ops, err := unit.destroyOps(); err {
230 » » switch { 230 » » case errRefresh:
231 » » case err == errRefresh: 231 » » case errAlreadyDying:
232 » » case err == errAlreadyDying:
233 return nil 232 return nil
234 » » case err != nil: 233 » » case nil:
235 » » » return err
236 » » default:
237 if err := unit.st.runTransaction(ops); err != txn.ErrAbo rted { 234 if err := unit.st.runTransaction(ops); err != txn.ErrAbo rted {
238 return err 235 return err
239 } 236 }
237 default:
238 return err
240 } 239 }
241 if err := unit.Refresh(); errors.IsNotFoundError(err) { 240 if err := unit.Refresh(); errors.IsNotFoundError(err) {
242 return nil 241 return nil
243 } else if err != nil { 242 } else if err != nil {
244 return err 243 return err
245 } 244 }
246 } 245 }
247 return ErrExcessiveContention 246 return ErrExcessiveContention
248 } 247 }
249 248
250 // destroyOps returns the operations required to destroy the unit. If it 249 // destroyOps returns the operations required to destroy the unit. If it
251 // returns errRefresh, the unit should be refreshed and the destruction 250 // returns errRefresh, the unit should be refreshed and the destruction
252 // operations recalculated. 251 // operations recalculated.
253 func (u *Unit) destroyOps() ([]txn.Op, error) { 252 func (u *Unit) destroyOps() ([]txn.Op, error) {
254 if u.doc.Life != Alive { 253 if u.doc.Life != Alive {
255 return nil, errAlreadyDying 254 return nil, errAlreadyDying
256 } 255 }
257 » // In many cases, we just want to set Dying and let the agents deal with it. 256
258 » defaultOps := []txn.Op{{ 257 » // Where possible, we'd like to be able to short-circuit unit destructio n
258 » // such that units can be removed directly rather than waiting for their
259 » // agents to start, observe Dying, set Dead, and shut down; this takes a
260 » // long time and is vexing to users. This turns out to be possible if an d
261 » // only if the unit agent has not yet set its status; this implies that the
262 » // most the unit could possibly have done is to run its install hook.
263 » //
264 » // There's no harm in removing a unit that's run its install hook only - -
265 » // or, at least, there is no more harm than there is in removing a unit
266 » // that's run its stop hook, and that's the usual condition.
267 » //
268 » // Principals with subordinates are never eligible for this shortcut,
269 » // because the unit agent must inevitably have set a status before getti ng
270 » // to the point where it can actually create its subordinate.
271 » //
272 » // Subordinates should be eligible for the shortcut but are not currentl y
273 » // considered, on the basis that (1) they were created by active princip als
274 » // and can be expected to be deployed pretty soon afterwards, so we don' t
275 » // lose much time and (2) by maintaining this restriction, I can reduce
276 » // the number of tests that have to change and defer that improvement to
277 » // its own CL.
278 » minUnitsOp := minUnitsTriggerOp(u.st, u.ServiceName())
279 » setDyingOps := []txn.Op{{
259 C: u.st.units.Name, 280 C: u.st.units.Name,
260 Id: u.doc.Name, 281 Id: u.doc.Name,
261 Assert: isAliveDoc, 282 Assert: isAliveDoc,
262 Update: D{{"$set", D{{"life", Dying}}}}, 283 Update: D{{"$set", D{{"life", Dying}}}},
263 » }} 284 » }, minUnitsOp}
264
265 » // Subordinates, and principals with subordinates, are left for the agen ts.
266 if u.doc.Principal != "" { 285 if u.doc.Principal != "" {
267 » » return defaultOps, nil 286 » » return setDyingOps, nil
268 } else if len(u.doc.Subordinates) != 0 { 287 } else if len(u.doc.Subordinates) != 0 {
269 » » return defaultOps, nil 288 » » return setDyingOps, nil
270 » } 289 » }
271 290
272 » // If the (known principal) unit has no assigned machine id, the unit ca n 291 » sdocId := u.globalKey()
273 » // be removed directly. 292 » sdoc, err := getStatus(u.st, sdocId)
274 » asserts := D{{"machineid", u.doc.MachineId}}
275 » asserts = append(asserts, unitHasNoSubordinates...)
276 » asserts = append(asserts, isAliveDoc...)
277 » if u.doc.MachineId == "" {
278 » » return u.removeOps(asserts)
279 » }
280
281 » // If the unit's machine has an instance id, leave it for the agents.
282 » m, err := u.st.Machine(u.doc.MachineId)
283 if errors.IsNotFoundError(err) { 293 if errors.IsNotFoundError(err) {
284 » » return nil, errRefresh 294 » » return nil, errAlreadyDying
285 } else if err != nil { 295 } else if err != nil {
286 return nil, err 296 return nil, err
287 } 297 }
288 » if _, found := m.InstanceId(); found { 298 » if sdoc.Status != params.StatusPending {
289 » » return defaultOps, nil 299 » » return setDyingOps, nil
290 » } 300 » }
291 301 » ops := []txn.Op{{
292 » // Units assigned to unprovisioned machines can be removed directly. 302 » » C: u.st.statuses.Name,
293 » ops := []txn.Op{{ 303 » » Id: sdocId,
294 » » C: u.st.machines.Name, 304 » » Assert: D{{"status", params.StatusPending}},
295 » » Id: u.doc.MachineId, 305 » }, minUnitsOp}
296 » » Assert: D{{"instanceid", ""}}, 306 » removeAsserts := append(isAliveDoc, unitHasNoSubordinates...)
297 » }} 307 » removeOps, err := u.removeOps(removeAsserts)
298 » removeOps, err := u.removeOps(asserts) 308 » if err == errAlreadyRemoved {
299 » if err != nil { 309 » » return nil, errAlreadyDying
310 » } else if err != nil {
300 return nil, err 311 return nil, err
301 } 312 }
302 return append(ops, removeOps...), nil 313 return append(ops, removeOps...), nil
303 } 314 }
315
316 var errAlreadyRemoved = stderrors.New("entity has already been removed")
304 317
305 // removeOps returns the operations necessary to remove the unit, assuming 318 // removeOps returns the operations necessary to remove the unit, assuming
306 // the supplied asserts apply to the unit document. 319 // the supplied asserts apply to the unit document.
307 func (u *Unit) removeOps(asserts D) ([]txn.Op, error) { 320 func (u *Unit) removeOps(asserts D) ([]txn.Op, error) {
308 svc, err := u.st.Service(u.doc.Service) 321 svc, err := u.st.Service(u.doc.Service)
309 » if err != nil { 322 » if errors.IsNotFoundError(err) {
323 » » // If the service has been removed, the unit must already have b een.
324 » » return nil, errAlreadyRemoved
325 » } else if err != nil {
310 return nil, err 326 return nil, err
311 } 327 }
312 return svc.removeUnitOps(u, asserts) 328 return svc.removeUnitOps(u, asserts)
313 } 329 }
314 330
315 var ErrUnitHasSubordinates = stderrors.New("unit has subordinates") 331 var ErrUnitHasSubordinates = stderrors.New("unit has subordinates")
316 332
317 var unitHasNoSubordinates = D{{ 333 var unitHasNoSubordinates = D{{
318 "$or", []D{ 334 "$or", []D{
319 {{"subordinates", D{{"$size", 0}}}}, 335 {{"subordinates", D{{"$size", 0}}}},
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
351 } 367 }
352 368
353 // Remove removes the unit from state, and may remove its service as well, if 369 // Remove removes the unit from state, and may remove its service as well, if
354 // the service is Dying and no other references to it exist. It will fail if 370 // the service is Dying and no other references to it exist. It will fail if
355 // the unit is not Dead. 371 // the unit is not Dead.
356 func (u *Unit) Remove() (err error) { 372 func (u *Unit) Remove() (err error) {
357 defer utils.ErrorContextf(&err, "cannot remove unit %q", u) 373 defer utils.ErrorContextf(&err, "cannot remove unit %q", u)
358 if u.doc.Life != Dead { 374 if u.doc.Life != Dead {
359 return stderrors.New("unit is not dead") 375 return stderrors.New("unit is not dead")
360 } 376 }
361 svc, err := u.st.Service(u.doc.Service)
362 if err != nil {
363 return err
364 }
365 unit := &Unit{st: u.st, doc: u.doc} 377 unit := &Unit{st: u.st, doc: u.doc}
366 for i := 0; i < 5; i++ { 378 for i := 0; i < 5; i++ {
367 » » ops, err := svc.removeUnitOps(unit, isDeadDoc) 379 » » switch ops, err := unit.removeOps(isDeadDoc); err {
368 » » if err != nil { 380 » » case errRefresh:
369 » » » return err 381 » » case errAlreadyRemoved:
370 » » }
371 » » if err := svc.st.runTransaction(ops); err != txn.ErrAborted {
372 » » » return err
373 » » }
374 » » if err := svc.Refresh(); errors.IsNotFoundError(err) {
375 return nil 382 return nil
376 » » } else if err != nil { 383 » » case nil:
384 » » » if err := u.st.runTransaction(ops); err != txn.ErrAborte d {
385 » » » » return err
386 » » » }
387 » » default:
377 return err 388 return err
378 } 389 }
379 if err := unit.Refresh(); errors.IsNotFoundError(err) { 390 if err := unit.Refresh(); errors.IsNotFoundError(err) {
380 return nil 391 return nil
381 } else if err != nil { 392 } else if err != nil {
382 return err 393 return err
383 } 394 }
384 } 395 }
385 return ErrExcessiveContention 396 return ErrExcessiveContention
386 } 397 }
(...skipping 633 matching lines...) Expand 10 before | Expand all | Expand 10 after
1020 return p1.Protocol < p2.Protocol 1031 return p1.Protocol < p2.Protocol
1021 } 1032 }
1022 return p1.Number < p2.Number 1033 return p1.Number < p2.Number
1023 } 1034 }
1024 1035
1025 // SortPorts sorts the given ports, first by protocol, 1036 // SortPorts sorts the given ports, first by protocol,
1026 // then by number. 1037 // then by number.
1027 func SortPorts(ports []instance.Port) { 1038 func SortPorts(ports []instance.Port) {
1028 sort.Sort(portSlice(ports)) 1039 sort.Sort(portSlice(ports))
1029 } 1040 }
LEFTRIGHT

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