github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/state/watcher.go (about) 1 // Copyright 2012, 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package state 5 6 import ( 7 "fmt" 8 "reflect" 9 "regexp" 10 "strings" 11 "time" 12 13 "github.com/juju/errors" 14 "github.com/juju/loggo" 15 "github.com/juju/utils/set" 16 "gopkg.in/juju/names.v2" 17 "gopkg.in/mgo.v2" 18 "gopkg.in/mgo.v2/bson" 19 "gopkg.in/tomb.v1" 20 21 "github.com/juju/juju/instance" 22 "github.com/juju/juju/mongo" 23 "github.com/juju/juju/state/watcher" 24 "github.com/juju/juju/state/workers" 25 26 // TODO(fwereade): 2015-11-18 lp:1517428 27 // 28 // This gets an import block of its own because it's such staggeringly bad 29 // practice. It's here because (1) it always has been, just not quite so 30 // explicitly and (2) even if we had the state watchers implemented as 31 // juju/watcher~s rather than juju/state/watcher~s -- which we don't, so 32 // it's misleading to use those *Chan types etc -- we don't yet have any 33 // ability to transform watcher output in the apiserver layer, so we're 34 // kinda stuck producing what we always have. 35 // 36 // See RelationUnitsWatcher below. 37 "github.com/juju/juju/apiserver/params" 38 ) 39 40 var watchLogger = loggo.GetLogger("juju.state.watch") 41 42 // Watcher is implemented by all watchers; the actual 43 // changes channel is returned by a watcher-specific 44 // Changes method. 45 type Watcher interface { 46 // Kill asks the watcher to stop without waiting for it do so. 47 Kill() 48 // Wait waits for the watcher to die and returns any 49 // error encountered when it was running. 50 Wait() error 51 // Stop kills the watcher, then waits for it to die. 52 Stop() error 53 // Err returns any error encountered while the watcher 54 // has been running. 55 Err() error 56 } 57 58 // NotifyWatcher generates signals when something changes, but it does not 59 // return any content for those changes 60 type NotifyWatcher interface { 61 Watcher 62 Changes() <-chan struct{} 63 } 64 65 // StringsWatcher generates signals when something changes, returning 66 // the changes as a list of strings. 67 type StringsWatcher interface { 68 Watcher 69 Changes() <-chan []string 70 } 71 72 // RelationUnitsWatcher generates signals when units enter or leave 73 // the scope of a RelationUnit, and changes to the settings of those 74 // units known to have entered. 75 type RelationUnitsWatcher interface { 76 Watcher 77 78 // Note that it's not very nice exposing a params type directly here. This 79 // is a continuation of existing bad behaviour and not good practice; do 80 // not use this as a model. (FWIW, it used to be in multiwatcher; which is 81 // also api-ey; and the multiwatcher type was used directly in params 82 // anyway.) 83 Changes() <-chan params.RelationUnitsChange 84 } 85 86 // newCommonWatcher exists so that all embedders have a place from which 87 // to get a single TxnLogWatcher that will not be replaced in the lifetime 88 // of the embedder (and also to restrict the width of the interface by 89 // which they can access the rest of State, by storing st as a 90 // modelBackend). 91 func newCommonWatcher(st *State) commonWatcher { 92 return commonWatcher{ 93 st: st, 94 watcher: st.workers.TxnLogWatcher(), 95 } 96 } 97 98 // commonWatcher is part of all client watchers. 99 type commonWatcher struct { 100 st modelBackend 101 watcher workers.TxnLogWatcher 102 tomb tomb.Tomb 103 } 104 105 // Stop stops the watcher, and returns any error encountered while running 106 // or shutting down. 107 func (w *commonWatcher) Stop() error { 108 w.Kill() 109 return w.Wait() 110 } 111 112 // Kill kills the watcher without waiting for it to shut down. 113 func (w *commonWatcher) Kill() { 114 w.tomb.Kill(nil) 115 } 116 117 // Wait waits for the watcher to die and returns any 118 // error encountered when it was running. 119 func (w *commonWatcher) Wait() error { 120 return w.tomb.Wait() 121 } 122 123 // Err returns any error encountered while running or shutting down, or 124 // tomb.ErrStillAlive if the watcher is still running. 125 func (w *commonWatcher) Err() error { 126 return w.tomb.Err() 127 } 128 129 // collect combines the effects of the one change, and any further changes read 130 // from more in the next 10ms. The result map describes the existence, or not, 131 // of every id observed to have changed. If a value is read from the supplied 132 // stop chan, collect returns false immediately. 133 func collect(one watcher.Change, more <-chan watcher.Change, stop <-chan struct{}) (map[interface{}]bool, bool) { 134 var count int 135 result := map[interface{}]bool{} 136 handle := func(ch watcher.Change) { 137 count++ 138 result[ch.Id] = ch.Revno != -1 139 } 140 handle(one) 141 // TODO(fwereade): 2016-03-17 lp:1558657 142 timeout := time.After(10 * time.Millisecond) 143 for done := false; !done; { 144 select { 145 case <-stop: 146 return nil, false 147 case another := <-more: 148 handle(another) 149 case <-timeout: 150 done = true 151 } 152 } 153 watchLogger.Tracef("read %d events for %d documents", count, len(result)) 154 return result, true 155 } 156 157 func hasString(changes []string, name string) bool { 158 for _, v := range changes { 159 if v == name { 160 return true 161 } 162 } 163 return false 164 } 165 166 var _ Watcher = (*lifecycleWatcher)(nil) 167 168 // lifecycleWatcher notifies about lifecycle changes for a set of entities of 169 // the same kind. The first event emitted will contain the ids of all 170 // entities; subsequent events are emitted whenever one or more entities are 171 // added, or change their lifecycle state. After an entity is found to be 172 // Dead, no further event will include it. 173 type lifecycleWatcher struct { 174 commonWatcher 175 out chan []string 176 177 // coll is a function returning the mongo.Collection holding all 178 // interesting entities 179 coll func() (mongo.Collection, func()) 180 collName string 181 182 // members is used to select the initial set of interesting entities. 183 members bson.D 184 // filter is used to exclude events not affecting interesting entities. 185 filter func(interface{}) bool 186 // transform, if non-nil, is used to transform a document ID immediately 187 // prior to emitting to the out channel. 188 transform func(string) string 189 // life holds the most recent known life states of interesting entities. 190 life map[string]Life 191 } 192 193 func collFactory(st *State, collName string) func() (mongo.Collection, func()) { 194 return func() (mongo.Collection, func()) { 195 return st.getCollection(collName) 196 } 197 } 198 199 // WatchModels returns a StringsWatcher that notifies of changes 200 // to the lifecycles of all models. 201 func (st *State) WatchModels() StringsWatcher { 202 return newLifecycleWatcher(st, modelsC, nil, nil, nil) 203 } 204 205 // WatchModelVolumes returns a StringsWatcher that notifies of changes to 206 // the lifecycles of all model-scoped volumes. 207 func (st *State) WatchModelVolumes() StringsWatcher { 208 return st.watchModelMachinestorage(volumesC) 209 } 210 211 // WatchModelFilesystems returns a StringsWatcher that notifies of changes 212 // to the lifecycles of all model-scoped filesystems. 213 func (st *State) WatchModelFilesystems() StringsWatcher { 214 return st.watchModelMachinestorage(filesystemsC) 215 } 216 217 func (st *State) watchModelMachinestorage(collection string) StringsWatcher { 218 pattern := fmt.Sprintf("^%s$", st.docID(names.NumberSnippet)) 219 members := bson.D{{"_id", bson.D{{"$regex", pattern}}}} 220 filter := func(id interface{}) bool { 221 k, err := st.strictLocalID(id.(string)) 222 if err != nil { 223 return false 224 } 225 return !strings.Contains(k, "/") 226 } 227 return newLifecycleWatcher(st, collection, members, filter, nil) 228 } 229 230 // WatchMachineVolumes returns a StringsWatcher that notifies of changes to 231 // the lifecycles of all volumes scoped to the specified machine. 232 func (st *State) WatchMachineVolumes(m names.MachineTag) StringsWatcher { 233 return st.watchMachineStorage(m, volumesC) 234 } 235 236 // WatchMachineFilesystems returns a StringsWatcher that notifies of changes 237 // to the lifecycles of all filesystems scoped to the specified machine. 238 func (st *State) WatchMachineFilesystems(m names.MachineTag) StringsWatcher { 239 return st.watchMachineStorage(m, filesystemsC) 240 } 241 242 func (st *State) watchMachineStorage(m names.MachineTag, collection string) StringsWatcher { 243 pattern := fmt.Sprintf("^%s/%s$", st.docID(m.Id()), names.NumberSnippet) 244 members := bson.D{{"_id", bson.D{{"$regex", pattern}}}} 245 prefix := m.Id() + "/" 246 filter := func(id interface{}) bool { 247 k, err := st.strictLocalID(id.(string)) 248 if err != nil { 249 return false 250 } 251 return strings.HasPrefix(k, prefix) 252 } 253 return newLifecycleWatcher(st, collection, members, filter, nil) 254 } 255 256 // WatchEnvironVolumeAttachments returns a StringsWatcher that notifies of 257 // changes to the lifecycles of all volume attachments related to environ- 258 // scoped volumes. 259 func (st *State) WatchEnvironVolumeAttachments() StringsWatcher { 260 return st.watchModelMachinestorageAttachments(volumeAttachmentsC) 261 } 262 263 // WatchEnvironFilesystemAttachments returns a StringsWatcher that notifies 264 // of changes to the lifecycles of all filesystem attachments related to 265 // environ-scoped filesystems. 266 func (st *State) WatchEnvironFilesystemAttachments() StringsWatcher { 267 return st.watchModelMachinestorageAttachments(filesystemAttachmentsC) 268 } 269 270 func (st *State) watchModelMachinestorageAttachments(collection string) StringsWatcher { 271 pattern := fmt.Sprintf("^%s.*:%s$", st.docID(""), names.NumberSnippet) 272 members := bson.D{{"_id", bson.D{{"$regex", pattern}}}} 273 filter := func(id interface{}) bool { 274 k, err := st.strictLocalID(id.(string)) 275 if err != nil { 276 return false 277 } 278 colon := strings.IndexRune(k, ':') 279 if colon == -1 { 280 return false 281 } 282 return !strings.Contains(k[colon+1:], "/") 283 } 284 return newLifecycleWatcher(st, collection, members, filter, nil) 285 } 286 287 // WatchMachineVolumeAttachments returns a StringsWatcher that notifies of 288 // changes to the lifecycles of all volume attachments related to the specified 289 // machine, for volumes scoped to the machine. 290 func (st *State) WatchMachineVolumeAttachments(m names.MachineTag) StringsWatcher { 291 return st.watchMachineStorageAttachments(m, volumeAttachmentsC) 292 } 293 294 // WatchMachineFilesystemAttachments returns a StringsWatcher that notifies of 295 // changes to the lifecycles of all filesystem attachments related to the specified 296 // machine, for filesystems scoped to the machine. 297 func (st *State) WatchMachineFilesystemAttachments(m names.MachineTag) StringsWatcher { 298 return st.watchMachineStorageAttachments(m, filesystemAttachmentsC) 299 } 300 301 func (st *State) watchMachineStorageAttachments(m names.MachineTag, collection string) StringsWatcher { 302 pattern := fmt.Sprintf("^%s:%s/.*", st.docID(m.Id()), m.Id()) 303 members := bson.D{{"_id", bson.D{{"$regex", pattern}}}} 304 prefix := m.Id() + fmt.Sprintf(":%s/", m.Id()) 305 filter := func(id interface{}) bool { 306 k, err := st.strictLocalID(id.(string)) 307 if err != nil { 308 return false 309 } 310 return strings.HasPrefix(k, prefix) 311 } 312 return newLifecycleWatcher(st, collection, members, filter, nil) 313 } 314 315 // WatchServices returns a StringsWatcher that notifies of changes to 316 // the lifecycles of the services in the model. 317 func (st *State) WatchServices() StringsWatcher { 318 return newLifecycleWatcher(st, applicationsC, nil, isLocalID(st), nil) 319 } 320 321 // WatchStorageAttachments returns a StringsWatcher that notifies of 322 // changes to the lifecycles of all storage instances attached to the 323 // specified unit. 324 func (st *State) WatchStorageAttachments(unit names.UnitTag) StringsWatcher { 325 members := bson.D{{"unitid", unit.Id()}} 326 prefix := unitGlobalKey(unit.Id()) + "#" 327 filter := func(id interface{}) bool { 328 k, err := st.strictLocalID(id.(string)) 329 if err != nil { 330 return false 331 } 332 return strings.HasPrefix(k, prefix) 333 } 334 tr := func(id string) string { 335 // Transform storage attachment document ID to storage ID. 336 return id[len(prefix):] 337 } 338 return newLifecycleWatcher(st, storageAttachmentsC, members, filter, tr) 339 } 340 341 // WatchUnits returns a StringsWatcher that notifies of changes to the 342 // lifecycles of units of s. 343 func (s *Application) WatchUnits() StringsWatcher { 344 members := bson.D{{"application", s.doc.Name}} 345 prefix := s.doc.Name + "/" 346 filter := func(unitDocID interface{}) bool { 347 unitName, err := s.st.strictLocalID(unitDocID.(string)) 348 if err != nil { 349 return false 350 } 351 return strings.HasPrefix(unitName, prefix) 352 } 353 return newLifecycleWatcher(s.st, unitsC, members, filter, nil) 354 } 355 356 // WatchRelations returns a StringsWatcher that notifies of changes to the 357 // lifecycles of relations involving s. 358 func (s *Application) WatchRelations() StringsWatcher { 359 prefix := s.doc.Name + ":" 360 infix := " " + prefix 361 filter := func(id interface{}) bool { 362 k, err := s.st.strictLocalID(id.(string)) 363 if err != nil { 364 return false 365 } 366 out := strings.HasPrefix(k, prefix) || strings.Contains(k, infix) 367 return out 368 } 369 370 members := bson.D{{"endpoints.applicationname", s.doc.Name}} 371 return newLifecycleWatcher(s.st, relationsC, members, filter, nil) 372 } 373 374 // WatchModelMachines returns a StringsWatcher that notifies of changes to 375 // the lifecycles of the machines (but not containers) in the model. 376 func (st *State) WatchModelMachines() StringsWatcher { 377 members := bson.D{{"$or", []bson.D{ 378 {{"containertype", ""}}, 379 {{"containertype", bson.D{{"$exists", false}}}}, 380 }}} 381 filter := func(id interface{}) bool { 382 k, err := st.strictLocalID(id.(string)) 383 if err != nil { 384 return false 385 } 386 return !strings.Contains(k, "/") 387 } 388 return newLifecycleWatcher(st, machinesC, members, filter, nil) 389 } 390 391 // WatchContainers returns a StringsWatcher that notifies of changes to the 392 // lifecycles of containers of the specified type on a machine. 393 func (m *Machine) WatchContainers(ctype instance.ContainerType) StringsWatcher { 394 isChild := fmt.Sprintf("^%s/%s/%s$", m.doc.DocID, ctype, names.NumberSnippet) 395 return m.containersWatcher(isChild) 396 } 397 398 // WatchAllContainers returns a StringsWatcher that notifies of changes to the 399 // lifecycles of all containers on a machine. 400 func (m *Machine) WatchAllContainers() StringsWatcher { 401 isChild := fmt.Sprintf("^%s/%s/%s$", m.doc.DocID, names.ContainerTypeSnippet, names.NumberSnippet) 402 return m.containersWatcher(isChild) 403 } 404 405 func (m *Machine) containersWatcher(isChildRegexp string) StringsWatcher { 406 members := bson.D{{"_id", bson.D{{"$regex", isChildRegexp}}}} 407 compiled := regexp.MustCompile(isChildRegexp) 408 filter := func(key interface{}) bool { 409 k := key.(string) 410 _, err := m.st.strictLocalID(k) 411 if err != nil { 412 return false 413 } 414 return compiled.MatchString(k) 415 } 416 return newLifecycleWatcher(m.st, machinesC, members, filter, nil) 417 } 418 419 func newLifecycleWatcher( 420 st *State, 421 collName string, 422 members bson.D, 423 filter func(key interface{}) bool, 424 transform func(id string) string, 425 ) StringsWatcher { 426 w := &lifecycleWatcher{ 427 commonWatcher: newCommonWatcher(st), 428 coll: collFactory(st, collName), 429 collName: collName, 430 members: members, 431 filter: filter, 432 transform: transform, 433 life: make(map[string]Life), 434 out: make(chan []string), 435 } 436 go func() { 437 defer w.tomb.Done() 438 defer close(w.out) 439 w.tomb.Kill(w.loop()) 440 }() 441 return w 442 } 443 444 type lifeDoc struct { 445 Id string `bson:"_id"` 446 Life Life 447 } 448 449 var lifeFields = bson.D{{"_id", 1}, {"life", 1}} 450 451 // Changes returns the event channel for the LifecycleWatcher. 452 func (w *lifecycleWatcher) Changes() <-chan []string { 453 return w.out 454 } 455 456 func (w *lifecycleWatcher) initial() (set.Strings, error) { 457 coll, closer := w.coll() 458 defer closer() 459 460 ids := make(set.Strings) 461 var doc lifeDoc 462 iter := coll.Find(w.members).Select(lifeFields).Iter() 463 for iter.Next(&doc) { 464 id := w.st.localID(doc.Id) 465 ids.Add(id) 466 if doc.Life != Dead { 467 w.life[id] = doc.Life 468 } 469 } 470 return ids, iter.Close() 471 } 472 473 func (w *lifecycleWatcher) merge(ids set.Strings, updates map[interface{}]bool) error { 474 coll, closer := w.coll() 475 defer closer() 476 477 // Separate ids into those thought to exist and those known to be removed. 478 var changed []string 479 latest := make(map[string]Life) 480 for docID, exists := range updates { 481 switch docID := docID.(type) { 482 case string: 483 if exists { 484 changed = append(changed, docID) 485 } else { 486 latest[w.st.localID(docID)] = Dead 487 } 488 default: 489 return errors.Errorf("id is not of type string, got %T", docID) 490 } 491 } 492 493 // Collect life states from ids thought to exist. Any that don't actually 494 // exist are ignored (we'll hear about them in the next set of updates -- 495 // all that's actually happened in that situation is that the watcher 496 // events have lagged a little behind reality). 497 iter := coll.Find(bson.D{{"_id", bson.D{{"$in", changed}}}}).Select(lifeFields).Iter() 498 var doc lifeDoc 499 for iter.Next(&doc) { 500 latest[w.st.localID(doc.Id)] = doc.Life 501 } 502 if err := iter.Close(); err != nil { 503 return err 504 } 505 506 // Add to ids any whose life state is known to have changed. 507 for id, newLife := range latest { 508 gone := newLife == Dead 509 oldLife, known := w.life[id] 510 switch { 511 case known && gone: 512 delete(w.life, id) 513 case !known && !gone: 514 w.life[id] = newLife 515 case known && newLife != oldLife: 516 w.life[id] = newLife 517 default: 518 continue 519 } 520 ids.Add(id) 521 } 522 return nil 523 } 524 525 // ErrStateClosed is returned from watchers if their underlying 526 // state connection has been closed. 527 var ErrStateClosed = fmt.Errorf("state has been closed") 528 529 // stateWatcherDeadError processes the error received when the watcher 530 // inside a state connection dies. If the State has been closed, the 531 // watcher will have been stopped and error will be nil, so we ensure 532 // that higher level watchers return a non-nil error in that case, as 533 // watchers are not expected to die unexpectedly without an error. 534 func stateWatcherDeadError(err error) error { 535 if err != nil { 536 return err 537 } 538 return ErrStateClosed 539 } 540 541 func (w *lifecycleWatcher) loop() error { 542 in := make(chan watcher.Change) 543 w.watcher.WatchCollectionWithFilter(w.collName, in, w.filter) 544 defer w.watcher.UnwatchCollection(w.collName, in) 545 ids, err := w.initial() 546 if err != nil { 547 return err 548 } 549 out := w.out 550 for { 551 values := ids.Values() 552 if w.transform != nil { 553 for i, v := range values { 554 values[i] = w.transform(v) 555 } 556 } 557 select { 558 case <-w.tomb.Dying(): 559 return tomb.ErrDying 560 case <-w.watcher.Dead(): 561 return stateWatcherDeadError(w.watcher.Err()) 562 case ch := <-in: 563 updates, ok := collect(ch, in, w.tomb.Dying()) 564 if !ok { 565 return tomb.ErrDying 566 } 567 if err := w.merge(ids, updates); err != nil { 568 return err 569 } 570 if !ids.IsEmpty() { 571 out = w.out 572 } 573 case out <- values: 574 ids = make(set.Strings) 575 out = nil 576 } 577 } 578 } 579 580 // minUnitsWatcher notifies about MinUnits changes of the services requiring 581 // a minimum number of units to be alive. The first event returned by the 582 // watcher is the set of application names requiring a minimum number of units. 583 // Subsequent events are generated when a service increases MinUnits, or when 584 // one or more units belonging to a service are destroyed. 585 type minUnitsWatcher struct { 586 commonWatcher 587 known map[string]int 588 out chan []string 589 } 590 591 var _ Watcher = (*minUnitsWatcher)(nil) 592 593 func newMinUnitsWatcher(st *State) StringsWatcher { 594 w := &minUnitsWatcher{ 595 commonWatcher: newCommonWatcher(st), 596 known: make(map[string]int), 597 out: make(chan []string), 598 } 599 go func() { 600 defer w.tomb.Done() 601 defer close(w.out) 602 w.tomb.Kill(w.loop()) 603 }() 604 return w 605 } 606 607 // WatchMinUnits returns a StringsWatcher for the minUnits collection 608 func (st *State) WatchMinUnits() StringsWatcher { 609 return newMinUnitsWatcher(st) 610 } 611 612 func (w *minUnitsWatcher) initial() (set.Strings, error) { 613 applicationnames := make(set.Strings) 614 var doc minUnitsDoc 615 newMinUnits, closer := w.st.getCollection(minUnitsC) 616 defer closer() 617 618 iter := newMinUnits.Find(nil).Iter() 619 for iter.Next(&doc) { 620 w.known[doc.ApplicationName] = doc.Revno 621 applicationnames.Add(doc.ApplicationName) 622 } 623 return applicationnames, iter.Close() 624 } 625 626 func (w *minUnitsWatcher) merge(applicationnames set.Strings, change watcher.Change) error { 627 applicationname := w.st.localID(change.Id.(string)) 628 if change.Revno == -1 { 629 delete(w.known, applicationname) 630 applicationnames.Remove(applicationname) 631 return nil 632 } 633 doc := minUnitsDoc{} 634 newMinUnits, closer := w.st.getCollection(minUnitsC) 635 defer closer() 636 if err := newMinUnits.FindId(change.Id).One(&doc); err != nil { 637 return err 638 } 639 revno, known := w.known[applicationname] 640 w.known[applicationname] = doc.Revno 641 if !known || doc.Revno > revno { 642 applicationnames.Add(applicationname) 643 } 644 return nil 645 } 646 647 func (w *minUnitsWatcher) loop() (err error) { 648 ch := make(chan watcher.Change) 649 w.watcher.WatchCollectionWithFilter(minUnitsC, ch, isLocalID(w.st)) 650 defer w.watcher.UnwatchCollection(minUnitsC, ch) 651 applicationnames, err := w.initial() 652 if err != nil { 653 return err 654 } 655 out := w.out 656 for { 657 select { 658 case <-w.tomb.Dying(): 659 return tomb.ErrDying 660 case <-w.watcher.Dead(): 661 return stateWatcherDeadError(w.watcher.Err()) 662 case change := <-ch: 663 if err = w.merge(applicationnames, change); err != nil { 664 return err 665 } 666 if !applicationnames.IsEmpty() { 667 out = w.out 668 } 669 case out <- applicationnames.Values(): 670 out = nil 671 applicationnames = set.NewStrings() 672 } 673 } 674 } 675 676 func (w *minUnitsWatcher) Changes() <-chan []string { 677 return w.out 678 } 679 680 // scopeInfo holds a RelationScopeWatcher's last-delivered state, and any 681 // known but undelivered changes thereto. 682 type scopeInfo struct { 683 base map[string]bool 684 diff map[string]bool 685 } 686 687 func (info *scopeInfo) add(name string) { 688 if info.base[name] { 689 delete(info.diff, name) 690 } else { 691 info.diff[name] = true 692 } 693 } 694 695 func (info *scopeInfo) remove(name string) { 696 if info.base[name] { 697 info.diff[name] = false 698 } else { 699 delete(info.diff, name) 700 } 701 } 702 703 func (info *scopeInfo) commit() { 704 for name, change := range info.diff { 705 if change { 706 info.base[name] = true 707 } else { 708 delete(info.base, name) 709 } 710 } 711 info.diff = map[string]bool{} 712 } 713 714 func (info *scopeInfo) hasChanges() bool { 715 return len(info.diff) > 0 716 } 717 718 func (info *scopeInfo) changes() *RelationScopeChange { 719 ch := &RelationScopeChange{} 720 for name, change := range info.diff { 721 if change { 722 ch.Entered = append(ch.Entered, name) 723 } else { 724 ch.Left = append(ch.Left, name) 725 } 726 } 727 return ch 728 } 729 730 var _ Watcher = (*RelationScopeWatcher)(nil) 731 732 // RelationScopeChange contains information about units that have 733 // entered or left a particular scope. 734 type RelationScopeChange struct { 735 Entered []string 736 Left []string 737 } 738 739 // RelationScopeWatcher observes changes to the set of units 740 // in a particular relation scope. 741 type RelationScopeWatcher struct { 742 commonWatcher 743 prefix string 744 ignore string 745 out chan *RelationScopeChange 746 } 747 748 func newRelationScopeWatcher(st *State, scope, ignore string) *RelationScopeWatcher { 749 w := &RelationScopeWatcher{ 750 commonWatcher: newCommonWatcher(st), 751 prefix: scope + "#", 752 ignore: ignore, 753 out: make(chan *RelationScopeChange), 754 } 755 go func() { 756 defer w.tomb.Done() 757 defer close(w.out) 758 w.tomb.Kill(w.loop()) 759 }() 760 return w 761 } 762 763 // Changes returns a channel that will receive changes when units enter and 764 // leave a relation scope. The Entered field in the first event on the channel 765 // holds the initial state. 766 func (w *RelationScopeWatcher) Changes() <-chan *RelationScopeChange { 767 return w.out 768 } 769 770 // initialInfo returns an uncommitted scopeInfo with the current set of units. 771 func (w *RelationScopeWatcher) initialInfo() (info *scopeInfo, err error) { 772 relationScopes, closer := w.st.getCollection(relationScopesC) 773 defer closer() 774 775 docs := []relationScopeDoc{} 776 sel := bson.D{ 777 {"key", bson.D{{"$regex", "^" + w.prefix}}}, 778 {"departing", bson.D{{"$ne", true}}}, 779 } 780 if err = relationScopes.Find(sel).All(&docs); err != nil { 781 return nil, err 782 } 783 info = &scopeInfo{ 784 base: map[string]bool{}, 785 diff: map[string]bool{}, 786 } 787 for _, doc := range docs { 788 if name := doc.unitName(); name != w.ignore { 789 info.add(name) 790 } 791 } 792 return info, nil 793 } 794 795 // mergeChanges updates info with the contents of the changes in ids. False 796 // values are always treated as removed; true values cause the associated 797 // document to be read, and whether it's treated as added or removed depends 798 // on the value of the document's Departing field. 799 func (w *RelationScopeWatcher) mergeChanges(info *scopeInfo, ids map[interface{}]bool) error { 800 relationScopes, closer := w.st.getCollection(relationScopesC) 801 defer closer() 802 803 var existIds []string 804 for id, exists := range ids { 805 switch id := id.(type) { 806 case string: 807 if exists { 808 existIds = append(existIds, id) 809 } else { 810 key, err := w.st.strictLocalID(id) 811 if err != nil { 812 return errors.Trace(err) 813 } 814 info.remove(unitNameFromScopeKey(key)) 815 } 816 default: 817 logger.Warningf("ignoring bad relation scope id: %#v", id) 818 } 819 } 820 var docs []relationScopeDoc 821 sel := bson.D{{"_id", bson.D{{"$in", existIds}}}} 822 if err := relationScopes.Find(sel).All(&docs); err != nil { 823 return err 824 } 825 for _, doc := range docs { 826 name := doc.unitName() 827 if doc.Departing { 828 info.remove(name) 829 } else if name != w.ignore { 830 info.add(name) 831 } 832 } 833 return nil 834 } 835 836 func (w *RelationScopeWatcher) loop() error { 837 in := make(chan watcher.Change) 838 fullPrefix := w.st.docID(w.prefix) 839 filter := func(id interface{}) bool { 840 return strings.HasPrefix(id.(string), fullPrefix) 841 } 842 w.watcher.WatchCollectionWithFilter(relationScopesC, in, filter) 843 defer w.watcher.UnwatchCollection(relationScopesC, in) 844 info, err := w.initialInfo() 845 if err != nil { 846 return err 847 } 848 sent := false 849 out := w.out 850 for { 851 select { 852 case <-w.watcher.Dead(): 853 return stateWatcherDeadError(w.watcher.Err()) 854 case <-w.tomb.Dying(): 855 return tomb.ErrDying 856 case ch := <-in: 857 latest, ok := collect(ch, in, w.tomb.Dying()) 858 if !ok { 859 return tomb.ErrDying 860 } 861 if err := w.mergeChanges(info, latest); err != nil { 862 return err 863 } 864 if info.hasChanges() { 865 out = w.out 866 } else if sent { 867 out = nil 868 } 869 case out <- info.changes(): 870 info.commit() 871 sent = true 872 out = nil 873 } 874 } 875 } 876 877 // relationUnitsWatcher sends notifications of units entering and leaving the 878 // scope of a RelationUnit, and changes to the settings of those units known 879 // to have entered. 880 type relationUnitsWatcher struct { 881 commonWatcher 882 sw *RelationScopeWatcher 883 watching set.Strings 884 updates chan watcher.Change 885 out chan params.RelationUnitsChange 886 } 887 888 // Watch returns a watcher that notifies of changes to conterpart units in 889 // the relation. 890 func (ru *RelationUnit) Watch() RelationUnitsWatcher { 891 return newRelationUnitsWatcher(ru) 892 } 893 894 func newRelationUnitsWatcher(ru *RelationUnit) RelationUnitsWatcher { 895 w := &relationUnitsWatcher{ 896 commonWatcher: newCommonWatcher(ru.st), 897 sw: ru.WatchScope(), 898 watching: make(set.Strings), 899 updates: make(chan watcher.Change), 900 out: make(chan params.RelationUnitsChange), 901 } 902 go func() { 903 defer w.finish() 904 w.tomb.Kill(w.loop()) 905 }() 906 return w 907 } 908 909 // Changes returns a channel that will receive the changes to 910 // counterpart units in a relation. The first event on the 911 // channel holds the initial state of the relation in its 912 // Changed field. 913 func (w *relationUnitsWatcher) Changes() <-chan params.RelationUnitsChange { 914 return w.out 915 } 916 917 func emptyRelationUnitsChanges(changes *params.RelationUnitsChange) bool { 918 return len(changes.Changed)+len(changes.Departed) == 0 919 } 920 921 func setRelationUnitChangeVersion(changes *params.RelationUnitsChange, key string, version int64) { 922 name := unitNameFromScopeKey(key) 923 settings := params.UnitSettings{Version: version} 924 if changes.Changed == nil { 925 changes.Changed = map[string]params.UnitSettings{} 926 } 927 changes.Changed[name] = settings 928 } 929 930 // mergeSettings reads the relation settings node for the unit with the 931 // supplied key, and sets a value in the Changed field keyed on the unit's 932 // name. It returns the mgo/txn revision number of the settings node. 933 func (w *relationUnitsWatcher) mergeSettings(changes *params.RelationUnitsChange, key string) (int64, error) { 934 var doc struct { 935 TxnRevno int64 `bson:"txn-revno"` 936 Version int64 `bson:"version"` 937 } 938 if err := readSettingsDocInto(w.st, settingsC, key, &doc); err != nil { 939 return -1, err 940 } 941 setRelationUnitChangeVersion(changes, key, doc.Version) 942 return doc.TxnRevno, nil 943 } 944 945 // mergeScope starts and stops settings watches on the units entering and 946 // leaving the scope in the supplied RelationScopeChange event, and applies 947 // the expressed changes to the supplied RelationUnitsChange event. 948 func (w *relationUnitsWatcher) mergeScope(changes *params.RelationUnitsChange, c *RelationScopeChange) error { 949 for _, name := range c.Entered { 950 key := w.sw.prefix + name 951 docID := w.st.docID(key) 952 revno, err := w.mergeSettings(changes, key) 953 if err != nil { 954 return err 955 } 956 changes.Departed = remove(changes.Departed, name) 957 w.watcher.Watch(settingsC, docID, revno, w.updates) 958 w.watching.Add(docID) 959 } 960 for _, name := range c.Left { 961 key := w.sw.prefix + name 962 docID := w.st.docID(key) 963 changes.Departed = append(changes.Departed, name) 964 if changes.Changed != nil { 965 delete(changes.Changed, name) 966 } 967 w.watcher.Unwatch(settingsC, docID, w.updates) 968 w.watching.Remove(docID) 969 } 970 return nil 971 } 972 973 // remove removes s from strs and returns the modified slice. 974 func remove(strs []string, s string) []string { 975 for i, v := range strs { 976 if s == v { 977 strs[i] = strs[len(strs)-1] 978 return strs[:len(strs)-1] 979 } 980 } 981 return strs 982 } 983 984 func (w *relationUnitsWatcher) finish() { 985 watcher.Stop(w.sw, &w.tomb) 986 for _, watchedValue := range w.watching.Values() { 987 w.watcher.Unwatch(settingsC, watchedValue, w.updates) 988 } 989 close(w.updates) 990 close(w.out) 991 w.tomb.Done() 992 } 993 994 func (w *relationUnitsWatcher) loop() (err error) { 995 var ( 996 sentInitial bool 997 changes params.RelationUnitsChange 998 out chan<- params.RelationUnitsChange 999 ) 1000 for { 1001 select { 1002 case <-w.watcher.Dead(): 1003 return stateWatcherDeadError(w.watcher.Err()) 1004 case <-w.tomb.Dying(): 1005 return tomb.ErrDying 1006 case c, ok := <-w.sw.Changes(): 1007 if !ok { 1008 return watcher.EnsureErr(w.sw) 1009 } 1010 if err = w.mergeScope(&changes, c); err != nil { 1011 return err 1012 } 1013 if !sentInitial || !emptyRelationUnitsChanges(&changes) { 1014 out = w.out 1015 } else { 1016 out = nil 1017 } 1018 case c := <-w.updates: 1019 id, ok := c.Id.(string) 1020 if !ok { 1021 logger.Warningf("ignoring bad relation scope id: %#v", c.Id) 1022 } 1023 if _, err := w.mergeSettings(&changes, id); err != nil { 1024 return err 1025 } 1026 out = w.out 1027 case out <- changes: 1028 sentInitial = true 1029 changes = params.RelationUnitsChange{} 1030 out = nil 1031 } 1032 } 1033 } 1034 1035 // unitsWatcher notifies of changes to a set of units. Notifications will be 1036 // sent when units enter or leave the set, and when units in the set change 1037 // their lifecycle status. The initial event contains all units in the set, 1038 // regardless of lifecycle status; once a unit observed to be Dead or removed 1039 // has been reported, it will not be reported again. 1040 type unitsWatcher struct { 1041 commonWatcher 1042 tag string 1043 getUnits func() ([]string, error) 1044 life map[string]Life 1045 in chan watcher.Change 1046 out chan []string 1047 } 1048 1049 var _ Watcher = (*unitsWatcher)(nil) 1050 1051 // WatchSubordinateUnits returns a StringsWatcher tracking the unit's subordinate units. 1052 func (u *Unit) WatchSubordinateUnits() StringsWatcher { 1053 u = &Unit{st: u.st, doc: u.doc} 1054 coll := unitsC 1055 getUnits := func() ([]string, error) { 1056 if err := u.Refresh(); err != nil { 1057 return nil, err 1058 } 1059 return u.doc.Subordinates, nil 1060 } 1061 return newUnitsWatcher(u.st, u.Tag(), getUnits, coll, u.doc.DocID) 1062 } 1063 1064 // WatchPrincipalUnits returns a StringsWatcher tracking the machine's principal 1065 // units. 1066 func (m *Machine) WatchPrincipalUnits() StringsWatcher { 1067 m = &Machine{st: m.st, doc: m.doc} 1068 coll := machinesC 1069 getUnits := func() ([]string, error) { 1070 if err := m.Refresh(); err != nil { 1071 return nil, err 1072 } 1073 return m.doc.Principals, nil 1074 } 1075 return newUnitsWatcher(m.st, m.Tag(), getUnits, coll, m.doc.DocID) 1076 } 1077 1078 func newUnitsWatcher(st *State, tag names.Tag, getUnits func() ([]string, error), coll, id string) StringsWatcher { 1079 w := &unitsWatcher{ 1080 commonWatcher: newCommonWatcher(st), 1081 tag: tag.String(), 1082 getUnits: getUnits, 1083 life: map[string]Life{}, 1084 in: make(chan watcher.Change), 1085 out: make(chan []string), 1086 } 1087 go func() { 1088 defer w.tomb.Done() 1089 defer close(w.out) 1090 w.tomb.Kill(w.loop(coll, id)) 1091 }() 1092 return w 1093 } 1094 1095 // Tag returns the tag of the entity whose units are being watched. 1096 func (w *unitsWatcher) Tag() string { 1097 return w.tag 1098 } 1099 1100 // Changes returns the UnitsWatcher's output channel. 1101 func (w *unitsWatcher) Changes() <-chan []string { 1102 return w.out 1103 } 1104 1105 // lifeWatchDoc holds the fields used in starting and maintaining a watch 1106 // on a entity's lifecycle. 1107 type lifeWatchDoc struct { 1108 Id string `bson:"_id"` 1109 Life Life 1110 TxnRevno int64 `bson:"txn-revno"` 1111 } 1112 1113 // lifeWatchFields specifies the fields of a lifeWatchDoc. 1114 var lifeWatchFields = bson.D{{"_id", 1}, {"life", 1}, {"txn-revno", 1}} 1115 1116 // initial returns every member of the tracked set. 1117 func (w *unitsWatcher) initial() ([]string, error) { 1118 initialNames, err := w.getUnits() 1119 if err != nil { 1120 return nil, err 1121 } 1122 newUnits, closer := w.st.getCollection(unitsC) 1123 defer closer() 1124 query := bson.D{{"name", bson.D{{"$in", initialNames}}}} 1125 docs := []lifeWatchDoc{} 1126 if err := newUnits.Find(query).Select(lifeWatchFields).All(&docs); err != nil { 1127 return nil, err 1128 } 1129 changes := []string{} 1130 for _, doc := range docs { 1131 unitName, err := w.st.strictLocalID(doc.Id) 1132 if err != nil { 1133 return nil, errors.Trace(err) 1134 } 1135 changes = append(changes, unitName) 1136 if doc.Life != Dead { 1137 w.life[unitName] = doc.Life 1138 w.watcher.Watch(unitsC, doc.Id, doc.TxnRevno, w.in) 1139 } 1140 } 1141 return changes, nil 1142 } 1143 1144 // update adds to and returns changes, such that it contains the names of any 1145 // non-Dead units to have entered or left the tracked set. 1146 func (w *unitsWatcher) update(changes []string) ([]string, error) { 1147 latest, err := w.getUnits() 1148 if err != nil { 1149 return nil, err 1150 } 1151 for _, name := range latest { 1152 if _, known := w.life[name]; !known { 1153 changes, err = w.merge(changes, name) 1154 if err != nil { 1155 return nil, err 1156 } 1157 } 1158 } 1159 for name := range w.life { 1160 if hasString(latest, name) { 1161 continue 1162 } 1163 if !hasString(changes, name) { 1164 changes = append(changes, name) 1165 } 1166 delete(w.life, name) 1167 w.watcher.Unwatch(unitsC, w.st.docID(name), w.in) 1168 } 1169 return changes, nil 1170 } 1171 1172 // merge adds to and returns changes, such that it contains the supplied unit 1173 // name if that unit is unknown and non-Dead, or has changed lifecycle status. 1174 func (w *unitsWatcher) merge(changes []string, name string) ([]string, error) { 1175 units, closer := w.st.getCollection(unitsC) 1176 defer closer() 1177 1178 unitDocID := w.st.docID(name) 1179 doc := lifeWatchDoc{} 1180 err := units.FindId(unitDocID).Select(lifeWatchFields).One(&doc) 1181 gone := false 1182 if err == mgo.ErrNotFound { 1183 gone = true 1184 } else if err != nil { 1185 return nil, err 1186 } else if doc.Life == Dead { 1187 gone = true 1188 } 1189 life, known := w.life[name] 1190 switch { 1191 case known && gone: 1192 delete(w.life, name) 1193 w.watcher.Unwatch(unitsC, unitDocID, w.in) 1194 case !known && !gone: 1195 w.watcher.Watch(unitsC, unitDocID, doc.TxnRevno, w.in) 1196 w.life[name] = doc.Life 1197 case known && life != doc.Life: 1198 w.life[name] = doc.Life 1199 default: 1200 return changes, nil 1201 } 1202 if !hasString(changes, name) { 1203 changes = append(changes, name) 1204 } 1205 return changes, nil 1206 } 1207 1208 func (w *unitsWatcher) loop(coll, id string) error { 1209 collection, closer := w.st.getCollection(coll) 1210 revno, err := getTxnRevno(collection, id) 1211 closer() 1212 if err != nil { 1213 return err 1214 } 1215 1216 w.watcher.Watch(coll, id, revno, w.in) 1217 defer func() { 1218 w.watcher.Unwatch(coll, id, w.in) 1219 for name := range w.life { 1220 w.watcher.Unwatch(unitsC, w.st.docID(name), w.in) 1221 } 1222 }() 1223 changes, err := w.initial() 1224 if err != nil { 1225 return err 1226 } 1227 rootLocalID := w.st.localID(id) 1228 out := w.out 1229 for { 1230 select { 1231 case <-w.watcher.Dead(): 1232 return stateWatcherDeadError(w.watcher.Err()) 1233 case <-w.tomb.Dying(): 1234 return tomb.ErrDying 1235 case c := <-w.in: 1236 localID := w.st.localID(c.Id.(string)) 1237 if localID == rootLocalID { 1238 changes, err = w.update(changes) 1239 } else { 1240 changes, err = w.merge(changes, localID) 1241 } 1242 if err != nil { 1243 return err 1244 } 1245 if len(changes) > 0 { 1246 out = w.out 1247 } 1248 case out <- changes: 1249 out = nil 1250 changes = nil 1251 } 1252 } 1253 } 1254 1255 // WatchHardwareCharacteristics returns a watcher for observing changes to a machine's hardware characteristics. 1256 func (m *Machine) WatchHardwareCharacteristics() NotifyWatcher { 1257 return newEntityWatcher(m.st, instanceDataC, m.doc.DocID) 1258 } 1259 1260 // WatchControllerInfo returns a NotifyWatcher for the controllers collection 1261 func (st *State) WatchControllerInfo() NotifyWatcher { 1262 return newEntityWatcher(st, controllersC, modelGlobalKey) 1263 } 1264 1265 // Watch returns a watcher for observing changes to a machine. 1266 func (m *Machine) Watch() NotifyWatcher { 1267 return newEntityWatcher(m.st, machinesC, m.doc.DocID) 1268 } 1269 1270 // Watch returns a watcher for observing changes to a service. 1271 func (s *Application) Watch() NotifyWatcher { 1272 return newEntityWatcher(s.st, applicationsC, s.doc.DocID) 1273 } 1274 1275 // WatchLeaderSettings returns a watcher for observing changed to a service's 1276 // leader settings. 1277 func (s *Application) WatchLeaderSettings() NotifyWatcher { 1278 docId := s.st.docID(leadershipSettingsKey(s.Name())) 1279 return newEntityWatcher(s.st, settingsC, docId) 1280 } 1281 1282 // Watch returns a watcher for observing changes to a unit. 1283 func (u *Unit) Watch() NotifyWatcher { 1284 return newEntityWatcher(u.st, unitsC, u.doc.DocID) 1285 } 1286 1287 // Watch returns a watcher for observing changes to an model. 1288 func (e *Model) Watch() NotifyWatcher { 1289 return newEntityWatcher(e.st, modelsC, e.doc.UUID) 1290 } 1291 1292 // WatchUpgradeInfo returns a watcher for observing changes to upgrade 1293 // synchronisation state. 1294 func (st *State) WatchUpgradeInfo() NotifyWatcher { 1295 return newEntityWatcher(st, upgradeInfoC, currentUpgradeId) 1296 } 1297 1298 // WatchRestoreInfoChanges returns a NotifyWatcher that will inform 1299 // when the restore status changes. 1300 func (st *State) WatchRestoreInfoChanges() NotifyWatcher { 1301 return newEntityWatcher(st, restoreInfoC, currentRestoreId) 1302 } 1303 1304 // WatchForModelConfigChanges returns a NotifyWatcher waiting for the Model 1305 // Config to change. 1306 func (st *State) WatchForModelConfigChanges() NotifyWatcher { 1307 return newEntityWatcher(st, settingsC, st.docID(modelGlobalKey)) 1308 } 1309 1310 // WatchForUnitAssignment watches for new services that request units to be 1311 // assigned to machines. 1312 func (st *State) WatchForUnitAssignment() StringsWatcher { 1313 return newcollectionWatcher(st, colWCfg{col: assignUnitC}) 1314 } 1315 1316 // WatchAPIHostPorts returns a NotifyWatcher that notifies 1317 // when the set of API addresses changes. 1318 func (st *State) WatchAPIHostPorts() NotifyWatcher { 1319 return newEntityWatcher(st, controllersC, apiHostPortsKey) 1320 } 1321 1322 // WatchStorageAttachment returns a watcher for observing changes 1323 // to a storage attachment. 1324 func (st *State) WatchStorageAttachment(s names.StorageTag, u names.UnitTag) NotifyWatcher { 1325 id := storageAttachmentId(u.Id(), s.Id()) 1326 return newEntityWatcher(st, storageAttachmentsC, st.docID(id)) 1327 } 1328 1329 // WatchVolumeAttachment returns a watcher for observing changes 1330 // to a volume attachment. 1331 func (st *State) WatchVolumeAttachment(m names.MachineTag, v names.VolumeTag) NotifyWatcher { 1332 id := volumeAttachmentId(m.Id(), v.Id()) 1333 return newEntityWatcher(st, volumeAttachmentsC, st.docID(id)) 1334 } 1335 1336 // WatchFilesystemAttachment returns a watcher for observing changes 1337 // to a filesystem attachment. 1338 func (st *State) WatchFilesystemAttachment(m names.MachineTag, f names.FilesystemTag) NotifyWatcher { 1339 id := filesystemAttachmentId(m.Id(), f.Id()) 1340 return newEntityWatcher(st, filesystemAttachmentsC, st.docID(id)) 1341 } 1342 1343 // WatchConfigSettings returns a watcher for observing changes to the 1344 // unit's service configuration settings. The unit must have a charm URL 1345 // set before this method is called, and the returned watcher will be 1346 // valid only while the unit's charm URL is not changed. 1347 // TODO(fwereade): this could be much smarter; if it were, uniter.Filter 1348 // could be somewhat simpler. 1349 func (u *Unit) WatchConfigSettings() (NotifyWatcher, error) { 1350 if u.doc.CharmURL == nil { 1351 return nil, fmt.Errorf("unit charm not set") 1352 } 1353 settingsKey := applicationSettingsKey(u.doc.Application, u.doc.CharmURL) 1354 return newEntityWatcher(u.st, settingsC, u.st.docID(settingsKey)), nil 1355 } 1356 1357 // WatchMeterStatus returns a watcher observing changes that affect the meter status 1358 // of a unit. 1359 func (u *Unit) WatchMeterStatus() NotifyWatcher { 1360 return newDocWatcher(u.st, []docKey{ 1361 { 1362 meterStatusC, 1363 u.st.docID(u.globalMeterStatusKey()), 1364 }, { 1365 metricsManagerC, 1366 metricsManagerKey, 1367 }, 1368 }) 1369 } 1370 1371 func newEntityWatcher(st *State, collName string, key interface{}) NotifyWatcher { 1372 return newDocWatcher(st, []docKey{{collName, key}}) 1373 } 1374 1375 // docWatcher watches for changes in 1 or more mongo documents 1376 // across collections. 1377 type docWatcher struct { 1378 commonWatcher 1379 out chan struct{} 1380 } 1381 1382 var _ Watcher = (*docWatcher)(nil) 1383 1384 // docKey identifies a single item in a single collection. 1385 // It's used as a parameter to newDocWatcher to specify 1386 // which documents should be watched. 1387 type docKey struct { 1388 coll string 1389 docId interface{} 1390 } 1391 1392 // newDocWatcher returns a new docWatcher. 1393 // docKeys identifies the documents that should be watched (their id and which collection they are in) 1394 func newDocWatcher(st *State, docKeys []docKey) NotifyWatcher { 1395 w := &docWatcher{ 1396 commonWatcher: newCommonWatcher(st), 1397 out: make(chan struct{}), 1398 } 1399 go func() { 1400 defer w.tomb.Done() 1401 defer close(w.out) 1402 w.tomb.Kill(w.loop(docKeys)) 1403 }() 1404 return w 1405 } 1406 1407 // Changes returns the event channel for the docWatcher. 1408 func (w *docWatcher) Changes() <-chan struct{} { 1409 return w.out 1410 } 1411 1412 // getTxnRevno returns the transaction revision number of the 1413 // given document id in the given collection. It is useful to enable 1414 // a watcher.Watcher to be primed with the correct revision 1415 // id. 1416 func getTxnRevno(coll mongo.Collection, id interface{}) (int64, error) { 1417 doc := struct { 1418 TxnRevno int64 `bson:"txn-revno"` 1419 }{} 1420 fields := bson.D{{"txn-revno", 1}} 1421 if err := coll.FindId(id).Select(fields).One(&doc); err == mgo.ErrNotFound { 1422 return -1, nil 1423 } else if err != nil { 1424 return 0, err 1425 } 1426 return doc.TxnRevno, nil 1427 } 1428 1429 func (w *docWatcher) loop(docKeys []docKey) error { 1430 in := make(chan watcher.Change) 1431 for _, k := range docKeys { 1432 coll, closer := w.st.getCollection(k.coll) 1433 txnRevno, err := getTxnRevno(coll, k.docId) 1434 closer() 1435 if err != nil { 1436 return err 1437 } 1438 w.watcher.Watch(coll.Name(), k.docId, txnRevno, in) 1439 defer w.watcher.Unwatch(coll.Name(), k.docId, in) 1440 } 1441 out := w.out 1442 for { 1443 select { 1444 case <-w.tomb.Dying(): 1445 return tomb.ErrDying 1446 case <-w.watcher.Dead(): 1447 return stateWatcherDeadError(w.watcher.Err()) 1448 case ch := <-in: 1449 if _, ok := collect(ch, in, w.tomb.Dying()); !ok { 1450 return tomb.ErrDying 1451 } 1452 out = w.out 1453 case out <- struct{}{}: 1454 out = nil 1455 } 1456 } 1457 } 1458 1459 // machineUnitsWatcher notifies about assignments and lifecycle changes 1460 // for all units of a machine. 1461 // 1462 // The first event emitted contains the unit names of all units currently 1463 // assigned to the machine, irrespective of their life state. From then on, 1464 // a new event is emitted whenever a unit is assigned to or unassigned from 1465 // the machine, or the lifecycle of a unit that is currently assigned to 1466 // the machine changes. 1467 // 1468 // After a unit is found to be Dead, no further event will include it. 1469 type machineUnitsWatcher struct { 1470 commonWatcher 1471 machine *Machine 1472 out chan []string 1473 in chan watcher.Change 1474 known map[string]Life 1475 } 1476 1477 var _ Watcher = (*machineUnitsWatcher)(nil) 1478 1479 // WatchUnits returns a new StringsWatcher watching m's units. 1480 func (m *Machine) WatchUnits() StringsWatcher { 1481 return newMachineUnitsWatcher(m) 1482 } 1483 1484 func newMachineUnitsWatcher(m *Machine) StringsWatcher { 1485 w := &machineUnitsWatcher{ 1486 commonWatcher: newCommonWatcher(m.st), 1487 out: make(chan []string), 1488 in: make(chan watcher.Change), 1489 known: make(map[string]Life), 1490 machine: &Machine{st: m.st, doc: m.doc}, // Copy so it may be freely refreshed 1491 } 1492 go func() { 1493 defer w.tomb.Done() 1494 defer close(w.out) 1495 w.tomb.Kill(w.loop()) 1496 }() 1497 return w 1498 } 1499 1500 // Changes returns the event channel for w. 1501 func (w *machineUnitsWatcher) Changes() <-chan []string { 1502 return w.out 1503 } 1504 1505 func (w *machineUnitsWatcher) updateMachine(pending []string) (new []string, err error) { 1506 err = w.machine.Refresh() 1507 if err != nil { 1508 return nil, err 1509 } 1510 for _, unitName := range w.machine.doc.Principals { 1511 if _, ok := w.known[unitName]; !ok { 1512 pending, err = w.merge(pending, unitName) 1513 if err != nil { 1514 return nil, err 1515 } 1516 } 1517 } 1518 return pending, nil 1519 } 1520 1521 func (w *machineUnitsWatcher) merge(pending []string, unitName string) (new []string, err error) { 1522 doc := unitDoc{} 1523 newUnits, closer := w.st.getCollection(unitsC) 1524 defer closer() 1525 err = newUnits.FindId(unitName).One(&doc) 1526 if err != nil && err != mgo.ErrNotFound { 1527 return nil, err 1528 } 1529 life, known := w.known[unitName] 1530 if err == mgo.ErrNotFound || doc.Principal == "" && (doc.MachineId == "" || doc.MachineId != w.machine.doc.Id) { 1531 // Unit was removed or unassigned from w.machine. 1532 if known { 1533 delete(w.known, unitName) 1534 w.watcher.Unwatch(unitsC, w.st.docID(unitName), w.in) 1535 if life != Dead && !hasString(pending, unitName) { 1536 pending = append(pending, unitName) 1537 } 1538 for _, subunitName := range doc.Subordinates { 1539 if sublife, subknown := w.known[subunitName]; subknown { 1540 delete(w.known, subunitName) 1541 w.watcher.Unwatch(unitsC, w.st.docID(subunitName), w.in) 1542 if sublife != Dead && !hasString(pending, subunitName) { 1543 pending = append(pending, subunitName) 1544 } 1545 } 1546 } 1547 } 1548 return pending, nil 1549 } 1550 if !known { 1551 w.watcher.Watch(unitsC, doc.DocID, doc.TxnRevno, w.in) 1552 pending = append(pending, unitName) 1553 } else if life != doc.Life && !hasString(pending, unitName) { 1554 pending = append(pending, unitName) 1555 } 1556 w.known[unitName] = doc.Life 1557 for _, subunitName := range doc.Subordinates { 1558 if _, ok := w.known[subunitName]; !ok { 1559 pending, err = w.merge(pending, subunitName) 1560 if err != nil { 1561 return nil, err 1562 } 1563 } 1564 } 1565 return pending, nil 1566 } 1567 1568 func (w *machineUnitsWatcher) loop() error { 1569 defer func() { 1570 for unit := range w.known { 1571 w.watcher.Unwatch(unitsC, w.st.docID(unit), w.in) 1572 } 1573 }() 1574 1575 machines, closer := w.st.getCollection(machinesC) 1576 revno, err := getTxnRevno(machines, w.machine.doc.DocID) 1577 closer() 1578 if err != nil { 1579 return err 1580 } 1581 machineCh := make(chan watcher.Change) 1582 w.watcher.Watch(machinesC, w.machine.doc.DocID, revno, machineCh) 1583 defer w.watcher.Unwatch(machinesC, w.machine.doc.DocID, machineCh) 1584 changes, err := w.updateMachine([]string(nil)) 1585 if err != nil { 1586 return err 1587 } 1588 out := w.out 1589 for { 1590 select { 1591 case <-w.watcher.Dead(): 1592 return stateWatcherDeadError(w.watcher.Err()) 1593 case <-w.tomb.Dying(): 1594 return tomb.ErrDying 1595 case <-machineCh: 1596 changes, err = w.updateMachine(changes) 1597 if err != nil { 1598 return err 1599 } 1600 if len(changes) > 0 { 1601 out = w.out 1602 } 1603 case c := <-w.in: 1604 changes, err = w.merge(changes, w.st.localID(c.Id.(string))) 1605 if err != nil { 1606 return err 1607 } 1608 if len(changes) > 0 { 1609 out = w.out 1610 } 1611 case out <- changes: 1612 out = nil 1613 changes = nil 1614 } 1615 } 1616 } 1617 1618 // machineAddressesWatcher notifies about changes to a machine's addresses. 1619 // 1620 // The first event emitted contains the addresses currently assigned to the 1621 // machine. From then on, a new event is emitted whenever the machine's 1622 // addresses change. 1623 type machineAddressesWatcher struct { 1624 commonWatcher 1625 machine *Machine 1626 out chan struct{} 1627 } 1628 1629 var _ Watcher = (*machineAddressesWatcher)(nil) 1630 1631 // WatchAddresses returns a new NotifyWatcher watching m's addresses. 1632 func (m *Machine) WatchAddresses() NotifyWatcher { 1633 return newMachineAddressesWatcher(m) 1634 } 1635 1636 func newMachineAddressesWatcher(m *Machine) NotifyWatcher { 1637 w := &machineAddressesWatcher{ 1638 commonWatcher: newCommonWatcher(m.st), 1639 out: make(chan struct{}), 1640 machine: &Machine{st: m.st, doc: m.doc}, // Copy so it may be freely refreshed 1641 } 1642 go func() { 1643 defer w.tomb.Done() 1644 defer close(w.out) 1645 w.tomb.Kill(w.loop()) 1646 }() 1647 return w 1648 } 1649 1650 // Changes returns the event channel for w. 1651 func (w *machineAddressesWatcher) Changes() <-chan struct{} { 1652 return w.out 1653 } 1654 1655 func (w *machineAddressesWatcher) loop() error { 1656 machines, closer := w.st.getCollection(machinesC) 1657 revno, err := getTxnRevno(machines, w.machine.doc.DocID) 1658 closer() 1659 if err != nil { 1660 return err 1661 } 1662 machineCh := make(chan watcher.Change) 1663 w.watcher.Watch(machinesC, w.machine.doc.DocID, revno, machineCh) 1664 defer w.watcher.Unwatch(machinesC, w.machine.doc.DocID, machineCh) 1665 addresses := w.machine.Addresses() 1666 out := w.out 1667 for { 1668 select { 1669 case <-w.watcher.Dead(): 1670 return stateWatcherDeadError(w.watcher.Err()) 1671 case <-w.tomb.Dying(): 1672 return tomb.ErrDying 1673 case <-machineCh: 1674 if err := w.machine.Refresh(); err != nil { 1675 return err 1676 } 1677 newAddresses := w.machine.Addresses() 1678 if !addressesEqual(newAddresses, addresses) { 1679 addresses = newAddresses 1680 out = w.out 1681 } 1682 case out <- struct{}{}: 1683 out = nil 1684 } 1685 } 1686 } 1687 1688 // WatchCleanups starts and returns a CleanupWatcher. 1689 func (st *State) WatchCleanups() NotifyWatcher { 1690 return newNotifyCollWatcher(st, cleanupsC, isLocalID(st)) 1691 } 1692 1693 // actionStatusWatcher is a StringsWatcher that filters notifications 1694 // to Action Id's that match the ActionReceiver and ActionStatus set 1695 // provided. 1696 type actionStatusWatcher struct { 1697 commonWatcher 1698 source chan watcher.Change 1699 sink chan []string 1700 receiverFilter bson.D 1701 statusFilter bson.D 1702 } 1703 1704 var _ StringsWatcher = (*actionStatusWatcher)(nil) 1705 1706 // newActionStatusWatcher returns the StringsWatcher that will notify 1707 // on changes to Actions with the given ActionReceiver and ActionStatus 1708 // filters. 1709 func newActionStatusWatcher(st *State, receivers []ActionReceiver, statusSet ...ActionStatus) StringsWatcher { 1710 watchLogger.Debugf("newActionStatusWatcher receivers:'%+v', statuses'%+v'", receivers, statusSet) 1711 w := &actionStatusWatcher{ 1712 commonWatcher: newCommonWatcher(st), 1713 source: make(chan watcher.Change), 1714 sink: make(chan []string), 1715 receiverFilter: actionReceiverInCollectionOp(receivers...), 1716 statusFilter: statusInCollectionOp(statusSet...), 1717 } 1718 1719 go func() { 1720 defer w.tomb.Done() 1721 defer close(w.sink) 1722 w.tomb.Kill(w.loop()) 1723 }() 1724 1725 return w 1726 } 1727 1728 // Changes returns the channel that sends the ids of any 1729 // Actions that change in the actionsC collection, if they 1730 // match the ActionReceiver and ActionStatus filters on the 1731 // watcher. 1732 func (w *actionStatusWatcher) Changes() <-chan []string { 1733 watchLogger.Tracef("actionStatusWatcher Changes()") 1734 return w.sink 1735 } 1736 1737 // loop performs the main event loop cycle, polling for changes and 1738 // responding to Changes requests 1739 func (w *actionStatusWatcher) loop() error { 1740 watchLogger.Tracef("actionStatusWatcher loop()") 1741 var ( 1742 changes []string 1743 in <-chan watcher.Change = w.source 1744 out chan<- []string = w.sink 1745 ) 1746 w.watcher.WatchCollectionWithFilter(actionsC, w.source, isLocalID(w.st)) 1747 defer w.watcher.UnwatchCollection(actionsC, w.source) 1748 1749 changes, err := w.initial() 1750 if err != nil { 1751 return err 1752 } 1753 1754 for { 1755 select { 1756 case <-w.tomb.Dying(): 1757 return tomb.ErrDying 1758 case <-w.watcher.Dead(): 1759 return stateWatcherDeadError(w.watcher.Err()) 1760 case ch := <-in: 1761 updates, ok := collect(ch, in, w.tomb.Dying()) 1762 if !ok { 1763 return tomb.ErrDying 1764 } 1765 if err := w.filterAndMergeIds(&changes, updates); err != nil { 1766 return err 1767 } 1768 if len(changes) > 0 { 1769 out = w.sink 1770 } 1771 case out <- changes: 1772 changes = nil 1773 out = nil 1774 } 1775 } 1776 } 1777 1778 // initial pre-loads the id's that have already been added to the 1779 // collection that would otherwise not normally trigger the watcher 1780 func (w *actionStatusWatcher) initial() ([]string, error) { 1781 watchLogger.Tracef("actionStatusWatcher initial()") 1782 return w.matchingIds() 1783 } 1784 1785 // matchingIds is a helper function that filters the actionsC collection 1786 // on the ActionReceivers and ActionStatus set defined on the watcher. 1787 // If ids are passed in the collection is further filtered to only 1788 // Actions that also have one of the supplied _id's. 1789 func (w *actionStatusWatcher) matchingIds(ids ...string) ([]string, error) { 1790 watchLogger.Tracef("actionStatusWatcher matchingIds() ids:'%+v'", ids) 1791 1792 coll, closer := w.st.getCollection(actionsC) 1793 defer closer() 1794 1795 idFilter := localIdInCollectionOp(w.st, ids...) 1796 query := bson.D{{"$and", []bson.D{idFilter, w.receiverFilter, w.statusFilter}}} 1797 iter := coll.Find(query).Iter() 1798 var found []string 1799 var doc actionDoc 1800 for iter.Next(&doc) { 1801 found = append(found, w.st.localID(doc.DocId)) 1802 } 1803 watchLogger.Debugf("actionStatusWatcher matchingIds() ids:'%+v', found:'%+v'", ids, found) 1804 return found, iter.Close() 1805 } 1806 1807 // filterAndMergeIds combines existing pending changes along with 1808 // updates from the upstream watcher, and updates the changes set. 1809 // If the upstream changes do not match the ActionReceivers and 1810 // ActionStatus set filters defined on the watcher, they are silently 1811 // dropped. 1812 func (w *actionStatusWatcher) filterAndMergeIds(changes *[]string, updates map[interface{}]bool) error { 1813 watchLogger.Tracef("actionStatusWatcher filterAndMergeIds(changes:'%+v', updates:'%+v')", changes, updates) 1814 var adds []string 1815 for id, exists := range updates { 1816 switch id := id.(type) { 1817 case string: 1818 localId := w.st.localID(id) 1819 chIx, idAlreadyInChangeset := indexOf(localId, *changes) 1820 if exists { 1821 if !idAlreadyInChangeset { 1822 adds = append(adds, localId) 1823 } 1824 } else { 1825 if idAlreadyInChangeset { 1826 // remove id from changes 1827 *changes = append([]string(*changes)[:chIx], []string(*changes)[chIx+1:]...) 1828 } 1829 } 1830 default: 1831 return errors.Errorf("id is not of type string, got %T", id) 1832 } 1833 } 1834 if len(adds) > 0 { 1835 ids, err := w.matchingIds(adds...) 1836 if err != nil { 1837 return errors.Trace(err) 1838 } 1839 *changes = append(*changes, ids...) 1840 } 1841 return nil 1842 } 1843 1844 // inCollectionOp takes a key name and a list of potential values and 1845 // returns a bson.D Op that will match on the supplied key and values. 1846 func inCollectionOp(key string, ids ...string) bson.D { 1847 ret := bson.D{} 1848 switch len(ids) { 1849 case 0: 1850 case 1: 1851 ret = append(ret, bson.DocElem{key, ids[0]}) 1852 default: 1853 ret = append(ret, bson.DocElem{key, bson.D{{"$in", ids}}}) 1854 } 1855 return ret 1856 } 1857 1858 // localIdInCollectionOp is a special form of inCollectionOp that just 1859 // converts id's to their model-uuid prefixed form. 1860 func localIdInCollectionOp(st modelBackend, localIds ...string) bson.D { 1861 ids := make([]string, len(localIds)) 1862 for i, id := range localIds { 1863 ids[i] = st.docID(id) 1864 } 1865 return inCollectionOp("_id", ids...) 1866 } 1867 1868 // actionReceiverInCollectionOp is a special form of inCollectionOp 1869 // that just converts []ActionReceiver to a []string containing the 1870 // ActionReceiver Name() values. 1871 func actionReceiverInCollectionOp(receivers ...ActionReceiver) bson.D { 1872 ids := make([]string, len(receivers)) 1873 for i, r := range receivers { 1874 ids[i] = r.Tag().Id() 1875 } 1876 return inCollectionOp("receiver", ids...) 1877 } 1878 1879 // statusInCollectionOp is a special form of inCollectionOp that just 1880 // converts []ActionStatus to a []string with the same values. 1881 func statusInCollectionOp(statusSet ...ActionStatus) bson.D { 1882 ids := make([]string, len(statusSet)) 1883 for i, s := range statusSet { 1884 ids[i] = string(s) 1885 } 1886 return inCollectionOp("status", ids...) 1887 } 1888 1889 // collectionWatcher is a StringsWatcher that watches for changes on the 1890 // specified collection that match a filter on the id. 1891 type collectionWatcher struct { 1892 commonWatcher 1893 colWCfg 1894 source chan watcher.Change 1895 sink chan []string 1896 } 1897 1898 // colWCfg contains the parameters for watching a collection. 1899 type colWCfg struct { 1900 col string 1901 filter func(interface{}) bool 1902 idconv func(string) string 1903 } 1904 1905 // newcollectionWatcher starts and returns a new StringsWatcher configured 1906 // with the given collection and filter function 1907 func newcollectionWatcher(st *State, cfg colWCfg) StringsWatcher { 1908 // Always ensure that there is at least filtering on the 1909 // model in place. 1910 backstop := isLocalID(st) 1911 if cfg.filter == nil { 1912 cfg.filter = backstop 1913 } else { 1914 innerFilter := cfg.filter 1915 cfg.filter = func(id interface{}) bool { 1916 if !backstop(id) { 1917 return false 1918 } 1919 return innerFilter(id) 1920 } 1921 } 1922 1923 w := &collectionWatcher{ 1924 colWCfg: cfg, 1925 commonWatcher: newCommonWatcher(st), 1926 source: make(chan watcher.Change), 1927 sink: make(chan []string), 1928 } 1929 1930 go func() { 1931 defer w.tomb.Done() 1932 defer close(w.sink) 1933 defer close(w.source) 1934 w.tomb.Kill(w.loop()) 1935 }() 1936 1937 return w 1938 } 1939 1940 // Changes returns the event channel for this watcher 1941 func (w *collectionWatcher) Changes() <-chan []string { 1942 return w.sink 1943 } 1944 1945 // loop performs the main event loop cycle, polling for changes and 1946 // responding to Changes requests 1947 func (w *collectionWatcher) loop() error { 1948 var ( 1949 changes []string 1950 in = (<-chan watcher.Change)(w.source) 1951 out = (chan<- []string)(w.sink) 1952 ) 1953 1954 w.watcher.WatchCollectionWithFilter(w.col, w.source, w.filter) 1955 defer w.watcher.UnwatchCollection(w.col, w.source) 1956 1957 changes, err := w.initial() 1958 if err != nil { 1959 return err 1960 } 1961 1962 for { 1963 select { 1964 case <-w.tomb.Dying(): 1965 return tomb.ErrDying 1966 case <-w.watcher.Dead(): 1967 return stateWatcherDeadError(w.watcher.Err()) 1968 case ch := <-in: 1969 updates, ok := collect(ch, in, w.tomb.Dying()) 1970 if !ok { 1971 return tomb.ErrDying 1972 } 1973 if err := w.mergeIds(&changes, updates); err != nil { 1974 return err 1975 } 1976 if len(changes) > 0 { 1977 out = w.sink 1978 } 1979 case out <- changes: 1980 changes = []string{} 1981 out = nil 1982 } 1983 } 1984 } 1985 1986 // makeIdFilter constructs a predicate to filter keys that have the 1987 // prefix matching one of the passed in ActionReceivers, or returns nil 1988 // if tags is empty 1989 func makeIdFilter(st *State, marker string, receivers ...ActionReceiver) func(interface{}) bool { 1990 if len(receivers) == 0 { 1991 return nil 1992 } 1993 ensureMarkerFn := ensureSuffixFn(marker) 1994 prefixes := make([]string, len(receivers)) 1995 for ix, receiver := range receivers { 1996 prefixes[ix] = st.docID(ensureMarkerFn(receiver.Tag().Id())) 1997 } 1998 1999 return func(key interface{}) bool { 2000 switch key.(type) { 2001 case string: 2002 for _, prefix := range prefixes { 2003 if strings.HasPrefix(key.(string), prefix) { 2004 return true 2005 } 2006 } 2007 default: 2008 watchLogger.Errorf("key is not type string, got %T", key) 2009 } 2010 return false 2011 } 2012 } 2013 2014 // initial pre-loads the id's that have already been added to the 2015 // collection that would otherwise not normally trigger the watcher 2016 func (w *collectionWatcher) initial() ([]string, error) { 2017 var ids []string 2018 var doc struct { 2019 DocId string `bson:"_id"` 2020 } 2021 coll, closer := w.st.getCollection(w.col) 2022 defer closer() 2023 iter := coll.Find(nil).Iter() 2024 for iter.Next(&doc) { 2025 if w.filter == nil || w.filter(doc.DocId) { 2026 id := w.st.localID(doc.DocId) 2027 if w.idconv != nil { 2028 id = w.idconv(id) 2029 } 2030 ids = append(ids, id) 2031 } 2032 } 2033 return ids, iter.Close() 2034 } 2035 2036 // mergeIds is used for merging actionId's and actionResultId's that 2037 // come in via the updates map. It cleans up the pending changes to 2038 // account for id's being removed before the watcher consumes them, 2039 // and to account for the potential overlap between the id's that were 2040 // pending before the watcher started, and the new id's detected by the 2041 // watcher. 2042 // Additionally, mergeIds strips the model UUID prefix from the id 2043 // before emitting it through the watcher. 2044 func (w *collectionWatcher) mergeIds(changes *[]string, updates map[interface{}]bool) error { 2045 return mergeIds(w.st, changes, updates, w.idconv) 2046 } 2047 2048 func mergeIds(st modelBackend, changes *[]string, updates map[interface{}]bool, idconv func(string) string) error { 2049 for val, idExists := range updates { 2050 id, ok := val.(string) 2051 if !ok { 2052 return errors.Errorf("id is not of type string, got %T", val) 2053 } 2054 2055 // Strip off the env UUID prefix. We only expect ids for a 2056 // single model. 2057 id, err := st.strictLocalID(id) 2058 if err != nil { 2059 return errors.Annotatef(err, "collection watcher") 2060 } 2061 2062 if idconv != nil { 2063 id = idconv(id) 2064 } 2065 2066 chIx, idAlreadyInChangeset := indexOf(id, *changes) 2067 if idExists { 2068 if !idAlreadyInChangeset { 2069 *changes = append(*changes, id) 2070 } 2071 } else { 2072 if idAlreadyInChangeset { 2073 // remove id from changes 2074 *changes = append([]string(*changes)[:chIx], []string(*changes)[chIx+1:]...) 2075 } 2076 } 2077 } 2078 return nil 2079 } 2080 2081 func actionNotificationIdToActionId(id string) string { 2082 ix := strings.Index(id, actionMarker) 2083 if ix == -1 { 2084 return id 2085 } 2086 return id[ix+len(actionMarker):] 2087 } 2088 2089 func indexOf(find string, in []string) (int, bool) { 2090 for ix, cur := range in { 2091 if cur == find { 2092 return ix, true 2093 } 2094 } 2095 return -1, false 2096 } 2097 2098 // ensureSuffixFn returns a function that will make sure the passed in 2099 // string has the marker token at the end of it 2100 func ensureSuffixFn(marker string) func(string) string { 2101 return func(p string) string { 2102 if !strings.HasSuffix(p, marker) { 2103 p = p + marker 2104 } 2105 return p 2106 } 2107 } 2108 2109 // watchEnqueuedActionsFilteredBy starts and returns a StringsWatcher 2110 // that notifies on new Actions being enqueued on the ActionRecevers 2111 // being watched. 2112 func (st *State) watchEnqueuedActionsFilteredBy(receivers ...ActionReceiver) StringsWatcher { 2113 return newcollectionWatcher(st, colWCfg{ 2114 col: actionNotificationsC, 2115 filter: makeIdFilter(st, actionMarker, receivers...), 2116 idconv: actionNotificationIdToActionId, 2117 }) 2118 } 2119 2120 // WatchControllerStatusChanges starts and returns a StringsWatcher that 2121 // notifies when the status of a controller machine changes. 2122 // TODO(cherylj) Add unit tests for this, as per bug 1543408. 2123 func (st *State) WatchControllerStatusChanges() StringsWatcher { 2124 return newcollectionWatcher(st, colWCfg{ 2125 col: statusesC, 2126 filter: makeControllerIdFilter(st), 2127 }) 2128 } 2129 2130 func makeControllerIdFilter(st *State) func(interface{}) bool { 2131 initialInfo, err := st.ControllerInfo() 2132 if err != nil { 2133 return nil 2134 } 2135 machines := initialInfo.MachineIds 2136 return func(key interface{}) bool { 2137 switch key.(type) { 2138 case string: 2139 info, err := st.ControllerInfo() 2140 if err != nil { 2141 // Most likely, things will be killed and 2142 // restarted if we hit this error. Just use 2143 // the machine list we knew about last time. 2144 logger.Debugf("unable to get controller info: %v", err) 2145 } else { 2146 machines = info.MachineIds 2147 } 2148 for _, machine := range machines { 2149 if strings.HasSuffix(key.(string), fmt.Sprintf("m#%s", machine)) { 2150 return true 2151 } 2152 } 2153 default: 2154 watchLogger.Errorf("key is not type string, got %T", key) 2155 } 2156 return false 2157 } 2158 2159 } 2160 2161 // WatchActionResults starts and returns a StringsWatcher that 2162 // notifies on new ActionResults being added. 2163 func (st *State) WatchActionResults() StringsWatcher { 2164 return st.WatchActionResultsFilteredBy() 2165 } 2166 2167 // WatchActionResultsFilteredBy starts and returns a StringsWatcher 2168 // that notifies on new ActionResults being added for the ActionRecevers 2169 // being watched. 2170 func (st *State) WatchActionResultsFilteredBy(receivers ...ActionReceiver) StringsWatcher { 2171 return newActionStatusWatcher(st, receivers, []ActionStatus{ActionCompleted, ActionCancelled, ActionFailed}...) 2172 } 2173 2174 // openedPortsWatcher notifies of changes in the openedPorts 2175 // collection 2176 type openedPortsWatcher struct { 2177 commonWatcher 2178 known map[string]int64 2179 out chan []string 2180 } 2181 2182 var _ Watcher = (*openedPortsWatcher)(nil) 2183 2184 // WatchOpenedPorts starts and returns a StringsWatcher notifying of changes to 2185 // the openedPorts collection. Reported changes have the following format: 2186 // "<machine-id>:[<subnet-CIDR>]", i.e. "0:10.20.0.0/16" or "1:" (empty subnet 2187 // ID is allowed for backwards-compatibility). 2188 func (st *State) WatchOpenedPorts() StringsWatcher { 2189 return newOpenedPortsWatcher(st) 2190 } 2191 2192 func newOpenedPortsWatcher(st *State) StringsWatcher { 2193 w := &openedPortsWatcher{ 2194 commonWatcher: newCommonWatcher(st), 2195 known: make(map[string]int64), 2196 out: make(chan []string), 2197 } 2198 go func() { 2199 defer w.tomb.Done() 2200 defer close(w.out) 2201 w.tomb.Kill(w.loop()) 2202 }() 2203 2204 return w 2205 } 2206 2207 // Changes returns the event channel for w 2208 func (w *openedPortsWatcher) Changes() <-chan []string { 2209 return w.out 2210 } 2211 2212 // transformId converts a global key for a ports document (e.g. 2213 // "m#42#0.1.2.0/24") into a colon-separated string with the machine and subnet 2214 // IDs (e.g. "42:0.1.2.0/24"). Subnet ID (a.k.a. CIDR) can be empty for 2215 // backwards-compatibility. 2216 func (w *openedPortsWatcher) transformID(globalKey string) (string, error) { 2217 parts, err := extractPortsIDParts(globalKey) 2218 if err != nil { 2219 return "", errors.Trace(err) 2220 } 2221 return fmt.Sprintf("%s:%s", parts[machineIDPart], parts[subnetIDPart]), nil 2222 } 2223 2224 func (w *openedPortsWatcher) initial() (set.Strings, error) { 2225 ports, closer := w.st.getCollection(openedPortsC) 2226 defer closer() 2227 2228 portDocs := set.NewStrings() 2229 var doc portsDoc 2230 iter := ports.Find(nil).Select(bson.D{{"_id", 1}, {"txn-revno", 1}}).Iter() 2231 for iter.Next(&doc) { 2232 id, err := w.st.strictLocalID(doc.DocID) 2233 if err != nil { 2234 return nil, errors.Trace(err) 2235 } 2236 if doc.TxnRevno != -1 { 2237 w.known[id] = doc.TxnRevno 2238 } 2239 if changeID, err := w.transformID(id); err != nil { 2240 logger.Errorf(err.Error()) 2241 } else { 2242 portDocs.Add(changeID) 2243 } 2244 } 2245 return portDocs, errors.Trace(iter.Close()) 2246 } 2247 2248 func (w *openedPortsWatcher) loop() error { 2249 in := make(chan watcher.Change) 2250 changes, err := w.initial() 2251 if err != nil { 2252 return errors.Trace(err) 2253 } 2254 w.watcher.WatchCollectionWithFilter(openedPortsC, in, isLocalID(w.st)) 2255 defer w.watcher.UnwatchCollection(openedPortsC, in) 2256 2257 out := w.out 2258 for { 2259 select { 2260 case <-w.tomb.Dying(): 2261 return tomb.ErrDying 2262 case <-w.watcher.Dead(): 2263 return stateWatcherDeadError(w.watcher.Err()) 2264 case ch := <-in: 2265 if err = w.merge(changes, ch); err != nil { 2266 return errors.Trace(err) 2267 } 2268 if !changes.IsEmpty() { 2269 out = w.out 2270 } 2271 case out <- changes.Values(): 2272 out = nil 2273 changes = set.NewStrings() 2274 } 2275 } 2276 } 2277 2278 func (w *openedPortsWatcher) merge(ids set.Strings, change watcher.Change) error { 2279 id, ok := change.Id.(string) 2280 if !ok { 2281 return errors.Errorf("id %v is not of type string, got %T", id, id) 2282 } 2283 localID, err := w.st.strictLocalID(id) 2284 if err != nil { 2285 return errors.Trace(err) 2286 } 2287 if change.Revno == -1 { 2288 delete(w.known, localID) 2289 if changeID, err := w.transformID(localID); err != nil { 2290 logger.Errorf(err.Error()) 2291 } else { 2292 // Report the removed id. 2293 ids.Add(changeID) 2294 } 2295 return nil 2296 } 2297 openedPorts, closer := w.st.getCollection(openedPortsC) 2298 currentRevno, err := getTxnRevno(openedPorts, id) 2299 closer() 2300 if err != nil { 2301 return err 2302 } 2303 knownRevno, isKnown := w.known[localID] 2304 w.known[localID] = currentRevno 2305 if !isKnown || currentRevno > knownRevno { 2306 if changeID, err := w.transformID(localID); err != nil { 2307 logger.Errorf(err.Error()) 2308 } else { 2309 // Report the unknown-so-far id. 2310 ids.Add(changeID) 2311 } 2312 } 2313 return nil 2314 } 2315 2316 // WatchForRebootEvent returns a notify watcher that will trigger an event 2317 // when the reboot flag is set on our machine agent, our parent machine agent 2318 // or grandparent machine agent 2319 func (m *Machine) WatchForRebootEvent() NotifyWatcher { 2320 machineIds := m.machinesToCareAboutRebootsFor() 2321 machines := set.NewStrings(machineIds...) 2322 2323 filter := func(key interface{}) bool { 2324 if id, ok := key.(string); ok { 2325 if id, err := m.st.strictLocalID(id); err == nil { 2326 return machines.Contains(id) 2327 } else { 2328 return false 2329 } 2330 } 2331 return false 2332 } 2333 return newNotifyCollWatcher(m.st, rebootC, filter) 2334 } 2335 2336 // blockDevicesWatcher notifies about changes to all block devices 2337 // associated with a machine. 2338 type blockDevicesWatcher struct { 2339 commonWatcher 2340 machineId string 2341 out chan struct{} 2342 } 2343 2344 var _ NotifyWatcher = (*blockDevicesWatcher)(nil) 2345 2346 func newBlockDevicesWatcher(st *State, machineId string) NotifyWatcher { 2347 w := &blockDevicesWatcher{ 2348 commonWatcher: newCommonWatcher(st), 2349 machineId: machineId, 2350 out: make(chan struct{}), 2351 } 2352 go func() { 2353 defer w.tomb.Done() 2354 defer close(w.out) 2355 w.tomb.Kill(w.loop()) 2356 }() 2357 return w 2358 } 2359 2360 // Changes returns the event channel for w. 2361 func (w *blockDevicesWatcher) Changes() <-chan struct{} { 2362 return w.out 2363 } 2364 2365 func (w *blockDevicesWatcher) loop() error { 2366 docID := w.st.docID(w.machineId) 2367 coll, closer := w.st.getCollection(blockDevicesC) 2368 revno, err := getTxnRevno(coll, docID) 2369 closer() 2370 if err != nil { 2371 return errors.Trace(err) 2372 } 2373 changes := make(chan watcher.Change) 2374 w.watcher.Watch(blockDevicesC, docID, revno, changes) 2375 defer w.watcher.Unwatch(blockDevicesC, docID, changes) 2376 blockDevices, err := getBlockDevices(w.st, w.machineId) 2377 if err != nil { 2378 return errors.Trace(err) 2379 } 2380 out := w.out 2381 for { 2382 select { 2383 case <-w.watcher.Dead(): 2384 return stateWatcherDeadError(w.watcher.Err()) 2385 case <-w.tomb.Dying(): 2386 return tomb.ErrDying 2387 case <-changes: 2388 newBlockDevices, err := getBlockDevices(w.st, w.machineId) 2389 if err != nil { 2390 return errors.Trace(err) 2391 } 2392 if !reflect.DeepEqual(newBlockDevices, blockDevices) { 2393 blockDevices = newBlockDevices 2394 out = w.out 2395 } 2396 case out <- struct{}{}: 2397 out = nil 2398 } 2399 } 2400 } 2401 2402 // WatchForMigration returns a notify watcher which reports when 2403 // a migration is in progress for the model associated with the 2404 // State. 2405 func (st *State) WatchForMigration() NotifyWatcher { 2406 return newMigrationActiveWatcher(st) 2407 } 2408 2409 type migrationActiveWatcher struct { 2410 commonWatcher 2411 collName string 2412 id string 2413 sink chan struct{} 2414 } 2415 2416 func newMigrationActiveWatcher(st *State) NotifyWatcher { 2417 w := &migrationActiveWatcher{ 2418 commonWatcher: newCommonWatcher(st), 2419 collName: migrationsActiveC, 2420 id: st.ModelUUID(), 2421 sink: make(chan struct{}), 2422 } 2423 go func() { 2424 defer w.tomb.Done() 2425 defer close(w.sink) 2426 w.tomb.Kill(w.loop()) 2427 }() 2428 return w 2429 } 2430 2431 // Changes returns the event channel for this watcher. 2432 func (w *migrationActiveWatcher) Changes() <-chan struct{} { 2433 return w.sink 2434 } 2435 2436 func (w *migrationActiveWatcher) loop() error { 2437 collection, closer := w.st.getCollection(w.collName) 2438 revno, err := getTxnRevno(collection, w.id) 2439 closer() 2440 if err != nil { 2441 return errors.Trace(err) 2442 } 2443 2444 in := make(chan watcher.Change) 2445 w.watcher.Watch(w.collName, w.id, revno, in) 2446 defer w.watcher.Unwatch(w.collName, w.id, in) 2447 2448 out := w.sink 2449 for { 2450 select { 2451 case <-w.tomb.Dying(): 2452 return tomb.ErrDying 2453 case <-w.watcher.Dead(): 2454 return stateWatcherDeadError(w.watcher.Err()) 2455 case change := <-in: 2456 if _, ok := collect(change, in, w.tomb.Dying()); !ok { 2457 return tomb.ErrDying 2458 } 2459 out = w.sink 2460 case out <- struct{}{}: 2461 out = nil 2462 } 2463 } 2464 } 2465 2466 // WatchMigrationStatus returns a NotifyWatcher which triggers 2467 // whenever the status of latest migration for the State's model 2468 // changes. One instance can be used across migrations. The watcher 2469 // will report changes when one migration finishes and another one 2470 // begins. 2471 // 2472 // Note that this watcher does not produce an initial event if there's 2473 // never been a migration attempt for the model. 2474 func (st *State) WatchMigrationStatus() NotifyWatcher { 2475 // Watch the entire migrationsStatusC collection for migration 2476 // status updates related to the State's model. This is more 2477 // efficient and simpler than tracking the current active 2478 // migration (and changing watchers when one migration finishes 2479 // and another starts. 2480 // 2481 // This approach is safe because there are strong guarantees that 2482 // there will only be one active migration per model. The watcher 2483 // will only see changes for one migration status document at a 2484 // time for the model. 2485 return newNotifyCollWatcher(st, migrationsStatusC, isLocalID(st)) 2486 } 2487 2488 // WatchMachineRemovals returns a NotifyWatcher which triggers 2489 // whenever machine removal records are added or removed. 2490 func (st *State) WatchMachineRemovals() NotifyWatcher { 2491 return newNotifyCollWatcher(st, machineRemovalsC, isLocalID(st)) 2492 } 2493 2494 // notifyCollWatcher implements NotifyWatcher, triggering when a 2495 // change is seen in a specific collection matching the provided 2496 // filter function. 2497 type notifyCollWatcher struct { 2498 commonWatcher 2499 collName string 2500 filter func(interface{}) bool 2501 sink chan struct{} 2502 } 2503 2504 func newNotifyCollWatcher(st *State, collName string, filter func(interface{}) bool) NotifyWatcher { 2505 w := ¬ifyCollWatcher{ 2506 commonWatcher: newCommonWatcher(st), 2507 collName: collName, 2508 filter: filter, 2509 sink: make(chan struct{}), 2510 } 2511 go func() { 2512 defer w.tomb.Done() 2513 defer close(w.sink) 2514 w.tomb.Kill(w.loop()) 2515 }() 2516 return w 2517 } 2518 2519 // Changes returns the event channel for this watcher. 2520 func (w *notifyCollWatcher) Changes() <-chan struct{} { 2521 return w.sink 2522 } 2523 2524 func (w *notifyCollWatcher) loop() error { 2525 in := make(chan watcher.Change) 2526 2527 w.watcher.WatchCollectionWithFilter(w.collName, in, w.filter) 2528 defer w.watcher.UnwatchCollection(w.collName, in) 2529 2530 out := w.sink // out set so that initial event is sent. 2531 for { 2532 select { 2533 case <-w.tomb.Dying(): 2534 return tomb.ErrDying 2535 case <-w.watcher.Dead(): 2536 return stateWatcherDeadError(w.watcher.Err()) 2537 case change := <-in: 2538 if _, ok := collect(change, in, w.tomb.Dying()); !ok { 2539 return tomb.ErrDying 2540 } 2541 out = w.sink 2542 case out <- struct{}{}: 2543 out = nil 2544 } 2545 } 2546 }