github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/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  	"crypto/sha256"
     8  	"encoding/json"
     9  	"fmt"
    10  	"hash"
    11  	"reflect"
    12  	"regexp"
    13  	"sort"
    14  	"strings"
    15  	"sync"
    16  	"time"
    17  
    18  	"github.com/juju/charm/v12"
    19  	"github.com/juju/clock"
    20  	"github.com/juju/collections/set"
    21  	"github.com/juju/errors"
    22  	"github.com/juju/loggo"
    23  	"github.com/juju/mgo/v3"
    24  	"github.com/juju/mgo/v3/bson"
    25  	"github.com/juju/names/v5"
    26  	"github.com/kr/pretty"
    27  	"gopkg.in/tomb.v2"
    28  
    29  	"github.com/juju/juju/core/actions"
    30  	"github.com/juju/juju/core/instance"
    31  	"github.com/juju/juju/core/lxdprofile"
    32  	corenetwork "github.com/juju/juju/core/network"
    33  	corewatcher "github.com/juju/juju/core/watcher"
    34  	"github.com/juju/juju/mongo"
    35  	"github.com/juju/juju/state/watcher"
    36  )
    37  
    38  var watchLogger = loggo.GetLogger("juju.state.watch")
    39  
    40  // Watcher is implemented by all watchers; the actual
    41  // changes channel is returned by a watcher-specific
    42  // Changes method.
    43  type Watcher interface {
    44  	// Kill asks the watcher to stop without waiting for it do so.
    45  	Kill()
    46  	// Wait waits for the watcher to die and returns any
    47  	// error encountered when it was running.
    48  	Wait() error
    49  	// Stop kills the watcher, then waits for it to die.
    50  	Stop() error
    51  	// Err returns any error encountered while the watcher
    52  	// has been running.
    53  	Err() error
    54  }
    55  
    56  // NotifyWatcher generates signals when something changes, but it does not
    57  // return any content for those changes
    58  type NotifyWatcher interface {
    59  	Watcher
    60  	Changes() <-chan struct{}
    61  }
    62  
    63  // StringsWatcher generates signals when something changes, returning
    64  // the changes as a list of strings.
    65  type StringsWatcher interface {
    66  	Watcher
    67  	Changes() <-chan []string
    68  }
    69  
    70  // RelationUnitsWatcher generates signals when units enter or leave
    71  // the scope of a RelationUnit, and changes to the settings of those
    72  // units known to have entered.
    73  type RelationUnitsWatcher interface {
    74  	Watcher
    75  
    76  	Changes() corewatcher.RelationUnitsChannel
    77  }
    78  
    79  // newCommonWatcher exists so that all embedders have a place from which
    80  // to get a single TxnLogWatcher that will not be replaced in the lifetime
    81  // of the embedder (and also to restrict the width of the interface by
    82  // which they can access the rest of State, by storing st as a
    83  // modelBackend).
    84  func newCommonWatcher(backend modelBackend) commonWatcher {
    85  	return commonWatcher{
    86  		backend: backend,
    87  		db:      backend.db(),
    88  		watcher: backend.txnLogWatcher(),
    89  	}
    90  }
    91  
    92  // commonWatcher is part of all client watchers.
    93  type commonWatcher struct {
    94  	backend modelBackend
    95  	db      Database
    96  	watcher watcher.BaseWatcher
    97  	tomb    tomb.Tomb
    98  }
    99  
   100  // Stop stops the watcher, and returns any error encountered while running
   101  // or shutting down.
   102  func (w *commonWatcher) Stop() error {
   103  	w.Kill()
   104  	return w.Wait()
   105  }
   106  
   107  // Kill kills the watcher without waiting for it to shut down.
   108  func (w *commonWatcher) Kill() {
   109  	w.tomb.Kill(nil)
   110  }
   111  
   112  // Wait waits for the watcher to die and returns any
   113  // error encountered when it was running.
   114  func (w *commonWatcher) Wait() error {
   115  	return w.tomb.Wait()
   116  }
   117  
   118  // Err returns any error encountered while running or shutting down, or
   119  // tomb.ErrStillAlive if the watcher is still running.
   120  func (w *commonWatcher) Err() error {
   121  	return w.tomb.Err()
   122  }
   123  
   124  // collect combines the effects of the one change, and any further
   125  // changes read from more in the next 10ms. The result map describes the
   126  // existence, or not, of every id observed to have changed. If a value is read
   127  // from the supplied stop chan, collect returns false immediately.
   128  func collect(one watcher.Change, more <-chan watcher.Change, stop <-chan struct{}) (map[interface{}]bool, bool) {
   129  	return collectWhereRevnoGreaterThan(one, more, stop, 0)
   130  }
   131  
   132  // collectWhereRevnoGreaterThan combines the effects of the one change, and any
   133  // further changes read from more in the next 10ms. The result map describes
   134  // the existence, or not, of every id observed to have changed. If a value is
   135  // read from the supplied stop chan, collect returns false immediately.
   136  //
   137  // The implementation will flag result doc IDs as existing iff the doc revno
   138  // is greater than the provided revnoThreshold value.
   139  func collectWhereRevnoGreaterThan(one watcher.Change, more <-chan watcher.Change, stop <-chan struct{}, revnoThreshold int64) (map[interface{}]bool, bool) {
   140  	var count int
   141  	result := map[interface{}]bool{}
   142  	handle := func(ch watcher.Change) {
   143  		count++
   144  		result[ch.Id] = ch.Revno > revnoThreshold
   145  	}
   146  	handle(one)
   147  	// TODO(fwereade): 2016-03-17 lp:1558657
   148  	timeout := time.After(10 * time.Millisecond)
   149  	for done := false; !done; {
   150  		select {
   151  		case <-stop:
   152  			return nil, false
   153  		case another := <-more:
   154  			handle(another)
   155  		case <-timeout:
   156  			done = true
   157  		}
   158  	}
   159  	watchLogger.Tracef("read %d events for %d documents", count, len(result))
   160  	return result, true
   161  }
   162  
   163  func hasString(changes []string, name string) bool {
   164  	for _, v := range changes {
   165  		if v == name {
   166  			return true
   167  		}
   168  	}
   169  	return false
   170  }
   171  
   172  var _ Watcher = (*lifecycleWatcher)(nil)
   173  
   174  // lifecycleWatcher notifies about lifecycle changes for a set of entities of
   175  // the same kind. The first event emitted will contain the ids of all
   176  // entities; subsequent events are emitted whenever one or more entities are
   177  // added, or change their lifecycle state. After an entity is found to be
   178  // Dead, no further event will include it.
   179  type lifecycleWatcher struct {
   180  	commonWatcher
   181  	out chan []string
   182  
   183  	// coll is a function returning the mongo.Collection holding all
   184  	// interesting entities
   185  	coll     func() (mongo.Collection, func())
   186  	collName string
   187  
   188  	// members is used to select the initial set of interesting entities.
   189  	members bson.D
   190  	// filter is used to exclude events not affecting interesting entities.
   191  	filter func(interface{}) bool
   192  	// transform, if non-nil, is used to transform a document ID immediately
   193  	// prior to emitting to the out channel.
   194  	transform func(string) string
   195  	// life holds the most recent known life states of interesting entities.
   196  	life map[string]Life
   197  }
   198  
   199  func collFactory(db Database, collName string) func() (mongo.Collection, func()) {
   200  	return func() (mongo.Collection, func()) {
   201  		return db.GetCollection(collName)
   202  	}
   203  }
   204  
   205  // WatchModels returns a StringsWatcher that notifies of changes to
   206  // any models. If a model is removed this *won't* signal that the
   207  // model has gone away - it's based on a collectionWatcher which omits
   208  // these events.
   209  func (st *State) WatchModels() StringsWatcher {
   210  	return newCollectionWatcher(st, colWCfg{
   211  		col:    modelsC,
   212  		global: true,
   213  	})
   214  }
   215  
   216  // WatchModelLives returns a StringsWatcher that notifies of changes
   217  // to any model life values. The watcher will not send any more events
   218  // for a model after it has been observed to be Dead.
   219  func (st *State) WatchModelLives() StringsWatcher {
   220  	return newLifecycleWatcher(st, modelsC, nil, nil, nil)
   221  }
   222  
   223  // WatchModelVolumes returns a StringsWatcher that notifies of changes to
   224  // the lifecycles of all model-scoped volumes.
   225  func (sb *storageBackend) WatchModelVolumes() StringsWatcher {
   226  	return sb.watchModelHostStorage(volumesC)
   227  }
   228  
   229  // WatchModelFilesystems returns a StringsWatcher that notifies of changes
   230  // to the lifecycles of all model-scoped filesystems.
   231  func (sb *storageBackend) WatchModelFilesystems() StringsWatcher {
   232  	return sb.watchModelHostStorage(filesystemsC)
   233  }
   234  
   235  var machineOrUnitSnippet = "(" + names.NumberSnippet + "|" + names.UnitSnippet + ")"
   236  
   237  func (sb *storageBackend) watchModelHostStorage(collection string) StringsWatcher {
   238  	mb := sb.mb
   239  	pattern := fmt.Sprintf("^%s$", mb.docID(machineOrUnitSnippet))
   240  	members := bson.D{{"_id", bson.D{{"$regex", pattern}}}}
   241  	filter := func(id interface{}) bool {
   242  		k, err := mb.strictLocalID(id.(string))
   243  		if err != nil {
   244  			return false
   245  		}
   246  		return !strings.Contains(k, "/")
   247  	}
   248  	return newLifecycleWatcher(mb, collection, members, filter, nil)
   249  }
   250  
   251  // WatchMachineVolumes returns a StringsWatcher that notifies of changes to
   252  // the lifecycles of all volumes scoped to the specified machine.
   253  func (sb *storageBackend) WatchMachineVolumes(m names.MachineTag) StringsWatcher {
   254  	return sb.watchHostStorage(m, volumesC)
   255  }
   256  
   257  // WatchMachineFilesystems returns a StringsWatcher that notifies of changes
   258  // to the lifecycles of all filesystems scoped to the specified machine.
   259  func (sb *storageBackend) WatchMachineFilesystems(m names.MachineTag) StringsWatcher {
   260  	return sb.watchHostStorage(m, filesystemsC)
   261  }
   262  
   263  // WatchUnitFilesystems returns a StringsWatcher that notifies of changes
   264  // to the lifecycles of all filesystems scoped to units of the specified application.
   265  func (sb *storageBackend) WatchUnitFilesystems(app names.ApplicationTag) StringsWatcher {
   266  	return sb.watchHostStorage(app, filesystemsC)
   267  }
   268  
   269  func (sb *storageBackend) watchHostStorage(host names.Tag, collection string) StringsWatcher {
   270  	mb := sb.mb
   271  	// The regexp patterns below represent either machine or unit attached storage, <hostid>/<number>.
   272  	// For machines, it can be something like 4/6.
   273  	// For units the pattern becomes something like mariadb/0/6.
   274  	// The host parameter passed into this method is the application name, any of whose units we are interested in.
   275  	pattern := fmt.Sprintf("^%s(/%s)?/%s$", mb.docID(host.Id()), names.NumberSnippet, names.NumberSnippet)
   276  	members := bson.D{{"_id", bson.D{{"$regex", pattern}}}}
   277  	prefix := fmt.Sprintf("%s(/%s)?/.*", host.Id(), names.NumberSnippet)
   278  	matchExp := regexp.MustCompile(prefix)
   279  	filter := func(id interface{}) bool {
   280  		k, err := mb.strictLocalID(id.(string))
   281  		if err != nil {
   282  			return false
   283  		}
   284  		return matchExp.MatchString(k)
   285  	}
   286  	return newLifecycleWatcher(mb, collection, members, filter, nil)
   287  }
   288  
   289  // WatchMachineAttachmentsPlans returns a StringsWatcher that notifies machine agents
   290  // that a volume has been attached to their instance by the environment provider.
   291  // This allows machine agents to do extra initialization to the volume, in cases
   292  // such as iSCSI disks, or other disks that have similar requirements
   293  func (sb *storageBackend) WatchMachineAttachmentsPlans(m names.MachineTag) StringsWatcher {
   294  	return sb.watchMachineVolumeAttachmentPlans(m)
   295  }
   296  
   297  func (sb *storageBackend) watchMachineVolumeAttachmentPlans(m names.MachineTag) StringsWatcher {
   298  	mb := sb.mb
   299  	pattern := fmt.Sprintf("^%s:%s$", mb.docID(m.Id()), names.NumberSnippet)
   300  	members := bson.D{{"_id", bson.D{{"$regex", pattern}}}}
   301  	prefix := fmt.Sprintf("%s:", m.Id())
   302  	filter := func(id interface{}) bool {
   303  		k, err := mb.strictLocalID(id.(string))
   304  		if err != nil {
   305  			return false
   306  		}
   307  		return strings.HasPrefix(k, prefix)
   308  	}
   309  	return newLifecycleWatcher(mb, volumeAttachmentPlanC, members, filter, nil)
   310  }
   311  
   312  // WatchModelVolumeAttachments returns a StringsWatcher that notifies of
   313  // changes to the lifecycles of all volume attachments related to environ-
   314  // scoped volumes.
   315  func (sb *storageBackend) WatchModelVolumeAttachments() StringsWatcher {
   316  	return sb.watchModelHostStorageAttachments(volumeAttachmentsC)
   317  }
   318  
   319  // WatchModelFilesystemAttachments returns a StringsWatcher that notifies
   320  // of changes to the lifecycles of all filesystem attachments related to
   321  // environ-scoped filesystems.
   322  func (sb *storageBackend) WatchModelFilesystemAttachments() StringsWatcher {
   323  	return sb.watchModelHostStorageAttachments(filesystemAttachmentsC)
   324  }
   325  
   326  func (sb *storageBackend) watchModelHostStorageAttachments(collection string) StringsWatcher {
   327  	mb := sb.mb
   328  	pattern := fmt.Sprintf("^%s.*:%s$", mb.docID(""), machineOrUnitSnippet)
   329  	members := bson.D{{"_id", bson.D{{"$regex", pattern}}}}
   330  	filter := func(id interface{}) bool {
   331  		k, err := mb.strictLocalID(id.(string))
   332  		if err != nil {
   333  			return false
   334  		}
   335  		colon := strings.IndexRune(k, ':')
   336  		if colon == -1 {
   337  			return false
   338  		}
   339  		return !strings.Contains(k[colon+1:], "/")
   340  	}
   341  	return newLifecycleWatcher(mb, collection, members, filter, nil)
   342  }
   343  
   344  // WatchMachineVolumeAttachments returns a StringsWatcher that notifies of
   345  // changes to the lifecycles of all volume attachments related to the specified
   346  // machine, for volumes scoped to the machine.
   347  func (sb *storageBackend) WatchMachineVolumeAttachments(m names.MachineTag) StringsWatcher {
   348  	return sb.watchHostStorageAttachments(m, volumeAttachmentsC)
   349  }
   350  
   351  // WatchMachineFilesystemAttachments returns a StringsWatcher that notifies of
   352  // changes to the lifecycles of all filesystem attachments related to the specified
   353  // machine, for filesystems scoped to the machine.
   354  func (sb *storageBackend) WatchMachineFilesystemAttachments(m names.MachineTag) StringsWatcher {
   355  	return sb.watchHostStorageAttachments(m, filesystemAttachmentsC)
   356  }
   357  
   358  // WatchUnitVolumeAttachments returns a StringsWatcher that notifies of
   359  // changes to the lifecycles of all volume attachments related to the specified
   360  // application's units, for volumes scoped to the application's units.
   361  // TODO(caas) - currently untested since units don't directly support attached volumes
   362  func (sb *storageBackend) WatchUnitVolumeAttachments(app names.ApplicationTag) StringsWatcher {
   363  	return sb.watchHostStorageAttachments(app, volumeAttachmentsC)
   364  }
   365  
   366  // WatchUnitFilesystemAttachments returns a StringsWatcher that notifies of
   367  // changes to the lifecycles of all filesystem attachments related to the specified
   368  // application's units, for filesystems scoped to the application's units.
   369  func (sb *storageBackend) WatchUnitFilesystemAttachments(app names.ApplicationTag) StringsWatcher {
   370  	return sb.watchHostStorageAttachments(app, filesystemAttachmentsC)
   371  }
   372  
   373  func (sb *storageBackend) watchHostStorageAttachments(host names.Tag, collection string) StringsWatcher {
   374  	mb := sb.mb
   375  	// Go's regex doesn't support lookbacks so the pattern match is a bit clumsy.
   376  	// We look for either a machine attachment id, eg 0:0/42
   377  	// or a unit attachment id, eg mariadb/0:mariadb/0/42
   378  	// The host parameter passed into this method is the application name, any of whose units we are interested in.
   379  	pattern := fmt.Sprintf("^%s(/%s)?:%s(/%s)?/.*", mb.docID(host.Id()), names.NumberSnippet, host.Id(), names.NumberSnippet)
   380  	members := bson.D{{"_id", bson.D{{"$regex", pattern}}}}
   381  	prefix := fmt.Sprintf("%s(/%s)?:%s(/%s)?/.*", host.Id(), names.NumberSnippet, host.Id(), names.NumberSnippet)
   382  	matchExp := regexp.MustCompile(prefix)
   383  	filter := func(id interface{}) bool {
   384  		k, err := mb.strictLocalID(id.(string))
   385  		if err != nil {
   386  			return false
   387  		}
   388  		matches := matchExp.FindStringSubmatch(k)
   389  		return len(matches) == 3 && matches[1] == matches[2]
   390  	}
   391  	return newLifecycleWatcher(mb, collection, members, filter, nil)
   392  }
   393  
   394  // WatchApplications returns a StringsWatcher that notifies of changes to
   395  // the lifecycles of the applications in the model.
   396  func (st *State) WatchApplications() StringsWatcher {
   397  	return newLifecycleWatcher(st, applicationsC, nil, isLocalID(st), nil)
   398  }
   399  
   400  // WatchRemoteApplications returns a StringsWatcher that notifies of changes to
   401  // the lifecycles of the remote applications in the model.
   402  func (st *State) WatchRemoteApplications() StringsWatcher {
   403  	return newLifecycleWatcher(st, remoteApplicationsC, nil, isLocalID(st), nil)
   404  }
   405  
   406  // WatchApplicationCharms notifies when application charm URLs change.
   407  // TODO(wallyworld) - use a filter to only trigger on charm URL changes.
   408  func (st *State) WatchApplicationCharms() StringsWatcher {
   409  	return newCollectionWatcher(st, colWCfg{col: applicationsC})
   410  }
   411  
   412  // WatchUnits notifies when units change.
   413  func (st *State) WatchUnits() StringsWatcher {
   414  	return newCollectionWatcher(st, colWCfg{col: unitsC})
   415  }
   416  
   417  // WatchMachines notifies when machines change.
   418  func (st *State) WatchMachines() StringsWatcher {
   419  	return newLifecycleWatcher(st, machinesC, nil, isLocalID(st), nil)
   420  }
   421  
   422  // WatchCharms notifies when charms change.
   423  func (st *State) WatchCharms() StringsWatcher {
   424  	return newCollectionWatcher(st, colWCfg{col: charmsC})
   425  }
   426  
   427  // WatchStorageAttachments returns a StringsWatcher that notifies of
   428  // changes to the lifecycles of all storage instances attached to the
   429  // specified unit.
   430  func (sb *storageBackend) WatchStorageAttachments(unit names.UnitTag) StringsWatcher {
   431  	members := bson.D{{"unitid", unit.Id()}}
   432  	prefix := unitGlobalKey(unit.Id()) + "#"
   433  	filter := func(id interface{}) bool {
   434  		k, err := sb.mb.strictLocalID(id.(string))
   435  		if err != nil {
   436  			return false
   437  		}
   438  		return strings.HasPrefix(k, prefix)
   439  	}
   440  	tr := func(id string) string {
   441  		// Transform storage attachment document ID to storage ID.
   442  		return id[len(prefix):]
   443  	}
   444  	return newLifecycleWatcher(sb.mb, storageAttachmentsC, members, filter, tr)
   445  }
   446  
   447  // WatchUnits returns a StringsWatcher that notifies of changes to the
   448  // lifecycles of units of a.
   449  func (a *Application) WatchUnits() StringsWatcher {
   450  	members := bson.D{{"application", a.doc.Name}}
   451  	prefix := a.doc.Name + "/"
   452  	filter := func(unitDocID interface{}) bool {
   453  		unitName, err := a.st.strictLocalID(unitDocID.(string))
   454  		if err != nil {
   455  			return false
   456  		}
   457  		return strings.HasPrefix(unitName, prefix)
   458  	}
   459  	return newLifecycleWatcher(a.st, unitsC, members, filter, nil)
   460  }
   461  
   462  // WatchScale returns a new NotifyWatcher watching for
   463  // changes to the specified application's scale value.
   464  func (a *Application) WatchScale() NotifyWatcher {
   465  	currentScale := -1
   466  	filter := func(id interface{}) bool {
   467  		k, err := a.st.strictLocalID(id.(string))
   468  		if err != nil {
   469  			return false
   470  		}
   471  		if k != a.doc.Name {
   472  			return false
   473  		}
   474  		applications, closer := a.st.db().GetCollection(applicationsC)
   475  		defer closer()
   476  
   477  		var scaleField = bson.D{{"scale", 1}}
   478  		var doc *applicationDoc
   479  		if err := applications.FindId(k).Select(scaleField).One(&doc); err != nil {
   480  			return false
   481  		}
   482  		match := doc.DesiredScale != currentScale
   483  		currentScale = doc.DesiredScale
   484  		return match
   485  	}
   486  	return newNotifyCollWatcher(a.st, applicationsC, filter)
   487  }
   488  
   489  // WatchRelations returns a StringsWatcher that notifies of changes to the
   490  // lifecycles of relations involving a.
   491  func (a *Application) WatchRelations() StringsWatcher {
   492  	return watchApplicationRelations(a.st, a.doc.Name)
   493  }
   494  
   495  // WatchRelations returns a StringsWatcher that notifies of changes to the
   496  // lifecycles of relations involving a.
   497  func (a *RemoteApplication) WatchRelations() StringsWatcher {
   498  	return watchApplicationRelations(a.st, a.doc.Name)
   499  }
   500  
   501  func watchApplicationRelations(backend modelBackend, applicationName string) StringsWatcher {
   502  	prefix := applicationName + ":"
   503  	infix := " " + prefix
   504  	filter := func(id interface{}) bool {
   505  		k, err := backend.strictLocalID(id.(string))
   506  		if err != nil {
   507  			return false
   508  		}
   509  		return strings.HasPrefix(k, prefix) || strings.Contains(k, infix)
   510  	}
   511  	members := bson.D{{"endpoints.applicationname", applicationName}}
   512  	return newRelationLifeSuspendedWatcher(backend, members, filter, nil)
   513  }
   514  
   515  // WatchModelMachineStartTimes watches the non-container machines in the model
   516  // for changes to the Life or AgentStartTime fields and reports them as a batch
   517  // after the specified quiesceInterval time has passed without seeing any new
   518  // change events.
   519  func (st *State) WatchModelMachineStartTimes(quiesceInterval time.Duration) StringsWatcher {
   520  	return newModelMachineStartTimeWatcher(st, st.clock(), quiesceInterval)
   521  }
   522  
   523  type modelMachineStartTimeFieldDoc struct {
   524  	Id             string    `bson:"_id"`
   525  	Life           Life      `bson:"life"`
   526  	AgentStartedAt time.Time `bson:"agent-started-at"`
   527  }
   528  
   529  var (
   530  	notContainerQuery = bson.D{{"$or", []bson.D{
   531  		{{"containertype", ""}},
   532  		{{"containertype", bson.D{{"$exists", false}}}},
   533  	}}}
   534  
   535  	modelMachineStartTimeFields = bson.D{
   536  		{"_id", 1}, {"life", 1}, {"agent-started-at", 1},
   537  	}
   538  )
   539  
   540  type modelMachineStartTimeWatcher struct {
   541  	commonWatcher
   542  	outCh chan []string
   543  
   544  	clk             clock.Clock
   545  	quiesceInterval time.Duration
   546  	seenDocs        map[string]modelMachineStartTimeFieldDoc
   547  }
   548  
   549  func newModelMachineStartTimeWatcher(backend modelBackend, clk clock.Clock, quiesceInterval time.Duration) StringsWatcher {
   550  	w := &modelMachineStartTimeWatcher{
   551  		commonWatcher:   newCommonWatcher(backend),
   552  		outCh:           make(chan []string),
   553  		clk:             clk,
   554  		quiesceInterval: quiesceInterval,
   555  		seenDocs:        make(map[string]modelMachineStartTimeFieldDoc),
   556  	}
   557  
   558  	w.tomb.Go(func() error {
   559  		defer close(w.outCh)
   560  		return w.loop()
   561  	})
   562  	return w
   563  }
   564  
   565  // Changes returns the event channel for the watcher.
   566  func (w *modelMachineStartTimeWatcher) Changes() <-chan []string {
   567  	return w.outCh
   568  }
   569  
   570  func (w *modelMachineStartTimeWatcher) loop() error {
   571  	docWatcher := newCollectionWatcher(w.backend, colWCfg{col: machinesC})
   572  	defer func() { _ = docWatcher.Stop() }()
   573  
   574  	var (
   575  		timer      = w.clk.NewTimer(w.quiesceInterval)
   576  		timerArmed = true
   577  		// unprocessedDocs is a list of document IDs that need to be processed
   578  		// with a deadline they must be sent by.
   579  		unprocessedDocs = make(map[string]time.Time)
   580  		outCh           chan []string
   581  		changeSet       []string
   582  	)
   583  	defer func() { _ = timer.Stop() }()
   584  
   585  	// Collect and initial set of machine IDs; this makes the worker
   586  	// compatible with other workers that expect the full state to be
   587  	// immediately emitted once the worker starts.
   588  	initialSet, err := w.initialMachineSet()
   589  	if err != nil {
   590  		return errors.Trace(err)
   591  	}
   592  	changeSet = initialSet.Values()
   593  	outCh = w.outCh
   594  
   595  	for {
   596  		select {
   597  		case <-w.tomb.Dying():
   598  			return tomb.ErrDying
   599  		case <-w.watcher.Dead():
   600  			return stateWatcherDeadError(w.watcher.Err())
   601  		case changes := <-docWatcher.Changes():
   602  			if len(changes) == 0 {
   603  				continue
   604  			}
   605  			for _, docID := range changes {
   606  				// filter out doc IDs that correspond to containers
   607  				if strings.ContainsRune(docID, '/') {
   608  					continue
   609  				}
   610  				id := w.backend.docID(docID)
   611  				if _, ok := unprocessedDocs[id]; ok {
   612  					continue
   613  				}
   614  				unprocessedDocs[id] = w.clk.Now().Add(w.quiesceInterval)
   615  			}
   616  
   617  			// Restart the timer if currently stopped.
   618  			if !timerArmed {
   619  				_ = timer.Reset(w.quiesceInterval)
   620  				timerArmed = true
   621  			}
   622  		case <-timer.Chan():
   623  			timerArmed = false
   624  			if len(unprocessedDocs) == 0 {
   625  				continue // nothing to process
   626  			}
   627  
   628  			visible := make(set.Strings)
   629  			now := w.clk.Now()
   630  			var next time.Time
   631  			hasNext := false
   632  			for k, due := range unprocessedDocs {
   633  				if due.After(now) {
   634  					if !hasNext || due.Before(next) {
   635  						hasNext = true
   636  						next = due
   637  					}
   638  					continue
   639  				}
   640  				delete(unprocessedDocs, k)
   641  				visible.Add(k)
   642  			}
   643  			if hasNext {
   644  				_ = timer.Reset(next.Sub(now))
   645  				timerArmed = true
   646  			}
   647  
   648  			changedIDs, err := w.processChanges(visible)
   649  			if err != nil {
   650  				return err
   651  			} else if changedIDs.IsEmpty() {
   652  				continue // nothing to report
   653  			}
   654  
   655  			if len(changeSet) == 0 {
   656  				changeSet = changedIDs.Values()
   657  				outCh = w.outCh
   658  			} else {
   659  				// Append new set of changes to the not yet consumed changeset
   660  				changeSet = append(changeSet, changedIDs.Values()...)
   661  			}
   662  		case outCh <- changeSet:
   663  			changeSet = changeSet[:0]
   664  			outCh = nil
   665  		}
   666  	}
   667  }
   668  
   669  func (w *modelMachineStartTimeWatcher) initialMachineSet() (set.Strings, error) {
   670  	coll, closer := w.db.GetCollection(machinesC)
   671  	defer closer()
   672  
   673  	// Select the fields we need from documents that are not referring to
   674  	// containers.
   675  	iter := coll.Find(notContainerQuery).Select(modelMachineStartTimeFields).Iter()
   676  
   677  	var (
   678  		doc modelMachineStartTimeFieldDoc
   679  		ids = make(set.Strings)
   680  	)
   681  	for iter.Next(&doc) {
   682  		id := w.backend.localID(doc.Id)
   683  		ids.Add(id)
   684  		if doc.Life != Dead {
   685  			w.seenDocs[id] = doc
   686  		}
   687  	}
   688  	return ids, iter.Close()
   689  }
   690  
   691  func (w *modelMachineStartTimeWatcher) processChanges(pendingDocs set.Strings) (set.Strings, error) {
   692  	coll, closer := w.db.GetCollection(machinesC)
   693  	defer closer()
   694  
   695  	// Select the fields we need from the changed documents that are not
   696  	// referring to containers.
   697  	iter := coll.Find(
   698  		append(
   699  			bson.D{{"_id", bson.D{{"$in", pendingDocs.Values()}}}},
   700  			notContainerQuery...,
   701  		),
   702  	).Select(modelMachineStartTimeFields).Iter()
   703  
   704  	var (
   705  		doc          modelMachineStartTimeFieldDoc
   706  		ids          = make(set.Strings)
   707  		notFoundDocs = set.NewStrings(pendingDocs.Values()...)
   708  	)
   709  	for iter.Next(&doc) {
   710  		id := w.backend.localID(doc.Id)
   711  		old, exists := w.seenDocs[id]
   712  		if !exists || old.Life != doc.Life || old.AgentStartedAt != doc.AgentStartedAt {
   713  			w.seenDocs[id] = doc
   714  			ids.Add(id)
   715  		}
   716  
   717  		// If the machine is now dead we won't see a change for it again
   718  		// and therefore can permanently remove its entry from docHash
   719  		if doc.Life == Dead {
   720  			delete(w.seenDocs, id)
   721  		}
   722  
   723  		notFoundDocs.Remove(doc.Id)
   724  	}
   725  
   726  	// Assume that any doc in the notFound list belongs to a dead machine
   727  	// that has been reaped from the DB.
   728  	for docId := range notFoundDocs {
   729  		id := w.backend.localID(docId)
   730  		ids.Add(id)
   731  		delete(w.seenDocs, id)
   732  	}
   733  
   734  	return ids, iter.Close()
   735  }
   736  
   737  // WatchModelMachines returns a StringsWatcher that notifies of changes to
   738  // the lifecycles of the machines (but not containers) in the model.
   739  func (st *State) WatchModelMachines() StringsWatcher {
   740  	filter := func(id interface{}) bool {
   741  		k, err := st.strictLocalID(id.(string))
   742  		if err != nil {
   743  			return false
   744  		}
   745  		return !strings.Contains(k, "/")
   746  	}
   747  	return newLifecycleWatcher(st, machinesC, notContainerQuery, filter, nil)
   748  }
   749  
   750  // WatchContainers returns a StringsWatcher that notifies of changes to the
   751  // lifecycles of containers of the specified type on a machine.
   752  func (m *Machine) WatchContainers(ctype instance.ContainerType) StringsWatcher {
   753  	isChild := fmt.Sprintf("^%s/%s/%s$", m.doc.DocID, ctype, names.NumberSnippet)
   754  	return m.containersWatcher(isChild)
   755  }
   756  
   757  // WatchAllContainers returns a StringsWatcher that notifies of changes to the
   758  // lifecycles of all containers on a machine.
   759  func (m *Machine) WatchAllContainers() StringsWatcher {
   760  	isChild := fmt.Sprintf("^%s/%s/%s$", m.doc.DocID, names.ContainerTypeSnippet, names.NumberSnippet)
   761  	return m.containersWatcher(isChild)
   762  }
   763  
   764  func (m *Machine) containersWatcher(isChildRegexp string) StringsWatcher {
   765  	members := bson.D{{"_id", bson.D{{"$regex", isChildRegexp}}}}
   766  	compiled := regexp.MustCompile(isChildRegexp)
   767  	filter := func(key interface{}) bool {
   768  		k := key.(string)
   769  		_, err := m.st.strictLocalID(k)
   770  		if err != nil {
   771  			return false
   772  		}
   773  		return compiled.MatchString(k)
   774  	}
   775  	return newLifecycleWatcher(m.st, machinesC, members, filter, nil)
   776  }
   777  
   778  func newLifecycleWatcher(
   779  	backend modelBackend,
   780  	collName string,
   781  	members bson.D,
   782  	filter func(key interface{}) bool,
   783  	transform func(id string) string,
   784  ) StringsWatcher {
   785  	w := &lifecycleWatcher{
   786  		commonWatcher: newCommonWatcher(backend),
   787  		coll:          collFactory(backend.db(), collName),
   788  		collName:      collName,
   789  		members:       members,
   790  		filter:        filter,
   791  		transform:     transform,
   792  		life:          make(map[string]Life),
   793  		out:           make(chan []string),
   794  	}
   795  	w.tomb.Go(func() error {
   796  		defer close(w.out)
   797  		return w.loop()
   798  	})
   799  	return w
   800  }
   801  
   802  type lifeDoc struct {
   803  	Id   string `bson:"_id"`
   804  	Life Life
   805  }
   806  
   807  var lifeFields = bson.D{{"_id", 1}, {"life", 1}}
   808  
   809  // Changes returns the event channel for the LifecycleWatcher.
   810  func (w *lifecycleWatcher) Changes() <-chan []string {
   811  	return w.out
   812  }
   813  
   814  func (w *lifecycleWatcher) initial() (set.Strings, error) {
   815  	coll, closer := w.coll()
   816  	defer closer()
   817  
   818  	ids := make(set.Strings)
   819  	var doc lifeDoc
   820  	iter := coll.Find(w.members).Select(lifeFields).Iter()
   821  	for iter.Next(&doc) {
   822  		// If no members criteria is specified, use the filter
   823  		// to reject any unsuitable initial elements.
   824  		if w.members == nil && w.filter != nil && !w.filter(doc.Id) {
   825  			continue
   826  		}
   827  		id := w.backend.localID(doc.Id)
   828  		ids.Add(id)
   829  		if doc.Life != Dead {
   830  			w.life[id] = doc.Life
   831  		}
   832  	}
   833  	return ids, iter.Close()
   834  }
   835  
   836  func (w *lifecycleWatcher) merge(ids set.Strings, updates map[interface{}]bool) error {
   837  	coll, closer := w.coll()
   838  	defer closer()
   839  
   840  	// Separate ids into those thought to exist and those known to be removed.
   841  	var changed []string
   842  	latest := make(map[string]Life)
   843  	for docID, exists := range updates {
   844  		switch docID := docID.(type) {
   845  		case string:
   846  			if exists {
   847  				changed = append(changed, docID)
   848  			} else {
   849  				latest[w.backend.localID(docID)] = Dead
   850  			}
   851  		default:
   852  			return errors.Errorf("id is not of type string, got %T", docID)
   853  		}
   854  	}
   855  
   856  	// Collect life states from ids thought to exist. Any that don't actually
   857  	// exist are ignored (we'll hear about them in the next set of updates --
   858  	// all that's actually happened in that situation is that the watcher
   859  	// events have lagged a little behind reality).
   860  	iter := coll.Find(bson.D{{"_id", bson.D{{"$in", changed}}}}).Select(lifeFields).Iter()
   861  	var doc lifeDoc
   862  	for iter.Next(&doc) {
   863  		latest[w.backend.localID(doc.Id)] = doc.Life
   864  	}
   865  	if err := iter.Close(); err != nil {
   866  		return err
   867  	}
   868  
   869  	// Add to ids any whose life state is known to have changed.
   870  	for id, newLife := range latest {
   871  		gone := newLife == Dead
   872  		oldLife, known := w.life[id]
   873  		switch {
   874  		case known && gone:
   875  			delete(w.life, id)
   876  		case !known && !gone:
   877  			w.life[id] = newLife
   878  		case known && newLife != oldLife:
   879  			w.life[id] = newLife
   880  		default:
   881  			continue
   882  		}
   883  		ids.Add(id)
   884  	}
   885  	return nil
   886  }
   887  
   888  // ErrStateClosed is returned from watchers if their underlying
   889  // state connection has been closed.
   890  var ErrStateClosed = fmt.Errorf("state has been closed")
   891  
   892  // stateWatcherDeadError processes the error received when the watcher
   893  // inside a state connection dies. If the State has been closed, the
   894  // watcher will have been stopped and error will be nil, so we ensure
   895  // that higher level watchers return a non-nil error in that case, as
   896  // watchers are not expected to die unexpectedly without an error.
   897  func stateWatcherDeadError(err error) error {
   898  	if err != nil {
   899  		return err
   900  	}
   901  	return ErrStateClosed
   902  }
   903  
   904  func (w *lifecycleWatcher) loop() error {
   905  	in := make(chan watcher.Change)
   906  	w.watcher.WatchCollectionWithFilter(w.collName, in, w.filter)
   907  	defer w.watcher.UnwatchCollection(w.collName, in)
   908  	ids, err := w.initial()
   909  	if err != nil {
   910  		return err
   911  	}
   912  	out := w.out
   913  	for {
   914  		values := ids.Values()
   915  		if w.transform != nil {
   916  			for i, v := range values {
   917  				values[i] = w.transform(v)
   918  			}
   919  		}
   920  		select {
   921  		case <-w.tomb.Dying():
   922  			return tomb.ErrDying
   923  		case <-w.watcher.Dead():
   924  			return stateWatcherDeadError(w.watcher.Err())
   925  		case ch := <-in:
   926  			updates, ok := collect(ch, in, w.tomb.Dying())
   927  			if !ok {
   928  				return tomb.ErrDying
   929  			}
   930  			if err := w.merge(ids, updates); err != nil {
   931  				return err
   932  			}
   933  			if !ids.IsEmpty() {
   934  				out = w.out
   935  			}
   936  		case out <- values:
   937  			ids = make(set.Strings)
   938  			out = nil
   939  		}
   940  	}
   941  }
   942  
   943  // minUnitsWatcher notifies about MinUnits changes of the applications requiring
   944  // a minimum number of units to be alive. The first event returned by the
   945  // watcher is the set of application names requiring a minimum number of units.
   946  // Subsequent events are generated when an application increases MinUnits, or when
   947  // one or more units belonging to an application are destroyed.
   948  type minUnitsWatcher struct {
   949  	commonWatcher
   950  	known map[string]int
   951  	out   chan []string
   952  }
   953  
   954  var _ Watcher = (*minUnitsWatcher)(nil)
   955  
   956  func newMinUnitsWatcher(backend modelBackend) StringsWatcher {
   957  	w := &minUnitsWatcher{
   958  		commonWatcher: newCommonWatcher(backend),
   959  		known:         make(map[string]int),
   960  		out:           make(chan []string),
   961  	}
   962  	w.tomb.Go(func() error {
   963  		defer close(w.out)
   964  		return w.loop()
   965  	})
   966  	return w
   967  }
   968  
   969  // WatchMinUnits returns a StringsWatcher for the minUnits collection
   970  func (st *State) WatchMinUnits() StringsWatcher {
   971  	return newMinUnitsWatcher(st)
   972  }
   973  
   974  func (w *minUnitsWatcher) initial() (set.Strings, error) {
   975  	applicationnames := make(set.Strings)
   976  	var doc minUnitsDoc
   977  	newMinUnits, closer := w.db.GetCollection(minUnitsC)
   978  	defer closer()
   979  
   980  	iter := newMinUnits.Find(nil).Iter()
   981  	for iter.Next(&doc) {
   982  		w.known[doc.ApplicationName] = doc.Revno
   983  		applicationnames.Add(doc.ApplicationName)
   984  	}
   985  	return applicationnames, iter.Close()
   986  }
   987  
   988  func (w *minUnitsWatcher) merge(applicationnames set.Strings, change watcher.Change) error {
   989  	applicationname := w.backend.localID(change.Id.(string))
   990  	if change.Revno < 0 {
   991  		delete(w.known, applicationname)
   992  		applicationnames.Remove(applicationname)
   993  		return nil
   994  	}
   995  	doc := minUnitsDoc{}
   996  	newMinUnits, closer := w.db.GetCollection(minUnitsC)
   997  	defer closer()
   998  	if err := newMinUnits.FindId(change.Id).One(&doc); err != nil {
   999  		return err
  1000  	}
  1001  	revno, known := w.known[applicationname]
  1002  	w.known[applicationname] = doc.Revno
  1003  	if !known || doc.Revno > revno {
  1004  		applicationnames.Add(applicationname)
  1005  	}
  1006  	return nil
  1007  }
  1008  
  1009  func (w *minUnitsWatcher) loop() (err error) {
  1010  	ch := make(chan watcher.Change)
  1011  	w.watcher.WatchCollectionWithFilter(minUnitsC, ch, isLocalID(w.backend))
  1012  	defer w.watcher.UnwatchCollection(minUnitsC, ch)
  1013  	applicationnames, err := w.initial()
  1014  	if err != nil {
  1015  		return err
  1016  	}
  1017  	out := w.out
  1018  	for {
  1019  		select {
  1020  		case <-w.tomb.Dying():
  1021  			return tomb.ErrDying
  1022  		case <-w.watcher.Dead():
  1023  			return stateWatcherDeadError(w.watcher.Err())
  1024  		case change := <-ch:
  1025  			if err = w.merge(applicationnames, change); err != nil {
  1026  				return err
  1027  			}
  1028  			if !applicationnames.IsEmpty() {
  1029  				out = w.out
  1030  			}
  1031  		case out <- applicationnames.Values():
  1032  			out = nil
  1033  			applicationnames = set.NewStrings()
  1034  		}
  1035  	}
  1036  }
  1037  
  1038  func (w *minUnitsWatcher) Changes() <-chan []string {
  1039  	return w.out
  1040  }
  1041  
  1042  // scopeInfo holds a RelationScopeWatcher's last-delivered state, and any
  1043  // known but undelivered changes thereto.
  1044  type scopeInfo struct {
  1045  	base map[string]bool
  1046  	diff map[string]bool
  1047  }
  1048  
  1049  func (info *scopeInfo) add(name string) {
  1050  	if info.base[name] {
  1051  		delete(info.diff, name)
  1052  	} else {
  1053  		info.diff[name] = true
  1054  	}
  1055  }
  1056  
  1057  func (info *scopeInfo) remove(name string) {
  1058  	if info.base[name] {
  1059  		info.diff[name] = false
  1060  	} else {
  1061  		delete(info.diff, name)
  1062  	}
  1063  }
  1064  
  1065  func (info *scopeInfo) commit() {
  1066  	for name, change := range info.diff {
  1067  		if change {
  1068  			info.base[name] = true
  1069  		} else {
  1070  			delete(info.base, name)
  1071  		}
  1072  	}
  1073  	info.diff = map[string]bool{}
  1074  }
  1075  
  1076  func (info *scopeInfo) hasChanges() bool {
  1077  	return len(info.diff) > 0
  1078  }
  1079  
  1080  func (info *scopeInfo) changes() *RelationScopeChange {
  1081  	ch := &RelationScopeChange{}
  1082  	for name, change := range info.diff {
  1083  		if change {
  1084  			ch.Entered = append(ch.Entered, name)
  1085  		} else {
  1086  			ch.Left = append(ch.Left, name)
  1087  		}
  1088  	}
  1089  	return ch
  1090  }
  1091  
  1092  var _ Watcher = (*RelationScopeWatcher)(nil)
  1093  
  1094  // RelationScopeChange contains information about units that have
  1095  // entered or left a particular scope.
  1096  type RelationScopeChange struct {
  1097  	Entered []string
  1098  	Left    []string
  1099  }
  1100  
  1101  // RelationScopeWatcher observes changes to the set of units
  1102  // in a particular relation scope.
  1103  type RelationScopeWatcher struct {
  1104  	commonWatcher
  1105  	prefix string
  1106  	ignore string
  1107  	out    chan *RelationScopeChange
  1108  }
  1109  
  1110  func newRelationScopeWatcher(backend modelBackend, scope, ignore string) *RelationScopeWatcher {
  1111  	w := &RelationScopeWatcher{
  1112  		commonWatcher: newCommonWatcher(backend),
  1113  		prefix:        scope + "#",
  1114  		ignore:        ignore,
  1115  		out:           make(chan *RelationScopeChange),
  1116  	}
  1117  	w.tomb.Go(func() error {
  1118  		defer close(w.out)
  1119  		return w.loop()
  1120  	})
  1121  	return w
  1122  }
  1123  
  1124  // Changes returns a channel that will receive changes when units enter and
  1125  // leave a relation scope. The Entered field in the first event on the channel
  1126  // holds the initial state.
  1127  func (w *RelationScopeWatcher) Changes() <-chan *RelationScopeChange {
  1128  	return w.out
  1129  }
  1130  
  1131  // initialInfo returns an uncommitted scopeInfo with the current set of units.
  1132  func (w *RelationScopeWatcher) initialInfo() (info *scopeInfo, err error) {
  1133  	relationScopes, closer := w.db.GetCollection(relationScopesC)
  1134  	defer closer()
  1135  
  1136  	docs := []relationScopeDoc{}
  1137  	sel := bson.D{
  1138  		{"key", bson.D{{"$regex", "^" + w.prefix}}},
  1139  		{"departing", bson.D{{"$ne", true}}},
  1140  	}
  1141  	if err = relationScopes.Find(sel).All(&docs); err != nil {
  1142  		return nil, err
  1143  	}
  1144  	info = &scopeInfo{
  1145  		base: map[string]bool{},
  1146  		diff: map[string]bool{},
  1147  	}
  1148  	for _, doc := range docs {
  1149  		if name := doc.unitName(); name != w.ignore {
  1150  			info.add(name)
  1151  		}
  1152  	}
  1153  	logger.Tracef("relationScopeWatcher prefix %q initializing with %# v",
  1154  		w.prefix, pretty.Formatter(info))
  1155  	return info, nil
  1156  }
  1157  
  1158  // mergeChanges updates info with the contents of the changes in ids. False
  1159  // values are always treated as removed; true values cause the associated
  1160  // document to be read, and whether it's treated as added or removed depends
  1161  // on the value of the document's Departing field.
  1162  func (w *RelationScopeWatcher) mergeChanges(info *scopeInfo, ids map[interface{}]bool) error {
  1163  	relationScopes, closer := w.db.GetCollection(relationScopesC)
  1164  	defer closer()
  1165  
  1166  	var existIds []string
  1167  	for id, exists := range ids {
  1168  		switch id := id.(type) {
  1169  		case string:
  1170  			if exists {
  1171  				existIds = append(existIds, id)
  1172  			} else {
  1173  				key, err := w.backend.strictLocalID(id)
  1174  				if err != nil {
  1175  					return errors.Trace(err)
  1176  				}
  1177  				info.remove(unitNameFromScopeKey(key))
  1178  			}
  1179  		default:
  1180  			logger.Warningf("ignoring bad relation scope id: %#v", id)
  1181  		}
  1182  	}
  1183  	var docs []relationScopeDoc
  1184  	sel := bson.D{{"_id", bson.D{{"$in", existIds}}}}
  1185  	if err := relationScopes.Find(sel).All(&docs); err != nil {
  1186  		return err
  1187  	}
  1188  	for _, doc := range docs {
  1189  		name := doc.unitName()
  1190  		if doc.Departing {
  1191  			info.remove(name)
  1192  		} else if name != w.ignore {
  1193  			info.add(name)
  1194  		}
  1195  	}
  1196  	logger.Tracef("RelationScopeWatcher prefix %q merge scope to %# v from ids: %# v",
  1197  		w.prefix, pretty.Formatter(info), pretty.Formatter(ids))
  1198  	return nil
  1199  }
  1200  
  1201  func (w *RelationScopeWatcher) loop() error {
  1202  	in := make(chan watcher.Change)
  1203  	fullPrefix := w.backend.docID(w.prefix)
  1204  	filter := func(id interface{}) bool {
  1205  		return strings.HasPrefix(id.(string), fullPrefix)
  1206  	}
  1207  	w.watcher.WatchCollectionWithFilter(relationScopesC, in, filter)
  1208  	defer w.watcher.UnwatchCollection(relationScopesC, in)
  1209  	info, err := w.initialInfo()
  1210  	if err != nil {
  1211  		return err
  1212  	}
  1213  	sent := false
  1214  	out := w.out
  1215  	for {
  1216  		select {
  1217  		case <-w.watcher.Dead():
  1218  			return stateWatcherDeadError(w.watcher.Err())
  1219  		case <-w.tomb.Dying():
  1220  			return tomb.ErrDying
  1221  		case ch := <-in:
  1222  			latest, ok := collect(ch, in, w.tomb.Dying())
  1223  			if !ok {
  1224  				return tomb.ErrDying
  1225  			}
  1226  			if err := w.mergeChanges(info, latest); err != nil {
  1227  				return err
  1228  			}
  1229  			if info.hasChanges() {
  1230  				out = w.out
  1231  			} else if sent {
  1232  				out = nil
  1233  			}
  1234  		case out <- info.changes():
  1235  			info.commit()
  1236  			sent = true
  1237  			out = nil
  1238  		}
  1239  	}
  1240  }
  1241  
  1242  // relationUnitsWatcher sends notifications of units entering and leaving the
  1243  // scope of a RelationUnit, and changes to the settings of those units known
  1244  // to have entered.
  1245  type relationUnitsWatcher struct {
  1246  	commonWatcher
  1247  	sw              *RelationScopeWatcher
  1248  	watching        set.Strings
  1249  	updates         chan watcher.Change
  1250  	appSettingsKeys []string
  1251  	appUpdates      chan watcher.Change
  1252  	out             chan corewatcher.RelationUnitsChange
  1253  	logger          loggo.Logger
  1254  }
  1255  
  1256  // Watch returns a watcher that notifies of changes to counterpart units in
  1257  // the relation.
  1258  func (ru *RelationUnit) Watch() RelationUnitsWatcher {
  1259  	// TODO(jam): 2019-10-21 passing in ru.counterpartApplicationSettingsKeys() feels wrong here.
  1260  	//  we need *some* way to give the relation units watcher an idea of what actual
  1261  	//  relation it is watching, not just the Scope of what units have/haven't entered.
  1262  	//  However, we need the relation ID (which isn't currently passed), and
  1263  	//  the application names to be passed. We could
  1264  	//  a) pass in 'RelationUnit'
  1265  	//  b) pass just the relation id and app names separately
  1266  	//  c) filter on what enters scope to determine what 'apps' are connected,
  1267  	//     but I was hoping to decouple app settings from scope.
  1268  	return newRelationUnitsWatcher(ru.st, ru.WatchScope(), ru.counterpartApplicationSettingsKeys())
  1269  }
  1270  
  1271  // WatchUnits returns a watcher that notifies of changes to the units of the
  1272  // specified application endpoint in the relation. This method will return an error
  1273  // if the endpoint is not globally scoped.
  1274  func (r *Relation) WatchUnits(appName string) (RelationUnitsWatcher, error) {
  1275  	ep, err := r.Endpoint(appName)
  1276  	if err != nil {
  1277  		return nil, err
  1278  	}
  1279  	if ep.Scope != charm.ScopeGlobal {
  1280  		return nil, errors.Errorf("%q endpoint is not globally scoped", ep.Name)
  1281  	}
  1282  	rsw := watchRelationScope(r.st, r.globalScope(), ep.Role, "")
  1283  	appSettingsKey := relationApplicationSettingsKey(r.Id(), appName)
  1284  	logger.Child("relationunits").Tracef("Relation.WatchUnits(%q) watching: %q", appName, appSettingsKey)
  1285  	return newRelationUnitsWatcher(r.st, rsw, []string{appSettingsKey}), nil
  1286  }
  1287  
  1288  func newRelationUnitsWatcher(backend modelBackend, sw *RelationScopeWatcher, appSettingsKeys []string) RelationUnitsWatcher {
  1289  	w := &relationUnitsWatcher{
  1290  		commonWatcher:   newCommonWatcher(backend),
  1291  		sw:              sw,
  1292  		appSettingsKeys: appSettingsKeys,
  1293  		watching:        make(set.Strings),
  1294  		updates:         make(chan watcher.Change),
  1295  		appUpdates:      make(chan watcher.Change),
  1296  		out:             make(chan corewatcher.RelationUnitsChange),
  1297  		logger:          logger.Child("relationunits"),
  1298  	}
  1299  	w.tomb.Go(func() error {
  1300  		defer w.finish()
  1301  		return w.loop()
  1302  	})
  1303  	return w
  1304  }
  1305  
  1306  // Changes returns a channel that will receive the changes to
  1307  // counterpart units in a relation. The first event on the
  1308  // channel holds the initial state of the relation in its
  1309  // Changed field.
  1310  func (w *relationUnitsWatcher) Changes() corewatcher.RelationUnitsChannel {
  1311  	return w.out
  1312  }
  1313  
  1314  func emptyRelationUnitsChanges(changes *corewatcher.RelationUnitsChange) bool {
  1315  	return len(changes.Changed)+len(changes.AppChanged)+len(changes.Departed) == 0
  1316  }
  1317  
  1318  func setRelationUnitChangeVersion(changes *corewatcher.RelationUnitsChange, key string, version int64) {
  1319  	name := unitNameFromScopeKey(key)
  1320  	settings := corewatcher.UnitSettings{Version: version}
  1321  	if changes.Changed == nil {
  1322  		changes.Changed = map[string]corewatcher.UnitSettings{}
  1323  	}
  1324  	changes.Changed[name] = settings
  1325  }
  1326  
  1327  func (w *relationUnitsWatcher) watchRelatedAppSettings(changes *corewatcher.RelationUnitsChange) error {
  1328  	idsAsInterface := make([]interface{}, len(w.appSettingsKeys))
  1329  	for i, key := range w.appSettingsKeys {
  1330  		idsAsInterface[i] = w.backend.docID(key)
  1331  	}
  1332  	w.logger.Tracef("relationUnitsWatcher %q watching app keys: %v", w.sw.prefix, w.appSettingsKeys)
  1333  	if err := w.watcher.WatchMulti(settingsC, idsAsInterface, w.appUpdates); err != nil {
  1334  		return errors.Trace(err)
  1335  	}
  1336  	// WatchMulti (as a raw DB watcher) does *not* fire an initial event, it just starts the watch, which
  1337  	// you then use to know you can read the database without missing updates.
  1338  	for _, key := range w.appSettingsKeys {
  1339  		if err := w.mergeAppSettings(changes, key); err != nil {
  1340  			return errors.Trace(err)
  1341  		}
  1342  	}
  1343  	return nil
  1344  }
  1345  
  1346  // mergeSettings reads the relation settings node for the unit with the
  1347  // supplied key, and sets a value in the Changed field keyed on the unit's
  1348  // name. It returns the mgo/txn revision number of the settings node.
  1349  func (w *relationUnitsWatcher) mergeSettings(changes *corewatcher.RelationUnitsChange, key string) error {
  1350  	version, err := readSettingsDocVersion(w.backend.db(), settingsC, key)
  1351  	if err != nil {
  1352  		w.logger.Tracef("relationUnitsWatcher %q merging key %q (not found)", w.sw.prefix, key)
  1353  		return errors.Trace(err)
  1354  	}
  1355  	w.logger.Tracef("relationUnitsWatcher %q merging key %q version: %d", w.sw.prefix, key, version)
  1356  	setRelationUnitChangeVersion(changes, key, version)
  1357  	return nil
  1358  }
  1359  
  1360  func (w *relationUnitsWatcher) mergeAppSettings(changes *corewatcher.RelationUnitsChange, key string) error {
  1361  	version, err := readSettingsDocVersion(w.backend.db(), settingsC, key)
  1362  	if err != nil {
  1363  		w.logger.Tracef("relationUnitsWatcher %q merging app key %q (not found)", w.sw.prefix, key)
  1364  		return errors.Trace(err)
  1365  	}
  1366  	w.logger.Tracef("relationUnitsWatcher %q merging app key %q version: %d", w.sw.prefix, key, version)
  1367  	if changes.AppChanged == nil {
  1368  		changes.AppChanged = make(map[string]int64)
  1369  	}
  1370  	// This also works for appName
  1371  	name := unitNameFromScopeKey(key)
  1372  	changes.AppChanged[name] = version
  1373  	return nil
  1374  }
  1375  
  1376  // mergeScope starts and stops settings watches on the units entering and
  1377  // leaving the scope in the supplied RelationScopeChange event, and applies
  1378  // the expressed changes to the supplied RelationUnitsChange event.
  1379  func (w *relationUnitsWatcher) mergeScope(changes *corewatcher.RelationUnitsChange, c *RelationScopeChange) error {
  1380  	docIds := make([]interface{}, len(c.Entered))
  1381  	for i, name := range c.Entered {
  1382  		key := w.sw.prefix + name
  1383  		docID := w.backend.docID(key)
  1384  		docIds[i] = docID
  1385  	}
  1386  	w.logger.Tracef("relationUnitsWatcher %q watching newly entered: %v, and unwatching left %v", w.sw.prefix, c.Entered, c.Left)
  1387  	if err := w.watcher.WatchMulti(settingsC, docIds, w.updates); err != nil {
  1388  		return errors.Trace(err)
  1389  	}
  1390  	for _, docID := range docIds {
  1391  		w.watching.Add(docID.(string))
  1392  	}
  1393  	for _, name := range c.Entered {
  1394  		key := w.sw.prefix + name
  1395  		if err := w.mergeSettings(changes, key); err != nil {
  1396  			return errors.Annotatef(err, "while merging settings for %q entering relation scope", name)
  1397  		}
  1398  		changes.Departed = remove(changes.Departed, name)
  1399  	}
  1400  	for _, name := range c.Left {
  1401  		key := w.sw.prefix + name
  1402  		docID := w.backend.docID(key)
  1403  		changes.Departed = append(changes.Departed, name)
  1404  		if changes.Changed != nil {
  1405  			delete(changes.Changed, name)
  1406  		}
  1407  		w.watcher.Unwatch(settingsC, docID, w.updates)
  1408  		w.watching.Remove(docID)
  1409  	}
  1410  	w.logger.Tracef("relationUnitsWatcher %q Change updated to: %# v", w.sw.prefix, changes)
  1411  	return nil
  1412  }
  1413  
  1414  // remove removes s from strs and returns the modified slice.
  1415  func remove(strs []string, s string) []string {
  1416  	for i, v := range strs {
  1417  		if s == v {
  1418  			strs[i] = strs[len(strs)-1]
  1419  			return strs[:len(strs)-1]
  1420  		}
  1421  	}
  1422  	return strs
  1423  }
  1424  
  1425  func (w *relationUnitsWatcher) finish() {
  1426  	watcher.Stop(w.sw, &w.tomb)
  1427  	for _, watchedValue := range w.watching.Values() {
  1428  		w.watcher.Unwatch(settingsC, watchedValue, w.updates)
  1429  	}
  1430  	for _, appKey := range w.appSettingsKeys {
  1431  		docID := w.backend.docID(appKey)
  1432  		w.watcher.Unwatch(settingsC, docID, w.appUpdates)
  1433  	}
  1434  	close(w.appUpdates)
  1435  	close(w.updates)
  1436  	close(w.out)
  1437  }
  1438  
  1439  func (w *relationUnitsWatcher) loop() (err error) {
  1440  	var (
  1441  		gotInitialScopeWatcher bool
  1442  		sentInitial            bool
  1443  		changes                corewatcher.RelationUnitsChange
  1444  		out                    chan<- corewatcher.RelationUnitsChange
  1445  	)
  1446  	// Note that w.ScopeWatcher *does* trigger an initial event, while
  1447  	// WatchMulti from raw document watchers does *not*. (raw database watchers
  1448  	// don't send initial events, logical watchers built on top of them do.)
  1449  	if err := w.watchRelatedAppSettings(&changes); err != nil {
  1450  		return errors.Trace(err)
  1451  	}
  1452  	for {
  1453  		select {
  1454  		case <-w.watcher.Dead():
  1455  			return stateWatcherDeadError(w.watcher.Err())
  1456  		case <-w.tomb.Dying():
  1457  			return tomb.ErrDying
  1458  		case c, ok := <-w.sw.Changes():
  1459  			if !ok {
  1460  				return watcher.EnsureErr(w.sw)
  1461  			}
  1462  			gotInitialScopeWatcher = true
  1463  			if w.logger.IsTraceEnabled() {
  1464  				w.logger.Tracef("relationUnitsWatcher %q scope Changes(): %# v", w.sw.prefix, pretty.Formatter(c))
  1465  			}
  1466  			if err = w.mergeScope(&changes, c); err != nil {
  1467  				return err
  1468  			}
  1469  			if !sentInitial || !emptyRelationUnitsChanges(&changes) {
  1470  				out = w.out
  1471  			} else {
  1472  				// If we get a change that negates a previous change, cancel the event
  1473  				out = nil
  1474  			}
  1475  		case c := <-w.updates:
  1476  			id, ok := c.Id.(string)
  1477  			if !ok {
  1478  				w.logger.Warningf("relationUnitsWatcher %q ignoring bad relation scope id: %#v", w.sw.prefix, c.Id)
  1479  				continue
  1480  			}
  1481  			w.logger.Tracef("relationUnitsWatcher %q relation update %q", w.sw.prefix, id)
  1482  			if err := w.mergeSettings(&changes, id); err != nil {
  1483  				return errors.Annotatef(err, "relation scope id %q", id)
  1484  			}
  1485  			if gotInitialScopeWatcher && !emptyRelationUnitsChanges(&changes) {
  1486  				out = w.out
  1487  			}
  1488  		case c := <-w.appUpdates:
  1489  			id, ok := c.Id.(string)
  1490  			if !ok {
  1491  				w.logger.Warningf("relationUnitsWatcher %q ignoring bad application settings id: %#v", w.sw.prefix, c.Id)
  1492  				continue
  1493  			}
  1494  			w.logger.Tracef("relationUnitsWatcher %q app settings update %q", w.sw.prefix, id)
  1495  			if err := w.mergeAppSettings(&changes, id); err != nil {
  1496  				return errors.Annotatef(err, "relation scope id %q", id)
  1497  			}
  1498  			if gotInitialScopeWatcher && (!sentInitial || !emptyRelationUnitsChanges(&changes)) {
  1499  				out = w.out
  1500  			}
  1501  		case out <- changes:
  1502  			if w.logger.IsTraceEnabled() {
  1503  				w.logger.Tracef("relationUnitsWatcher %q sent changes %# v", w.sw.prefix, pretty.Formatter(changes))
  1504  			}
  1505  			sentInitial = true
  1506  			changes = corewatcher.RelationUnitsChange{}
  1507  			out = nil
  1508  		}
  1509  	}
  1510  }
  1511  
  1512  // WatchLifeSuspendedStatus returns a watcher that notifies of changes to the life
  1513  // or suspended status of the relation.
  1514  func (r *Relation) WatchLifeSuspendedStatus() StringsWatcher {
  1515  	filter := func(id interface{}) bool {
  1516  		k, err := r.st.strictLocalID(id.(string))
  1517  		if err != nil {
  1518  			return false
  1519  		}
  1520  		return k == r.Tag().Id()
  1521  	}
  1522  	members := bson.D{{"id", r.Id()}}
  1523  	return newRelationLifeSuspendedWatcher(r.st, members, filter, nil)
  1524  }
  1525  
  1526  type relationLifeSuspended struct {
  1527  	life      Life
  1528  	suspended bool
  1529  }
  1530  
  1531  // relationLifeSuspendedWatcher sends notifications of changes to the life or
  1532  // suspended status of specific relations.
  1533  type relationLifeSuspendedWatcher struct {
  1534  	commonWatcher
  1535  	out           chan []string
  1536  	lifeSuspended map[string]relationLifeSuspended
  1537  
  1538  	members   bson.D
  1539  	filter    func(interface{}) bool
  1540  	transform func(id string) string
  1541  }
  1542  
  1543  // newRelationLifeSuspendedWatcher creates a watcher that sends changes when the
  1544  // life or suspended status of specific relations change.
  1545  func newRelationLifeSuspendedWatcher(
  1546  	backend modelBackend,
  1547  	members bson.D,
  1548  	filter func(key interface{}) bool,
  1549  	transform func(id string) string,
  1550  ) *relationLifeSuspendedWatcher {
  1551  	w := &relationLifeSuspendedWatcher{
  1552  		commonWatcher: newCommonWatcher(backend),
  1553  		out:           make(chan []string),
  1554  		members:       members,
  1555  		filter:        filter,
  1556  		transform:     transform,
  1557  		lifeSuspended: make(map[string]relationLifeSuspended),
  1558  	}
  1559  	w.tomb.Go(func() error {
  1560  		defer close(w.out)
  1561  		return w.loop()
  1562  	})
  1563  	return w
  1564  }
  1565  
  1566  func (w *relationLifeSuspendedWatcher) Changes() <-chan []string {
  1567  	return w.out
  1568  }
  1569  
  1570  type relationLifeSuspendedDoc struct {
  1571  	DocId     string `bson:"_id"`
  1572  	Life      Life   `bson:"life"`
  1573  	Suspended bool   `bson:"suspended"`
  1574  }
  1575  
  1576  var relationLifeSuspendedFields = bson.D{{"_id", 1}, {"life", 1}, {"suspended", 1}}
  1577  
  1578  func (w *relationLifeSuspendedWatcher) initial() (set.Strings, error) {
  1579  	coll, closer := w.db.GetCollection(relationsC)
  1580  	defer closer()
  1581  
  1582  	ids := make(set.Strings)
  1583  	var doc relationLifeSuspendedDoc
  1584  	iter := coll.Find(w.members).Select(relationLifeSuspendedFields).Iter()
  1585  	for iter.Next(&doc) {
  1586  		// If no members criteria is specified, use the filter
  1587  		// to reject any unsuitable initial elements.
  1588  		if w.members == nil && w.filter != nil && !w.filter(doc.DocId) {
  1589  			continue
  1590  		}
  1591  		id := w.backend.localID(doc.DocId)
  1592  		ids.Add(id)
  1593  		if doc.Life != Dead {
  1594  			w.lifeSuspended[id] = relationLifeSuspended{life: doc.Life, suspended: doc.Suspended}
  1595  		}
  1596  	}
  1597  	return ids, iter.Close()
  1598  }
  1599  
  1600  func (w *relationLifeSuspendedWatcher) merge(ids set.Strings, updates map[interface{}]bool) error {
  1601  	coll, closer := w.db.GetCollection(relationsC)
  1602  	defer closer()
  1603  
  1604  	// Separate ids into those thought to exist and those known to be removed.
  1605  	var changed []string
  1606  	latest := make(map[string]relationLifeSuspended)
  1607  	for docID, exists := range updates {
  1608  		switch docID := docID.(type) {
  1609  		case string:
  1610  			if exists {
  1611  				changed = append(changed, docID)
  1612  			} else {
  1613  				latest[w.backend.localID(docID)] = relationLifeSuspended{life: Dead}
  1614  			}
  1615  		default:
  1616  			return errors.Errorf("id is not of type string, got %T", docID)
  1617  		}
  1618  	}
  1619  
  1620  	// Collect life states from ids thought to exist. Any that don't actually
  1621  	// exist are ignored (we'll hear about them in the next set of updates --
  1622  	// all that's actually happened in that situation is that the watcher
  1623  	// events have lagged a little behind reality).
  1624  	iter := coll.Find(bson.D{{"_id", bson.D{{"$in", changed}}}}).Select(relationLifeSuspendedFields).Iter()
  1625  	var doc relationLifeSuspendedDoc
  1626  	for iter.Next(&doc) {
  1627  		latest[w.backend.localID(doc.DocId)] = relationLifeSuspended{life: doc.Life, suspended: doc.Suspended}
  1628  	}
  1629  	if err := iter.Close(); err != nil {
  1630  		return err
  1631  	}
  1632  
  1633  	// Add to ids any whose life state is known to have changed.
  1634  	for id, newLifeSuspended := range latest {
  1635  		gone := newLifeSuspended.life == Dead
  1636  		oldLifeSuspended, known := w.lifeSuspended[id]
  1637  		switch {
  1638  		case known && gone:
  1639  			delete(w.lifeSuspended, id)
  1640  		case !known && !gone:
  1641  			w.lifeSuspended[id] = newLifeSuspended
  1642  		case known &&
  1643  			(newLifeSuspended.life != oldLifeSuspended.life || newLifeSuspended.suspended != oldLifeSuspended.suspended):
  1644  			w.lifeSuspended[id] = newLifeSuspended
  1645  		default:
  1646  			continue
  1647  		}
  1648  		ids.Add(id)
  1649  	}
  1650  	return nil
  1651  }
  1652  
  1653  func (w *relationLifeSuspendedWatcher) loop() error {
  1654  	in := make(chan watcher.Change)
  1655  	w.watcher.WatchCollectionWithFilter(relationsC, in, w.filter)
  1656  	defer w.watcher.UnwatchCollection(relationsC, in)
  1657  	ids, err := w.initial()
  1658  	if err != nil {
  1659  		return err
  1660  	}
  1661  	out := w.out
  1662  	for {
  1663  		values := ids.Values()
  1664  		if w.transform != nil {
  1665  			for i, v := range values {
  1666  				values[i] = w.transform(v)
  1667  			}
  1668  		}
  1669  		select {
  1670  		case <-w.tomb.Dying():
  1671  			return tomb.ErrDying
  1672  		case <-w.watcher.Dead():
  1673  			return stateWatcherDeadError(w.watcher.Err())
  1674  		case ch := <-in:
  1675  			updates, ok := collect(ch, in, w.tomb.Dying())
  1676  			if !ok {
  1677  				return tomb.ErrDying
  1678  			}
  1679  			if err := w.merge(ids, updates); err != nil {
  1680  				return err
  1681  			}
  1682  			if !ids.IsEmpty() {
  1683  				out = w.out
  1684  			}
  1685  		case out <- values:
  1686  			ids = make(set.Strings)
  1687  			out = nil
  1688  		}
  1689  	}
  1690  }
  1691  
  1692  // unitsWatcher notifies of changes to a set of units. Notifications will be
  1693  // sent when units enter or leave the set, and when units in the set change
  1694  // their lifecycle status. The initial event contains all units in the set,
  1695  // regardless of lifecycle status; once a unit observed to be Dead or removed
  1696  // has been reported, it will not be reported again.
  1697  type unitsWatcher struct {
  1698  	commonWatcher
  1699  	tag      string
  1700  	getUnits func() ([]string, error)
  1701  	life     map[string]Life
  1702  	in       chan watcher.Change
  1703  	out      chan []string
  1704  }
  1705  
  1706  var _ Watcher = (*unitsWatcher)(nil)
  1707  
  1708  // WatchSubordinateUnits returns a StringsWatcher tracking the unit's subordinate units.
  1709  func (u *Unit) WatchSubordinateUnits() StringsWatcher {
  1710  	u = &Unit{st: u.st, doc: u.doc}
  1711  	coll := unitsC
  1712  	getUnits := func() ([]string, error) {
  1713  		if err := u.Refresh(); err != nil {
  1714  			return nil, err
  1715  		}
  1716  		return u.doc.Subordinates, nil
  1717  	}
  1718  	return newUnitsWatcher(u.st, u.Tag(), getUnits, coll, u.doc.DocID)
  1719  }
  1720  
  1721  // WatchPrincipalUnits returns a StringsWatcher tracking the machine's principal
  1722  // units.
  1723  func (m *Machine) WatchPrincipalUnits() StringsWatcher {
  1724  	m = &Machine{st: m.st, doc: m.doc}
  1725  	coll := machinesC
  1726  	getUnits := func() ([]string, error) {
  1727  		if err := m.Refresh(); err != nil {
  1728  			return nil, err
  1729  		}
  1730  		return m.doc.Principals, nil
  1731  	}
  1732  	return newUnitsWatcher(m.st, m.Tag(), getUnits, coll, m.doc.DocID)
  1733  }
  1734  
  1735  func newUnitsWatcher(backend modelBackend, tag names.Tag, getUnits func() ([]string, error), coll, id string) StringsWatcher {
  1736  	w := &unitsWatcher{
  1737  		commonWatcher: newCommonWatcher(backend),
  1738  		tag:           tag.String(),
  1739  		getUnits:      getUnits,
  1740  		life:          map[string]Life{},
  1741  		in:            make(chan watcher.Change),
  1742  		out:           make(chan []string),
  1743  	}
  1744  	w.tomb.Go(func() error {
  1745  		defer close(w.out)
  1746  		return w.loop(coll, id)
  1747  	})
  1748  	return w
  1749  }
  1750  
  1751  // Tag returns the tag of the entity whose units are being watched.
  1752  func (w *unitsWatcher) Tag() string {
  1753  	return w.tag
  1754  }
  1755  
  1756  // Changes returns the UnitsWatcher's output channel.
  1757  func (w *unitsWatcher) Changes() <-chan []string {
  1758  	return w.out
  1759  }
  1760  
  1761  // lifeWatchDoc holds the fields used in starting and maintaining a watch
  1762  // on a entity's lifecycle.
  1763  type lifeWatchDoc struct {
  1764  	Id       string `bson:"_id"`
  1765  	Life     Life
  1766  	TxnRevno int64 `bson:"txn-revno"`
  1767  }
  1768  
  1769  // lifeWatchFields specifies the fields of a lifeWatchDoc.
  1770  var lifeWatchFields = bson.D{{"_id", 1}, {"life", 1}, {"txn-revno", 1}}
  1771  
  1772  // initial returns every member of the tracked set.
  1773  func (w *unitsWatcher) initial() ([]string, error) {
  1774  	initialNames, err := w.getUnits()
  1775  	if err != nil {
  1776  		return nil, err
  1777  	}
  1778  	return w.watchUnits(initialNames, nil)
  1779  }
  1780  
  1781  func (w *unitsWatcher) watchUnits(names, changes []string) ([]string, error) {
  1782  	docs := []lifeWatchDoc{}
  1783  	ids := make([]interface{}, len(names))
  1784  	for i := range names {
  1785  		ids[i] = w.backend.docID(names[i])
  1786  	}
  1787  	if err := w.watcher.WatchMulti(unitsC, ids, w.in); err != nil {
  1788  		logger.Tracef("error watching %q in %q: %v", ids, unitsC, err)
  1789  		return nil, errors.Trace(err)
  1790  	}
  1791  	logger.Tracef("watching %q ids: %q", unitsC, ids)
  1792  	newUnits, closer := w.db.GetCollection(unitsC)
  1793  	err := newUnits.Find(bson.M{"_id": bson.M{"$in": names}}).Select(lifeWatchFields).All(&docs)
  1794  	closer()
  1795  	if err != nil {
  1796  		return nil, errors.Trace(err)
  1797  	}
  1798  
  1799  	found := set.NewStrings()
  1800  	for _, doc := range docs {
  1801  		localId, err := w.backend.strictLocalID(doc.Id)
  1802  		if err != nil {
  1803  			return nil, errors.Trace(err)
  1804  		}
  1805  		found.Add(localId)
  1806  		if !hasString(changes, localId) {
  1807  			logger.Tracef("marking change for %q", localId)
  1808  			changes = append(changes, localId)
  1809  		}
  1810  		if doc.Life != Dead {
  1811  			logger.Tracef("setting life of %q to %q", localId, doc.Life)
  1812  			w.life[localId] = doc.Life
  1813  		} else {
  1814  			// Note(jam): 2019-01-31 This was done to match existing behavior, it is not guaranteed
  1815  			// to be the behavior we want. Specifically, if we see a Dead unit we will report that
  1816  			// it exists in the initial event. However, we stop watching because
  1817  			// the object is dead, so you don't get an event when the doc is
  1818  			// removed from the database. It seems better if we either/
  1819  			// a) don't tell you about Dead documents
  1820  			// b) give you an event if a Dead document goes away.
  1821  			logger.Tracef("unwatching Dead unit: %q", localId)
  1822  			w.watcher.Unwatch(unitsC, doc.Id, w.in)
  1823  			delete(w.life, localId)
  1824  		}
  1825  	}
  1826  	// See if there are any entries that we wanted to watch but are actually gone
  1827  	for _, name := range names {
  1828  		if !found.Contains(name) {
  1829  			logger.Tracef("looking for unit %q, found it gone, Unwatching", name)
  1830  			if _, ok := w.life[name]; ok {
  1831  				// we see this doc, but it doesn't exist
  1832  				if !hasString(changes, name) {
  1833  					changes = append(changes, name)
  1834  				}
  1835  				delete(w.life, name)
  1836  			}
  1837  			w.watcher.Unwatch(unitsC, w.backend.docID(name), w.in)
  1838  		}
  1839  	}
  1840  	logger.Tracef("changes: %q", changes)
  1841  	return changes, nil
  1842  }
  1843  
  1844  // update adds to and returns changes, such that it contains the names of any
  1845  // non-Dead units to have entered or left the tracked set.
  1846  func (w *unitsWatcher) update(changes []string) ([]string, error) {
  1847  	latest, err := w.getUnits()
  1848  	if err != nil {
  1849  		return nil, err
  1850  	}
  1851  	var unknown []string
  1852  	for _, name := range latest {
  1853  		if _, found := w.life[name]; !found {
  1854  			unknown = append(unknown, name)
  1855  		}
  1856  	}
  1857  	if len(unknown) > 0 {
  1858  		changes, err = w.watchUnits(unknown, changes)
  1859  		if err != nil {
  1860  			return nil, errors.Trace(err)
  1861  		}
  1862  	}
  1863  	for name := range w.life {
  1864  		if hasString(latest, name) {
  1865  			continue
  1866  		}
  1867  		if !hasString(changes, name) {
  1868  			changes = append(changes, name)
  1869  		}
  1870  		logger.Tracef("unit %q %q no longer in latest, removing watch", unitsC, name)
  1871  		delete(w.life, name)
  1872  		w.watcher.Unwatch(unitsC, w.backend.docID(name), w.in)
  1873  	}
  1874  	logger.Tracef("update reports changes: %q", changes)
  1875  	return changes, nil
  1876  }
  1877  
  1878  // merge adds to and returns changes, such that it contains the supplied unit
  1879  // name if that unit is unknown and non-Dead, or has changed lifecycle status.
  1880  func (w *unitsWatcher) merge(changes []string, name string) ([]string, error) {
  1881  	logger.Tracef("merging change for %q %q", unitsC, name)
  1882  	var doc lifeWatchDoc
  1883  	units, closer := w.db.GetCollection(unitsC)
  1884  	err := units.FindId(name).Select(lifeWatchFields).One(&doc)
  1885  	closer()
  1886  	gone := false
  1887  	if err == mgo.ErrNotFound {
  1888  		gone = true
  1889  	} else if err != nil {
  1890  		return nil, err
  1891  	} else if doc.Life == Dead {
  1892  		gone = true
  1893  	}
  1894  	life := w.life[name]
  1895  	switch {
  1896  	case gone:
  1897  		delete(w.life, name)
  1898  		logger.Tracef("document gone, unwatching %q %q", unitsC, name)
  1899  		w.watcher.Unwatch(unitsC, w.backend.docID(name), w.in)
  1900  	case life != doc.Life:
  1901  		logger.Tracef("updating doc life %q %q to %q", unitsC, name, doc.Life)
  1902  		w.life[name] = doc.Life
  1903  	default:
  1904  		return changes, nil
  1905  	}
  1906  	if !hasString(changes, name) {
  1907  		changes = append(changes, name)
  1908  	}
  1909  	logger.Tracef("merge reporting changes: %q", changes)
  1910  	return changes, nil
  1911  }
  1912  
  1913  func (w *unitsWatcher) loop(coll, id string) error {
  1914  	logger.Tracef("watching root channel %q %q", coll, id)
  1915  	rootCh := make(chan watcher.Change)
  1916  	w.watcher.Watch(coll, id, rootCh)
  1917  	defer func() {
  1918  		w.watcher.Unwatch(coll, id, rootCh)
  1919  		for name := range w.life {
  1920  			w.watcher.Unwatch(unitsC, w.backend.docID(name), w.in)
  1921  		}
  1922  	}()
  1923  	changes, err := w.initial()
  1924  	if err != nil {
  1925  		return err
  1926  	}
  1927  	out := w.out
  1928  	for {
  1929  		select {
  1930  		case <-w.watcher.Dead():
  1931  			return stateWatcherDeadError(w.watcher.Err())
  1932  		case <-w.tomb.Dying():
  1933  			return tomb.ErrDying
  1934  		case <-rootCh:
  1935  			changes, err = w.update(changes)
  1936  			if err != nil {
  1937  				return err
  1938  			}
  1939  			if len(changes) > 0 {
  1940  				out = w.out
  1941  			}
  1942  		case c := <-w.in:
  1943  			localID := w.backend.localID(c.Id.(string))
  1944  			changes, err = w.merge(changes, localID)
  1945  			if err != nil {
  1946  				return err
  1947  			}
  1948  			if len(changes) > 0 {
  1949  				out = w.out
  1950  			}
  1951  		case out <- changes:
  1952  			logger.Tracef("watcher reported changes: %q", changes)
  1953  			out = nil
  1954  			changes = nil
  1955  		}
  1956  	}
  1957  }
  1958  
  1959  // WatchInstanceData returns a watcher for observing changes to a machine's instance data.
  1960  func (m *Machine) WatchInstanceData() NotifyWatcher {
  1961  	return newEntityWatcher(m.st, instanceDataC, m.doc.DocID)
  1962  }
  1963  
  1964  // WatchControllerInfo returns a StringsWatcher for the controllers collection
  1965  func (st *State) WatchControllerInfo() StringsWatcher {
  1966  	return newCollectionWatcher(st, colWCfg{col: controllerNodesC})
  1967  }
  1968  
  1969  // WatchControllerConfig returns a NotifyWatcher for controller settings.
  1970  func (st *State) WatchControllerConfig() NotifyWatcher {
  1971  	return newEntityWatcher(st, controllersC, ControllerSettingsGlobalKey)
  1972  }
  1973  
  1974  // Watch returns a watcher for observing changes to a controller service.
  1975  func (c *CloudService) Watch() NotifyWatcher {
  1976  	return newEntityWatcher(c.st, cloudServicesC, c.doc.DocID)
  1977  }
  1978  
  1979  // Watch returns a watcher for observing changes to a machine.
  1980  func (m *Machine) Watch() NotifyWatcher {
  1981  	return newEntityWatcher(m.st, machinesC, m.doc.DocID)
  1982  }
  1983  
  1984  // Watch returns a watcher for observing changes to an application.
  1985  func (a *Application) Watch() NotifyWatcher {
  1986  	return newEntityWatcher(a.st, applicationsC, a.doc.DocID)
  1987  }
  1988  
  1989  // WatchLeaderSettings returns a watcher for observing changed to an application's
  1990  // leader settings.
  1991  func (a *Application) WatchLeaderSettings() NotifyWatcher {
  1992  	docId := a.st.docID(leadershipSettingsKey(a.Name()))
  1993  	return newEntityWatcher(a.st, settingsC, docId)
  1994  }
  1995  
  1996  // Watch returns a watcher for observing changes to a unit.
  1997  func (u *Unit) Watch() NotifyWatcher {
  1998  	return newEntityWatcher(u.st, unitsC, u.doc.DocID)
  1999  }
  2000  
  2001  // Watch returns a watcher for observing changes to a model.
  2002  func (m *Model) Watch() NotifyWatcher {
  2003  	return newEntityWatcher(m.st, modelsC, m.doc.UUID)
  2004  }
  2005  
  2006  // WatchUpgradeInfo returns a watcher for observing changes to upgrade
  2007  // synchronisation state.
  2008  func (st *State) WatchUpgradeInfo() NotifyWatcher {
  2009  	return newEntityWatcher(st, upgradeInfoC, currentUpgradeId)
  2010  }
  2011  
  2012  // WatchForModelConfigChanges returns a NotifyWatcher waiting for the Model
  2013  // Config to change.
  2014  func (model *Model) WatchForModelConfigChanges() NotifyWatcher {
  2015  	return newEntityWatcher(model.st, settingsC, model.st.docID(modelGlobalKey))
  2016  }
  2017  
  2018  // WatchCloudSpecChanges returns a NotifyWatcher waiting for the cloud
  2019  // to change for the model.
  2020  func (model *Model) WatchCloudSpecChanges() NotifyWatcher {
  2021  	return newEntityWatcher(model.st, cloudsC, model.CloudName())
  2022  }
  2023  
  2024  // WatchModelEntityReferences returns a NotifyWatcher waiting for the Model
  2025  // Entity references to change for specified model.
  2026  func (st *State) WatchModelEntityReferences(mUUID string) NotifyWatcher {
  2027  	return newEntityWatcher(st, modelEntityRefsC, mUUID)
  2028  }
  2029  
  2030  // WatchForUnitAssignment watches for new applications that request units to be
  2031  // assigned to machines.
  2032  func (st *State) WatchForUnitAssignment() StringsWatcher {
  2033  	return newCollectionWatcher(st, colWCfg{col: assignUnitC})
  2034  }
  2035  
  2036  // WatchAPIHostPortsForClients returns a NotifyWatcher that notifies
  2037  // when the set of API addresses changes.
  2038  func (st *State) WatchAPIHostPortsForClients() NotifyWatcher {
  2039  	return newEntityWatcher(st, controllersC, apiHostPortsKey)
  2040  }
  2041  
  2042  // WatchAPIHostPortsForAgents returns a NotifyWatcher that notifies
  2043  // when the set of API addresses usable by agents changes.
  2044  func (st *State) WatchAPIHostPortsForAgents() NotifyWatcher {
  2045  	return newEntityWatcher(st, controllersC, apiHostPortsForAgentsKey)
  2046  }
  2047  
  2048  // WatchStorageAttachment returns a watcher for observing changes
  2049  // to a storage attachment.
  2050  func (sb *storageBackend) WatchStorageAttachment(s names.StorageTag, u names.UnitTag) NotifyWatcher {
  2051  	id := storageAttachmentId(u.Id(), s.Id())
  2052  	return newEntityWatcher(sb.mb, storageAttachmentsC, sb.mb.docID(id))
  2053  }
  2054  
  2055  // WatchVolumeAttachment returns a watcher for observing changes
  2056  // to a volume attachment.
  2057  func (sb *storageBackend) WatchVolumeAttachment(host names.Tag, v names.VolumeTag) NotifyWatcher {
  2058  	id := volumeAttachmentId(host.Id(), v.Id())
  2059  	return newEntityWatcher(sb.mb, volumeAttachmentsC, sb.mb.docID(id))
  2060  }
  2061  
  2062  // WatchFilesystemAttachment returns a watcher for observing changes
  2063  // to a filesystem attachment.
  2064  func (sb *storageBackend) WatchFilesystemAttachment(host names.Tag, f names.FilesystemTag) NotifyWatcher {
  2065  	id := filesystemAttachmentId(host.Id(), f.Id())
  2066  	return newEntityWatcher(sb.mb, filesystemAttachmentsC, sb.mb.docID(id))
  2067  }
  2068  
  2069  // WatchCharmConfig returns a watcher for observing changes to the
  2070  // application's charm configuration settings. The returned watcher will be
  2071  // valid only while the application's charm URL is not changed.
  2072  func (a *Application) WatchCharmConfig() (NotifyWatcher, error) {
  2073  	configKey := a.charmConfigKey()
  2074  	return newEntityWatcher(a.st, settingsC, a.st.docID(configKey)), nil
  2075  }
  2076  
  2077  // WatchConfigSettings returns a watcher for observing changes to the
  2078  // unit's application configuration settings. The unit must have a charm URL
  2079  // set before this method is called, and the returned watcher will be
  2080  // valid only while the unit's charm URL is not changed.
  2081  // TODO(fwereade): this could be much smarter; if it were, uniter.Filter
  2082  // could be somewhat simpler.
  2083  func (u *Unit) WatchConfigSettings() (NotifyWatcher, error) {
  2084  	if u.doc.CharmURL == nil {
  2085  		return nil, fmt.Errorf("unit's charm URL must be set before watching config")
  2086  	}
  2087  	charmConfigKey := applicationCharmConfigKey(u.doc.Application, u.doc.CharmURL)
  2088  	return newEntityWatcher(u.st, settingsC, u.st.docID(charmConfigKey)), nil
  2089  }
  2090  
  2091  // WatchApplicationConfigSettings is the same as WatchConfigSettings but
  2092  // notifies on changes to application configuration not charm configuration.
  2093  func (u *Unit) WatchApplicationConfigSettings() (NotifyWatcher, error) {
  2094  	applicationConfigKey := applicationConfigKey(u.ApplicationName())
  2095  	return newEntityWatcher(u.st, settingsC, u.st.docID(applicationConfigKey)), nil
  2096  }
  2097  
  2098  // WatchConfigSettingsHash returns a watcher that yields a hash of the
  2099  // unit's charm config settings whenever they are changed. The
  2100  // returned watcher will be valid only while the application's charm
  2101  // URL is not changed.
  2102  func (u *Unit) WatchConfigSettingsHash() (StringsWatcher, error) {
  2103  	if u.doc.CharmURL == nil {
  2104  		return nil, fmt.Errorf("unit's charm URL must be set before watching config")
  2105  	}
  2106  	charmConfigKey := applicationCharmConfigKey(u.doc.Application, u.doc.CharmURL)
  2107  	return newSettingsHashWatcher(u.st, charmConfigKey), nil
  2108  }
  2109  
  2110  // WatchApplicationConfigSettingsHash is the same as
  2111  // WatchConfigSettingsHash but watches the application's config rather
  2112  // than charm configuration. Yields a hash of the application config
  2113  // with each change.
  2114  func (u *Unit) WatchApplicationConfigSettingsHash() (StringsWatcher, error) {
  2115  	applicationConfigKey := applicationConfigKey(u.ApplicationName())
  2116  	return newSettingsHashWatcher(u.st, applicationConfigKey), nil
  2117  }
  2118  
  2119  // WatchMeterStatus returns a watcher observing changes that affect the meter status
  2120  // of a unit.
  2121  func (u *Unit) WatchMeterStatus() NotifyWatcher {
  2122  	return newDocWatcher(u.st, []docKey{
  2123  		{
  2124  			meterStatusC,
  2125  			u.st.docID(u.globalMeterStatusKey()),
  2126  		}, {
  2127  			meterStatusC,
  2128  			metricsManagerKey(u.st),
  2129  		},
  2130  	})
  2131  }
  2132  
  2133  // WatchLXDProfileUpgradeNotifications returns a watcher that observes the status
  2134  // of a lxd profile upgrade by monitoring changes on the unit machine's lxd profile
  2135  // upgrade completed field that is specific to an application name.  Used by
  2136  // UniterAPI v9.
  2137  func (m *Machine) WatchLXDProfileUpgradeNotifications(applicationName string) (StringsWatcher, error) {
  2138  	app, err := m.st.Application(applicationName)
  2139  	if err != nil {
  2140  		return nil, errors.Trace(err)
  2141  	}
  2142  	watchDocId := app.doc.DocID
  2143  	return watchInstanceCharmProfileCompatibilityData(m.st, watchDocId), nil
  2144  }
  2145  
  2146  // WatchLXDProfileUpgradeNotifications returns a watcher that observes the status
  2147  // of a lxd profile upgrade by monitoring changes on the unit machine's lxd profile
  2148  // upgrade completed field that is specific to itself.
  2149  func (u *Unit) WatchLXDProfileUpgradeNotifications() (StringsWatcher, error) {
  2150  	app, err := u.Application()
  2151  	if err != nil {
  2152  		return nil, errors.Trace(err)
  2153  	}
  2154  	watchDocId := app.doc.DocID
  2155  	return watchInstanceCharmProfileCompatibilityData(u.st, watchDocId), nil
  2156  }
  2157  
  2158  func watchInstanceCharmProfileCompatibilityData(backend modelBackend, watchDocId string) StringsWatcher {
  2159  	initial := ""
  2160  	members := bson.D{{"_id", watchDocId}}
  2161  	collection := applicationsC
  2162  	filter := func(id interface{}) bool {
  2163  		return id.(string) == watchDocId
  2164  	}
  2165  	extract := func(query documentFieldWatcherQuery) (string, error) {
  2166  		var doc applicationDoc
  2167  		if err := query.One(&doc); err != nil {
  2168  			return "", err
  2169  		}
  2170  		return *doc.CharmURL, nil
  2171  	}
  2172  	transform := func(value string) string {
  2173  		return lxdprofile.NotRequiredStatus
  2174  	}
  2175  	return newDocumentFieldWatcher(backend, collection, members, initial, filter, extract, transform)
  2176  }
  2177  
  2178  // *Deprecated* Although this watcher seems fairly admirable in terms of what
  2179  // it does, it unfortunately does things at the wrong level. With the
  2180  // consequence of wiring up complex structures on something that wasn't intended
  2181  // from the outset for it to do.
  2182  //
  2183  // documentFieldWatcher notifies about any changes to a document field
  2184  // specifically, the watcher looks for changes to a document field, and records
  2185  // the current document field (known value). If the document doesn't exist an
  2186  // initialKnown value can be set for the default.
  2187  // Events are generated when there are changes to a document field that is
  2188  // different from the known value. So setting field multiple times won't
  2189  // dispatch an event, on changes that differ will be dispatched.
  2190  type documentFieldWatcher struct {
  2191  	commonWatcher
  2192  	// docId is used to select the initial interesting entities.
  2193  	collection   string
  2194  	members      bson.D
  2195  	known        *string
  2196  	initialKnown string
  2197  	filter       func(interface{}) bool
  2198  	extract      func(documentFieldWatcherQuery) (string, error)
  2199  	transform    func(string) string
  2200  	out          chan []string
  2201  }
  2202  
  2203  // documentFieldWatcherQuery is a point of use interface, to prevent the leaking
  2204  // of query interface out of the core watcher.
  2205  type documentFieldWatcherQuery interface {
  2206  	One(result interface{}) (err error)
  2207  }
  2208  
  2209  var _ Watcher = (*documentFieldWatcher)(nil)
  2210  
  2211  func newDocumentFieldWatcher(
  2212  	backend modelBackend,
  2213  	collection string,
  2214  	members bson.D,
  2215  	initialKnown string,
  2216  	filter func(interface{}) bool,
  2217  	extract func(documentFieldWatcherQuery) (string, error),
  2218  	transform func(string) string,
  2219  ) StringsWatcher {
  2220  	w := &documentFieldWatcher{
  2221  		commonWatcher: newCommonWatcher(backend),
  2222  		collection:    collection,
  2223  		members:       members,
  2224  		initialKnown:  initialKnown,
  2225  		filter:        filter,
  2226  		extract:       extract,
  2227  		transform:     transform,
  2228  		out:           make(chan []string),
  2229  	}
  2230  	w.tomb.Go(func() error {
  2231  		defer close(w.out)
  2232  		return w.loop()
  2233  	})
  2234  	return w
  2235  }
  2236  
  2237  func (w *documentFieldWatcher) initial() error {
  2238  	col, closer := w.db.GetCollection(w.collection)
  2239  	defer closer()
  2240  
  2241  	field := w.initialKnown
  2242  
  2243  	if newField, err := w.extract(col.Find(w.members)); err == nil {
  2244  		field = newField
  2245  	}
  2246  	w.known = &field
  2247  
  2248  	logger.Tracef("Started watching %s for %v: %q", w.collection, w.members, field)
  2249  	return nil
  2250  }
  2251  
  2252  func (w *documentFieldWatcher) merge(change watcher.Change) (bool, error) {
  2253  	// we care about change.Revno equalling -1 as we want to know about
  2254  	// documents being deleted.
  2255  	if change.Revno == -1 {
  2256  		// treat this as the document being deleted
  2257  		if w.known != nil {
  2258  			w.known = nil
  2259  			return true, nil
  2260  		}
  2261  		return false, nil
  2262  	}
  2263  	col, closer := w.db.GetCollection(w.collection)
  2264  	defer closer()
  2265  
  2266  	// check the field before adding it to the known value
  2267  	currentField, err := w.extract(col.Find(w.members))
  2268  	if err != nil {
  2269  		if err != mgo.ErrNotFound {
  2270  			logger.Debugf("%s NOT mgo err not found", w.collection)
  2271  			return false, err
  2272  		}
  2273  		// treat this as the document being deleted
  2274  		if w.known != nil {
  2275  			w.known = nil
  2276  			return true, nil
  2277  		}
  2278  		return false, nil
  2279  	}
  2280  	if w.known == nil || *w.known != currentField {
  2281  		w.known = &currentField
  2282  
  2283  		logger.Tracef("Changes in watching %s for %v: %q", w.collection, w.members, currentField)
  2284  		return true, nil
  2285  	}
  2286  	return false, nil
  2287  }
  2288  
  2289  func (w *documentFieldWatcher) loop() error {
  2290  	err := w.initial()
  2291  	if err != nil {
  2292  		return err
  2293  	}
  2294  
  2295  	ch := make(chan watcher.Change)
  2296  	w.watcher.WatchCollectionWithFilter(w.collection, ch, w.filter)
  2297  	defer w.watcher.UnwatchCollection(w.collection, ch)
  2298  
  2299  	out := w.out
  2300  	for {
  2301  		var value string
  2302  		if w.known != nil {
  2303  			value = *w.known
  2304  		}
  2305  		if w.transform != nil {
  2306  			value = w.transform(value)
  2307  		}
  2308  		select {
  2309  		case <-w.watcher.Dead():
  2310  			return stateWatcherDeadError(w.watcher.Err())
  2311  		case <-w.tomb.Dying():
  2312  			return tomb.ErrDying
  2313  		case change := <-ch:
  2314  			isChanged, err := w.merge(change)
  2315  			if err != nil {
  2316  				return err
  2317  			}
  2318  			if isChanged {
  2319  				out = w.out
  2320  			}
  2321  		case out <- []string{value}:
  2322  			out = nil
  2323  		}
  2324  	}
  2325  }
  2326  
  2327  func (w *documentFieldWatcher) Changes() <-chan []string {
  2328  	return w.out
  2329  }
  2330  
  2331  // WatchUpgradeSeriesNotifications returns a watcher that observes the status of
  2332  // a series upgrade by monitoring changes to its parent machine's upgrade series
  2333  // lock.
  2334  func (m *Machine) WatchUpgradeSeriesNotifications() (NotifyWatcher, error) {
  2335  	watch := newEntityWatcher(m.st, machineUpgradeSeriesLocksC, m.doc.DocID)
  2336  	if _, ok := <-watch.Changes(); ok {
  2337  		return watch, nil
  2338  	}
  2339  
  2340  	return nil, watcher.EnsureErr(watch)
  2341  }
  2342  
  2343  func newEntityWatcher(backend modelBackend, collName string, key interface{}) NotifyWatcher {
  2344  	return newDocWatcher(backend, []docKey{{collName, key}})
  2345  }
  2346  
  2347  // docWatcher watches for changes in 1 or more mongo documents
  2348  // across collections.
  2349  type docWatcher struct {
  2350  	commonWatcher
  2351  	out chan struct{}
  2352  }
  2353  
  2354  var _ Watcher = (*docWatcher)(nil)
  2355  
  2356  // docKey identifies a single item in a single collection.
  2357  // It's used as a parameter to newDocWatcher to specify
  2358  // which documents should be watched.
  2359  type docKey struct {
  2360  	coll  string
  2361  	docId interface{}
  2362  }
  2363  
  2364  // newDocWatcher returns a new docWatcher.
  2365  // docKeys identifies the documents that should be watched (their id and which collection they are in)
  2366  func newDocWatcher(backend modelBackend, docKeys []docKey) NotifyWatcher {
  2367  	w := &docWatcher{
  2368  		commonWatcher: newCommonWatcher(backend),
  2369  		out:           make(chan struct{}),
  2370  	}
  2371  	w.tomb.Go(func() error {
  2372  		defer close(w.out)
  2373  		return w.loop(docKeys)
  2374  	})
  2375  	return w
  2376  }
  2377  
  2378  // Changes returns the event channel for the docWatcher.
  2379  func (w *docWatcher) Changes() <-chan struct{} {
  2380  	return w.out
  2381  }
  2382  
  2383  // getTxnRevno returns the transaction revision number of the
  2384  // given document id in the given collection. It is useful to enable
  2385  // a watcher.Watcher to be primed with the correct revision
  2386  // id.
  2387  func getTxnRevno(coll mongo.Collection, id interface{}) (int64, error) {
  2388  	doc := struct {
  2389  		TxnRevno int64 `bson:"txn-revno"`
  2390  	}{}
  2391  	fields := bson.D{{"txn-revno", 1}}
  2392  	if err := coll.FindId(id).Select(fields).One(&doc); err == mgo.ErrNotFound {
  2393  		return -1, nil
  2394  	} else if err != nil {
  2395  		return 0, err
  2396  	}
  2397  	return doc.TxnRevno, nil
  2398  }
  2399  
  2400  func (w *docWatcher) loop(docKeys []docKey) error {
  2401  	in := make(chan watcher.Change)
  2402  	logger.Tracef("watching docs: %v", docKeys)
  2403  	for _, k := range docKeys {
  2404  		w.watcher.Watch(k.coll, k.docId, in)
  2405  		defer w.watcher.Unwatch(k.coll, k.docId, in)
  2406  	}
  2407  	// Check to see if there is a backing event that should be coalesced with the
  2408  	// first event
  2409  	if _, ok := collect(watcher.Change{}, in, w.tomb.Dying()); !ok {
  2410  		return tomb.ErrDying
  2411  	}
  2412  	out := w.out
  2413  	n := 1
  2414  	for {
  2415  		select {
  2416  		case <-w.tomb.Dying():
  2417  			return tomb.ErrDying
  2418  		case <-w.watcher.Dead():
  2419  			return stateWatcherDeadError(w.watcher.Err())
  2420  		case ch := <-in:
  2421  			if _, ok := collect(ch, in, w.tomb.Dying()); !ok {
  2422  				return tomb.ErrDying
  2423  			}
  2424  			// TODO(quiescence): reimplement quiescence
  2425  			// increment the number of notifications to send.
  2426  			n++
  2427  			out = w.out
  2428  		case out <- struct{}{}:
  2429  			n--
  2430  			if n == 0 {
  2431  				out = nil
  2432  			}
  2433  		}
  2434  	}
  2435  }
  2436  
  2437  // machineUnitsWatcher notifies about assignments and lifecycle changes
  2438  // for all units of a machine.
  2439  //
  2440  // The first event emitted contains the unit names of all units currently
  2441  // assigned to the machine, irrespective of their life state. From then on,
  2442  // a new event is emitted whenever a unit is assigned to or unassigned from
  2443  // the machine, or the lifecycle of a unit that is currently assigned to
  2444  // the machine changes.
  2445  //
  2446  // After a unit is found to be Dead, no further event will include it.
  2447  type machineUnitsWatcher struct {
  2448  	commonWatcher
  2449  	machine *Machine
  2450  	out     chan []string
  2451  	in      chan watcher.Change
  2452  	known   map[string]Life
  2453  }
  2454  
  2455  var _ Watcher = (*machineUnitsWatcher)(nil)
  2456  
  2457  // WatchUnits returns a new StringsWatcher watching m's units.
  2458  func (m *Machine) WatchUnits() StringsWatcher {
  2459  	return newMachineUnitsWatcher(m)
  2460  }
  2461  
  2462  func newMachineUnitsWatcher(m *Machine) StringsWatcher {
  2463  	w := &machineUnitsWatcher{
  2464  		commonWatcher: newCommonWatcher(m.st),
  2465  		out:           make(chan []string),
  2466  		in:            make(chan watcher.Change),
  2467  		known:         make(map[string]Life),
  2468  		machine:       &Machine{st: m.st, doc: m.doc}, // Copy so it may be freely refreshed
  2469  	}
  2470  	w.tomb.Go(func() error {
  2471  		defer close(w.out)
  2472  		return w.loop()
  2473  	})
  2474  	return w
  2475  }
  2476  
  2477  // Changes returns the event channel for w.
  2478  func (w *machineUnitsWatcher) Changes() <-chan []string {
  2479  	return w.out
  2480  }
  2481  
  2482  func (w *machineUnitsWatcher) updateMachine(pending []string) (new []string, err error) {
  2483  	err = w.machine.Refresh()
  2484  	if err != nil {
  2485  		return nil, err
  2486  	}
  2487  	var unknown []string
  2488  	for _, unitName := range w.machine.doc.Principals {
  2489  		if _, ok := w.known[unitName]; !ok {
  2490  			unknown = append(unknown, unitName)
  2491  		}
  2492  	}
  2493  	if len(unknown) > 0 {
  2494  		pending, err = w.watchNewUnits(unknown, pending, nil)
  2495  		if err != nil {
  2496  			return nil, errors.Trace(err)
  2497  		}
  2498  	}
  2499  	return pending, nil
  2500  }
  2501  
  2502  // watchNewUnits sets up a watcher for all of the named units and then updates pending changes.
  2503  // There is an assumption that all unitNames being passed are unknown and do not have a watch active for them.
  2504  func (w *machineUnitsWatcher) watchNewUnits(unitNames, pending []string, unitColl mongo.Collection) ([]string, error) {
  2505  	if len(unitNames) == 0 {
  2506  		return pending, nil
  2507  	}
  2508  	ids := make([]interface{}, len(unitNames))
  2509  	for i := range unitNames {
  2510  		ids[i] = w.backend.docID(unitNames[i])
  2511  	}
  2512  	logger.Tracef("for machine %q watching new units %q", w.machine.doc.DocID, unitNames)
  2513  	err := w.watcher.WatchMulti(unitsC, ids, w.in)
  2514  	if err != nil {
  2515  		return nil, errors.Trace(err)
  2516  	}
  2517  
  2518  	if unitColl == nil {
  2519  		var closer SessionCloser
  2520  		unitColl, closer = w.db.GetCollection(unitsC)
  2521  		defer closer()
  2522  	}
  2523  	var doc unitDoc
  2524  	iter := unitColl.Find(bson.M{"_id": bson.M{"$in": unitNames}}).Iter()
  2525  	unknownSubs := set.NewStrings()
  2526  	notfound := set.NewStrings(unitNames...)
  2527  	for iter.Next(&doc) {
  2528  		notfound.Remove(doc.Name)
  2529  		w.known[doc.Name] = doc.Life
  2530  		pending = append(pending, doc.Name)
  2531  		// now load subordinates
  2532  		for _, subunitName := range doc.Subordinates {
  2533  			if _, subknown := w.known[subunitName]; !subknown {
  2534  				unknownSubs.Add(subunitName)
  2535  			}
  2536  		}
  2537  	}
  2538  	if err := iter.Close(); err != nil {
  2539  		return nil, errors.Trace(err)
  2540  	}
  2541  	for name := range notfound {
  2542  		logger.Debugf("unit %q referenced but not found", name)
  2543  		w.watcher.Unwatch(unitsC, w.backend.docID(name), w.in)
  2544  	}
  2545  	if !unknownSubs.IsEmpty() {
  2546  		pending, err = w.watchNewUnits(unknownSubs.Values(), pending, unitColl)
  2547  		if err != nil {
  2548  			return nil, errors.Trace(err)
  2549  		}
  2550  	}
  2551  	return pending, nil
  2552  }
  2553  
  2554  // removeWatchedUnit stops watching the unit, and all subordinates for this unit
  2555  func (w *machineUnitsWatcher) removeWatchedUnit(unitName string, doc unitDoc, pending []string) ([]string, error) {
  2556  	logger.Tracef("machineUnitsWatcher removing unit %q for life %q", doc.Name, doc.Life)
  2557  	life, known := w.known[unitName]
  2558  	// Unit was removed or unassigned from w.machine
  2559  	if known {
  2560  		delete(w.known, unitName)
  2561  		docID := w.backend.docID(unitName)
  2562  		w.watcher.Unwatch(unitsC, docID, w.in)
  2563  		if life != Dead && !hasString(pending, unitName) {
  2564  			pending = append(pending, unitName)
  2565  		}
  2566  		for _, subunitName := range doc.Subordinates {
  2567  			if sublife, subknown := w.known[subunitName]; subknown {
  2568  				delete(w.known, subunitName)
  2569  				w.watcher.Unwatch(unitsC, w.backend.docID(subunitName), w.in)
  2570  				if sublife != Dead && !hasString(pending, subunitName) {
  2571  					pending = append(pending, subunitName)
  2572  				}
  2573  			}
  2574  		}
  2575  	}
  2576  	return pending, nil
  2577  }
  2578  
  2579  // merge checks if this unitName has been modified and if so, updates pending accordingly.
  2580  // merge() should only be called for documents that are already being watched and part of known
  2581  // use watchNewUnits if you have a new object
  2582  func (w *machineUnitsWatcher) merge(pending []string, unitName string) (new []string, err error) {
  2583  	doc := unitDoc{}
  2584  	newUnits, closer := w.db.GetCollection(unitsC)
  2585  	defer closer()
  2586  	err = newUnits.FindId(unitName).One(&doc)
  2587  	if err != nil && err != mgo.ErrNotFound {
  2588  		return nil, errors.Trace(err)
  2589  	}
  2590  	if err == mgo.ErrNotFound || doc.Principal == "" && (doc.MachineId == "" || doc.MachineId != w.machine.doc.Id) {
  2591  		// We always pass the unitName because the document may be deleted, and thus not have a name on the object
  2592  		pending, err := w.removeWatchedUnit(unitName, doc, pending)
  2593  		if err != nil {
  2594  			return nil, errors.Trace(err)
  2595  		}
  2596  		return pending, nil
  2597  	}
  2598  	life, known := w.known[unitName]
  2599  	if !known {
  2600  		return nil, errors.Errorf("merge() called with an unknown document: %q", doc.DocID)
  2601  	}
  2602  	if life != doc.Life && !hasString(pending, doc.Name) {
  2603  		logger.Tracef("machineUnitsWatcher found life changed to %q => %q for %q", life, doc.Life, doc.Name)
  2604  		pending = append(pending, doc.Name)
  2605  	}
  2606  	w.known[doc.Name] = doc.Life
  2607  	unknownSubordinates := set.NewStrings()
  2608  	for _, subunitName := range doc.Subordinates {
  2609  		if _, ok := w.known[subunitName]; !ok {
  2610  			unknownSubordinates.Add(subunitName)
  2611  		}
  2612  	}
  2613  	if !unknownSubordinates.IsEmpty() {
  2614  		pending, err = w.watchNewUnits(unknownSubordinates.Values(), pending, nil)
  2615  		if err != nil {
  2616  			return nil, errors.Trace(err)
  2617  		}
  2618  	}
  2619  	return pending, nil
  2620  }
  2621  
  2622  func (w *machineUnitsWatcher) loop() error {
  2623  	defer func() {
  2624  		for unit := range w.known {
  2625  			w.watcher.Unwatch(unitsC, w.backend.docID(unit), w.in)
  2626  		}
  2627  	}()
  2628  
  2629  	machineCh := make(chan watcher.Change)
  2630  	w.watcher.Watch(machinesC, w.machine.doc.DocID, machineCh)
  2631  	defer w.watcher.Unwatch(machinesC, w.machine.doc.DocID, machineCh)
  2632  	changes, err := w.updateMachine(nil)
  2633  	if err != nil {
  2634  		return errors.Trace(err)
  2635  	}
  2636  	out := w.out
  2637  	for {
  2638  		select {
  2639  		case <-w.watcher.Dead():
  2640  			return stateWatcherDeadError(w.watcher.Err())
  2641  		case <-w.tomb.Dying():
  2642  			return tomb.ErrDying
  2643  		case <-machineCh:
  2644  			changes, err = w.updateMachine(changes)
  2645  			if err != nil {
  2646  				return errors.Trace(err)
  2647  			}
  2648  			if len(changes) > 0 {
  2649  				out = w.out
  2650  			}
  2651  		case c := <-w.in:
  2652  			changes, err = w.merge(changes, w.backend.localID(c.Id.(string)))
  2653  			if err != nil {
  2654  				return errors.Trace(err)
  2655  			}
  2656  			if len(changes) > 0 {
  2657  				out = w.out
  2658  			}
  2659  		case out <- changes:
  2660  			out = nil
  2661  			changes = nil
  2662  		}
  2663  	}
  2664  }
  2665  
  2666  // machineAddressesWatcher notifies about changes to a machine's addresses.
  2667  //
  2668  // The first event emitted contains the addresses currently assigned to the
  2669  // machine. From then on, a new event is emitted whenever the machine's
  2670  // addresses change.
  2671  type machineAddressesWatcher struct {
  2672  	commonWatcher
  2673  	machine *Machine
  2674  	out     chan struct{}
  2675  }
  2676  
  2677  var _ Watcher = (*machineAddressesWatcher)(nil)
  2678  
  2679  // WatchAddresses returns a new NotifyWatcher watching m's addresses.
  2680  func (m *Machine) WatchAddresses() NotifyWatcher {
  2681  	return newMachineAddressesWatcher(m)
  2682  }
  2683  
  2684  func newMachineAddressesWatcher(m *Machine) NotifyWatcher {
  2685  	w := &machineAddressesWatcher{
  2686  		commonWatcher: newCommonWatcher(m.st),
  2687  		out:           make(chan struct{}),
  2688  		machine:       &Machine{st: m.st, doc: m.doc}, // Copy so it may be freely refreshed
  2689  	}
  2690  	w.tomb.Go(func() error {
  2691  		defer close(w.out)
  2692  		return w.loop()
  2693  	})
  2694  	return w
  2695  }
  2696  
  2697  // Changes returns the event channel for w.
  2698  func (w *machineAddressesWatcher) Changes() <-chan struct{} {
  2699  	return w.out
  2700  }
  2701  
  2702  func (w *machineAddressesWatcher) loop() error {
  2703  	machineCh := make(chan watcher.Change)
  2704  	w.watcher.Watch(machinesC, w.machine.doc.DocID, machineCh)
  2705  	defer w.watcher.Unwatch(machinesC, w.machine.doc.DocID, machineCh)
  2706  	addresses := w.machine.Addresses()
  2707  	out := w.out
  2708  	for {
  2709  		select {
  2710  		case <-w.watcher.Dead():
  2711  			return stateWatcherDeadError(w.watcher.Err())
  2712  		case <-w.tomb.Dying():
  2713  			return tomb.ErrDying
  2714  		case <-machineCh:
  2715  			if err := w.machine.Refresh(); err != nil {
  2716  				return err
  2717  			}
  2718  			newAddresses := w.machine.Addresses()
  2719  			if !addressesEqual(newAddresses, addresses) {
  2720  				addresses = newAddresses
  2721  				out = w.out
  2722  			}
  2723  		case out <- struct{}{}:
  2724  			out = nil
  2725  		}
  2726  	}
  2727  }
  2728  
  2729  // WatchCleanups starts and returns a CleanupWatcher.
  2730  func (st *State) WatchCleanups() NotifyWatcher {
  2731  	return newNotifyCollWatcher(st, cleanupsC, isLocalID(st))
  2732  }
  2733  
  2734  // WatchActionLogs starts and returns a StringsWatcher that
  2735  // notifies on new log messages for a specified action being added.
  2736  // The strings are json encoded action messages.
  2737  func (st *State) WatchActionLogs(actionId string) StringsWatcher {
  2738  	return newActionLogsWatcher(st, actionId)
  2739  }
  2740  
  2741  // actionLogsWatcher reports new action progress messages.
  2742  type actionLogsWatcher struct {
  2743  	commonWatcher
  2744  	coll func() (mongo.Collection, func())
  2745  	out  chan []string
  2746  
  2747  	actionId string
  2748  }
  2749  
  2750  var _ Watcher = (*actionLogsWatcher)(nil)
  2751  
  2752  func newActionLogsWatcher(st *State, actionId string) StringsWatcher {
  2753  	w := &actionLogsWatcher{
  2754  		commonWatcher: newCommonWatcher(st),
  2755  		coll:          collFactory(st.db(), actionsC),
  2756  		out:           make(chan []string),
  2757  		actionId:      actionId,
  2758  	}
  2759  	w.tomb.Go(func() error {
  2760  		defer close(w.out)
  2761  		return w.loop()
  2762  	})
  2763  	return w
  2764  }
  2765  
  2766  // Changes returns the event channel for w.
  2767  func (w *actionLogsWatcher) Changes() <-chan []string {
  2768  	return w.out
  2769  }
  2770  
  2771  func (w *actionLogsWatcher) messages() ([]string, error) {
  2772  	// Get the initial logs.
  2773  	type messagesDoc struct {
  2774  		Messages []ActionMessage `bson:"messages"`
  2775  	}
  2776  	coll, closer := w.coll()
  2777  	defer closer()
  2778  	var doc messagesDoc
  2779  	err := coll.FindId(w.backend.docID(w.actionId)).Select(bson.D{{"messages", 1}}).One(&doc)
  2780  	if err != nil {
  2781  		return nil, errors.Trace(err)
  2782  	}
  2783  	var changes []string
  2784  	for _, m := range doc.Messages {
  2785  		mjson, err := json.Marshal(actions.ActionMessage{
  2786  			Message:   m.MessageValue,
  2787  			Timestamp: m.TimestampValue.UTC(),
  2788  		})
  2789  		if err != nil {
  2790  			return nil, errors.Trace(err)
  2791  		}
  2792  		changes = append(changes, string(mjson))
  2793  	}
  2794  	return changes, nil
  2795  }
  2796  
  2797  func (w *actionLogsWatcher) loop() error {
  2798  	in := make(chan watcher.Change)
  2799  	filter := func(id interface{}) bool {
  2800  		k, err := w.backend.strictLocalID(id.(string))
  2801  		if err != nil {
  2802  			return false
  2803  		}
  2804  		return k == w.actionId
  2805  	}
  2806  
  2807  	w.watcher.WatchCollectionWithFilter(actionsC, in, filter)
  2808  	defer w.watcher.UnwatchCollection(actionsC, in)
  2809  
  2810  	changes, err := w.messages()
  2811  	if err != nil {
  2812  		return errors.Trace(err)
  2813  	}
  2814  	// Record how many messages already sent so we
  2815  	// only send new ones.
  2816  	var reportedCount int
  2817  	out := w.out
  2818  
  2819  	for {
  2820  		select {
  2821  		case <-w.watcher.Dead():
  2822  			return stateWatcherDeadError(w.watcher.Err())
  2823  		case <-w.tomb.Dying():
  2824  			return tomb.ErrDying
  2825  		case <-in:
  2826  			messages, err := w.messages()
  2827  			if err != nil {
  2828  				return errors.Trace(err)
  2829  			}
  2830  			if len(messages) > reportedCount {
  2831  				out = w.out
  2832  				changes = messages[reportedCount:]
  2833  			}
  2834  		case out <- changes:
  2835  			reportedCount += len(changes)
  2836  			out = nil
  2837  		}
  2838  	}
  2839  }
  2840  
  2841  // collectionWatcher is a StringsWatcher that watches for changes on the
  2842  // specified collection that match a filter on the id.
  2843  type collectionWatcher struct {
  2844  	commonWatcher
  2845  	colWCfg
  2846  	source chan watcher.Change
  2847  	sink   chan []string
  2848  }
  2849  
  2850  // colWCfg contains the parameters for watching a collection.
  2851  type colWCfg struct {
  2852  	col    string
  2853  	filter func(interface{}) bool
  2854  	idconv func(string) string
  2855  
  2856  	// If global is true the watcher won't be limited to this model.
  2857  	global bool
  2858  
  2859  	// Only return documents with a revno greater than revnoThreshold. The
  2860  	// default zero value ensures that only modified (i.e revno > 0) rather
  2861  	// than just created documents are returned.
  2862  	revnoThreshold int64
  2863  }
  2864  
  2865  // newCollectionWatcher starts and returns a new StringsWatcher configured
  2866  // with the given collection and filter function
  2867  func newCollectionWatcher(backend modelBackend, cfg colWCfg) StringsWatcher {
  2868  	if cfg.global {
  2869  		if cfg.filter == nil {
  2870  			cfg.filter = func(x interface{}) bool {
  2871  				return true
  2872  			}
  2873  		}
  2874  	} else {
  2875  		// Always ensure that there is at least filtering on the
  2876  		// model in place.
  2877  		backstop := isLocalID(backend)
  2878  		if cfg.filter == nil {
  2879  			cfg.filter = backstop
  2880  		} else {
  2881  			innerFilter := cfg.filter
  2882  			cfg.filter = func(id interface{}) bool {
  2883  				if !backstop(id) {
  2884  					return false
  2885  				}
  2886  				return innerFilter(id)
  2887  			}
  2888  		}
  2889  	}
  2890  
  2891  	w := &collectionWatcher{
  2892  		colWCfg:       cfg,
  2893  		commonWatcher: newCommonWatcher(backend),
  2894  		source:        make(chan watcher.Change),
  2895  		sink:          make(chan []string),
  2896  	}
  2897  
  2898  	w.tomb.Go(func() error {
  2899  		defer close(w.sink)
  2900  		defer close(w.source)
  2901  		return w.loop()
  2902  	})
  2903  
  2904  	return w
  2905  }
  2906  
  2907  // Changes returns the event channel for this watcher
  2908  func (w *collectionWatcher) Changes() <-chan []string {
  2909  	return w.sink
  2910  }
  2911  
  2912  // loop performs the main event loop cycle, polling for changes and
  2913  // responding to Changes requests
  2914  func (w *collectionWatcher) loop() error {
  2915  	var (
  2916  		changes []string
  2917  		in      = (<-chan watcher.Change)(w.source)
  2918  		out     = (chan<- []string)(w.sink)
  2919  	)
  2920  
  2921  	w.watcher.WatchCollectionWithFilter(w.col, w.source, w.filter)
  2922  	defer w.watcher.UnwatchCollection(w.col, w.source)
  2923  
  2924  	changes, err := w.initial()
  2925  	if err != nil {
  2926  		return err
  2927  	}
  2928  
  2929  	for {
  2930  		select {
  2931  		case <-w.tomb.Dying():
  2932  			return tomb.ErrDying
  2933  		case <-w.watcher.Dead():
  2934  			return stateWatcherDeadError(w.watcher.Err())
  2935  		case ch := <-in:
  2936  			updates, ok := collectWhereRevnoGreaterThan(ch, in, w.tomb.Dying(), w.colWCfg.revnoThreshold)
  2937  			if !ok {
  2938  				return tomb.ErrDying
  2939  			}
  2940  			if err := w.mergeIds(&changes, updates); err != nil {
  2941  				return err
  2942  			}
  2943  			if len(changes) > 0 {
  2944  				out = w.sink
  2945  			} else {
  2946  				out = nil
  2947  			}
  2948  		case out <- changes:
  2949  			changes = []string{}
  2950  			out = nil
  2951  		}
  2952  	}
  2953  }
  2954  
  2955  // makeIdFilter constructs a predicate to filter keys that have the
  2956  // prefix matching one of the passed in ActionReceivers, or returns nil
  2957  // if tags is empty
  2958  func makeIdFilter(backend modelBackend, marker string, receivers ...ActionReceiver) func(interface{}) bool {
  2959  	if len(receivers) == 0 {
  2960  		return nil
  2961  	}
  2962  	ensureMarkerFn := ensureSuffixFn(marker)
  2963  	prefixes := make([]string, len(receivers))
  2964  	for ix, receiver := range receivers {
  2965  		prefixes[ix] = backend.docID(ensureMarkerFn(receiver.Tag().Id()))
  2966  	}
  2967  
  2968  	return func(key interface{}) bool {
  2969  		switch key.(type) {
  2970  		case string:
  2971  			for _, prefix := range prefixes {
  2972  				if strings.HasPrefix(key.(string), prefix) {
  2973  					return true
  2974  				}
  2975  			}
  2976  		default:
  2977  			watchLogger.Errorf("key is not type string, got %T", key)
  2978  		}
  2979  		return false
  2980  	}
  2981  }
  2982  
  2983  // initial pre-loads the id's that have already been added to the
  2984  // collection that would otherwise not normally trigger the watcher
  2985  func (w *collectionWatcher) initial() ([]string, error) {
  2986  	var ids []string
  2987  	var doc struct {
  2988  		DocId string `bson:"_id"`
  2989  	}
  2990  	coll, closer := w.db.GetCollection(w.col)
  2991  	defer closer()
  2992  	iter := coll.Find(nil).Iter()
  2993  	for iter.Next(&doc) {
  2994  		if w.filter == nil || w.filter(doc.DocId) {
  2995  			id := doc.DocId
  2996  			if !w.colWCfg.global {
  2997  				id = w.backend.localID(id)
  2998  			}
  2999  			if w.idconv != nil {
  3000  				id = w.idconv(id)
  3001  			}
  3002  			ids = append(ids, id)
  3003  		}
  3004  	}
  3005  	return ids, iter.Close()
  3006  }
  3007  
  3008  // mergeIds is used for merging actionId's and actionResultId's that
  3009  // come in via the updates map. It cleans up the pending changes to
  3010  // account for id's being removed before the watcher consumes them,
  3011  // and to account for the potential overlap between the id's that were
  3012  // pending before the watcher started, and the new id's detected by the
  3013  // watcher.
  3014  // Additionally, mergeIds strips the model UUID prefix from the id
  3015  // before emitting it through the watcher.
  3016  func (w *collectionWatcher) mergeIds(changes *[]string, updates map[interface{}]bool) error {
  3017  	return mergeIds(changes, updates, w.convertId)
  3018  }
  3019  
  3020  func (w *collectionWatcher) convertId(id string) (string, error) {
  3021  	if !w.colWCfg.global {
  3022  		// Strip off the env UUID prefix.
  3023  		// We only expect ids for a single model.
  3024  		var err error
  3025  		id, err = w.backend.strictLocalID(id)
  3026  		if err != nil {
  3027  			return "", errors.Trace(err)
  3028  		}
  3029  	}
  3030  	if w.idconv != nil {
  3031  		id = w.idconv(id)
  3032  	}
  3033  	return id, nil
  3034  }
  3035  
  3036  func mergeIds(changes *[]string, updates map[interface{}]bool, idconv func(string) (string, error)) error {
  3037  	for val, idExists := range updates {
  3038  		id, ok := val.(string)
  3039  		if !ok {
  3040  			return errors.Errorf("id is not of type string, got %T", val)
  3041  		}
  3042  
  3043  		id, err := idconv(id)
  3044  		if err != nil {
  3045  			return errors.Annotatef(err, "collection watcher")
  3046  		}
  3047  
  3048  		chIx, idAlreadyInChangeset := indexOf(id, *changes)
  3049  		if idExists {
  3050  			if !idAlreadyInChangeset {
  3051  				*changes = append(*changes, id)
  3052  			}
  3053  		} else {
  3054  			if idAlreadyInChangeset {
  3055  				// remove id from changes
  3056  				*changes = append((*changes)[:chIx], (*changes)[chIx+1:]...)
  3057  			}
  3058  		}
  3059  	}
  3060  	return nil
  3061  }
  3062  
  3063  func actionNotificationIdToActionId(id string) string {
  3064  	ix := strings.Index(id, actionMarker)
  3065  	if ix == -1 {
  3066  		return id
  3067  	}
  3068  	return id[ix+len(actionMarker):]
  3069  }
  3070  
  3071  func indexOf(find string, in []string) (int, bool) {
  3072  	for ix, cur := range in {
  3073  		if cur == find {
  3074  			return ix, true
  3075  		}
  3076  	}
  3077  	return -1, false
  3078  }
  3079  
  3080  // ensureSuffixFn returns a function that will make sure the passed in
  3081  // string has the marker token at the end of it
  3082  func ensureSuffixFn(marker string) func(string) string {
  3083  	return func(p string) string {
  3084  		if !strings.HasSuffix(p, marker) {
  3085  			p = p + marker
  3086  		}
  3087  		return p
  3088  	}
  3089  }
  3090  
  3091  // watchActionNotificationsFilteredBy starts and returns a StringsWatcher
  3092  // that notifies on new Actions being enqueued on the ActionRecevers
  3093  // being watched as well as changes to non-completed Actions.
  3094  func (st *State) watchActionNotificationsFilteredBy(receivers ...ActionReceiver) StringsWatcher {
  3095  	return newActionNotificationWatcher(st, false, receivers...)
  3096  }
  3097  
  3098  // watchEnqueuedActionsFilteredBy starts and returns a StringsWatcher
  3099  // that notifies on new Actions being enqueued on the ActionRecevers
  3100  // being watched.
  3101  func (st *State) watchEnqueuedActionsFilteredBy(receivers ...ActionReceiver) StringsWatcher {
  3102  	return newActionNotificationWatcher(st, true, receivers...)
  3103  }
  3104  
  3105  // actionNotificationWatcher is a StringsWatcher that watches for changes on the
  3106  // action notification collection, but only triggers events once per action.
  3107  type actionNotificationWatcher struct {
  3108  	commonWatcher
  3109  	source chan watcher.Change
  3110  	sink   chan []string
  3111  	filter func(interface{}) bool
  3112  	// notifyPending when true will notify all pending and running actions as
  3113  	// initial events, but thereafter only notify on pending actions.
  3114  	notifyPending bool
  3115  }
  3116  
  3117  // newActionNotificationWatcher starts and returns a new StringsWatcher configured
  3118  // with the given collection and filter function. notifyPending when true will notify all pending and running actions as
  3119  // initial events, but thereafter only notify on pending actions.
  3120  func newActionNotificationWatcher(backend modelBackend, notifyPending bool, receivers ...ActionReceiver) StringsWatcher {
  3121  	w := &actionNotificationWatcher{
  3122  		commonWatcher: newCommonWatcher(backend),
  3123  		source:        make(chan watcher.Change),
  3124  		sink:          make(chan []string),
  3125  		filter:        makeIdFilter(backend, actionMarker, receivers...),
  3126  		notifyPending: notifyPending,
  3127  	}
  3128  
  3129  	w.tomb.Go(func() error {
  3130  		defer close(w.sink)
  3131  		defer close(w.source)
  3132  		return w.loop()
  3133  	})
  3134  
  3135  	return w
  3136  }
  3137  
  3138  // Changes returns the event channel for this watcher
  3139  func (w *actionNotificationWatcher) Changes() <-chan []string {
  3140  	return w.sink
  3141  }
  3142  
  3143  func (w *actionNotificationWatcher) loop() error {
  3144  	var (
  3145  		changes []string
  3146  		in      = (<-chan watcher.Change)(w.source)
  3147  		out     = (chan<- []string)(w.sink)
  3148  	)
  3149  
  3150  	w.watcher.WatchCollectionWithFilter(actionNotificationsC, w.source, w.filter)
  3151  	defer w.watcher.UnwatchCollection(actionNotificationsC, w.source)
  3152  
  3153  	changes, err := w.initial()
  3154  	if err != nil {
  3155  		return err
  3156  	}
  3157  
  3158  	for {
  3159  		select {
  3160  		case <-w.tomb.Dying():
  3161  			return tomb.ErrDying
  3162  		case <-w.watcher.Dead():
  3163  			return stateWatcherDeadError(w.watcher.Err())
  3164  		case ch := <-in:
  3165  			updates, ok := collect(ch, in, w.tomb.Dying())
  3166  			if !ok {
  3167  				return tomb.ErrDying
  3168  			}
  3169  			if w.notifyPending {
  3170  				if err := w.filterPendingAndMergeIds(&changes, updates); err != nil {
  3171  					return err
  3172  				}
  3173  			} else {
  3174  				if err := w.mergeIds(&changes, updates); err != nil {
  3175  					return err
  3176  				}
  3177  			}
  3178  			if len(changes) > 0 {
  3179  				out = w.sink
  3180  			}
  3181  		case out <- changes:
  3182  			changes = []string{}
  3183  			out = nil
  3184  		}
  3185  	}
  3186  }
  3187  
  3188  func (w *actionNotificationWatcher) initial() ([]string, error) {
  3189  	var ids []string
  3190  	var doc actionNotificationDoc
  3191  	coll, closer := w.db.GetCollection(actionNotificationsC)
  3192  	defer closer()
  3193  	iter := coll.Find(nil).Iter()
  3194  	for iter.Next(&doc) {
  3195  		if w.filter(doc.DocId) {
  3196  			ids = append(ids, actionNotificationIdToActionId(doc.DocId))
  3197  		}
  3198  	}
  3199  	return ids, iter.Close()
  3200  }
  3201  
  3202  // filterPendingAndMergeIds reduces the keys published to the first action notification (pending actions).
  3203  func (w *actionNotificationWatcher) filterPendingAndMergeIds(changes *[]string, updates map[interface{}]bool) error {
  3204  	var newIDs []string
  3205  	for val, idExists := range updates {
  3206  		docID, ok := val.(string)
  3207  		if !ok {
  3208  			return errors.Errorf("id is not of type string, got %T", val)
  3209  		}
  3210  
  3211  		id := actionNotificationIdToActionId(docID)
  3212  		chIx, idAlreadyInChangeset := indexOf(id, *changes)
  3213  		if idExists {
  3214  			if !idAlreadyInChangeset {
  3215  				// add id to fetch from mongo
  3216  				newIDs = append(newIDs, w.backend.localID(docID))
  3217  			}
  3218  		} else {
  3219  			if idAlreadyInChangeset {
  3220  				// remove id from changes
  3221  				*changes = append((*changes)[:chIx], (*changes)[chIx+1:]...)
  3222  			}
  3223  		}
  3224  	}
  3225  
  3226  	coll, closer := w.db.GetCollection(actionNotificationsC)
  3227  	defer closer()
  3228  
  3229  	// query for all documents that match the ids who
  3230  	// don't have a changed field. These are new pending actions.
  3231  	query := bson.D{{"_id", bson.D{{"$in", newIDs}}}}
  3232  	var doc actionNotificationDoc
  3233  	iter := coll.Find(query).Iter()
  3234  	for iter.Next(&doc) {
  3235  		if doc.Changed.IsZero() {
  3236  			*changes = append(*changes, actionNotificationIdToActionId(doc.DocId))
  3237  		}
  3238  	}
  3239  	return iter.Close()
  3240  }
  3241  
  3242  func (w *actionNotificationWatcher) mergeIds(changes *[]string, updates map[interface{}]bool) error {
  3243  	return mergeIds(changes, updates, func(id string) (string, error) {
  3244  		return actionNotificationIdToActionId(id), nil
  3245  	})
  3246  }
  3247  
  3248  // WatchControllerStatusChanges starts and returns a StringsWatcher that
  3249  // notifies when the status of a controller node changes.
  3250  // TODO(cherylj) Add unit tests for this, as per bug 1543408.
  3251  func (st *State) WatchControllerStatusChanges() StringsWatcher {
  3252  	return newCollectionWatcher(st, colWCfg{
  3253  		col:    statusesC,
  3254  		filter: makeControllerIdFilter(st),
  3255  	})
  3256  }
  3257  
  3258  func makeControllerIdFilter(st *State) func(interface{}) bool {
  3259  	initialNodes, err := st.ControllerNodes()
  3260  	if err != nil {
  3261  		logger.Debugf("unable to get controller nodes: %v", err)
  3262  		return nil
  3263  	}
  3264  
  3265  	filter := controllerIdFilter{
  3266  		st:        st,
  3267  		lastNodes: make([]string, len(initialNodes)),
  3268  	}
  3269  	for i, n := range initialNodes {
  3270  		filter.lastNodes[i] = n.Id()
  3271  	}
  3272  	return filter.match
  3273  }
  3274  
  3275  // controllerIdFilter is a stateful watcher filter function - if it
  3276  // can't get the current controller nodes it uses the
  3277  // last nodes retrieved. Since this is called from multiple
  3278  // goroutines getting/updating lastNodes is protected by a mutex.
  3279  type controllerIdFilter struct {
  3280  	mu        sync.Mutex
  3281  	st        *State
  3282  	lastNodes []string
  3283  }
  3284  
  3285  func (f *controllerIdFilter) nodeIds() []string {
  3286  	var result []string
  3287  	nodes, err := f.st.ControllerNodes()
  3288  	f.mu.Lock()
  3289  	if err != nil {
  3290  		// Most likely, things will be killed and
  3291  		// restarted if we hit this error.  Just use
  3292  		// the machine list we knew about last time.
  3293  		logger.Debugf("unable to get controller info: %v", err)
  3294  		result = f.lastNodes
  3295  	} else {
  3296  		ids := make([]string, len(nodes))
  3297  		for i, n := range nodes {
  3298  			ids[i] = n.Id()
  3299  		}
  3300  		f.lastNodes = ids
  3301  		result = ids
  3302  	}
  3303  	f.mu.Unlock()
  3304  	return result
  3305  }
  3306  
  3307  func (f *controllerIdFilter) match(key interface{}) bool {
  3308  	switch key.(type) {
  3309  	case string:
  3310  		nodeIds := f.nodeIds()
  3311  		for _, id := range nodeIds {
  3312  			if strings.HasSuffix(key.(string), fmt.Sprintf("m#%s", id)) {
  3313  				return true
  3314  			}
  3315  			// TODO(HA) - add k8s controller filter when we do k8s HA
  3316  		}
  3317  	default:
  3318  		watchLogger.Errorf("key is not type string, got %T", key)
  3319  	}
  3320  	return false
  3321  }
  3322  
  3323  // openedPortsWatcher notifies of changes in the openedPorts
  3324  // collection
  3325  type openedPortsWatcher struct {
  3326  	commonWatcher
  3327  	known map[string]int64
  3328  	out   chan []string
  3329  }
  3330  
  3331  var _ Watcher = (*openedPortsWatcher)(nil)
  3332  
  3333  // WatchOpenedPorts starts and returns a StringsWatcher notifying of changes to
  3334  // the openedPorts collection. Reported changes have the following format:
  3335  // "<machine-id>:[<subnet-CIDR>]", i.e. "0:10.20.0.0/16" or "1:" (empty subnet
  3336  // ID is allowed for backwards-compatibility).
  3337  func (st *State) WatchOpenedPorts() StringsWatcher {
  3338  	return newOpenedPortsWatcher(st)
  3339  }
  3340  
  3341  func newOpenedPortsWatcher(backend modelBackend) StringsWatcher {
  3342  	w := &openedPortsWatcher{
  3343  		commonWatcher: newCommonWatcher(backend),
  3344  		known:         make(map[string]int64),
  3345  		out:           make(chan []string),
  3346  	}
  3347  	w.tomb.Go(func() error {
  3348  		defer close(w.out)
  3349  		return w.loop()
  3350  	})
  3351  
  3352  	return w
  3353  }
  3354  
  3355  // Changes returns the event channel for w
  3356  func (w *openedPortsWatcher) Changes() <-chan []string {
  3357  	return w.out
  3358  }
  3359  
  3360  func (w *openedPortsWatcher) initial() (set.Strings, error) {
  3361  	ports, closer := w.db.GetCollection(openedPortsC)
  3362  	defer closer()
  3363  
  3364  	portDocs := set.NewStrings()
  3365  	var doc machinePortRangesDoc
  3366  	iter := ports.Find(nil).Select(bson.D{{"_id", 1}, {"txn-revno", 1}}).Iter()
  3367  	defer iter.Close()
  3368  	for iter.Next(&doc) {
  3369  		id, err := w.backend.strictLocalID(doc.DocID)
  3370  		if err != nil {
  3371  			return nil, errors.Trace(err)
  3372  		}
  3373  		if doc.TxnRevno != -1 {
  3374  			w.known[id] = doc.TxnRevno
  3375  		}
  3376  		portDocs.Add(id)
  3377  	}
  3378  	return portDocs, errors.Trace(iter.Close())
  3379  }
  3380  
  3381  func (w *openedPortsWatcher) loop() error {
  3382  	in := make(chan watcher.Change)
  3383  	changes, err := w.initial()
  3384  	if err != nil {
  3385  		return errors.Trace(err)
  3386  	}
  3387  	w.watcher.WatchCollectionWithFilter(openedPortsC, in, isLocalID(w.backend))
  3388  	defer w.watcher.UnwatchCollection(openedPortsC, in)
  3389  
  3390  	out := w.out
  3391  	for {
  3392  		select {
  3393  		case <-w.tomb.Dying():
  3394  			return tomb.ErrDying
  3395  		case <-w.watcher.Dead():
  3396  			return stateWatcherDeadError(w.watcher.Err())
  3397  		case ch := <-in:
  3398  			if err = w.merge(changes, ch); err != nil {
  3399  				return errors.Trace(err)
  3400  			}
  3401  			if !changes.IsEmpty() {
  3402  				out = w.out
  3403  			}
  3404  		case out <- changes.Values():
  3405  			out = nil
  3406  			changes = set.NewStrings()
  3407  		}
  3408  	}
  3409  }
  3410  
  3411  func (w *openedPortsWatcher) merge(ids set.Strings, change watcher.Change) error {
  3412  	id, ok := change.Id.(string)
  3413  	if !ok {
  3414  		return errors.Errorf("id %v is not of type string, got %T", id, id)
  3415  	}
  3416  	localID, err := w.backend.strictLocalID(id)
  3417  	if err != nil {
  3418  		return errors.Trace(err)
  3419  	}
  3420  	if change.Revno < 0 {
  3421  		// Report the removed id.
  3422  		delete(w.known, localID)
  3423  		ids.Add(localID)
  3424  		return nil
  3425  	}
  3426  	openedPorts, closer := w.db.GetCollection(openedPortsC)
  3427  	currentRevno, err := getTxnRevno(openedPorts, id)
  3428  	closer()
  3429  	if err != nil {
  3430  		return err
  3431  	}
  3432  	knownRevno, isKnown := w.known[localID]
  3433  	w.known[localID] = currentRevno
  3434  	if !isKnown || currentRevno > knownRevno {
  3435  		// Report the unknown-so-far id.
  3436  		ids.Add(localID)
  3437  	}
  3438  	return nil
  3439  }
  3440  
  3441  // WatchForRebootEvent returns a notify watcher that will trigger an event
  3442  // when the reboot flag is set on our machine agent, our parent machine agent
  3443  // or grandparent machine agent
  3444  func (m *Machine) WatchForRebootEvent() NotifyWatcher {
  3445  	machineIds := m.machinesToCareAboutRebootsFor()
  3446  	machines := set.NewStrings(machineIds...)
  3447  
  3448  	filter := func(key interface{}) bool {
  3449  		if id, ok := key.(string); ok {
  3450  			if id, err := m.st.strictLocalID(id); err == nil {
  3451  				return machines.Contains(id)
  3452  			} else {
  3453  				return false
  3454  			}
  3455  		}
  3456  		return false
  3457  	}
  3458  	return newNotifyCollWatcher(m.st, rebootC, filter)
  3459  }
  3460  
  3461  // blockDevicesWatcher notifies about changes to all block devices
  3462  // associated with a machine.
  3463  type blockDevicesWatcher struct {
  3464  	commonWatcher
  3465  	machineId string
  3466  	out       chan struct{}
  3467  }
  3468  
  3469  var _ NotifyWatcher = (*blockDevicesWatcher)(nil)
  3470  
  3471  func newBlockDevicesWatcher(backend modelBackend, machineId string) NotifyWatcher {
  3472  	w := &blockDevicesWatcher{
  3473  		commonWatcher: newCommonWatcher(backend),
  3474  		machineId:     machineId,
  3475  		out:           make(chan struct{}),
  3476  	}
  3477  	w.tomb.Go(func() error {
  3478  		defer close(w.out)
  3479  		return w.loop()
  3480  	})
  3481  	return w
  3482  }
  3483  
  3484  // Changes returns the event channel for w.
  3485  func (w *blockDevicesWatcher) Changes() <-chan struct{} {
  3486  	return w.out
  3487  }
  3488  
  3489  func (w *blockDevicesWatcher) loop() error {
  3490  	docID := w.backend.docID(w.machineId)
  3491  	changes := make(chan watcher.Change)
  3492  	w.watcher.Watch(blockDevicesC, docID, changes)
  3493  	defer w.watcher.Unwatch(blockDevicesC, docID, changes)
  3494  	blockDevices, err := getBlockDevices(w.db, w.machineId)
  3495  	if err != nil {
  3496  		return errors.Trace(err)
  3497  	}
  3498  	out := w.out
  3499  	for {
  3500  		select {
  3501  		case <-w.watcher.Dead():
  3502  			return stateWatcherDeadError(w.watcher.Err())
  3503  		case <-w.tomb.Dying():
  3504  			return tomb.ErrDying
  3505  		case <-changes:
  3506  			newBlockDevices, err := getBlockDevices(w.db, w.machineId)
  3507  			if err != nil {
  3508  				return errors.Trace(err)
  3509  			}
  3510  			if !reflect.DeepEqual(newBlockDevices, blockDevices) {
  3511  				blockDevices = newBlockDevices
  3512  				out = w.out
  3513  			}
  3514  		case out <- struct{}{}:
  3515  			out = nil
  3516  		}
  3517  	}
  3518  }
  3519  
  3520  // WatchForMigration returns a notify watcher which reports when
  3521  // a migration is in progress for the model associated with the
  3522  // State.
  3523  func (st *State) WatchForMigration() NotifyWatcher {
  3524  	return newMigrationActiveWatcher(st)
  3525  }
  3526  
  3527  type migrationActiveWatcher struct {
  3528  	commonWatcher
  3529  	collName string
  3530  	id       string
  3531  	sink     chan struct{}
  3532  }
  3533  
  3534  func newMigrationActiveWatcher(st *State) NotifyWatcher {
  3535  	w := &migrationActiveWatcher{
  3536  		commonWatcher: newCommonWatcher(st),
  3537  		collName:      migrationsActiveC,
  3538  		id:            st.ModelUUID(),
  3539  		sink:          make(chan struct{}),
  3540  	}
  3541  	w.tomb.Go(func() error {
  3542  		defer close(w.sink)
  3543  		return w.loop()
  3544  	})
  3545  	return w
  3546  }
  3547  
  3548  // Changes returns the event channel for this watcher.
  3549  func (w *migrationActiveWatcher) Changes() <-chan struct{} {
  3550  	return w.sink
  3551  }
  3552  
  3553  func (w *migrationActiveWatcher) loop() error {
  3554  	in := make(chan watcher.Change)
  3555  	w.watcher.Watch(w.collName, w.id, in)
  3556  	defer w.watcher.Unwatch(w.collName, w.id, in)
  3557  
  3558  	// check if there are any pending changes before the first event
  3559  	if _, ok := collect(watcher.Change{}, in, w.tomb.Dying()); !ok {
  3560  		return tomb.ErrDying
  3561  	}
  3562  	out := w.sink
  3563  	for {
  3564  		select {
  3565  		case <-w.tomb.Dying():
  3566  			return tomb.ErrDying
  3567  		case <-w.watcher.Dead():
  3568  			return stateWatcherDeadError(w.watcher.Err())
  3569  		case change := <-in:
  3570  			if _, ok := collect(change, in, w.tomb.Dying()); !ok {
  3571  				return tomb.ErrDying
  3572  			}
  3573  			out = w.sink
  3574  		case out <- struct{}{}:
  3575  			out = nil
  3576  		}
  3577  	}
  3578  }
  3579  
  3580  // WatchMigrationStatus returns a NotifyWatcher which triggers
  3581  // whenever the status of latest migration for the State's model
  3582  // changes. One instance can be used across migrations. The watcher
  3583  // will report changes when one migration finishes and another one
  3584  // begins.
  3585  //
  3586  // Note that this watcher does not produce an initial event if there's
  3587  // never been a migration attempt for the model.
  3588  func (st *State) WatchMigrationStatus() NotifyWatcher {
  3589  	// Watch the entire migrationsStatusC collection for migration
  3590  	// status updates related to the State's model. This is more
  3591  	// efficient and simpler than tracking the current active
  3592  	// migration (and changing watchers when one migration finishes
  3593  	// and another starts.
  3594  	//
  3595  	// This approach is safe because there are strong guarantees that
  3596  	// there will only be one active migration per model. The watcher
  3597  	// will only see changes for one migration status document at a
  3598  	// time for the model.
  3599  	return newNotifyCollWatcher(st, migrationsStatusC, isLocalID(st))
  3600  }
  3601  
  3602  // WatchMachineRemovals returns a NotifyWatcher which triggers
  3603  // whenever machine removal records are added or removed.
  3604  func (st *State) WatchMachineRemovals() NotifyWatcher {
  3605  	return newNotifyCollWatcher(st, machineRemovalsC, isLocalID(st))
  3606  }
  3607  
  3608  // notifyCollWatcher implements NotifyWatcher, triggering when a
  3609  // change is seen in a specific collection matching the provided
  3610  // filter function.
  3611  type notifyCollWatcher struct {
  3612  	commonWatcher
  3613  	collName string
  3614  	filter   func(interface{}) bool
  3615  	sink     chan struct{}
  3616  }
  3617  
  3618  func newNotifyCollWatcher(backend modelBackend, collName string, filter func(interface{}) bool) NotifyWatcher {
  3619  	w := &notifyCollWatcher{
  3620  		commonWatcher: newCommonWatcher(backend),
  3621  		collName:      collName,
  3622  		filter:        filter,
  3623  		sink:          make(chan struct{}),
  3624  	}
  3625  	w.tomb.Go(func() error {
  3626  		defer close(w.sink)
  3627  		return w.loop()
  3628  	})
  3629  	return w
  3630  }
  3631  
  3632  // Changes returns the event channel for this watcher.
  3633  func (w *notifyCollWatcher) Changes() <-chan struct{} {
  3634  	return w.sink
  3635  }
  3636  
  3637  func (w *notifyCollWatcher) loop() error {
  3638  	in := make(chan watcher.Change)
  3639  
  3640  	w.watcher.WatchCollectionWithFilter(w.collName, in, w.filter)
  3641  	defer w.watcher.UnwatchCollection(w.collName, in)
  3642  
  3643  	// check if there are any pending changes before the first event
  3644  	if _, ok := collect(watcher.Change{}, in, w.tomb.Dying()); !ok {
  3645  		return tomb.ErrDying
  3646  	}
  3647  	out := w.sink // out set so that initial event is sent.
  3648  	for {
  3649  		select {
  3650  		case <-w.tomb.Dying():
  3651  			return tomb.ErrDying
  3652  		case <-w.watcher.Dead():
  3653  			return stateWatcherDeadError(w.watcher.Err())
  3654  		case change := <-in:
  3655  			if _, ok := collect(change, in, w.tomb.Dying()); !ok {
  3656  				return tomb.ErrDying
  3657  			}
  3658  			out = w.sink
  3659  		case out <- struct{}{}:
  3660  			out = nil
  3661  		}
  3662  	}
  3663  }
  3664  
  3665  // WatchRemoteRelations returns a StringsWatcher that notifies of changes to
  3666  // the lifecycles of the remote relations in the model.
  3667  func (st *State) WatchRemoteRelations() StringsWatcher {
  3668  	// Use a no-op transform func to record the known ids.
  3669  	known := make(map[interface{}]bool)
  3670  	tr := func(id string) string {
  3671  		known[id] = true
  3672  		return id
  3673  	}
  3674  
  3675  	filter := func(id interface{}) bool {
  3676  		id, err := st.strictLocalID(id.(string))
  3677  		if err != nil {
  3678  			return false
  3679  		}
  3680  
  3681  		// Gather the remote app names.
  3682  		remoteApps, closer := st.db().GetCollection(remoteApplicationsC)
  3683  		defer closer()
  3684  
  3685  		type remoteAppDoc struct {
  3686  			Name string
  3687  		}
  3688  		remoteAppNameField := bson.D{{"name", 1}}
  3689  		var apps []remoteAppDoc
  3690  		err = remoteApps.Find(nil).Select(remoteAppNameField).All(&apps)
  3691  		if err != nil {
  3692  			watchLogger.Errorf("could not lookup remote application names: %v", err)
  3693  			return false
  3694  		}
  3695  		remoteAppNames := set.NewStrings()
  3696  		for _, a := range apps {
  3697  			remoteAppNames.Add(a.Name)
  3698  		}
  3699  
  3700  		// Run a query to pickup any relations to those remote apps.
  3701  		relations, closer := st.db().GetCollection(relationsC)
  3702  		defer closer()
  3703  
  3704  		query := bson.D{
  3705  			{"key", id},
  3706  			{"endpoints.applicationname", bson.D{{"$in", remoteAppNames.Values()}}},
  3707  		}
  3708  		num, err := relations.Find(query).Count()
  3709  		if err != nil {
  3710  			watchLogger.Errorf("could not lookup remote relations: %v", err)
  3711  			return false
  3712  		}
  3713  		// The relation (or remote app) may have been deleted, but if it has been
  3714  		// seen previously, return true.
  3715  		if num == 0 {
  3716  			_, seen := known[id]
  3717  			delete(known, id)
  3718  			return seen
  3719  		}
  3720  		return num > 0
  3721  	}
  3722  	return newRelationLifeSuspendedWatcher(st, nil, filter, tr)
  3723  }
  3724  
  3725  // WatchSubnets returns a StringsWatcher that notifies of changes to
  3726  // the subnets in the model.
  3727  func (st *State) WatchSubnets(subnetFilter func(id interface{}) bool) StringsWatcher {
  3728  	filter := func(id interface{}) bool {
  3729  		subnet, err := st.strictLocalID(id.(string))
  3730  		if err != nil {
  3731  			return false
  3732  		}
  3733  		if subnetFilter == nil {
  3734  			return true
  3735  		}
  3736  		return subnetFilter(subnet)
  3737  	}
  3738  
  3739  	return newCollectionWatcher(st, colWCfg{
  3740  		col:    subnetsC,
  3741  		filter: filter,
  3742  	})
  3743  }
  3744  
  3745  // isLocalID returns a watcher filter func that rejects ids not specific
  3746  // to the supplied modelBackend.
  3747  func isLocalID(st modelBackend) func(interface{}) bool {
  3748  	return func(id interface{}) bool {
  3749  		key, ok := id.(string)
  3750  		if !ok {
  3751  			return false
  3752  		}
  3753  		_, err := st.strictLocalID(key)
  3754  		return err == nil
  3755  	}
  3756  }
  3757  
  3758  // relationNetworksWatcher notifies of changes in the
  3759  // relationNetworks collection, either ingress of egress.
  3760  type relationNetworksWatcher struct {
  3761  	commonWatcher
  3762  	key         string
  3763  	direction   string
  3764  	filter      func(key interface{}) bool
  3765  	knownTxnRev int64
  3766  	knownCidrs  set.Strings
  3767  	out         chan []string
  3768  }
  3769  
  3770  var _ Watcher = (*relationNetworksWatcher)(nil)
  3771  
  3772  // WatchRelationIngressNetworks starts and returns a StringsWatcher notifying
  3773  // of ingress changes to the relationNetworks collection for the relation.
  3774  func (r *Relation) WatchRelationIngressNetworks() StringsWatcher {
  3775  	return newrelationNetworksWatcher(r.st, r.Tag().Id(), IngressDirection.String())
  3776  }
  3777  
  3778  // WatchRelationEgressNetworks starts and returns a StringsWatcher notifying
  3779  // of egress changes to the relationNetworks collection for the relation.
  3780  func (r *Relation) WatchRelationEgressNetworks() StringsWatcher {
  3781  	return newrelationNetworksWatcher(r.st, r.Tag().Id(), EgressDirection.String())
  3782  }
  3783  
  3784  func newrelationNetworksWatcher(st modelBackend, relationKey, direction string) StringsWatcher {
  3785  	filter := func(id interface{}) bool {
  3786  		k, err := st.strictLocalID(id.(string))
  3787  		if err != nil {
  3788  			return false
  3789  		}
  3790  		return strings.HasPrefix(k, relationKey+":"+direction+":")
  3791  	}
  3792  	w := &relationNetworksWatcher{
  3793  		commonWatcher: newCommonWatcher(st),
  3794  		key:           relationKey,
  3795  		direction:     direction,
  3796  		filter:        filter,
  3797  		knownCidrs:    set.NewStrings(),
  3798  		out:           make(chan []string),
  3799  	}
  3800  	w.tomb.Go(func() error {
  3801  		defer close(w.out)
  3802  		return w.loop()
  3803  	})
  3804  
  3805  	return w
  3806  }
  3807  
  3808  // Changes returns the event channel for watching changes
  3809  // to a relation's ingress networks.
  3810  func (w *relationNetworksWatcher) Changes() <-chan []string {
  3811  	return w.out
  3812  }
  3813  
  3814  func (w *relationNetworksWatcher) loadCIDRs() (bool, error) {
  3815  	coll, closer := w.db.GetCollection(relationNetworksC)
  3816  	defer closer()
  3817  
  3818  	var doc struct {
  3819  		TxnRevno int64    `bson:"txn-revno"`
  3820  		Id       string   `bson:"_id"`
  3821  		CIDRs    []string `bson:"cidrs"`
  3822  	}
  3823  	err := coll.FindId(relationNetworkDocID(w.key, w.direction, relationNetworkAdmin)).One(&doc)
  3824  	if err == mgo.ErrNotFound {
  3825  		err = coll.FindId(relationNetworkDocID(w.key, w.direction, relationNetworkDefault)).One(&doc)
  3826  	}
  3827  	if err == mgo.ErrNotFound {
  3828  		// Record deleted.
  3829  		changed := w.knownCidrs.Size() > 0
  3830  		w.knownCidrs = set.NewStrings()
  3831  		return changed, nil
  3832  	}
  3833  	if err != nil {
  3834  		return false, errors.Trace(err)
  3835  
  3836  	}
  3837  	cidrs := w.knownCidrs
  3838  	if doc.TxnRevno == -1 {
  3839  		// Record deleted.
  3840  		cidrs = set.NewStrings()
  3841  	}
  3842  	if doc.TxnRevno > w.knownTxnRev {
  3843  		cidrs = set.NewStrings(doc.CIDRs...)
  3844  	}
  3845  	w.knownTxnRev = doc.TxnRevno
  3846  	changed := !cidrs.Difference(w.knownCidrs).IsEmpty() || !w.knownCidrs.Difference(cidrs).IsEmpty()
  3847  	w.knownCidrs = cidrs
  3848  	return changed, nil
  3849  }
  3850  
  3851  func (w *relationNetworksWatcher) loop() error {
  3852  	in := make(chan watcher.Change)
  3853  	w.watcher.WatchCollectionWithFilter(relationNetworksC, in, w.filter)
  3854  	defer w.watcher.UnwatchCollection(relationNetworksC, in)
  3855  
  3856  	var (
  3857  		sentInitial bool
  3858  		changed     bool
  3859  		out         chan<- []string
  3860  		err         error
  3861  	)
  3862  	if _, err = w.loadCIDRs(); err != nil {
  3863  		return errors.Trace(err)
  3864  	}
  3865  	for {
  3866  		if !sentInitial || changed {
  3867  			changed = false
  3868  			out = w.out
  3869  		}
  3870  		select {
  3871  		case <-w.tomb.Dying():
  3872  			return tomb.ErrDying
  3873  		case <-w.watcher.Dead():
  3874  			return stateWatcherDeadError(w.watcher.Err())
  3875  		case _, ok := <-in:
  3876  			if !ok {
  3877  				return tomb.ErrDying
  3878  			}
  3879  			if changed, err = w.loadCIDRs(); err != nil {
  3880  				return errors.Trace(err)
  3881  			}
  3882  		case out <- w.knownCidrs.Values():
  3883  			out = nil
  3884  			sentInitial = true
  3885  		}
  3886  		if w.knownTxnRev == -1 {
  3887  			// Record deleted
  3888  			return tomb.ErrDying
  3889  		}
  3890  	}
  3891  }
  3892  
  3893  // externalControllersWatcher notifies about addition and removal of
  3894  // external controller references.
  3895  type externalControllersWatcher struct {
  3896  	commonWatcher
  3897  	coll func() (mongo.Collection, func())
  3898  	out  chan []string
  3899  }
  3900  
  3901  var _ Watcher = (*externalControllersWatcher)(nil)
  3902  
  3903  func newExternalControllersWatcher(st *State) StringsWatcher {
  3904  	w := &externalControllersWatcher{
  3905  		commonWatcher: newCommonWatcher(st),
  3906  		coll:          collFactory(st.db(), externalControllersC),
  3907  		out:           make(chan []string),
  3908  	}
  3909  	w.tomb.Go(func() error {
  3910  		defer close(w.out)
  3911  		return w.loop()
  3912  	})
  3913  	return w
  3914  }
  3915  
  3916  // Changes returns the event channel for w.
  3917  func (w *externalControllersWatcher) Changes() <-chan []string {
  3918  	return w.out
  3919  }
  3920  
  3921  func (w *externalControllersWatcher) initial() (set.Strings, error) {
  3922  	// Get the initial documents in the collection.
  3923  	type idDoc struct {
  3924  		Id string `bson:"_id"`
  3925  	}
  3926  	coll, closer := w.coll()
  3927  	defer closer()
  3928  	changes := make(set.Strings)
  3929  	iter := coll.Find(nil).Select(bson.D{{"_id", 1}}).Iter()
  3930  	var doc idDoc
  3931  	for iter.Next(&doc) {
  3932  		changes.Add(doc.Id)
  3933  	}
  3934  	return changes, iter.Close()
  3935  }
  3936  
  3937  func (w *externalControllersWatcher) loop() error {
  3938  	in := make(chan watcher.Change)
  3939  	w.watcher.WatchCollection(externalControllersC, in)
  3940  	defer w.watcher.UnwatchCollection(externalControllersC, in)
  3941  
  3942  	changes, err := w.initial()
  3943  	if err != nil {
  3944  		return errors.Trace(err)
  3945  	}
  3946  
  3947  	reported := make(set.Strings)
  3948  	out := w.out
  3949  	for {
  3950  		select {
  3951  		case <-w.watcher.Dead():
  3952  			return stateWatcherDeadError(w.watcher.Err())
  3953  		case <-w.tomb.Dying():
  3954  			return tomb.ErrDying
  3955  		case ch := <-in:
  3956  			updates, ok := collect(ch, in, w.tomb.Dying())
  3957  			if !ok {
  3958  				return tomb.ErrDying
  3959  			}
  3960  			for id, updated := range updates {
  3961  				id := id.(string)
  3962  				if updated != reported.Contains(id) {
  3963  					// updated and hasn't been reported, or
  3964  					// removed and has been reported
  3965  					changes.Add(id)
  3966  				}
  3967  			}
  3968  			if changes.Size() > 0 {
  3969  				out = w.out
  3970  			}
  3971  		case out <- changes.SortedValues():
  3972  			out = nil
  3973  			for _, id := range changes.Values() {
  3974  				if reported.Contains(id) {
  3975  					reported.Remove(id)
  3976  				} else {
  3977  					reported.Add(id)
  3978  				}
  3979  			}
  3980  			changes = make(set.Strings)
  3981  		}
  3982  	}
  3983  }
  3984  
  3985  // WatchPodSpec returns a watcher observing changes that affect the
  3986  // pod spec for an application or unit.
  3987  func (m *CAASModel) WatchPodSpec(appTag names.ApplicationTag) (NotifyWatcher, error) {
  3988  	docKeys := []docKey{{
  3989  		podSpecsC,
  3990  		m.st.docID(applicationGlobalKey(appTag.Id())),
  3991  	}}
  3992  	return newDocWatcher(m.st, docKeys), nil
  3993  }
  3994  
  3995  // containerAddressesWatcher notifies about changes to a unit's pod address(es).
  3996  type containerAddressesWatcher struct {
  3997  	commonWatcher
  3998  	unit *Unit
  3999  	out  chan struct{}
  4000  }
  4001  
  4002  var _ Watcher = (*containerAddressesWatcher)(nil)
  4003  
  4004  // WatchContainerAddresses returns a new NotifyWatcher watching the unit's pod address(es).
  4005  func (u *Unit) WatchContainerAddresses() NotifyWatcher {
  4006  	return newContainerAddressesWatcher(u)
  4007  }
  4008  
  4009  func newContainerAddressesWatcher(u *Unit) NotifyWatcher {
  4010  	w := &containerAddressesWatcher{
  4011  		commonWatcher: newCommonWatcher(u.st),
  4012  		out:           make(chan struct{}),
  4013  		unit:          u,
  4014  	}
  4015  	w.tomb.Go(func() error {
  4016  		defer close(w.out)
  4017  		return w.loop()
  4018  	})
  4019  	return w
  4020  }
  4021  
  4022  // Changes returns the event channel for w.
  4023  func (w *containerAddressesWatcher) Changes() <-chan struct{} {
  4024  	return w.out
  4025  }
  4026  
  4027  func (w *containerAddressesWatcher) loop() error {
  4028  	id := w.backend.docID(w.unit.globalKey())
  4029  	containerCh := make(chan watcher.Change)
  4030  	w.watcher.Watch(cloudContainersC, id, containerCh)
  4031  	defer w.watcher.Unwatch(cloudContainersC, id, containerCh)
  4032  
  4033  	var currentAddress *address
  4034  	container, err := w.unit.cloudContainer()
  4035  	if err != nil && !errors.IsNotFound(err) {
  4036  		return err
  4037  	} else if err == nil {
  4038  		currentAddress = container.Address
  4039  	}
  4040  	out := w.out
  4041  	for {
  4042  		select {
  4043  		case <-w.watcher.Dead():
  4044  			return stateWatcherDeadError(w.watcher.Err())
  4045  		case <-w.tomb.Dying():
  4046  			return tomb.ErrDying
  4047  		case <-containerCh:
  4048  			container, err := w.unit.cloudContainer()
  4049  			if err != nil {
  4050  				return err
  4051  			}
  4052  			addressValue := func(addr *address) string {
  4053  				if addr == nil {
  4054  					return ""
  4055  				}
  4056  				return addr.Value
  4057  			}
  4058  			newAddress := container.Address
  4059  			if addressValue(newAddress) != addressValue(currentAddress) {
  4060  				currentAddress = newAddress
  4061  				out = w.out
  4062  			}
  4063  		case out <- struct{}{}:
  4064  			out = nil
  4065  		}
  4066  	}
  4067  }
  4068  
  4069  func newSettingsHashWatcher(st *State, localID string) StringsWatcher {
  4070  	docID := st.docID(localID)
  4071  	w := &hashWatcher{
  4072  		commonWatcher: newCommonWatcher(st),
  4073  		out:           make(chan []string),
  4074  		collection:    settingsC,
  4075  		id:            docID,
  4076  		hash: func() (string, error) {
  4077  			return hashSettings(st.db(), docID, localID)
  4078  		},
  4079  	}
  4080  	w.start()
  4081  	return w
  4082  }
  4083  
  4084  func hashSettings(db Database, id string, name string) (string, error) {
  4085  	settings, closer := db.GetCollection(settingsC)
  4086  	defer closer()
  4087  	var doc settingsDoc
  4088  	if err := settings.FindId(id).One(&doc); err == mgo.ErrNotFound {
  4089  		return "", nil
  4090  	} else if err != nil {
  4091  		return "", errors.Trace(err)
  4092  	}
  4093  	// Ensure elements are in a consistent order. If any are maps,
  4094  	// replace them with the equivalent sorted bson.Ds.
  4095  	items := toSortedBsonD(doc.Settings)
  4096  	data, err := bson.Marshal(items)
  4097  	if err != nil {
  4098  		return "", errors.Trace(err)
  4099  	}
  4100  	hash := sha256.New()
  4101  	_, _ = hash.Write([]byte(name))
  4102  	_, _ = hash.Write(data)
  4103  	return fmt.Sprintf("%x", hash.Sum(nil)), nil
  4104  }
  4105  
  4106  // WatchServiceAddressesHash returns a StringsWatcher that emits a
  4107  // hash of the unit's container address whenever it changes.
  4108  func (a *Application) WatchServiceAddressesHash() StringsWatcher {
  4109  	firstCall := true
  4110  	w := &hashWatcher{
  4111  		commonWatcher: newCommonWatcher(a.st),
  4112  		out:           make(chan []string),
  4113  		collection:    cloudServicesC,
  4114  		id:            a.st.docID(a.globalKey()),
  4115  		hash: func() (string, error) {
  4116  			result, err := hashServiceAddresses(a, firstCall)
  4117  			firstCall = false
  4118  			return result, err
  4119  		},
  4120  	}
  4121  	w.start()
  4122  	return w
  4123  }
  4124  
  4125  // WatchConfigSettingsHash returns a watcher that yields a hash of the
  4126  // application's config settings whenever they are changed.
  4127  func (a *Application) WatchConfigSettingsHash() StringsWatcher {
  4128  	applicationConfigKey := applicationConfigKey(a.Name())
  4129  	return newSettingsHashWatcher(a.st, applicationConfigKey)
  4130  }
  4131  
  4132  func hashServiceAddresses(a *Application, firstCall bool) (string, error) {
  4133  	service, err := a.ServiceInfo()
  4134  	if errors.IsNotFound(err) && firstCall {
  4135  		// To keep behaviour the same as
  4136  		// WatchServiceAddresses, we need to ignore NotFound
  4137  		// errors on the first call but propagate them after
  4138  		// that.
  4139  		return "", nil
  4140  	}
  4141  	if err != nil {
  4142  		return "", errors.Trace(err)
  4143  	}
  4144  	addresses := service.Addresses()
  4145  	if len(addresses) == 0 {
  4146  		return "", nil
  4147  	}
  4148  	address := addresses[0]
  4149  	hash := sha256.New()
  4150  	_, _ = hash.Write([]byte(address.Value))
  4151  	_, _ = hash.Write([]byte(address.Type))
  4152  	_, _ = hash.Write([]byte(address.Scope))
  4153  	_, _ = hash.Write([]byte(address.SpaceID))
  4154  	return fmt.Sprintf("%x", hash.Sum(nil)), nil
  4155  }
  4156  
  4157  type hashWatcher struct {
  4158  	commonWatcher
  4159  	collection string
  4160  	id         string
  4161  	hash       func() (string, error)
  4162  	out        chan []string
  4163  }
  4164  
  4165  func (w *hashWatcher) Changes() <-chan []string {
  4166  	return w.out
  4167  }
  4168  
  4169  func (w *hashWatcher) start() {
  4170  	w.tomb.Go(func() error {
  4171  		defer close(w.out)
  4172  		return w.loop()
  4173  	})
  4174  }
  4175  
  4176  func (w *hashWatcher) loop() error {
  4177  	changesCh := make(chan watcher.Change)
  4178  	w.watcher.Watch(w.collection, w.id, changesCh)
  4179  	defer w.watcher.Unwatch(w.collection, w.id, changesCh)
  4180  
  4181  	lastHash, err := w.hash()
  4182  	if err != nil {
  4183  		return errors.Trace(err)
  4184  	}
  4185  	out := w.out
  4186  	for {
  4187  		select {
  4188  		case <-w.watcher.Dead():
  4189  			return stateWatcherDeadError(w.watcher.Err())
  4190  		case <-w.tomb.Dying():
  4191  			return tomb.ErrDying
  4192  		case change := <-changesCh:
  4193  			if _, ok := collect(change, changesCh, w.tomb.Dying()); !ok {
  4194  				return tomb.ErrDying
  4195  			}
  4196  			newHash, err := w.hash()
  4197  			if err != nil {
  4198  				return errors.Trace(err)
  4199  			}
  4200  			if lastHash != newHash {
  4201  				lastHash = newHash
  4202  				out = w.out
  4203  			}
  4204  		case out <- []string{lastHash}:
  4205  			out = nil
  4206  		}
  4207  	}
  4208  }
  4209  
  4210  // WatchMachineAndEndpointAddressesHash returns a StringsWatcher that reports changes to
  4211  // the hash value of the address assignments to the unit's endpoints. The hash
  4212  // is recalculated when any of the following events occurs:
  4213  // - the machine addresses for the unit change.
  4214  // - the endpoint bindings for the unit's application change.
  4215  func (u *Unit) WatchMachineAndEndpointAddressesHash() (StringsWatcher, error) {
  4216  	app, err := u.Application()
  4217  	if err != nil {
  4218  		return nil, errors.Trace(err)
  4219  	}
  4220  	endpointsDoc, err := readEndpointBindingsDoc(app.st, app.globalKey())
  4221  	if err != nil {
  4222  		return nil, errors.Trace(err)
  4223  	}
  4224  	machineId, err := u.AssignedMachineId()
  4225  	if err != nil {
  4226  		return nil, errors.Trace(err)
  4227  	}
  4228  	machine, err := u.st.Machine(machineId)
  4229  	if err != nil {
  4230  		return nil, errors.Trace(err)
  4231  	}
  4232  	mCopy := &Machine{st: machine.st, doc: machine.doc}
  4233  
  4234  	// We need to check the hash when either the bindings change or when
  4235  	// the machine doc changes (e.g. machine has new network addresses).
  4236  	w := &hashMultiWatcher{
  4237  		commonWatcher: newCommonWatcher(app.st),
  4238  		out:           make(chan []string),
  4239  		collectionToIDMap: map[string]string{
  4240  			endpointBindingsC: endpointsDoc.DocID,
  4241  			machinesC:         machine.doc.DocID,
  4242  		},
  4243  		hash: func() (string, error) {
  4244  			bindings, err := app.EndpointBindings()
  4245  			if err != nil {
  4246  				return "", err
  4247  			}
  4248  			return hashMachineAddressesForEndpointBindings(mCopy, bindings.Map())
  4249  		},
  4250  	}
  4251  	w.start()
  4252  	return w, nil
  4253  }
  4254  
  4255  func hashMachineAddressesForEndpointBindings(m *Machine, bindingsToSpaceIDs map[string]string) (string, error) {
  4256  	if err := m.Refresh(); err != nil {
  4257  		return "", errors.Trace(err)
  4258  	}
  4259  	hash := sha256.New()
  4260  
  4261  	addresses := m.Addresses()
  4262  	sort.Slice(addresses, func(i, j int) bool { return addresses[i].Value < addresses[j].Value })
  4263  	for _, address := range addresses {
  4264  		hashAddr(hash, address)
  4265  	}
  4266  
  4267  	// Also include binding assignments to the hash. We don't care about
  4268  	// address assignments at this point; if the machine addresses change
  4269  	// (e.g. due to a reboot), the above code block would yield a different
  4270  	// hash.
  4271  	sortedEndpoints := make([]string, 0, len(bindingsToSpaceIDs))
  4272  	for epName := range bindingsToSpaceIDs {
  4273  		sortedEndpoints = append(sortedEndpoints, epName)
  4274  	}
  4275  	sort.Strings(sortedEndpoints)
  4276  
  4277  	for _, epName := range sortedEndpoints {
  4278  		if epName == "" {
  4279  			continue
  4280  		}
  4281  		_, _ = hash.Write([]byte(fmt.Sprintf("%s:%s", epName, bindingsToSpaceIDs[epName])))
  4282  	}
  4283  	return fmt.Sprintf("%x", hash.Sum(nil)), nil
  4284  }
  4285  
  4286  func hashAddr(h hash.Hash, addr corenetwork.SpaceAddress) {
  4287  	_, _ = h.Write([]byte(addr.Value))
  4288  	_, _ = h.Write([]byte(addr.Type))
  4289  	_, _ = h.Write([]byte(addr.Scope))
  4290  	_, _ = h.Write([]byte(addr.SpaceID))
  4291  }
  4292  
  4293  // hashMultiWatcher watches a set of documents for changes, invokes a
  4294  // user-defined hash function and emits changes in the hash value.
  4295  type hashMultiWatcher struct {
  4296  	commonWatcher
  4297  	collectionToIDMap map[string]string
  4298  	hash              func() (string, error)
  4299  	out               chan []string
  4300  }
  4301  
  4302  func (w *hashMultiWatcher) Changes() <-chan []string {
  4303  	return w.out
  4304  }
  4305  
  4306  func (w *hashMultiWatcher) start() {
  4307  	w.tomb.Go(func() error {
  4308  		defer close(w.out)
  4309  		return w.loop()
  4310  	})
  4311  }
  4312  
  4313  func (w *hashMultiWatcher) loop() error {
  4314  	changesCh := make(chan watcher.Change)
  4315  	for collection, id := range w.collectionToIDMap {
  4316  		w.watcher.Watch(collection, id, changesCh)
  4317  	}
  4318  	defer func() {
  4319  		for collection, id := range w.collectionToIDMap {
  4320  			w.watcher.Unwatch(collection, id, changesCh)
  4321  		}
  4322  	}()
  4323  
  4324  	lastHash, err := w.hash()
  4325  	if err != nil {
  4326  		return errors.Trace(err)
  4327  	}
  4328  	out := w.out
  4329  	for {
  4330  		select {
  4331  		case <-w.watcher.Dead():
  4332  			return stateWatcherDeadError(w.watcher.Err())
  4333  		case <-w.tomb.Dying():
  4334  			return tomb.ErrDying
  4335  		case change := <-changesCh:
  4336  			if _, ok := collect(change, changesCh, w.tomb.Dying()); !ok {
  4337  				return tomb.ErrDying
  4338  			}
  4339  			newHash, err := w.hash()
  4340  			if err != nil {
  4341  				return errors.Trace(err)
  4342  			}
  4343  			if lastHash != newHash {
  4344  				lastHash = newHash
  4345  				out = w.out
  4346  			}
  4347  		case out <- []string{lastHash}:
  4348  			out = nil
  4349  		}
  4350  	}
  4351  }
  4352  
  4353  func toSortedBsonD(values map[string]interface{}) bson.D {
  4354  	var items bson.D
  4355  	for name, value := range values {
  4356  		if mapValue, ok := value.(map[string]interface{}); ok {
  4357  			value = toSortedBsonD(mapValue)
  4358  		}
  4359  		items = append(items, bson.DocElem{Name: name, Value: value})
  4360  	}
  4361  	// We know that there aren't any equal names because the source is
  4362  	// a map.
  4363  	sort.Slice(items, func(i int, j int) bool {
  4364  		return items[i].Name < items[j].Name
  4365  	})
  4366  	return items
  4367  }