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