github.com/juju/juju@v0.0.0-20240327075706-a90865de2538/api/watcher/watcher.go (about)

     1  // Copyright 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package watcher
     5  
     6  import (
     7  	"sync"
     8  
     9  	"github.com/juju/errors"
    10  	"github.com/juju/loggo"
    11  	"github.com/juju/names/v5"
    12  	"github.com/kr/pretty"
    13  	"gopkg.in/tomb.v2"
    14  
    15  	"github.com/juju/juju/api/base"
    16  	"github.com/juju/juju/core/migration"
    17  	"github.com/juju/juju/core/secrets"
    18  	"github.com/juju/juju/core/status"
    19  	"github.com/juju/juju/core/watcher"
    20  	"github.com/juju/juju/rpc"
    21  	"github.com/juju/juju/rpc/params"
    22  )
    23  
    24  var logger = loggo.GetLogger("juju.api.watcher")
    25  
    26  // commonWatcher implements common watcher logic in one place to
    27  // reduce code duplication, but it's not in fact a complete watcher;
    28  // it's intended for embedding.
    29  type commonWatcher struct {
    30  	tomb tomb.Tomb
    31  	in   chan interface{}
    32  
    33  	// These fields must be set by the embedding watcher, before
    34  	// calling init().
    35  
    36  	// newResult must return a pointer to a value of the type returned
    37  	// by the watcher's Next call.
    38  	newResult func() interface{}
    39  
    40  	// call should invoke the given API method, placing the call's
    41  	// returned value in result (if any).
    42  	call watcherAPICall
    43  }
    44  
    45  // watcherAPICall wraps up the information about what facade and what watcher
    46  // Id we are calling, and just gives us a simple way to call a common method
    47  // with a given return value.
    48  type watcherAPICall func(method string, result interface{}) error
    49  
    50  // makeWatcherAPICaller creates a watcherAPICall function for a given facade name
    51  // and watcherId.
    52  func makeWatcherAPICaller(caller base.APICaller, facadeName, watcherId string) watcherAPICall {
    53  	bestVersion := caller.BestFacadeVersion(facadeName)
    54  	return func(request string, result interface{}) error {
    55  		return caller.APICall(facadeName, bestVersion,
    56  			watcherId, request, nil, &result)
    57  	}
    58  }
    59  
    60  // init must be called to initialize an embedded commonWatcher's
    61  // fields. Make sure newResult and call fields are set beforehand.
    62  func (w *commonWatcher) init() {
    63  	w.in = make(chan interface{})
    64  	if w.newResult == nil {
    65  		panic("newResult must be set")
    66  	}
    67  	if w.call == nil {
    68  		panic("call must be set")
    69  	}
    70  }
    71  
    72  // commonLoop implements the loop structure common to the client
    73  // watchers. It should be started in a separate goroutine by any
    74  // watcher that embeds commonWatcher. It kills the commonWatcher's
    75  // tomb when an error occurs.
    76  func (w *commonWatcher) commonLoop() {
    77  	defer close(w.in)
    78  	var wg sync.WaitGroup
    79  	wg.Add(1)
    80  	go func() {
    81  		// When the watcher has been stopped, we send a Stop request
    82  		// to the server, which will remove the watcher and return a
    83  		// CodeStopped error to any currently outstanding call to
    84  		// Next. If a call to Next happens just after the watcher has
    85  		// been stopped, we'll get a CodeNotFound error; Either way
    86  		// we'll return, wait for the stop request to complete, and
    87  		// the watcher will die with all resources cleaned up.
    88  		defer wg.Done()
    89  		<-w.tomb.Dying()
    90  		if err := w.call("Stop", nil); err != nil {
    91  			// Don't log an error if a watcher is stopped due to an agent restart,
    92  			// or if the entity being watched is already removed.
    93  			if !isAgentRestartError(err) &&
    94  				err.Error() != rpc.ErrShutdown.Error() && !params.IsCodeNotFound(err) {
    95  				logger.Errorf("error trying to stop watcher: %v", err)
    96  			}
    97  		}
    98  	}()
    99  	wg.Add(1)
   100  	go func() {
   101  		// Because Next blocks until there are changes, we need to
   102  		// call it in a separate goroutine, so the watcher can be
   103  		// stopped normally.
   104  		defer wg.Done()
   105  		for {
   106  			result := w.newResult()
   107  			err := w.call("Next", &result)
   108  			if err != nil {
   109  				if params.IsCodeStopped(err) || params.IsCodeNotFound(err) {
   110  					if w.tomb.Err() != tomb.ErrStillAlive {
   111  						// The watcher has been stopped at the client end, so we're
   112  						// expecting one of the above two kinds of error.
   113  						// We might see the same errors if the server itself
   114  						// has been shut down, in which case we leave them
   115  						// untouched.
   116  						err = tomb.ErrDying
   117  					}
   118  				}
   119  				// Something went wrong, just report the error and bail out.
   120  				w.tomb.Kill(err)
   121  				return
   122  			}
   123  			select {
   124  			case <-w.tomb.Dying():
   125  				return
   126  			case w.in <- result:
   127  				// Report back the result we just got.
   128  			}
   129  		}
   130  	}()
   131  	wg.Wait()
   132  }
   133  
   134  var (
   135  	// ErrRestartArgent matches juju/juju/worker/error.go ErrRestartAgent
   136  	// and is used to indicate that the watcher should be restarted.
   137  	ErrRestartAgent = errors.New("agent should be restarted")
   138  )
   139  
   140  func isAgentRestartError(err error) bool {
   141  	return err.Error() == ErrRestartAgent.Error()
   142  }
   143  
   144  // Kill is part of the worker.Worker interface.
   145  func (w *commonWatcher) Kill() {
   146  	w.tomb.Kill(nil)
   147  }
   148  
   149  // Wait is part of the worker.Worker interface.
   150  func (w *commonWatcher) Wait() error {
   151  	return w.tomb.Wait()
   152  }
   153  
   154  // notifyWatcher will send events when something changes.
   155  // It does not send content for those changes.
   156  type notifyWatcher struct {
   157  	commonWatcher
   158  	caller          base.APICaller
   159  	notifyWatcherId string
   160  	out             chan struct{}
   161  }
   162  
   163  // If an API call returns a NotifyWatchResult, you can use this to turn it into
   164  // a local Watcher.
   165  func NewNotifyWatcher(caller base.APICaller, result params.NotifyWatchResult) watcher.NotifyWatcher {
   166  	w := &notifyWatcher{
   167  		caller:          caller,
   168  		notifyWatcherId: result.NotifyWatcherId,
   169  		out:             make(chan struct{}),
   170  	}
   171  	w.tomb.Go(w.loop)
   172  	return w
   173  }
   174  
   175  func (w *notifyWatcher) loop() error {
   176  	// No results for this watcher type.
   177  	w.newResult = func() interface{} { return nil }
   178  	w.call = makeWatcherAPICaller(w.caller, "NotifyWatcher", w.notifyWatcherId)
   179  	w.commonWatcher.init()
   180  	go w.commonLoop()
   181  
   182  	for {
   183  		select {
   184  		// Since for a notifyWatcher there are no changes to send, we
   185  		// just set the event (initial first, then after each change).
   186  		case w.out <- struct{}{}:
   187  		case <-w.tomb.Dying():
   188  			return nil
   189  		}
   190  		if _, ok := <-w.in; !ok {
   191  			// The tomb is already killed with the correct
   192  			// error at this point, so just return.
   193  			return nil
   194  		}
   195  	}
   196  }
   197  
   198  // Changes returns a channel that receives a value when a given entity
   199  // changes in some way.
   200  func (w *notifyWatcher) Changes() watcher.NotifyChannel {
   201  	return w.out
   202  }
   203  
   204  // stringsWatcher will send events when something changes.
   205  // The content of the changes is a list of strings.
   206  type stringsWatcher struct {
   207  	commonWatcher
   208  	caller           base.APICaller
   209  	stringsWatcherId string
   210  	out              chan []string
   211  }
   212  
   213  func NewStringsWatcher(caller base.APICaller, result params.StringsWatchResult) watcher.StringsWatcher {
   214  	w := &stringsWatcher{
   215  		caller:           caller,
   216  		stringsWatcherId: result.StringsWatcherId,
   217  		out:              make(chan []string),
   218  	}
   219  	w.tomb.Go(func() error {
   220  		return w.loop(result.Changes)
   221  	})
   222  	return w
   223  }
   224  
   225  func (w *stringsWatcher) loop(initialChanges []string) error {
   226  	changes := initialChanges
   227  	w.newResult = func() interface{} { return new(params.StringsWatchResult) }
   228  	w.call = makeWatcherAPICaller(w.caller, "StringsWatcher", w.stringsWatcherId)
   229  	w.commonWatcher.init()
   230  	go w.commonLoop()
   231  
   232  	for {
   233  		select {
   234  		// Send the initial event or subsequent change.
   235  		case w.out <- changes:
   236  		case <-w.tomb.Dying():
   237  			return nil
   238  		}
   239  		// Read the next change.
   240  		data, ok := <-w.in
   241  		if !ok {
   242  			// The tomb is already killed with the correct error
   243  			// at this point, so just return.
   244  			return nil
   245  		}
   246  		changes = data.(*params.StringsWatchResult).Changes
   247  	}
   248  }
   249  
   250  // Changes returns a channel that receives a list of strings of watched
   251  // entities with changes.
   252  func (w *stringsWatcher) Changes() watcher.StringsChannel {
   253  	return w.out
   254  }
   255  
   256  // relationUnitsWatcher will sends notifications of units entering and
   257  // leaving the scope of a RelationUnit, and changes to the settings of
   258  // those units known to have entered.
   259  type relationUnitsWatcher struct {
   260  	commonWatcher
   261  	caller                 base.APICaller
   262  	logger                 loggo.Logger
   263  	relationUnitsWatcherId string
   264  	out                    chan watcher.RelationUnitsChange
   265  }
   266  
   267  func NewRelationUnitsWatcher(caller base.APICaller, result params.RelationUnitsWatchResult) watcher.RelationUnitsWatcher {
   268  	w := &relationUnitsWatcher{
   269  		caller:                 caller,
   270  		logger:                 logger.Child("relationunits"),
   271  		relationUnitsWatcherId: result.RelationUnitsWatcherId,
   272  		out:                    make(chan watcher.RelationUnitsChange),
   273  	}
   274  	w.tomb.Go(func() error {
   275  		return w.loop(result.Changes)
   276  	})
   277  	return w
   278  }
   279  
   280  func copyRelationUnitsChanged(src params.RelationUnitsChange) watcher.RelationUnitsChange {
   281  	dst := watcher.RelationUnitsChange{
   282  		Departed: src.Departed,
   283  	}
   284  	if src.Changed != nil {
   285  		dst.Changed = make(map[string]watcher.UnitSettings, len(src.Changed))
   286  		for name, unitSettings := range src.Changed {
   287  			dst.Changed[name] = watcher.UnitSettings{
   288  				Version: unitSettings.Version,
   289  			}
   290  		}
   291  	}
   292  	if src.AppChanged != nil {
   293  		dst.AppChanged = make(map[string]int64, len(src.AppChanged))
   294  		for name, appVersion := range src.AppChanged {
   295  			dst.AppChanged[name] = appVersion
   296  		}
   297  	}
   298  	return dst
   299  }
   300  
   301  func (w *relationUnitsWatcher) loop(initialChanges params.RelationUnitsChange) error {
   302  	changes := copyRelationUnitsChanged(initialChanges)
   303  	w.newResult = func() interface{} { return new(params.RelationUnitsWatchResult) }
   304  	w.call = makeWatcherAPICaller(w.caller, "RelationUnitsWatcher", w.relationUnitsWatcherId)
   305  	w.commonWatcher.init()
   306  	go w.commonLoop()
   307  
   308  	for {
   309  		select {
   310  		// Send the initial event or subsequent change.
   311  		case w.out <- changes:
   312  			if w.logger.IsTraceEnabled() {
   313  				w.logger.Tracef("sent relation units changes %# v", pretty.Formatter(changes))
   314  			}
   315  		case <-w.tomb.Dying():
   316  			return nil
   317  		}
   318  		// Read the next change.
   319  		data, ok := <-w.in
   320  		if !ok {
   321  			// The tomb is already killed with the correct error
   322  			// at this point, so just return.
   323  			return nil
   324  		}
   325  		changes = copyRelationUnitsChanged(data.(*params.RelationUnitsWatchResult).Changes)
   326  	}
   327  }
   328  
   329  // Changes returns a channel that will receive the changes to
   330  // counterpart units in a relation. The first event on the channel
   331  // holds the initial state of the relation in its Changed field.
   332  func (w *relationUnitsWatcher) Changes() watcher.RelationUnitsChannel {
   333  	return w.out
   334  }
   335  
   336  // RemoteRelationWatcher is a worker that emits remote relation change
   337  // events. It's not defined in core/watcher because it emits params
   338  // structs - this makes more sense than converting to a core struct
   339  // just to convert back when the event is published to the other
   340  // model's API.
   341  type RemoteRelationWatcher interface {
   342  	watcher.CoreWatcher
   343  	Changes() <-chan params.RemoteRelationChangeEvent
   344  }
   345  
   346  // remoteRelationWatcher sends notifications of units entering and
   347  // leaving scope of a relation and changes to unit/application
   348  // settings, but yielding fleshed-out events so the caller doesn't
   349  // need to call back to get the settings values.
   350  type remoteRelationWatcher struct {
   351  	commonWatcher
   352  	caller                  base.APICaller
   353  	logger                  loggo.Logger
   354  	remoteRelationWatcherId string
   355  	out                     chan params.RemoteRelationChangeEvent
   356  }
   357  
   358  // NewRemoteRelationWatcher returns a RemoteRelationWatcher receiving
   359  // events from the one running on the API server.
   360  func NewRemoteRelationWatcher(caller base.APICaller, result params.RemoteRelationWatchResult) RemoteRelationWatcher {
   361  	w := &remoteRelationWatcher{
   362  		caller:                  caller,
   363  		logger:                  logger.Child("remoterelations"),
   364  		remoteRelationWatcherId: result.RemoteRelationWatcherId,
   365  		out:                     make(chan params.RemoteRelationChangeEvent),
   366  	}
   367  	w.tomb.Go(func() error {
   368  		return w.loop(result.Changes)
   369  	})
   370  	return w
   371  }
   372  
   373  func (w *remoteRelationWatcher) loop(initialChange params.RemoteRelationChangeEvent) error {
   374  	change := initialChange
   375  	w.newResult = func() interface{} { return new(params.RemoteRelationWatchResult) }
   376  	w.call = makeWatcherAPICaller(w.caller, "RemoteRelationWatcher", w.remoteRelationWatcherId)
   377  	w.commonWatcher.init()
   378  	w.tomb.Go(func() error {
   379  		w.commonLoop()
   380  		return nil
   381  	})
   382  
   383  	for {
   384  		select {
   385  		// Send out the initial event or subsequent change.
   386  		case w.out <- change:
   387  			if w.logger.IsTraceEnabled() {
   388  				w.logger.Tracef("sent remote relation change %# v", pretty.Formatter(change))
   389  			}
   390  		case <-w.tomb.Dying():
   391  			return nil
   392  		}
   393  
   394  		data, ok := <-w.in
   395  		if !ok {
   396  			// The tomb is already killed with the correct error at
   397  			// this point, so just return.
   398  			return nil
   399  		}
   400  		result, ok := data.(*params.RemoteRelationWatchResult)
   401  		if !ok {
   402  			return errors.Errorf("expected *params.RemoteRelationWatchResult, got %#v", data)
   403  		}
   404  		if result.Error != nil {
   405  			return errors.Trace(result.Error)
   406  		}
   407  		change = result.Changes
   408  	}
   409  }
   410  
   411  // Changes returns a channel that will emit changes to the remote
   412  // relation units.
   413  func (w *remoteRelationWatcher) Changes() <-chan params.RemoteRelationChangeEvent {
   414  	return w.out
   415  }
   416  
   417  // SettingsGetter is a callback function the remote relation
   418  // compatibility watcher calls to get unit settings when expanding
   419  // events.
   420  type SettingsGetter func([]string) ([]params.SettingsResult, error)
   421  
   422  // remoteRelationCompatWatcher is a compatibility adapter that calls
   423  // back to the v1 crossmodelrelations API methods to wrap a
   424  // server-side RelationUnitsWatcher into a RemoteRelationWatcher. It
   425  // needs the relation and application token to include in the outgoing
   426  // change events.
   427  type remoteRelationCompatWatcher struct {
   428  	commonWatcher
   429  	caller                 base.APICaller
   430  	relationUnitsWatcherId string
   431  	relationToken          string
   432  	appToken               string
   433  	getSettings            SettingsGetter
   434  	out                    chan params.RemoteRelationChangeEvent
   435  }
   436  
   437  // NewRemoteRelationCompatWatcher returns a RemoteRelationWatcher
   438  // based on a server-side RelationUnitsWatcher.
   439  func NewRemoteRelationCompatWatcher(
   440  	caller base.APICaller,
   441  	result params.RelationUnitsWatchResult,
   442  	relationToken string,
   443  	appToken string,
   444  	getSettings SettingsGetter,
   445  ) RemoteRelationWatcher {
   446  	w := &remoteRelationCompatWatcher{
   447  		caller:                 caller,
   448  		relationUnitsWatcherId: result.RelationUnitsWatcherId,
   449  		relationToken:          relationToken,
   450  		appToken:               appToken,
   451  		getSettings:            getSettings,
   452  		out:                    make(chan params.RemoteRelationChangeEvent),
   453  	}
   454  	w.tomb.Go(func() error {
   455  		return w.loop(result.Changes)
   456  	})
   457  	return w
   458  }
   459  
   460  func (w *remoteRelationCompatWatcher) loop(initialChange params.RelationUnitsChange) error {
   461  	change := initialChange
   462  	w.newResult = func() interface{} { return new(params.RelationUnitsWatchResult) }
   463  	w.call = makeWatcherAPICaller(w.caller, "RelationUnitsWatcher", w.relationUnitsWatcherId)
   464  	w.commonWatcher.init()
   465  
   466  	// Ensure the worker loop waits for the commonLoop to stop before
   467  	// being fully finished.
   468  	w.tomb.Go(func() error {
   469  		w.commonLoop()
   470  		return nil
   471  	})
   472  
   473  	for {
   474  		expanded, err := w.expandChange(change)
   475  		if err != nil {
   476  			return errors.Trace(err)
   477  		}
   478  		select {
   479  		// Send out the initial event or subsequent change.
   480  		case w.out <- expanded:
   481  		case <-w.tomb.Dying():
   482  			return nil
   483  		}
   484  		data, ok := <-w.in
   485  		if !ok {
   486  			// The tomb is already killed with the correct error at
   487  			// this point, so just return.
   488  			return nil
   489  		}
   490  		result, ok := data.(*params.RelationUnitsWatchResult)
   491  		if !ok {
   492  			return errors.Errorf("expected *params.RelationUnitsWatchResult, got %#v", data)
   493  		}
   494  		if result.Error != nil {
   495  			return errors.Trace(result.Error)
   496  		}
   497  		change = result.Changes
   498  	}
   499  }
   500  
   501  func (w *remoteRelationCompatWatcher) expandChange(change params.RelationUnitsChange) (params.RemoteRelationChangeEvent, error) {
   502  	var empty params.RemoteRelationChangeEvent
   503  	var unitNames []string
   504  	for unit := range change.Changed {
   505  		unitNames = append(unitNames, unit)
   506  	}
   507  	var changedUnits []params.RemoteRelationUnitChange
   508  	if len(unitNames) > 0 {
   509  		results, err := w.getSettings(unitNames)
   510  		if err != nil {
   511  			return empty, errors.Annotatef(err, "getting relation unit settings for %q", unitNames)
   512  		}
   513  		for i, result := range results {
   514  			num, err := names.UnitNumber(unitNames[i])
   515  			if err != nil {
   516  				return empty, errors.Trace(err)
   517  			}
   518  			unitChange := params.RemoteRelationUnitChange{
   519  				UnitId:   num,
   520  				Settings: make(map[string]interface{}),
   521  			}
   522  			for k, v := range result.Settings {
   523  				unitChange.Settings[k] = v
   524  			}
   525  			changedUnits = append(changedUnits, unitChange)
   526  		}
   527  	}
   528  
   529  	var departedUnits []int
   530  	for _, unit := range change.Departed {
   531  		num, err := names.UnitNumber(unit)
   532  		if err != nil {
   533  			return empty, errors.Trace(err)
   534  		}
   535  		departedUnits = append(departedUnits, num)
   536  	}
   537  
   538  	expanded := params.RemoteRelationChangeEvent{
   539  		RelationToken:    w.relationToken,
   540  		ApplicationToken: w.appToken,
   541  		ChangedUnits:     changedUnits,
   542  		DepartedUnits:    departedUnits,
   543  	}
   544  	// No need to handle AppChanged here - the v1 API can't tell us
   545  	// app settings.
   546  	return expanded, nil
   547  
   548  }
   549  
   550  // Changes returns a channel that will emit changes to the remote
   551  // relation units.
   552  func (w *remoteRelationCompatWatcher) Changes() <-chan params.RemoteRelationChangeEvent {
   553  	return w.out
   554  }
   555  
   556  // relationStatusWatcher will sends notifications of changes to
   557  // relation life and suspended status.
   558  type relationStatusWatcher struct {
   559  	commonWatcher
   560  	caller                  base.APICaller
   561  	relationStatusWatcherId string
   562  	out                     chan []watcher.RelationStatusChange
   563  }
   564  
   565  // NewRelationStatusWatcher returns a watcher notifying of changes to
   566  // relation life and suspended status.
   567  func NewRelationStatusWatcher(
   568  	caller base.APICaller, result params.RelationLifeSuspendedStatusWatchResult,
   569  ) watcher.RelationStatusWatcher {
   570  	w := &relationStatusWatcher{
   571  		caller:                  caller,
   572  		relationStatusWatcherId: result.RelationStatusWatcherId,
   573  		out:                     make(chan []watcher.RelationStatusChange),
   574  	}
   575  	w.tomb.Go(func() error {
   576  		return w.loop(result.Changes)
   577  	})
   578  	return w
   579  }
   580  
   581  // mergeChanges combines the status changes in current and new, such that we end up with
   582  // only one change per offer in the result; the most recent change wins.
   583  func (w *relationStatusWatcher) mergeChanges(current, new []watcher.RelationStatusChange) []watcher.RelationStatusChange {
   584  	chMap := make(map[string]watcher.RelationStatusChange)
   585  	for _, c := range current {
   586  		chMap[c.Key] = c
   587  	}
   588  	for _, c := range new {
   589  		chMap[c.Key] = c
   590  	}
   591  	var result []watcher.RelationStatusChange
   592  	for _, c := range chMap {
   593  		result = append(result, c)
   594  	}
   595  	return result
   596  }
   597  
   598  func (w *relationStatusWatcher) loop(initialChanges []params.RelationLifeSuspendedStatusChange) error {
   599  	w.newResult = func() interface{} { return new(params.RelationLifeSuspendedStatusWatchResult) }
   600  	w.call = makeWatcherAPICaller(w.caller, "RelationStatusWatcher", w.relationStatusWatcherId)
   601  	w.commonWatcher.init()
   602  	go w.commonLoop()
   603  
   604  	copyChanges := func(changes []params.RelationLifeSuspendedStatusChange) []watcher.RelationStatusChange {
   605  		result := make([]watcher.RelationStatusChange, len(changes))
   606  		for i, ch := range changes {
   607  			result[i] = watcher.RelationStatusChange{
   608  				Key:             ch.Key,
   609  				Life:            ch.Life,
   610  				Suspended:       ch.Suspended,
   611  				SuspendedReason: ch.SuspendedReason,
   612  			}
   613  		}
   614  		return result
   615  	}
   616  	out := w.out
   617  	changes := copyChanges(initialChanges)
   618  	for {
   619  		select {
   620  		case <-w.tomb.Dying():
   621  			return tomb.ErrDying
   622  			// Read the next change.
   623  		case data, ok := <-w.in:
   624  			if !ok {
   625  				// The tomb is already killed with the correct error
   626  				// at this point, so just return.
   627  				return nil
   628  			}
   629  			newChanges := copyChanges(data.(*params.RelationLifeSuspendedStatusWatchResult).Changes)
   630  			changes = w.mergeChanges(changes, newChanges)
   631  			out = w.out
   632  		case out <- changes:
   633  			out = nil
   634  			changes = nil
   635  		}
   636  	}
   637  }
   638  
   639  // Changes returns a channel that will receive the changes to
   640  // the life and status of a relation. The first event reflects the current
   641  // values of these attributes.
   642  func (w *relationStatusWatcher) Changes() watcher.RelationStatusChannel {
   643  	return w.out
   644  }
   645  
   646  // offerStatusWatcher will send notifications of changes to offer status.
   647  type offerStatusWatcher struct {
   648  	commonWatcher
   649  	caller               base.APICaller
   650  	offerStatusWatcherId string
   651  	out                  chan []watcher.OfferStatusChange
   652  }
   653  
   654  // NewOfferStatusWatcher returns a watcher notifying of changes to
   655  // offer status.
   656  func NewOfferStatusWatcher(
   657  	caller base.APICaller, result params.OfferStatusWatchResult,
   658  ) watcher.OfferStatusWatcher {
   659  	w := &offerStatusWatcher{
   660  		caller:               caller,
   661  		offerStatusWatcherId: result.OfferStatusWatcherId,
   662  		out:                  make(chan []watcher.OfferStatusChange),
   663  	}
   664  	w.tomb.Go(func() error {
   665  		return w.loop(result.Changes)
   666  	})
   667  	return w
   668  }
   669  
   670  // mergeChanges combines the status changes in current and new, such that we end up with
   671  // only one change per offer in the result; the most recent change wins.
   672  func (w *offerStatusWatcher) mergeChanges(current, new []watcher.OfferStatusChange) []watcher.OfferStatusChange {
   673  	chMap := make(map[string]watcher.OfferStatusChange)
   674  	for _, c := range current {
   675  		chMap[c.Name] = c
   676  	}
   677  	for _, c := range new {
   678  		chMap[c.Name] = c
   679  	}
   680  	var result []watcher.OfferStatusChange
   681  	for _, c := range chMap {
   682  		result = append(result, c)
   683  	}
   684  	return result
   685  }
   686  
   687  func (w *offerStatusWatcher) loop(initialChanges []params.OfferStatusChange) error {
   688  	w.newResult = func() interface{} { return new(params.OfferStatusWatchResult) }
   689  	w.call = makeWatcherAPICaller(w.caller, "OfferStatusWatcher", w.offerStatusWatcherId)
   690  	w.commonWatcher.init()
   691  	go w.commonLoop()
   692  
   693  	copyChanges := func(changes []params.OfferStatusChange) []watcher.OfferStatusChange {
   694  		result := make([]watcher.OfferStatusChange, len(changes))
   695  		for i, ch := range changes {
   696  			result[i] = watcher.OfferStatusChange{
   697  				Name: ch.OfferName,
   698  				Status: status.StatusInfo{
   699  					Status:  ch.Status.Status,
   700  					Message: ch.Status.Info,
   701  					Data:    ch.Status.Data,
   702  					Since:   ch.Status.Since,
   703  				},
   704  			}
   705  		}
   706  		return result
   707  	}
   708  	out := w.out
   709  	changes := copyChanges(initialChanges)
   710  	for {
   711  		select {
   712  		case <-w.tomb.Dying():
   713  			return tomb.ErrDying
   714  		// Read the next change.
   715  		case data, ok := <-w.in:
   716  			if !ok {
   717  				// The tomb is already killed with the correct error
   718  				// at this point, so just return.
   719  				return nil
   720  			}
   721  			newChanges := copyChanges(data.(*params.OfferStatusWatchResult).Changes)
   722  			changes = w.mergeChanges(changes, newChanges)
   723  			out = w.out
   724  		case out <- changes:
   725  			out = nil
   726  			changes = nil
   727  		}
   728  	}
   729  }
   730  
   731  // Changes returns a channel that will receive the changes to
   732  // the status of an offer. The first event reflects the current
   733  // values of these attributes.
   734  func (w *offerStatusWatcher) Changes() watcher.OfferStatusChannel {
   735  	return w.out
   736  }
   737  
   738  // machineAttachmentsWatcher will sends notifications of units entering and
   739  // leaving the scope of a MachineStorageId, and changes to the settings of
   740  // those units known to have entered.
   741  type machineAttachmentsWatcher struct {
   742  	commonWatcher
   743  	caller                      base.APICaller
   744  	machineAttachmentsWatcherId string
   745  	out                         chan []watcher.MachineStorageId
   746  }
   747  
   748  // NewVolumeAttachmentsWatcher returns a MachineStorageIdsWatcher which
   749  // communicates with the VolumeAttachmentsWatcher API facade to watch
   750  // volume attachments.
   751  func NewVolumeAttachmentsWatcher(caller base.APICaller, result params.MachineStorageIdsWatchResult) watcher.MachineStorageIdsWatcher {
   752  	return newMachineStorageIdsWatcher("VolumeAttachmentsWatcher", caller, result)
   753  }
   754  
   755  // NewVolumeAttachmentPlansWatcher returns a MachineStorageIdsWatcher which
   756  // communicates with the VolumeAttachmentPlansWatcher API facade to watch
   757  // volume attachments.
   758  func NewVolumeAttachmentPlansWatcher(caller base.APICaller, result params.MachineStorageIdsWatchResult) watcher.MachineStorageIdsWatcher {
   759  	return newMachineStorageIdsWatcher("VolumeAttachmentPlansWatcher", caller, result)
   760  }
   761  
   762  // NewFilesystemAttachmentsWatcher returns a MachineStorageIdsWatcher which
   763  // communicates with the FilesystemAttachmentsWatcher API facade to watch
   764  // filesystem attachments.
   765  func NewFilesystemAttachmentsWatcher(caller base.APICaller, result params.MachineStorageIdsWatchResult) watcher.MachineStorageIdsWatcher {
   766  	return newMachineStorageIdsWatcher("FilesystemAttachmentsWatcher", caller, result)
   767  }
   768  
   769  func newMachineStorageIdsWatcher(facade string, caller base.APICaller, result params.MachineStorageIdsWatchResult) watcher.MachineStorageIdsWatcher {
   770  	w := &machineAttachmentsWatcher{
   771  		caller:                      caller,
   772  		machineAttachmentsWatcherId: result.MachineStorageIdsWatcherId,
   773  		out:                         make(chan []watcher.MachineStorageId),
   774  	}
   775  	w.tomb.Go(func() error {
   776  		return w.loop(facade, result.Changes)
   777  	})
   778  	return w
   779  }
   780  
   781  func copyMachineStorageIds(src []params.MachineStorageId) []watcher.MachineStorageId {
   782  	dst := make([]watcher.MachineStorageId, len(src))
   783  	for i, msi := range src {
   784  		dst[i] = watcher.MachineStorageId{
   785  			MachineTag:    msi.MachineTag,
   786  			AttachmentTag: msi.AttachmentTag,
   787  		}
   788  	}
   789  	return dst
   790  }
   791  
   792  func (w *machineAttachmentsWatcher) loop(facade string, initialChanges []params.MachineStorageId) error {
   793  	changes := copyMachineStorageIds(initialChanges)
   794  	w.newResult = func() interface{} { return new(params.MachineStorageIdsWatchResult) }
   795  	w.call = makeWatcherAPICaller(w.caller, facade, w.machineAttachmentsWatcherId)
   796  	w.commonWatcher.init()
   797  	go w.commonLoop()
   798  
   799  	for {
   800  		select {
   801  		// Send the initial event or subsequent change.
   802  		case w.out <- changes:
   803  		case <-w.tomb.Dying():
   804  			return nil
   805  		}
   806  		// Read the next change.
   807  		data, ok := <-w.in
   808  		if !ok {
   809  			// The tomb is already killed with the correct error
   810  			// at this point, so just return.
   811  			return nil
   812  		}
   813  		changes = copyMachineStorageIds(data.(*params.MachineStorageIdsWatchResult).Changes)
   814  	}
   815  }
   816  
   817  // Changes returns a channel that will receive the IDs of machine
   818  // storage entity attachments which have changed.
   819  func (w *machineAttachmentsWatcher) Changes() watcher.MachineStorageIdsChannel {
   820  	return w.out
   821  }
   822  
   823  // NewMigrationStatusWatcher takes the NotifyWatcherId returns by the
   824  // MigrationSlave.Watch API and returns a watcher which will report
   825  // status changes for any migration of the model associated with the
   826  // API connection.
   827  func NewMigrationStatusWatcher(caller base.APICaller, watcherId string) watcher.MigrationStatusWatcher {
   828  	w := &migrationStatusWatcher{
   829  		caller: caller,
   830  		id:     watcherId,
   831  		out:    make(chan watcher.MigrationStatus),
   832  	}
   833  	w.tomb.Go(w.loop)
   834  	return w
   835  }
   836  
   837  type migrationStatusWatcher struct {
   838  	commonWatcher
   839  	caller base.APICaller
   840  	id     string
   841  	out    chan watcher.MigrationStatus
   842  }
   843  
   844  func (w *migrationStatusWatcher) loop() error {
   845  	w.newResult = func() interface{} { return new(params.MigrationStatus) }
   846  	w.call = makeWatcherAPICaller(w.caller, "MigrationStatusWatcher", w.id)
   847  	w.commonWatcher.init()
   848  	go w.commonLoop()
   849  
   850  	for {
   851  		var data interface{}
   852  		var ok bool
   853  
   854  		select {
   855  		case data, ok = <-w.in:
   856  			if !ok {
   857  				// The tomb is already killed with the correct error
   858  				// at this point, so just return.
   859  				return nil
   860  			}
   861  		case <-w.tomb.Dying():
   862  			return nil
   863  		}
   864  
   865  		inStatus := *data.(*params.MigrationStatus)
   866  		phase, ok := migration.ParsePhase(inStatus.Phase)
   867  		if !ok {
   868  			return errors.Errorf("invalid phase %q", inStatus.Phase)
   869  		}
   870  		outStatus := watcher.MigrationStatus{
   871  			MigrationId:    inStatus.MigrationId,
   872  			Attempt:        inStatus.Attempt,
   873  			Phase:          phase,
   874  			SourceAPIAddrs: inStatus.SourceAPIAddrs,
   875  			SourceCACert:   inStatus.SourceCACert,
   876  			TargetAPIAddrs: inStatus.TargetAPIAddrs,
   877  			TargetCACert:   inStatus.TargetCACert,
   878  		}
   879  		select {
   880  		case w.out <- outStatus:
   881  		case <-w.tomb.Dying():
   882  			return nil
   883  		}
   884  	}
   885  }
   886  
   887  // Changes returns a channel that reports the latest status of the
   888  // migration of a model.
   889  func (w *migrationStatusWatcher) Changes() <-chan watcher.MigrationStatus {
   890  	return w.out
   891  }
   892  
   893  // secretsTriggerWatcher will send notifications of changes to secret trigger times.
   894  type secretsTriggerWatcher struct {
   895  	commonWatcher
   896  	caller    base.APICaller
   897  	apiFacade string
   898  	watcherId string
   899  	out       chan []watcher.SecretTriggerChange
   900  }
   901  
   902  // NewSecretsTriggerWatcher returns a new secrets trigger watcher.
   903  func NewSecretsTriggerWatcher(
   904  	caller base.APICaller, result params.SecretTriggerWatchResult,
   905  ) watcher.SecretTriggerWatcher {
   906  	w := &secretsTriggerWatcher{
   907  		caller:    caller,
   908  		apiFacade: "SecretsTriggerWatcher",
   909  		watcherId: result.WatcherId,
   910  		out:       make(chan []watcher.SecretTriggerChange),
   911  	}
   912  	w.newResult = func() interface{} { return new(params.SecretTriggerWatchResult) }
   913  	w.tomb.Go(func() error {
   914  		defer close(w.out)
   915  		return w.loop(result.Changes)
   916  	})
   917  	return w
   918  }
   919  
   920  // mergeChanges combines the changes in current and newChanges, such that we end up with
   921  // only one change per trigger change in the result; the most recent change wins.
   922  func (w *secretsTriggerWatcher) mergeChanges(current, newChanges []watcher.SecretTriggerChange) []watcher.SecretTriggerChange {
   923  	chMap := make(map[string]watcher.SecretTriggerChange)
   924  	for _, c := range current {
   925  		chMap[c.URI.ID] = c
   926  	}
   927  	for _, c := range newChanges {
   928  		chMap[c.URI.ID] = c
   929  	}
   930  	result := make([]watcher.SecretTriggerChange, len(chMap))
   931  	i := 0
   932  	for _, c := range chMap {
   933  		result[i] = c
   934  		i++
   935  	}
   936  	return result
   937  }
   938  
   939  func (w *secretsTriggerWatcher) loop(initialChanges []params.SecretTriggerChange) error {
   940  	w.call = makeWatcherAPICaller(w.caller, w.apiFacade, w.watcherId)
   941  	w.commonWatcher.init()
   942  	go w.commonLoop()
   943  
   944  	copyChanges := func(changes []params.SecretTriggerChange) []watcher.SecretTriggerChange {
   945  		result := make([]watcher.SecretTriggerChange, len(changes))
   946  		for i, ch := range changes {
   947  			uri, err := secrets.ParseURI(ch.URI)
   948  			if err != nil {
   949  				logger.Errorf("ignoring invalid secret URI: %q", ch.URI)
   950  				continue
   951  			}
   952  			result[i] = watcher.SecretTriggerChange{
   953  				URI:             uri,
   954  				Revision:        ch.Revision,
   955  				NextTriggerTime: ch.NextTriggerTime,
   956  			}
   957  		}
   958  		return result
   959  	}
   960  	out := w.out
   961  	changes := copyChanges(initialChanges)
   962  	for {
   963  		select {
   964  		case <-w.tomb.Dying():
   965  			return tomb.ErrDying
   966  		// Read the next change.
   967  		case data, ok := <-w.in:
   968  			if !ok {
   969  				// The tomb is already killed with the correct error
   970  				// at this point, so just return.
   971  				return nil
   972  			}
   973  			newChanges := copyChanges(data.(*params.SecretTriggerWatchResult).Changes)
   974  			changes = w.mergeChanges(changes, newChanges)
   975  			out = w.out
   976  		case out <- changes:
   977  			out = nil
   978  			changes = nil
   979  		}
   980  	}
   981  }
   982  
   983  // Changes returns a channel that will receive the changes to
   984  // a secret trigger. The first event reflects the current
   985  // values of these attributes.
   986  func (w *secretsTriggerWatcher) Changes() watcher.SecretTriggerChannel {
   987  	return w.out
   988  }
   989  
   990  // secretBackendRotateWatcher will send notifications of changes to secret trigger times.
   991  type secretBackendRotateWatcher struct {
   992  	commonWatcher
   993  	caller    base.APICaller
   994  	watcherId string
   995  	out       chan []watcher.SecretBackendRotateChange
   996  }
   997  
   998  // NewSecretBackendRotateWatcher returns a new secret backend rotate watcher.
   999  func NewSecretBackendRotateWatcher(
  1000  	caller base.APICaller, result params.SecretBackendRotateWatchResult,
  1001  ) watcher.SecretBackendRotateWatcher {
  1002  	w := &secretBackendRotateWatcher{
  1003  		caller:    caller,
  1004  		watcherId: result.WatcherId,
  1005  		out:       make(chan []watcher.SecretBackendRotateChange),
  1006  	}
  1007  	w.newResult = func() interface{} { return new(params.SecretBackendRotateWatchResult) }
  1008  	w.tomb.Go(func() error {
  1009  		defer close(w.out)
  1010  		return w.loop(result.Changes)
  1011  	})
  1012  	return w
  1013  }
  1014  
  1015  // mergeChanges combines the changes in current and newChanges, such that we end up with
  1016  // only one change per trigger change in the result; the most recent change wins.
  1017  func (w *secretBackendRotateWatcher) mergeChanges(current, newChanges []watcher.SecretBackendRotateChange) []watcher.SecretBackendRotateChange {
  1018  	chMap := make(map[string]watcher.SecretBackendRotateChange)
  1019  	for _, c := range current {
  1020  		chMap[c.ID] = c
  1021  	}
  1022  	for _, c := range newChanges {
  1023  		chMap[c.ID] = c
  1024  	}
  1025  	result := make([]watcher.SecretBackendRotateChange, len(chMap))
  1026  	i := 0
  1027  	for _, c := range chMap {
  1028  		result[i] = c
  1029  		i++
  1030  	}
  1031  	return result
  1032  }
  1033  
  1034  func (w *secretBackendRotateWatcher) loop(initialChanges []params.SecretBackendRotateChange) error {
  1035  	w.call = makeWatcherAPICaller(w.caller, "SecretBackendsRotateWatcher", w.watcherId)
  1036  	w.commonWatcher.init()
  1037  	go w.commonLoop()
  1038  
  1039  	copyChanges := func(changes []params.SecretBackendRotateChange) []watcher.SecretBackendRotateChange {
  1040  		result := make([]watcher.SecretBackendRotateChange, len(changes))
  1041  		for i, ch := range changes {
  1042  			result[i] = watcher.SecretBackendRotateChange{
  1043  				ID:              ch.ID,
  1044  				Name:            ch.Name,
  1045  				NextTriggerTime: ch.NextTriggerTime,
  1046  			}
  1047  		}
  1048  		return result
  1049  	}
  1050  	out := w.out
  1051  	changes := copyChanges(initialChanges)
  1052  	for {
  1053  		select {
  1054  		case <-w.tomb.Dying():
  1055  			return tomb.ErrDying
  1056  		// Read the next change.
  1057  		case data, ok := <-w.in:
  1058  			if !ok {
  1059  				// The tomb is already killed with the correct error
  1060  				// at this point, so just return.
  1061  				return nil
  1062  			}
  1063  			newChanges := copyChanges(data.(*params.SecretBackendRotateWatchResult).Changes)
  1064  			changes = w.mergeChanges(changes, newChanges)
  1065  			out = w.out
  1066  		case out <- changes:
  1067  			out = nil
  1068  			changes = nil
  1069  		}
  1070  	}
  1071  }
  1072  
  1073  // Changes returns a channel that will receive the changes to
  1074  // a secret trigger. The first event reflects the current
  1075  // values of these attributes.
  1076  func (w *secretBackendRotateWatcher) Changes() watcher.SecretBackendRotateChannel {
  1077  	return w.out
  1078  }
  1079  
  1080  // SecretsRevisionWatcher will send notifications of changes to secret revisions.
  1081  type SecretsRevisionWatcher struct {
  1082  	commonWatcher
  1083  	caller    base.APICaller
  1084  	watcherId string
  1085  	out       chan []watcher.SecretRevisionChange
  1086  }
  1087  
  1088  // NewSecretsRevisionWatcher returns a watcher notifying of changes to
  1089  // secret revisions.
  1090  func NewSecretsRevisionWatcher(
  1091  	caller base.APICaller, result params.SecretRevisionWatchResult,
  1092  ) watcher.SecretsRevisionWatcher {
  1093  	w := &SecretsRevisionWatcher{
  1094  		caller:    caller,
  1095  		watcherId: result.WatcherId,
  1096  		out:       make(chan []watcher.SecretRevisionChange),
  1097  	}
  1098  	w.tomb.Go(func() error {
  1099  		return w.loop(result.Changes)
  1100  	})
  1101  	return w
  1102  }
  1103  
  1104  // mergeChanges combines the revision in current and new, such that we end up with
  1105  // only one change per secret in the result; the most recent change wins.
  1106  func (w *SecretsRevisionWatcher) mergeChanges(current, new []watcher.SecretRevisionChange) []watcher.SecretRevisionChange {
  1107  	chMap := make(map[string]watcher.SecretRevisionChange)
  1108  	for _, c := range current {
  1109  		chMap[c.URI.ID] = c
  1110  	}
  1111  	for _, c := range new {
  1112  		chMap[c.URI.ID] = c
  1113  	}
  1114  	var result []watcher.SecretRevisionChange
  1115  	for _, c := range chMap {
  1116  		result = append(result, c)
  1117  	}
  1118  	return result
  1119  }
  1120  
  1121  func (w *SecretsRevisionWatcher) loop(initialChanges []params.SecretRevisionChange) error {
  1122  	w.newResult = func() interface{} { return new(params.SecretRevisionWatchResult) }
  1123  	w.call = makeWatcherAPICaller(w.caller, "SecretsRevisionWatcher", w.watcherId)
  1124  	w.commonWatcher.init()
  1125  	go w.commonLoop()
  1126  
  1127  	copyChanges := func(changes []params.SecretRevisionChange) []watcher.SecretRevisionChange {
  1128  		var result []watcher.SecretRevisionChange
  1129  		for _, ch := range changes {
  1130  			uri, err := secrets.ParseURI(ch.URI)
  1131  			if err != nil {
  1132  				logger.Warningf("invalid secret URI: %v", ch.URI)
  1133  				continue
  1134  			}
  1135  			result = append(result, watcher.SecretRevisionChange{
  1136  				URI:      uri,
  1137  				Revision: ch.Revision,
  1138  			})
  1139  		}
  1140  		return result
  1141  	}
  1142  	out := w.out
  1143  	changes := copyChanges(initialChanges)
  1144  	for {
  1145  		select {
  1146  		case <-w.tomb.Dying():
  1147  			return tomb.ErrDying
  1148  		// Read the next change.
  1149  		case data, ok := <-w.in:
  1150  			if !ok {
  1151  				// The tomb is already killed with the correct error
  1152  				// at this point, so just return.
  1153  				return nil
  1154  			}
  1155  			newChanges := copyChanges(data.(*params.SecretRevisionWatchResult).Changes)
  1156  			changes = w.mergeChanges(changes, newChanges)
  1157  			out = w.out
  1158  		case out <- changes:
  1159  			out = nil
  1160  			changes = nil
  1161  		}
  1162  	}
  1163  }
  1164  
  1165  // Changes returns a channel that will receive the changes to
  1166  // a secret revision. The first event reflects the current
  1167  // values of these attributes.
  1168  func (w *SecretsRevisionWatcher) Changes() watcher.SecretRevisionChannel {
  1169  	return w.out
  1170  }