github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/worker/uniter/remotestate/watcher.go (about)

     1  // Copyright 2012-2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package remotestate
     5  
     6  import (
     7  	"sync"
     8  	"time"
     9  
    10  	"github.com/juju/errors"
    11  	"github.com/juju/loggo"
    12  	"gopkg.in/juju/names.v2"
    13  	"gopkg.in/juju/worker.v1"
    14  	"gopkg.in/juju/worker.v1/catacomb"
    15  
    16  	"github.com/juju/juju/apiserver/params"
    17  	"github.com/juju/juju/core/leadership"
    18  	"github.com/juju/juju/core/model"
    19  	"github.com/juju/juju/core/watcher"
    20  	jworker "github.com/juju/juju/worker"
    21  )
    22  
    23  var logger = loggo.GetLogger("juju.worker.uniter.remotestate")
    24  
    25  // RemoteStateWatcher collects unit, application, and application config information
    26  // from separate state watchers, and updates a Snapshot which is sent on a
    27  // channel upon change.
    28  type RemoteStateWatcher struct {
    29  	st                        State
    30  	unit                      Unit
    31  	application               Application
    32  	modelType                 model.ModelType
    33  	relations                 map[names.RelationTag]*relationUnitsWatcher
    34  	relationUnitsChanges      chan relationUnitsChange
    35  	storageAttachmentWatchers map[names.StorageTag]*storageAttachmentWatcher
    36  	storageAttachmentChanges  chan storageAttachmentChange
    37  	leadershipTracker         leadership.Tracker
    38  	updateStatusChannel       UpdateStatusTimerFunc
    39  	commandChannel            <-chan string
    40  	retryHookChannel          watcher.NotifyChannel
    41  	applicationChannel        watcher.NotifyChannel
    42  
    43  	catacomb catacomb.Catacomb
    44  
    45  	out     chan struct{}
    46  	mu      sync.Mutex
    47  	current Snapshot
    48  }
    49  
    50  // WatcherConfig holds configuration parameters for the
    51  // remote state watcher.
    52  type WatcherConfig struct {
    53  	State               State
    54  	LeadershipTracker   leadership.Tracker
    55  	UpdateStatusChannel UpdateStatusTimerFunc
    56  	CommandChannel      <-chan string
    57  	RetryHookChannel    watcher.NotifyChannel
    58  	ApplicationChannel  watcher.NotifyChannel
    59  	UnitTag             names.UnitTag
    60  	ModelType           model.ModelType
    61  }
    62  
    63  func (w WatcherConfig) validate() error {
    64  	if w.ModelType == model.CAAS && w.ApplicationChannel == nil {
    65  		return errors.NotValidf("watcher config for CAAS model with nil application channel")
    66  	}
    67  	return nil
    68  }
    69  
    70  // NewWatcher returns a RemoteStateWatcher that handles state changes pertaining to the
    71  // supplied unit.
    72  func NewWatcher(config WatcherConfig) (*RemoteStateWatcher, error) {
    73  	if err := config.validate(); err != nil {
    74  		return nil, errors.Trace(err)
    75  	}
    76  	w := &RemoteStateWatcher{
    77  		st:                        config.State,
    78  		relations:                 make(map[names.RelationTag]*relationUnitsWatcher),
    79  		relationUnitsChanges:      make(chan relationUnitsChange),
    80  		storageAttachmentWatchers: make(map[names.StorageTag]*storageAttachmentWatcher),
    81  		storageAttachmentChanges:  make(chan storageAttachmentChange),
    82  		leadershipTracker:         config.LeadershipTracker,
    83  		updateStatusChannel:       config.UpdateStatusChannel,
    84  		commandChannel:            config.CommandChannel,
    85  		retryHookChannel:          config.RetryHookChannel,
    86  		applicationChannel:        config.ApplicationChannel,
    87  		modelType:                 config.ModelType,
    88  		// Note: it is important that the out channel be buffered!
    89  		// The remote state watcher will perform a non-blocking send
    90  		// on the channel to wake up the observer. It is non-blocking
    91  		// so that we coalesce events while the observer is busy.
    92  		out: make(chan struct{}, 1),
    93  		current: Snapshot{
    94  			Relations: make(map[int]RelationSnapshot),
    95  			Storage:   make(map[names.StorageTag]StorageSnapshot),
    96  		},
    97  	}
    98  	err := catacomb.Invoke(catacomb.Plan{
    99  		Site: &w.catacomb,
   100  		Work: func() error {
   101  			return w.loop(config.UnitTag)
   102  		},
   103  	})
   104  	if err != nil {
   105  		return nil, errors.Trace(err)
   106  	}
   107  	return w, nil
   108  }
   109  
   110  // Kill is part of the worker.Worker interface.
   111  func (w *RemoteStateWatcher) Kill() {
   112  	w.catacomb.Kill(nil)
   113  }
   114  
   115  // Wait is part of the worker.Worker interface.
   116  func (w *RemoteStateWatcher) Wait() error {
   117  	return w.catacomb.Wait()
   118  }
   119  
   120  func (w *RemoteStateWatcher) RemoteStateChanged() <-chan struct{} {
   121  	return w.out
   122  }
   123  
   124  func (w *RemoteStateWatcher) Snapshot() Snapshot {
   125  	w.mu.Lock()
   126  	defer w.mu.Unlock()
   127  	snapshot := w.current
   128  	snapshot.Relations = make(map[int]RelationSnapshot)
   129  	for id, relationSnapshot := range w.current.Relations {
   130  		relationSnapshotCopy := RelationSnapshot{
   131  			Life:      relationSnapshot.Life,
   132  			Suspended: relationSnapshot.Suspended,
   133  			Members:   make(map[string]int64),
   134  		}
   135  		for name, version := range relationSnapshot.Members {
   136  			relationSnapshotCopy.Members[name] = version
   137  		}
   138  		snapshot.Relations[id] = relationSnapshotCopy
   139  	}
   140  	snapshot.Storage = make(map[names.StorageTag]StorageSnapshot)
   141  	for tag, storageSnapshot := range w.current.Storage {
   142  		snapshot.Storage[tag] = storageSnapshot
   143  	}
   144  	snapshot.Actions = make([]string, len(w.current.Actions))
   145  	copy(snapshot.Actions, w.current.Actions)
   146  	snapshot.Commands = make([]string, len(w.current.Commands))
   147  	copy(snapshot.Commands, w.current.Commands)
   148  	return snapshot
   149  }
   150  
   151  func (w *RemoteStateWatcher) ClearResolvedMode() {
   152  	w.mu.Lock()
   153  	w.current.ResolvedMode = params.ResolvedNone
   154  	w.mu.Unlock()
   155  }
   156  
   157  func (w *RemoteStateWatcher) CommandCompleted(completed string) {
   158  	w.mu.Lock()
   159  	defer w.mu.Unlock()
   160  	for i, id := range w.current.Commands {
   161  		if id != completed {
   162  			continue
   163  		}
   164  		w.current.Commands = append(
   165  			w.current.Commands[:i],
   166  			w.current.Commands[i+1:]...,
   167  		)
   168  		break
   169  	}
   170  }
   171  
   172  func (w *RemoteStateWatcher) setUp(unitTag names.UnitTag) error {
   173  	// TODO(axw) move this logic
   174  	var err error
   175  	defer func() {
   176  		cause := errors.Cause(err)
   177  		if params.IsCodeNotFoundOrCodeUnauthorized(cause) {
   178  			// We only want to terminate the agent for IAAS models.
   179  			if w.modelType == model.IAAS {
   180  				err = jworker.ErrTerminateAgent
   181  			}
   182  		}
   183  	}()
   184  	if w.unit, err = w.st.Unit(unitTag); err != nil {
   185  		return errors.Trace(err)
   186  	}
   187  	w.application, err = w.unit.Application()
   188  	if err != nil {
   189  		return errors.Trace(err)
   190  	}
   191  	return nil
   192  }
   193  
   194  func (w *RemoteStateWatcher) loop(unitTag names.UnitTag) (err error) {
   195  	if err := w.setUp(unitTag); err != nil {
   196  		return errors.Trace(err)
   197  	}
   198  
   199  	var requiredEvents int
   200  
   201  	var seenUnitChange bool
   202  	unitw, err := w.unit.Watch()
   203  	if err != nil {
   204  		return errors.Trace(err)
   205  	}
   206  	if err := w.catacomb.Add(unitw); err != nil {
   207  		return errors.Trace(err)
   208  	}
   209  	requiredEvents++
   210  
   211  	var seenConfigChange bool
   212  	charmConfigw, err := w.unit.WatchConfigSettingsHash()
   213  	if err != nil {
   214  		return errors.Trace(err)
   215  	}
   216  
   217  	if err := w.catacomb.Add(charmConfigw); err != nil {
   218  		return errors.Trace(err)
   219  	}
   220  	requiredEvents++
   221  
   222  	var seenTrustConfigChange bool
   223  	trustConfigw, err := w.unit.WatchTrustConfigSettingsHash()
   224  	if err != nil {
   225  		return errors.Trace(err)
   226  	}
   227  	if err := w.catacomb.Add(trustConfigw); err != nil {
   228  		return errors.Trace(err)
   229  	}
   230  	requiredEvents++
   231  
   232  	var seenRelationsChange bool
   233  	relationsw, err := w.unit.WatchRelations()
   234  	if err != nil {
   235  		return errors.Trace(err)
   236  	}
   237  	if err := w.catacomb.Add(relationsw); err != nil {
   238  		return errors.Trace(err)
   239  	}
   240  	requiredEvents++
   241  
   242  	var seenAddressesChange bool
   243  	addressesw, err := w.unit.WatchAddressesHash()
   244  	if err != nil {
   245  		return errors.Trace(err)
   246  	}
   247  	addressesChanges := addressesw.Changes()
   248  	if err := w.catacomb.Add(addressesw); err != nil {
   249  		return errors.Trace(err)
   250  	}
   251  	requiredEvents++
   252  
   253  	var (
   254  		seenApplicationChange bool
   255  
   256  		seenUpgradeSeriesChange bool
   257  		upgradeSeriesChanges    watcher.NotifyChannel
   258  
   259  		seenLXDProfileChange bool
   260  		lxdProfileChanges    watcher.StringsChannel
   261  	)
   262  
   263  	// CAAS models don't use an application watcher
   264  	// which fires an initial event.
   265  	if w.modelType == model.CAAS {
   266  		seenApplicationChange = true
   267  	}
   268  
   269  	if w.modelType == model.IAAS {
   270  		// This is in IAAS model so we need to watch state for application
   271  		// charm changes instead of being informed by the operator.
   272  		applicationw, err := w.application.Watch()
   273  		if err != nil {
   274  			return errors.Trace(err)
   275  		}
   276  		if err := w.catacomb.Add(applicationw); err != nil {
   277  			return errors.Trace(err)
   278  		}
   279  		w.applicationChannel = applicationw.Changes()
   280  		requiredEvents++
   281  
   282  		// Only IAAS models support upgrading the machine series.
   283  		// TODO(externalreality) This pattern should probably be extracted
   284  		upgradeSeriesw, err := w.unit.WatchUpgradeSeriesNotifications()
   285  		if err != nil {
   286  			return errors.Trace(err)
   287  		}
   288  		if err := w.catacomb.Add(upgradeSeriesw); err != nil {
   289  			return errors.Trace(err)
   290  		}
   291  		upgradeSeriesChanges = upgradeSeriesw.Changes()
   292  		requiredEvents++
   293  
   294  		lxdProfilew, err := w.unit.WatchLXDProfileUpgradeNotifications()
   295  		if err != nil {
   296  			return errors.Trace(err)
   297  		}
   298  		if err := w.catacomb.Add(lxdProfilew); err != nil {
   299  			return errors.Trace(err)
   300  		}
   301  		lxdProfileChanges = lxdProfilew.Changes()
   302  		requiredEvents++
   303  	}
   304  
   305  	var seenStorageChange bool
   306  	storagew, err := w.unit.WatchStorage()
   307  	if err != nil {
   308  		return errors.Trace(err)
   309  	}
   310  	if err := w.catacomb.Add(storagew); err != nil {
   311  		return errors.Trace(err)
   312  	}
   313  	requiredEvents++
   314  
   315  	var seenLeaderSettingsChange bool
   316  	leaderSettingsw, err := w.application.WatchLeadershipSettings()
   317  	if err != nil {
   318  		return errors.Trace(err)
   319  	}
   320  	if err := w.catacomb.Add(leaderSettingsw); err != nil {
   321  		return errors.Trace(err)
   322  	}
   323  	requiredEvents++
   324  
   325  	var seenActionsChange bool
   326  	actionsw, err := w.unit.WatchActionNotifications()
   327  	if err != nil {
   328  		return errors.Trace(err)
   329  	}
   330  	if err := w.catacomb.Add(actionsw); err != nil {
   331  		return errors.Trace(err)
   332  	}
   333  	requiredEvents++
   334  
   335  	var seenUpdateStatusIntervalChange bool
   336  	updateStatusIntervalw, err := w.st.WatchUpdateStatusHookInterval()
   337  	if err != nil {
   338  		return errors.Trace(err)
   339  	}
   340  	if err := w.catacomb.Add(updateStatusIntervalw); err != nil {
   341  		return errors.Trace(err)
   342  	}
   343  	requiredEvents++
   344  
   345  	var seenLeadershipChange bool
   346  	// There's no watcher for this per se; we wait on a channel
   347  	// returned by the leadership tracker.
   348  	requiredEvents++
   349  
   350  	var eventsObserved int
   351  	observedEvent := func(flag *bool) {
   352  		if flag != nil && !*flag {
   353  			*flag = true
   354  			eventsObserved++
   355  		}
   356  	}
   357  
   358  	// fire will, once the first event for each watcher has
   359  	// been observed, send a signal on the out channel.
   360  	fire := func() {
   361  		if eventsObserved != requiredEvents {
   362  			return
   363  		}
   364  		select {
   365  		case w.out <- struct{}{}:
   366  		default:
   367  		}
   368  	}
   369  
   370  	// Check the initial leadership status, and then we can flip-flop
   371  	// waiting on leader or minion to trigger the changed event.
   372  	var waitLeader, waitMinion <-chan struct{}
   373  	claimLeader := w.leadershipTracker.ClaimLeader()
   374  	select {
   375  	case <-w.catacomb.Dying():
   376  		return w.catacomb.ErrDying()
   377  	case <-claimLeader.Ready():
   378  		isLeader := claimLeader.Wait()
   379  		w.leadershipChanged(isLeader)
   380  		if isLeader {
   381  			waitMinion = w.leadershipTracker.WaitMinion().Ready()
   382  		} else {
   383  			waitLeader = w.leadershipTracker.WaitLeader().Ready()
   384  		}
   385  		observedEvent(&seenLeadershipChange)
   386  	}
   387  
   388  	var updateStatusInterval time.Duration
   389  	var updateStatusTimer <-chan time.Time
   390  	resetUpdateStatusTimer := func() {
   391  		updateStatusTimer = w.updateStatusChannel(updateStatusInterval).After()
   392  	}
   393  
   394  	for {
   395  		select {
   396  		case <-w.catacomb.Dying():
   397  			return w.catacomb.ErrDying()
   398  
   399  		case _, ok := <-unitw.Changes():
   400  			logger.Debugf("got unit change")
   401  			if !ok {
   402  				return errors.New("unit watcher closed")
   403  			}
   404  			if err := w.unitChanged(); err != nil {
   405  				return errors.Trace(err)
   406  			}
   407  			observedEvent(&seenUnitChange)
   408  
   409  		case _, ok := <-w.applicationChannel:
   410  			logger.Debugf("got application change")
   411  			if !ok {
   412  				return errors.New("application watcher closed")
   413  			}
   414  			if err := w.applicationChanged(); err != nil {
   415  				return errors.Trace(err)
   416  			}
   417  			observedEvent(&seenApplicationChange)
   418  
   419  		case hashes, ok := <-charmConfigw.Changes():
   420  			logger.Debugf("got config change: ok=%t, hashes=%v", ok, hashes)
   421  			if !ok {
   422  				return errors.New("config watcher closed")
   423  			}
   424  			if len(hashes) != 1 {
   425  				return errors.New("expected one hash in config change")
   426  			}
   427  			w.configHashChanged(hashes[0])
   428  			observedEvent(&seenConfigChange)
   429  
   430  		case hashes, ok := <-trustConfigw.Changes():
   431  			logger.Debugf("got trust config change: ok=%t, hashes=%v", ok, hashes)
   432  			if !ok {
   433  				return errors.New("trust config watcher closed")
   434  			}
   435  			if len(hashes) != 1 {
   436  				return errors.New("expected one hash in trust config change")
   437  			}
   438  			w.trustHashChanged(hashes[0])
   439  			observedEvent(&seenTrustConfigChange)
   440  
   441  		case _, ok := <-upgradeSeriesChanges:
   442  			logger.Debugf("got upgrade series change")
   443  			if !ok {
   444  				return errors.New("upgrades series watcher closed")
   445  			}
   446  			if err := w.upgradeSeriesStatusChanged(); err != nil {
   447  				return errors.Trace(err)
   448  			}
   449  			observedEvent(&seenUpgradeSeriesChange)
   450  
   451  		case changes, ok := <-lxdProfileChanges:
   452  			logger.Debugf("got lxd profile change")
   453  			if !ok {
   454  				return errors.New("lxd profile watcher closed")
   455  			}
   456  			if len(changes) != 1 {
   457  				return errors.New("expected one change in lxd profile watcher")
   458  			}
   459  			if err := w.lxdProfileStatusChanged(changes[0]); err != nil {
   460  				return errors.Trace(err)
   461  			}
   462  			observedEvent(&seenLXDProfileChange)
   463  
   464  		case hashes, ok := <-addressesChanges:
   465  			logger.Debugf("got address change: ok=%t, hashes=%v", ok, hashes)
   466  			if !ok {
   467  				return errors.New("addresses watcher closed")
   468  			}
   469  			if len(hashes) != 1 {
   470  				return errors.New("expected one hash in addresses change")
   471  			}
   472  			w.addressesHashChanged(hashes[0])
   473  			observedEvent(&seenAddressesChange)
   474  
   475  		case _, ok := <-leaderSettingsw.Changes():
   476  			logger.Debugf("got leader settings change: ok=%t", ok)
   477  			if !ok {
   478  				return errors.New("leader settings watcher closed")
   479  			}
   480  			if err := w.leaderSettingsChanged(); err != nil {
   481  				return errors.Trace(err)
   482  			}
   483  			observedEvent(&seenLeaderSettingsChange)
   484  
   485  		case actions, ok := <-actionsw.Changes():
   486  			logger.Debugf("got action change: %v ok=%t", actions, ok)
   487  			if !ok {
   488  				return errors.New("actions watcher closed")
   489  			}
   490  			w.actionsChanged(actions)
   491  			observedEvent(&seenActionsChange)
   492  
   493  		case keys, ok := <-relationsw.Changes():
   494  			logger.Debugf("got relations change: ok=%t", ok)
   495  			if !ok {
   496  				return errors.New("relations watcher closed")
   497  			}
   498  			if err := w.relationsChanged(keys); err != nil {
   499  				return errors.Trace(err)
   500  			}
   501  			observedEvent(&seenRelationsChange)
   502  
   503  		case keys, ok := <-storagew.Changes():
   504  			logger.Debugf("got storage change: %v ok=%t", keys, ok)
   505  			if !ok {
   506  				return errors.New("storage watcher closed")
   507  			}
   508  			if err := w.storageChanged(keys); err != nil {
   509  				return errors.Trace(err)
   510  			}
   511  			observedEvent(&seenStorageChange)
   512  
   513  		case _, ok := <-updateStatusIntervalw.Changes():
   514  			logger.Debugf("got update status interval change: ok=%t", ok)
   515  			if !ok {
   516  				return errors.New("update status interval watcher closed")
   517  			}
   518  			observedEvent(&seenUpdateStatusIntervalChange)
   519  
   520  			var err error
   521  			updateStatusInterval, err = w.st.UpdateStatusHookInterval()
   522  			if err != nil {
   523  				return errors.Trace(err)
   524  			}
   525  			wasActive := updateStatusTimer != nil
   526  			resetUpdateStatusTimer()
   527  			if wasActive {
   528  				// This is not the first time we've seen an update
   529  				// status interval change, so there's no need to
   530  				// fall out and fire an initial change event.
   531  				continue
   532  			}
   533  
   534  		case <-waitMinion:
   535  			logger.Debugf("got leadership change for %v: minion", unitTag.Id())
   536  			w.leadershipChanged(false)
   537  			waitMinion = nil
   538  			waitLeader = w.leadershipTracker.WaitLeader().Ready()
   539  
   540  		case <-waitLeader:
   541  			logger.Debugf("got leadership change for %v: leader", unitTag.Id())
   542  			w.leadershipChanged(true)
   543  			waitLeader = nil
   544  			waitMinion = w.leadershipTracker.WaitMinion().Ready()
   545  
   546  		case change := <-w.storageAttachmentChanges:
   547  			logger.Debugf("storage attachment change %v", change)
   548  			w.storageAttachmentChanged(change)
   549  
   550  		case change := <-w.relationUnitsChanges:
   551  			logger.Debugf("got a relation units change: %v", change)
   552  			if err := w.relationUnitsChanged(change); err != nil {
   553  				return errors.Trace(err)
   554  			}
   555  
   556  		case <-updateStatusTimer:
   557  			logger.Debugf("update status timer triggered")
   558  			w.updateStatusChanged()
   559  			resetUpdateStatusTimer()
   560  
   561  		case id, ok := <-w.commandChannel:
   562  			if !ok {
   563  				return errors.New("commandChannel closed")
   564  			}
   565  			logger.Debugf("command enqueued: %v", id)
   566  			w.commandsChanged(id)
   567  
   568  		case _, ok := <-w.retryHookChannel:
   569  			if !ok {
   570  				return errors.New("retryHookChannel closed")
   571  			}
   572  			logger.Debugf("retry hook timer triggered")
   573  			w.retryHookTimerTriggered()
   574  		}
   575  
   576  		// Something changed.
   577  		fire()
   578  	}
   579  }
   580  
   581  // upgradeSeriesStatusChanged is called when the remote status of a series
   582  // upgrade changes.
   583  func (w *RemoteStateWatcher) upgradeSeriesStatusChanged() error {
   584  	w.mu.Lock()
   585  	defer w.mu.Unlock()
   586  
   587  	status, err := w.upgradeSeriesStatus()
   588  	if errors.IsNotFound(err) {
   589  		// There is no remote state so no upgrade is started.
   590  		logger.Debugf("no upgrade series in progress, reinitializing local upgrade series state")
   591  		w.current.UpgradeSeriesStatus = model.UpgradeSeriesNotStarted
   592  		return nil
   593  	}
   594  	if err != nil {
   595  		return err
   596  	}
   597  	w.current.UpgradeSeriesStatus = status
   598  	return nil
   599  }
   600  
   601  func (w *RemoteStateWatcher) upgradeSeriesStatus() (model.UpgradeSeriesStatus, error) {
   602  	rawStatus, err := w.unit.UpgradeSeriesStatus()
   603  	if err != nil {
   604  		return "", err
   605  	}
   606  	status, err := model.ValidateUpgradeSeriesStatus(rawStatus)
   607  	if err != nil {
   608  		return "", err
   609  	}
   610  	return status, nil
   611  }
   612  
   613  // updateStatusChanged is called when the update status timer expires.
   614  func (w *RemoteStateWatcher) updateStatusChanged() {
   615  	w.mu.Lock()
   616  	w.current.UpdateStatusVersion++
   617  	w.mu.Unlock()
   618  }
   619  
   620  func (w *RemoteStateWatcher) lxdProfileStatusChanged(status string) error {
   621  	w.mu.Lock()
   622  	defer w.mu.Unlock()
   623  
   624  	w.current.UpgradeCharmProfileStatus = status
   625  	return nil
   626  }
   627  
   628  // commandsChanged is called when a command is enqueued.
   629  func (w *RemoteStateWatcher) commandsChanged(id string) {
   630  	w.mu.Lock()
   631  	w.current.Commands = append(w.current.Commands, id)
   632  	w.mu.Unlock()
   633  }
   634  
   635  // retryHookTimerTriggered is called when the retry hook timer expires.
   636  func (w *RemoteStateWatcher) retryHookTimerTriggered() {
   637  	w.mu.Lock()
   638  	w.current.RetryHookVersion++
   639  	w.mu.Unlock()
   640  }
   641  
   642  // unitChanged responds to changes in the unit.
   643  func (w *RemoteStateWatcher) unitChanged() error {
   644  	if err := w.unit.Refresh(); err != nil {
   645  		return errors.Trace(err)
   646  	}
   647  	w.mu.Lock()
   648  	defer w.mu.Unlock()
   649  	w.current.Life = w.unit.Life()
   650  	w.current.ResolvedMode = w.unit.Resolved()
   651  	return nil
   652  }
   653  
   654  // applicationChanged responds to changes in the application.
   655  func (w *RemoteStateWatcher) applicationChanged() error {
   656  	if err := w.application.Refresh(); err != nil {
   657  		return errors.Trace(err)
   658  	}
   659  	url, force, err := w.application.CharmURL()
   660  	if err != nil {
   661  		return errors.Trace(err)
   662  	}
   663  	ver, err := w.application.CharmModifiedVersion()
   664  	if err != nil {
   665  		return errors.Trace(err)
   666  	}
   667  	w.mu.Lock()
   668  	w.current.CharmURL = url
   669  	w.current.ForceCharmUpgrade = force
   670  	w.current.CharmModifiedVersion = ver
   671  	w.mu.Unlock()
   672  	return nil
   673  }
   674  
   675  func (w *RemoteStateWatcher) configHashChanged(value string) {
   676  	w.mu.Lock()
   677  	w.current.ConfigHash = value
   678  	w.mu.Unlock()
   679  }
   680  
   681  func (w *RemoteStateWatcher) trustHashChanged(value string) {
   682  	w.mu.Lock()
   683  	w.current.TrustHash = value
   684  	w.mu.Unlock()
   685  }
   686  
   687  func (w *RemoteStateWatcher) addressesHashChanged(value string) {
   688  	w.mu.Lock()
   689  	w.current.AddressesHash = value
   690  	w.mu.Unlock()
   691  }
   692  
   693  func (w *RemoteStateWatcher) leaderSettingsChanged() error {
   694  	w.mu.Lock()
   695  	w.current.LeaderSettingsVersion++
   696  	w.mu.Unlock()
   697  	return nil
   698  }
   699  
   700  func (w *RemoteStateWatcher) leadershipChanged(isLeader bool) {
   701  	w.mu.Lock()
   702  	w.current.Leader = isLeader
   703  	w.mu.Unlock()
   704  }
   705  
   706  // relationsChanged responds to application relation changes.
   707  func (w *RemoteStateWatcher) relationsChanged(keys []string) error {
   708  	w.mu.Lock()
   709  	defer w.mu.Unlock()
   710  	for _, key := range keys {
   711  		relationTag := names.NewRelationTag(key)
   712  		rel, err := w.st.Relation(relationTag)
   713  		if params.IsCodeNotFoundOrCodeUnauthorized(err) {
   714  			// If it's actually gone, this unit cannot have entered
   715  			// scope, and therefore never needs to know about it.
   716  			if ruw, ok := w.relations[relationTag]; ok {
   717  				worker.Stop(ruw)
   718  				delete(w.relations, relationTag)
   719  				delete(w.current.Relations, ruw.relationId)
   720  			}
   721  		} else if err != nil {
   722  			return errors.Trace(err)
   723  		} else {
   724  			if _, ok := w.relations[relationTag]; ok {
   725  				relationSnapshot := w.current.Relations[rel.Id()]
   726  				relationSnapshot.Life = rel.Life()
   727  				relationSnapshot.Suspended = rel.Suspended()
   728  				w.current.Relations[rel.Id()] = relationSnapshot
   729  				if rel.Suspended() {
   730  					// Relation has been suspended, so stop the listeners here.
   731  					// The relation itself is retained in the current relations
   732  					// in the suspended state so that departed/broken hooks can run.
   733  					if ruw, ok := w.relations[relationTag]; ok {
   734  						worker.Stop(ruw)
   735  						delete(w.relations, relationTag)
   736  					}
   737  				}
   738  				continue
   739  			}
   740  			// If the relation is suspended, we don't need to watch it.
   741  			if rel.Suspended() {
   742  				continue
   743  			}
   744  			ruw, err := w.st.WatchRelationUnits(relationTag, w.unit.Tag())
   745  			if err != nil {
   746  				return errors.Trace(err)
   747  			}
   748  			// Because of the delay before handing off responsibility to
   749  			// newRelationUnitsWatcher below, add to our own catacomb to
   750  			// ensure errors get picked up if they happen.
   751  			if err := w.catacomb.Add(ruw); err != nil {
   752  				return errors.Trace(err)
   753  			}
   754  			if err := w.watchRelationUnits(rel, relationTag, ruw); err != nil {
   755  				return errors.Trace(err)
   756  			}
   757  		}
   758  	}
   759  	return nil
   760  }
   761  
   762  // watchRelationUnits starts watching the relation units for the given
   763  // relation, waits for its first event, and records the information in
   764  // the current snapshot.
   765  func (w *RemoteStateWatcher) watchRelationUnits(
   766  	rel Relation, relationTag names.RelationTag, ruw watcher.RelationUnitsWatcher,
   767  ) error {
   768  	relationSnapshot := RelationSnapshot{
   769  		Life:      rel.Life(),
   770  		Suspended: rel.Suspended(),
   771  		Members:   make(map[string]int64),
   772  	}
   773  	select {
   774  	case <-w.catacomb.Dying():
   775  		return w.catacomb.ErrDying()
   776  	case change, ok := <-ruw.Changes():
   777  		if !ok {
   778  			return errors.New("relation units watcher closed")
   779  		}
   780  		for unit, settings := range change.Changed {
   781  			relationSnapshot.Members[unit] = settings.Version
   782  		}
   783  	}
   784  	innerRUW, err := newRelationUnitsWatcher(rel.Id(), ruw, w.relationUnitsChanges)
   785  	if err != nil {
   786  		return errors.Trace(err)
   787  	}
   788  	if err := w.catacomb.Add(innerRUW); err != nil {
   789  		return errors.Trace(err)
   790  	}
   791  	w.current.Relations[rel.Id()] = relationSnapshot
   792  	w.relations[relationTag] = innerRUW
   793  	return nil
   794  }
   795  
   796  // relationUnitsChanged responds to relation units changes.
   797  func (w *RemoteStateWatcher) relationUnitsChanged(change relationUnitsChange) error {
   798  	w.mu.Lock()
   799  	defer w.mu.Unlock()
   800  	snapshot, ok := w.current.Relations[change.relationId]
   801  	if !ok {
   802  		return nil
   803  	}
   804  	for unit, settings := range change.Changed {
   805  		snapshot.Members[unit] = settings.Version
   806  	}
   807  	for _, unit := range change.Departed {
   808  		delete(snapshot.Members, unit)
   809  	}
   810  	return nil
   811  }
   812  
   813  // storageAttachmentChanged responds to storage attachment changes.
   814  func (w *RemoteStateWatcher) storageAttachmentChanged(change storageAttachmentChange) {
   815  	w.mu.Lock()
   816  	w.current.Storage[change.Tag] = change.Snapshot
   817  	w.mu.Unlock()
   818  }
   819  
   820  func (w *RemoteStateWatcher) actionsChanged(actions []string) {
   821  	w.mu.Lock()
   822  	defer w.mu.Unlock()
   823  	w.current.Actions = append(w.current.Actions, actions...)
   824  }
   825  
   826  // storageChanged responds to unit storage changes.
   827  func (w *RemoteStateWatcher) storageChanged(keys []string) error {
   828  	tags := make([]names.StorageTag, len(keys))
   829  	for i, key := range keys {
   830  		tags[i] = names.NewStorageTag(key)
   831  	}
   832  	ids := make([]params.StorageAttachmentId, len(keys))
   833  	for i, tag := range tags {
   834  		ids[i] = params.StorageAttachmentId{
   835  			StorageTag: tag.String(),
   836  			UnitTag:    w.unit.Tag().String(),
   837  		}
   838  	}
   839  	results, err := w.st.StorageAttachmentLife(ids)
   840  	if err != nil {
   841  		return errors.Trace(err)
   842  	}
   843  
   844  	w.mu.Lock()
   845  	defer w.mu.Unlock()
   846  
   847  	for i, result := range results {
   848  		tag := tags[i]
   849  		if result.Error == nil {
   850  			if storageSnapshot, ok := w.current.Storage[tag]; ok {
   851  				// We've previously started a watcher for this storage
   852  				// attachment, so all we needed to do was update the
   853  				// lifecycle state.
   854  				storageSnapshot.Life = result.Life
   855  				w.current.Storage[tag] = storageSnapshot
   856  				continue
   857  			}
   858  			// We haven't seen this storage attachment before, so start
   859  			// a watcher now; add it to our catacomb in case of mishap;
   860  			// and wait for the initial event.
   861  			saw, err := w.st.WatchStorageAttachment(tag, w.unit.Tag())
   862  			if err != nil {
   863  				return errors.Annotate(err, "watching storage attachment")
   864  			}
   865  			if err := w.catacomb.Add(saw); err != nil {
   866  				return errors.Trace(err)
   867  			}
   868  			if err := w.watchStorageAttachment(tag, result.Life, saw); err != nil {
   869  				return errors.Trace(err)
   870  			}
   871  		} else if params.IsCodeNotFound(result.Error) {
   872  			if watcher, ok := w.storageAttachmentWatchers[tag]; ok {
   873  				// already under catacomb management, any error tracked already
   874  				worker.Stop(watcher)
   875  				delete(w.storageAttachmentWatchers, tag)
   876  			}
   877  			delete(w.current.Storage, tag)
   878  		} else {
   879  			return errors.Annotatef(
   880  				result.Error, "getting life of %s attachment",
   881  				names.ReadableString(tag),
   882  			)
   883  		}
   884  	}
   885  	return nil
   886  }
   887  
   888  // watchStorageAttachment starts watching the storage attachment with
   889  // the specified storage tag, waits for its first event, and records
   890  // the information in the current snapshot.
   891  func (w *RemoteStateWatcher) watchStorageAttachment(
   892  	tag names.StorageTag,
   893  	life params.Life,
   894  	saw watcher.NotifyWatcher,
   895  ) error {
   896  	var storageSnapshot StorageSnapshot
   897  	select {
   898  	case <-w.catacomb.Dying():
   899  		return w.catacomb.ErrDying()
   900  	case _, ok := <-saw.Changes():
   901  		if !ok {
   902  			return errors.New("storage attachment watcher closed")
   903  		}
   904  		var err error
   905  		storageSnapshot, err = getStorageSnapshot(w.st, tag, w.unit.Tag())
   906  		if params.IsCodeNotProvisioned(err) {
   907  			// If the storage is unprovisioned, we still want to
   908  			// record the attachment, but we'll mark it as
   909  			// unattached. This allows the uniter to wait for
   910  			// pending storage attachments to be provisioned.
   911  			storageSnapshot = StorageSnapshot{Life: life}
   912  		} else if err != nil {
   913  			return errors.Annotatef(err, "processing initial storage attachment change")
   914  		}
   915  	}
   916  	innerSAW, err := newStorageAttachmentWatcher(
   917  		w.st, saw, w.unit.Tag(), tag, w.storageAttachmentChanges,
   918  	)
   919  	if err != nil {
   920  		return errors.Trace(err)
   921  	}
   922  	w.current.Storage[tag] = storageSnapshot
   923  	w.storageAttachmentWatchers[tag] = innerSAW
   924  	return nil
   925  }