github.com/juju/juju@v0.0.0-20240327075706-a90865de2538/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  	"fmt"
     8  	"strconv"
     9  	"strings"
    10  	"sync"
    11  	"time"
    12  
    13  	"github.com/juju/collections/set"
    14  	"github.com/juju/errors"
    15  	"github.com/juju/names/v5"
    16  	"github.com/juju/worker/v3"
    17  	"github.com/juju/worker/v3/catacomb"
    18  
    19  	"github.com/juju/juju/core/leadership"
    20  	"github.com/juju/juju/core/life"
    21  	"github.com/juju/juju/core/model"
    22  	"github.com/juju/juju/core/secrets"
    23  	"github.com/juju/juju/core/watcher"
    24  	"github.com/juju/juju/rpc/params"
    25  	jworker "github.com/juju/juju/worker"
    26  )
    27  
    28  // Logger is here to stop the desire of creating a package level Logger.
    29  // Don't do this, instead use the one in the RemoteStateWatcher.
    30  type logger interface{}
    31  
    32  var _ logger = struct{}{}
    33  
    34  // Logger represents the logging methods used in this package.
    35  type Logger interface {
    36  	Warningf(string, ...interface{})
    37  	Debugf(string, ...interface{})
    38  	Criticalf(string, ...interface{})
    39  }
    40  
    41  // SecretTriggerWatcherFunc is a function returning a secrets trigger watcher.
    42  type SecretTriggerWatcherFunc func(names.UnitTag, bool, chan []string) (worker.Worker, error)
    43  
    44  // SecretsClient provides access to the secrets manager facade.
    45  type SecretsClient interface {
    46  	WatchConsumedSecretsChanges(unitName string) (watcher.StringsWatcher, error)
    47  	GetConsumerSecretsRevisionInfo(string, []string) (map[string]secrets.SecretRevisionInfo, error)
    48  	WatchObsolete(ownerTags ...names.Tag) (watcher.StringsWatcher, error)
    49  }
    50  
    51  // RemoteStateWatcher collects unit, application, and application config information
    52  // from separate state watchers, and updates a Snapshot which is sent on a
    53  // channel upon change.
    54  type RemoteStateWatcher struct {
    55  	st                           State
    56  	unit                         Unit
    57  	application                  Application
    58  	modelType                    model.ModelType
    59  	sidecar                      bool
    60  	enforcedCharmModifiedVersion int
    61  	logger                       Logger
    62  
    63  	relations                     map[names.RelationTag]*wrappedRelationUnitsWatcher
    64  	relationUnitsChanges          chan relationUnitsChange
    65  	storageAttachmentWatchers     map[names.StorageTag]*storageAttachmentWatcher
    66  	storageAttachmentChanges      chan storageAttachmentChange
    67  	leadershipTracker             leadership.Tracker
    68  	updateStatusChannel           UpdateStatusTimerFunc
    69  	commandChannel                <-chan string
    70  	retryHookChannel              watcher.NotifyChannel
    71  	containerRunningStatusChannel watcher.NotifyChannel
    72  	containerRunningStatusFunc    ContainerRunningStatusFunc
    73  	canApplyCharmProfile          bool
    74  	workloadEventChannel          <-chan string
    75  	shutdownChannel               <-chan bool
    76  
    77  	secretsClient SecretsClient
    78  
    79  	secretRotateWatcherFunc SecretTriggerWatcherFunc
    80  	secretRotateWatcher     worker.Worker
    81  	rotateSecretsChanges    chan []string
    82  
    83  	secretExpiryWatcherFunc SecretTriggerWatcherFunc
    84  	secretExpiryWatcher     worker.Worker
    85  	expireSecretsChanges    chan []string
    86  
    87  	obsoleteRevisionWatcher worker.Worker
    88  	obsoleteRevisionChanges watcher.StringsChannel
    89  
    90  	catacomb catacomb.Catacomb
    91  
    92  	out     chan struct{}
    93  	mu      sync.Mutex
    94  	current Snapshot
    95  }
    96  
    97  // ContainerRunningStatus is used on CAAS models to upgrade charms/block actions.
    98  type ContainerRunningStatus struct {
    99  	PodName          string
   100  	Initialising     bool
   101  	InitialisingTime time.Time
   102  	Running          bool
   103  }
   104  
   105  // ContainerRunningStatusFunc is used by the RemoteStateWatcher in a CAAS
   106  // model to determine if the unit is running and ready to execute actions.
   107  type ContainerRunningStatusFunc func(providerID string) (*ContainerRunningStatus, error)
   108  
   109  // WatcherConfig holds configuration parameters for the
   110  // remote state watcher.
   111  type WatcherConfig struct {
   112  	State                         State
   113  	LeadershipTracker             leadership.Tracker
   114  	SecretRotateWatcherFunc       SecretTriggerWatcherFunc
   115  	SecretExpiryWatcherFunc       SecretTriggerWatcherFunc
   116  	SecretsClient                 SecretsClient
   117  	UpdateStatusChannel           UpdateStatusTimerFunc
   118  	CommandChannel                <-chan string
   119  	RetryHookChannel              watcher.NotifyChannel
   120  	ContainerRunningStatusChannel watcher.NotifyChannel
   121  	ContainerRunningStatusFunc    ContainerRunningStatusFunc
   122  	UnitTag                       names.UnitTag
   123  	ModelType                     model.ModelType
   124  	Sidecar                       bool
   125  	EnforcedCharmModifiedVersion  int
   126  	Logger                        Logger
   127  	CanApplyCharmProfile          bool
   128  	WorkloadEventChannel          <-chan string
   129  	InitialWorkloadEventIDs       []string
   130  	ShutdownChannel               <-chan bool
   131  }
   132  
   133  func (w WatcherConfig) validate() error {
   134  	if w.ModelType == model.IAAS && w.Sidecar {
   135  		return errors.NewNotValid(nil, fmt.Sprintf("sidecar mode is only for %q model", model.CAAS))
   136  	}
   137  
   138  	if w.ModelType == model.CAAS && !w.Sidecar {
   139  		if w.ContainerRunningStatusChannel != nil &&
   140  			w.ContainerRunningStatusFunc == nil {
   141  			return errors.NotValidf("watcher config for CAAS model with nil container running status func")
   142  		}
   143  	}
   144  	if w.Logger == nil {
   145  		return errors.NotValidf("nil Logger")
   146  	}
   147  	return nil
   148  }
   149  
   150  // NewWatcher returns a RemoteStateWatcher that handles state changes pertaining to the
   151  // supplied unit.
   152  func NewWatcher(config WatcherConfig) (*RemoteStateWatcher, error) {
   153  	if err := config.validate(); err != nil {
   154  		return nil, errors.Trace(err)
   155  	}
   156  	w := &RemoteStateWatcher{
   157  		st:                            config.State,
   158  		relations:                     make(map[names.RelationTag]*wrappedRelationUnitsWatcher),
   159  		relationUnitsChanges:          make(chan relationUnitsChange),
   160  		storageAttachmentWatchers:     make(map[names.StorageTag]*storageAttachmentWatcher),
   161  		storageAttachmentChanges:      make(chan storageAttachmentChange),
   162  		leadershipTracker:             config.LeadershipTracker,
   163  		secretRotateWatcherFunc:       config.SecretRotateWatcherFunc,
   164  		secretExpiryWatcherFunc:       config.SecretExpiryWatcherFunc,
   165  		secretsClient:                 config.SecretsClient,
   166  		updateStatusChannel:           config.UpdateStatusChannel,
   167  		commandChannel:                config.CommandChannel,
   168  		retryHookChannel:              config.RetryHookChannel,
   169  		containerRunningStatusChannel: config.ContainerRunningStatusChannel,
   170  		containerRunningStatusFunc:    config.ContainerRunningStatusFunc,
   171  		modelType:                     config.ModelType,
   172  		logger:                        config.Logger,
   173  		canApplyCharmProfile:          config.CanApplyCharmProfile,
   174  		// Note: it is important that the out channel be buffered!
   175  		// The remote state watcher will perform a non-blocking send
   176  		// on the channel to wake up the observer. It is non-blocking
   177  		// so that we coalesce events while the observer is busy.
   178  		out: make(chan struct{}, 1),
   179  		current: Snapshot{
   180  			Relations:               make(map[int]RelationSnapshot),
   181  			Storage:                 make(map[names.StorageTag]StorageSnapshot),
   182  			ActionsBlocked:          config.ContainerRunningStatusChannel != nil,
   183  			ActionChanged:           make(map[string]int),
   184  			UpgradeMachineStatus:    model.UpgradeSeriesNotStarted,
   185  			WorkloadEvents:          config.InitialWorkloadEventIDs,
   186  			ConsumedSecretInfo:      make(map[string]secrets.SecretRevisionInfo),
   187  			ObsoleteSecretRevisions: make(map[string][]int),
   188  		},
   189  		sidecar:                      config.Sidecar,
   190  		enforcedCharmModifiedVersion: config.EnforcedCharmModifiedVersion,
   191  		workloadEventChannel:         config.WorkloadEventChannel,
   192  		shutdownChannel:              config.ShutdownChannel,
   193  	}
   194  	err := catacomb.Invoke(catacomb.Plan{
   195  		Site: &w.catacomb,
   196  		Work: func() error {
   197  			return w.loop(config.UnitTag)
   198  		},
   199  	})
   200  	if err != nil {
   201  		return nil, errors.Trace(err)
   202  	}
   203  	return w, nil
   204  }
   205  
   206  // Kill is part of the worker.Worker interface.
   207  func (w *RemoteStateWatcher) Kill() {
   208  	w.catacomb.Kill(nil)
   209  }
   210  
   211  // Wait is part of the worker.Worker interface.
   212  func (w *RemoteStateWatcher) Wait() error {
   213  	return w.catacomb.Wait()
   214  }
   215  
   216  func (w *RemoteStateWatcher) RemoteStateChanged() <-chan struct{} {
   217  	return w.out
   218  }
   219  
   220  func (w *RemoteStateWatcher) Snapshot() Snapshot {
   221  	w.mu.Lock()
   222  	defer w.mu.Unlock()
   223  	snapshot := w.current
   224  	snapshot.Relations = make(map[int]RelationSnapshot)
   225  	for id, relationSnapshot := range w.current.Relations {
   226  		relationSnapshotCopy := RelationSnapshot{
   227  			Life:               relationSnapshot.Life,
   228  			Suspended:          relationSnapshot.Suspended,
   229  			Members:            make(map[string]int64),
   230  			ApplicationMembers: make(map[string]int64),
   231  		}
   232  		for name, version := range relationSnapshot.Members {
   233  			relationSnapshotCopy.Members[name] = version
   234  		}
   235  		for name, version := range relationSnapshot.ApplicationMembers {
   236  			relationSnapshotCopy.ApplicationMembers[name] = version
   237  		}
   238  		snapshot.Relations[id] = relationSnapshotCopy
   239  	}
   240  	snapshot.Storage = make(map[names.StorageTag]StorageSnapshot)
   241  	for tag, storageSnapshot := range w.current.Storage {
   242  		snapshot.Storage[tag] = storageSnapshot
   243  	}
   244  	snapshot.ActionsPending = make([]string, len(w.current.ActionsPending))
   245  	copy(snapshot.ActionsPending, w.current.ActionsPending)
   246  	snapshot.Commands = make([]string, len(w.current.Commands))
   247  	copy(snapshot.Commands, w.current.Commands)
   248  	snapshot.WorkloadEvents = make([]string, len(w.current.WorkloadEvents))
   249  	copy(snapshot.WorkloadEvents, w.current.WorkloadEvents)
   250  	snapshot.ActionChanged = make(map[string]int)
   251  	for k, v := range w.current.ActionChanged {
   252  		snapshot.ActionChanged[k] = v
   253  	}
   254  	snapshot.SecretRotations = make([]string, len(w.current.SecretRotations))
   255  	copy(snapshot.SecretRotations, w.current.SecretRotations)
   256  	snapshot.ConsumedSecretInfo = make(map[string]secrets.SecretRevisionInfo)
   257  	for u, r := range w.current.ConsumedSecretInfo {
   258  		snapshot.ConsumedSecretInfo[u] = r
   259  	}
   260  	snapshot.ObsoleteSecretRevisions = make(map[string][]int)
   261  	for u, r := range w.current.ObsoleteSecretRevisions {
   262  		rCopy := make([]int, len(r))
   263  		copy(rCopy, r)
   264  		snapshot.ObsoleteSecretRevisions[u] = rCopy
   265  	}
   266  	snapshot.DeletedSecrets = make([]string, len(w.current.DeletedSecrets))
   267  	copy(snapshot.DeletedSecrets, w.current.DeletedSecrets)
   268  	return snapshot
   269  }
   270  
   271  func (w *RemoteStateWatcher) ClearResolvedMode() {
   272  	w.mu.Lock()
   273  	w.current.ResolvedMode = params.ResolvedNone
   274  	w.mu.Unlock()
   275  }
   276  
   277  func (w *RemoteStateWatcher) CommandCompleted(completed string) {
   278  	w.mu.Lock()
   279  	defer w.mu.Unlock()
   280  	for i, id := range w.current.Commands {
   281  		if id != completed {
   282  			continue
   283  		}
   284  		w.current.Commands = append(
   285  			w.current.Commands[:i],
   286  			w.current.Commands[i+1:]...,
   287  		)
   288  		break
   289  	}
   290  }
   291  
   292  func (w *RemoteStateWatcher) WorkloadEventCompleted(workloadEventID string) {
   293  	w.mu.Lock()
   294  	defer w.mu.Unlock()
   295  	for i, id := range w.current.WorkloadEvents {
   296  		if id != workloadEventID {
   297  			continue
   298  		}
   299  		w.current.WorkloadEvents = append(
   300  			w.current.WorkloadEvents[:i],
   301  			w.current.WorkloadEvents[i+1:]...,
   302  		)
   303  		break
   304  	}
   305  }
   306  
   307  // RotateSecretCompleted is called when a secret identified by the URL
   308  // has been rotated.
   309  func (w *RemoteStateWatcher) RotateSecretCompleted(rotatedURL string) {
   310  	w.mu.Lock()
   311  	defer w.mu.Unlock()
   312  	for i, url := range w.current.SecretRotations {
   313  		if url != rotatedURL {
   314  			continue
   315  		}
   316  		w.current.SecretRotations = append(
   317  			w.current.SecretRotations[:i],
   318  			w.current.SecretRotations[i+1:]...,
   319  		)
   320  		break
   321  	}
   322  }
   323  
   324  // ExpireRevisionCompleted is called when a secret revision
   325  // has been expired.
   326  func (w *RemoteStateWatcher) ExpireRevisionCompleted(expiredRevision string) {
   327  	w.mu.Lock()
   328  	defer w.mu.Unlock()
   329  	for i, rev := range w.current.ExpiredSecretRevisions {
   330  		if rev != expiredRevision {
   331  			continue
   332  		}
   333  		w.current.ExpiredSecretRevisions = append(
   334  			w.current.ExpiredSecretRevisions[:i],
   335  			w.current.ExpiredSecretRevisions[i+1:]...,
   336  		)
   337  		break
   338  	}
   339  }
   340  
   341  // RemoveSecretsCompleted is called when secrets have been deleted.
   342  func (w *RemoteStateWatcher) RemoveSecretsCompleted(uris []string) {
   343  	w.mu.Lock()
   344  	defer w.mu.Unlock()
   345  	deleted := set.NewStrings(uris...)
   346  	currentDeleted := set.NewStrings(w.current.DeletedSecrets...)
   347  	w.current.DeletedSecrets = currentDeleted.Difference(deleted).Values()
   348  }
   349  
   350  func (w *RemoteStateWatcher) setUp(unitTag names.UnitTag) (err error) {
   351  	// TODO(axw) move this logic
   352  	defer func() {
   353  		cause := errors.Cause(err)
   354  		if params.IsCodeNotFoundOrCodeUnauthorized(cause) {
   355  			// We only want to terminate the agent for IAAS models.
   356  			if w.modelType == model.IAAS {
   357  				err = jworker.ErrTerminateAgent
   358  			}
   359  		}
   360  	}()
   361  	if w.unit, err = w.st.Unit(unitTag); err != nil {
   362  		return errors.Trace(err)
   363  	}
   364  	w.application, err = w.unit.Application()
   365  	if err != nil {
   366  		return errors.Trace(err)
   367  	}
   368  	if w.containerRunningStatusFunc != nil {
   369  		providerID := w.unit.ProviderID()
   370  		if providerID != "" {
   371  			running, err := w.containerRunningStatusFunc(providerID)
   372  			if err != nil && !errors.IsNotFound(err) {
   373  				return errors.Trace(err)
   374  			}
   375  			if running != nil {
   376  				w.containerRunningStatus(*running)
   377  			}
   378  		}
   379  	}
   380  	w.logger.Debugf("starting remote state watcher, actions for %s; blocked=%v", w.unit.Tag(), w.current.ActionsBlocked)
   381  	return nil
   382  }
   383  
   384  func (w *RemoteStateWatcher) loop(unitTag names.UnitTag) (err error) {
   385  	if err := w.setUp(unitTag); err != nil {
   386  		return errors.Trace(err)
   387  	}
   388  
   389  	var requiredEvents int
   390  
   391  	var seenUnitChange bool
   392  	unitw, err := w.unit.Watch()
   393  	if err != nil {
   394  		return errors.Trace(err)
   395  	}
   396  	if err := w.catacomb.Add(unitw); err != nil {
   397  		return errors.Trace(err)
   398  	}
   399  	requiredEvents++
   400  
   401  	var seenConfigChange bool
   402  	charmConfigw, err := w.unit.WatchConfigSettingsHash()
   403  	if err != nil {
   404  		return errors.Trace(err)
   405  	}
   406  
   407  	if err := w.catacomb.Add(charmConfigw); err != nil {
   408  		return errors.Trace(err)
   409  	}
   410  	requiredEvents++
   411  
   412  	var seenTrustConfigChange bool
   413  	trustConfigw, err := w.unit.WatchTrustConfigSettingsHash()
   414  	if err != nil {
   415  		return errors.Trace(err)
   416  	}
   417  	if err := w.catacomb.Add(trustConfigw); err != nil {
   418  		return errors.Trace(err)
   419  	}
   420  	requiredEvents++
   421  
   422  	var seenRelationsChange bool
   423  	relationsw, err := w.unit.WatchRelations()
   424  	if err != nil {
   425  		return errors.Trace(err)
   426  	}
   427  	if err := w.catacomb.Add(relationsw); err != nil {
   428  		return errors.Trace(err)
   429  	}
   430  	requiredEvents++
   431  
   432  	var seenAddressesChange bool
   433  	addressesw, err := w.unit.WatchAddressesHash()
   434  	if err != nil {
   435  		return errors.Trace(err)
   436  	}
   437  	addressesChanges := addressesw.Changes()
   438  	if err := w.catacomb.Add(addressesw); err != nil {
   439  		return errors.Trace(err)
   440  	}
   441  	requiredEvents++
   442  
   443  	var seenSecretsChange bool
   444  	secretsw, err := w.secretsClient.WatchConsumedSecretsChanges(w.unit.Tag().Id())
   445  	if err != nil {
   446  		return errors.Trace(err)
   447  	}
   448  	secretsChanges := secretsw.Changes()
   449  	if err := w.catacomb.Add(secretsw); err != nil {
   450  		return errors.Trace(err)
   451  	}
   452  	requiredEvents++
   453  
   454  	var (
   455  		seenApplicationChange   bool
   456  		seenInstanceDataChange  bool
   457  		seenUpgradeSeriesChange bool
   458  		upgradeSeriesChanges    watcher.NotifyChannel
   459  		instanceDataChannel     watcher.NotifyChannel
   460  	)
   461  
   462  	applicationw, err := w.application.Watch()
   463  	if err != nil {
   464  		return errors.Trace(err)
   465  	}
   466  	if err := w.catacomb.Add(applicationw); err != nil {
   467  		return errors.Trace(err)
   468  	}
   469  	requiredEvents++
   470  
   471  	if w.modelType == model.IAAS {
   472  		// Only IAAS models support upgrading the machine series.
   473  		// TODO(externalreality) This pattern should probably be extracted
   474  		upgradeSeriesw, err := w.unit.WatchUpgradeSeriesNotifications()
   475  		if err != nil {
   476  			return errors.Trace(err)
   477  		}
   478  		if err := w.catacomb.Add(upgradeSeriesw); err != nil {
   479  			return errors.Trace(err)
   480  		}
   481  		upgradeSeriesChanges = upgradeSeriesw.Changes()
   482  		requiredEvents++
   483  	}
   484  
   485  	if w.canApplyCharmProfile {
   486  		// Note: canApplyCharmProfile will be false for a CAAS model.
   487  		instanceDataW, err := w.unit.WatchInstanceData()
   488  		if err != nil {
   489  			return errors.Trace(err)
   490  		}
   491  		if err := w.catacomb.Add(instanceDataW); err != nil {
   492  			return errors.Trace(err)
   493  		}
   494  		instanceDataChannel = instanceDataW.Changes()
   495  		requiredEvents++
   496  	}
   497  
   498  	var seenStorageChange bool
   499  	storagew, err := w.unit.WatchStorage()
   500  	if err != nil {
   501  		return errors.Trace(err)
   502  	}
   503  	if err := w.catacomb.Add(storagew); err != nil {
   504  		return errors.Trace(err)
   505  	}
   506  	requiredEvents++
   507  
   508  	var seenLeaderSettingsChange bool
   509  	leaderSettingsw, err := w.application.WatchLeadershipSettings()
   510  	if err != nil {
   511  		return errors.Trace(err)
   512  	}
   513  	if err := w.catacomb.Add(leaderSettingsw); err != nil {
   514  		return errors.Trace(err)
   515  	}
   516  	requiredEvents++
   517  
   518  	var seenActionsChange bool
   519  	actionsw, err := w.unit.WatchActionNotifications()
   520  	if err != nil {
   521  		return errors.Trace(err)
   522  	}
   523  	if err := w.catacomb.Add(actionsw); err != nil {
   524  		return errors.Trace(err)
   525  	}
   526  	requiredEvents++
   527  
   528  	var seenUpdateStatusIntervalChange bool
   529  	updateStatusIntervalw, err := w.st.WatchUpdateStatusHookInterval()
   530  	if err != nil {
   531  		return errors.Trace(err)
   532  	}
   533  	if err := w.catacomb.Add(updateStatusIntervalw); err != nil {
   534  		return errors.Trace(err)
   535  	}
   536  	requiredEvents++
   537  
   538  	var seenLeadershipChange bool
   539  	// There's no watcher for this per se; we wait on a channel
   540  	// returned by the leadership tracker.
   541  	requiredEvents++
   542  
   543  	var eventsObserved int
   544  	observedEvent := func(flag *bool) {
   545  		if flag == nil || !*flag {
   546  			*flag = true
   547  			eventsObserved++
   548  		}
   549  	}
   550  
   551  	// fire will, once the first event for each watcher has
   552  	// been observed, send a signal on the out channel.
   553  	fire := func() {
   554  		if eventsObserved != requiredEvents {
   555  			return
   556  		}
   557  		select {
   558  		case w.out <- struct{}{}:
   559  		default:
   560  		}
   561  	}
   562  
   563  	// Check the initial leadership status, and then we can flip-flop
   564  	// waiting on leader or minion to trigger the changed event.
   565  	var waitLeader, waitMinion <-chan struct{}
   566  	claimLeader := w.leadershipTracker.ClaimLeader()
   567  	select {
   568  	case <-w.catacomb.Dying():
   569  		return w.catacomb.ErrDying()
   570  	case <-claimLeader.Ready():
   571  		isLeader := claimLeader.Wait()
   572  		if err := w.leadershipChanged(isLeader); err != nil {
   573  			return errors.Trace(err)
   574  		}
   575  		if isLeader {
   576  			waitMinion = w.leadershipTracker.WaitMinion().Ready()
   577  		} else {
   578  			waitLeader = w.leadershipTracker.WaitLeader().Ready()
   579  		}
   580  		observedEvent(&seenLeadershipChange)
   581  	}
   582  
   583  	var updateStatusInterval time.Duration
   584  	var updateStatusTimer <-chan time.Time
   585  	resetUpdateStatusTimer := func() {
   586  		updateStatusTimer = w.updateStatusChannel(updateStatusInterval).After()
   587  	}
   588  
   589  	for {
   590  		select {
   591  		case <-w.catacomb.Dying():
   592  			return w.catacomb.ErrDying()
   593  
   594  		case _, ok := <-unitw.Changes():
   595  			w.logger.Debugf("got unit change for %s", w.unit.Tag().Id())
   596  			if !ok {
   597  				return errors.New("unit watcher closed")
   598  			}
   599  			if err := w.unitChanged(); err != nil {
   600  				return errors.Trace(err)
   601  			}
   602  			observedEvent(&seenUnitChange)
   603  
   604  		case _, ok := <-applicationw.Changes():
   605  			w.logger.Debugf("got application change for %s", w.unit.Tag().Id())
   606  			if !ok {
   607  				return errors.New("application watcher closed")
   608  			}
   609  			if err := w.applicationChanged(); err != nil {
   610  				return errors.Trace(err)
   611  			}
   612  			observedEvent(&seenApplicationChange)
   613  
   614  		case secrets, ok := <-secretsChanges:
   615  			w.logger.Debugf("got secrets change for %s: %s", w.unit.Tag().Id(), secrets)
   616  			if !ok {
   617  				return errors.New("secrets watcher closed")
   618  			}
   619  			if err := w.secretsChanged(secrets); err != nil {
   620  				return errors.Trace(err)
   621  			}
   622  			observedEvent(&seenSecretsChange)
   623  
   624  		case _, ok := <-instanceDataChannel:
   625  			w.logger.Debugf("got instance data change for %s", w.unit.Tag().Id())
   626  			if !ok {
   627  				return errors.New("instance data watcher closed")
   628  			}
   629  			if err := w.instanceDataChanged(); err != nil {
   630  				return errors.Trace(err)
   631  			}
   632  			observedEvent(&seenInstanceDataChange)
   633  
   634  		case _, ok := <-w.containerRunningStatusChannel:
   635  			w.logger.Debugf("got running status change for %s", w.unit.Tag().Id())
   636  			if !ok {
   637  				return errors.New("running status watcher closed")
   638  			}
   639  			if w.current.ProviderID == "" {
   640  				if err := w.unitChanged(); err != nil {
   641  					return errors.Trace(err)
   642  				}
   643  				if w.current.ProviderID == "" {
   644  					// This shouldn't happen.
   645  					w.logger.Warningf("we should already be assigned a provider id for %s but got an empty id", w.unit.Tag().Id())
   646  					return nil
   647  				}
   648  			}
   649  			runningStatus, err := w.containerRunningStatusFunc(w.current.ProviderID)
   650  			if err != nil && !errors.IsNotFound(err) {
   651  				return errors.Annotatef(err, "getting container running status for %q", unitTag.String())
   652  			}
   653  			if runningStatus != nil {
   654  				w.containerRunningStatus(*runningStatus)
   655  			}
   656  
   657  		case hashes, ok := <-charmConfigw.Changes():
   658  			w.logger.Debugf("got config change for %s: ok=%t, hashes=%v", w.unit.Tag().Id(), ok, hashes)
   659  			if !ok {
   660  				return errors.New("config watcher closed")
   661  			}
   662  			if len(hashes) != 1 {
   663  				return errors.New("expected one hash in config change")
   664  			}
   665  			w.configHashChanged(hashes[0])
   666  			observedEvent(&seenConfigChange)
   667  
   668  		case hashes, ok := <-trustConfigw.Changes():
   669  			w.logger.Debugf("got trust config change for %s: ok=%t, hashes=%v", w.unit.Tag().Id(), ok, hashes)
   670  			if !ok {
   671  				return errors.New("trust config watcher closed")
   672  			}
   673  			if len(hashes) != 1 {
   674  				return errors.New("expected one hash in trust config change")
   675  			}
   676  			w.trustHashChanged(hashes[0])
   677  			observedEvent(&seenTrustConfigChange)
   678  
   679  		case _, ok := <-upgradeSeriesChanges:
   680  			w.logger.Debugf("got upgrade series change")
   681  			if !ok {
   682  				return errors.New("upgrades series watcher closed")
   683  			}
   684  			if err := w.upgradeSeriesStatusChanged(); err != nil {
   685  				return errors.Trace(err)
   686  			}
   687  			observedEvent(&seenUpgradeSeriesChange)
   688  
   689  		case hashes, ok := <-addressesChanges:
   690  			w.logger.Debugf("got address change for %s: ok=%t, hashes=%v", w.unit.Tag().Id(), ok, hashes)
   691  			if !ok {
   692  				return errors.New("addresses watcher closed")
   693  			}
   694  			if len(hashes) != 1 {
   695  				return errors.New("expected one hash in addresses change")
   696  			}
   697  			w.addressesHashChanged(hashes[0])
   698  			observedEvent(&seenAddressesChange)
   699  
   700  		case _, ok := <-leaderSettingsw.Changes():
   701  			w.logger.Debugf("got leader settings change for %s: ok=%t", w.unit.Tag().Id(), ok)
   702  			if !ok {
   703  				return errors.New("leader settings watcher closed")
   704  			}
   705  			if err := w.leaderSettingsChanged(); err != nil {
   706  				return errors.Trace(err)
   707  			}
   708  			observedEvent(&seenLeaderSettingsChange)
   709  
   710  		case actions, ok := <-actionsw.Changes():
   711  			w.logger.Debugf("got action change for %s: %v ok=%t", w.unit.Tag().Id(), actions, ok)
   712  			if !ok {
   713  				return errors.New("actions watcher closed")
   714  			}
   715  			w.actionsChanged(actions)
   716  			observedEvent(&seenActionsChange)
   717  
   718  		case keys, ok := <-relationsw.Changes():
   719  			w.logger.Debugf("got relations change for %s: ok=%t", w.unit.Tag().Id(), ok)
   720  			if !ok {
   721  				return errors.New("relations watcher closed")
   722  			}
   723  			if err := w.relationsChanged(keys); err != nil {
   724  				return errors.Trace(err)
   725  			}
   726  			observedEvent(&seenRelationsChange)
   727  
   728  		case keys, ok := <-storagew.Changes():
   729  			w.logger.Debugf("got storage change for %s: %v ok=%t", w.unit.Tag().Id(), keys, ok)
   730  			if !ok {
   731  				return errors.New("storage watcher closed")
   732  			}
   733  			if err := w.storageChanged(keys); err != nil {
   734  				return errors.Trace(err)
   735  			}
   736  			observedEvent(&seenStorageChange)
   737  
   738  		case _, ok := <-updateStatusIntervalw.Changes():
   739  			w.logger.Debugf("got update status interval change for %s: ok=%t", w.unit.Tag().Id(), ok)
   740  			if !ok {
   741  				return errors.New("update status interval watcher closed")
   742  			}
   743  			observedEvent(&seenUpdateStatusIntervalChange)
   744  
   745  			var err error
   746  			updateStatusInterval, err = w.st.UpdateStatusHookInterval()
   747  			if err != nil {
   748  				return errors.Trace(err)
   749  			}
   750  			wasActive := updateStatusTimer != nil
   751  			resetUpdateStatusTimer()
   752  			if wasActive {
   753  				// This is not the first time we've seen an update
   754  				// status interval change, so there's no need to
   755  				// fall out and fire an initial change event.
   756  				continue
   757  			}
   758  
   759  		case <-waitMinion:
   760  			w.logger.Debugf("got leadership change for %v: minion", unitTag.Id())
   761  			if err := w.leadershipChanged(false); err != nil {
   762  				return errors.Trace(err)
   763  			}
   764  			waitMinion = nil
   765  			waitLeader = w.leadershipTracker.WaitLeader().Ready()
   766  
   767  		case <-waitLeader:
   768  			w.logger.Debugf("got leadership change for %v: leader", unitTag.Id())
   769  			if err := w.leadershipChanged(true); err != nil {
   770  				return errors.Trace(err)
   771  			}
   772  			waitLeader = nil
   773  			waitMinion = w.leadershipTracker.WaitMinion().Ready()
   774  
   775  		case uris, ok := <-w.rotateSecretsChanges:
   776  			if !ok || len(uris) == 0 {
   777  				continue
   778  			}
   779  			w.logger.Debugf("got rotate secret URIs: %q", uris)
   780  			w.rotateSecretURIs(uris)
   781  
   782  		case revisions, ok := <-w.expireSecretsChanges:
   783  			if !ok || len(revisions) == 0 {
   784  				continue
   785  			}
   786  			w.logger.Debugf("got expired secret revisions: %q", revisions)
   787  			w.expireSecretRevisions(revisions)
   788  
   789  		case secretRevisions, ok := <-w.obsoleteRevisionChanges:
   790  			w.logger.Debugf("got obsolete secret revisions change for %s: %s", w.application.Tag().Id(), secretRevisions)
   791  			if !ok {
   792  				return errors.New("secret revisions watcher closed")
   793  			}
   794  			if err := w.secretObsoleteRevisionsChanged(secretRevisions); err != nil {
   795  				return errors.Trace(err)
   796  			}
   797  
   798  		case change := <-w.storageAttachmentChanges:
   799  			w.logger.Debugf("storage attachment change for %s: %v", w.unit.Tag().Id(), change)
   800  			w.storageAttachmentChanged(change)
   801  
   802  		case change := <-w.relationUnitsChanges:
   803  			w.logger.Debugf("got a relation units change for %s : %v", w.unit.Tag().Id(), change)
   804  			if err := w.relationUnitsChanged(change); err != nil {
   805  				return errors.Trace(err)
   806  			}
   807  
   808  		case <-updateStatusTimer:
   809  			w.logger.Debugf("update status timer triggered for %s", w.unit.Tag().Id())
   810  			w.updateStatusChanged()
   811  			resetUpdateStatusTimer()
   812  
   813  		case id, ok := <-w.commandChannel:
   814  			if !ok {
   815  				return errors.New("commandChannel closed")
   816  			}
   817  			w.logger.Debugf("command enqueued for %s: %v", w.unit.Tag().Id(), id)
   818  			w.commandsChanged(id)
   819  
   820  		case id, ok := <-w.workloadEventChannel:
   821  			if !ok {
   822  				return errors.New("workloadEventChannel closed")
   823  			}
   824  			w.logger.Debugf("workloadEvent enqueued for %s: %v", w.unit.Tag().Id(), id)
   825  			w.workloadEventsChanged(id)
   826  
   827  		case _, ok := <-w.retryHookChannel:
   828  			if !ok {
   829  				return errors.New("retryHookChannel closed")
   830  			}
   831  			w.logger.Debugf("retry hook timer triggered for %s", w.unit.Tag().Id())
   832  			w.retryHookTimerTriggered()
   833  
   834  		case shutdown, ok := <-w.shutdownChannel:
   835  			if !ok {
   836  				return errors.New("shutdownChannel closed")
   837  			}
   838  			if shutdown {
   839  				w.markShutdown()
   840  			}
   841  		}
   842  
   843  		// Something changed.
   844  		fire()
   845  	}
   846  }
   847  
   848  // upgradeSeriesStatusChanged is called when the remote status of a series
   849  // upgrade changes.
   850  func (w *RemoteStateWatcher) upgradeSeriesStatusChanged() error {
   851  	w.mu.Lock()
   852  	defer w.mu.Unlock()
   853  
   854  	status, target, err := w.upgradeSeriesStatus()
   855  	if errors.IsNotFound(err) {
   856  		// There is no remote state so no upgrade is started.
   857  		w.logger.Debugf("no upgrade series in progress, reinitializing local upgrade series state")
   858  		w.current.UpgradeMachineStatus = model.UpgradeSeriesNotStarted
   859  		return nil
   860  	}
   861  	if err != nil {
   862  		return errors.Trace(err)
   863  	}
   864  
   865  	w.current.UpgradeMachineStatus = status
   866  	w.current.UpgradeMachineTarget = target
   867  
   868  	return nil
   869  }
   870  
   871  func (w *RemoteStateWatcher) upgradeSeriesStatus() (model.UpgradeSeriesStatus, string, error) {
   872  	status, target, err := w.unit.UpgradeSeriesStatus()
   873  	if err != nil {
   874  		return "", "", errors.Trace(err)
   875  	}
   876  
   877  	graph := model.UpgradeSeriesGraph()
   878  	if err := graph.Validate(); err != nil {
   879  		return "", "", errors.Trace(err)
   880  	}
   881  	if !graph.ValidState(status) {
   882  		return "", "", errors.NotValidf("upgrade series %q is", status)
   883  	}
   884  	return status, target, nil
   885  }
   886  
   887  // updateStatusChanged is called when the update status timer expires.
   888  func (w *RemoteStateWatcher) updateStatusChanged() {
   889  	w.mu.Lock()
   890  	w.current.UpdateStatusVersion++
   891  	w.mu.Unlock()
   892  }
   893  
   894  // commandsChanged is called when a command is enqueued.
   895  func (w *RemoteStateWatcher) commandsChanged(id string) {
   896  	w.mu.Lock()
   897  	w.current.Commands = append(w.current.Commands, id)
   898  	w.mu.Unlock()
   899  }
   900  
   901  // workloadEventsChanged is called when a container event is enqueued.
   902  func (w *RemoteStateWatcher) workloadEventsChanged(id string) {
   903  	w.mu.Lock()
   904  	defer w.mu.Unlock()
   905  	// Ensure we don't add the same ID twice.
   906  	for _, otherId := range w.current.WorkloadEvents {
   907  		if otherId == id {
   908  			return
   909  		}
   910  	}
   911  	w.current.WorkloadEvents = append(w.current.WorkloadEvents, id)
   912  }
   913  
   914  // retryHookTimerTriggered is called when the retry hook timer expires.
   915  func (w *RemoteStateWatcher) retryHookTimerTriggered() {
   916  	w.mu.Lock()
   917  	w.current.RetryHookVersion++
   918  	w.mu.Unlock()
   919  }
   920  
   921  // unitChanged responds to changes in the unit.
   922  func (w *RemoteStateWatcher) unitChanged() error {
   923  	if err := w.unit.Refresh(); err != nil {
   924  		return errors.Trace(err)
   925  	}
   926  	w.mu.Lock()
   927  	defer w.mu.Unlock()
   928  	w.current.Life = w.unit.Life()
   929  	w.current.ResolvedMode = w.unit.Resolved()
   930  	// It's ok to sync provider ID by watching unit rather than
   931  	// cloud container because it will not change once pod created.
   932  	w.current.ProviderID = w.unit.ProviderID()
   933  	return nil
   934  }
   935  
   936  // applicationChanged responds to changes in the application.
   937  func (w *RemoteStateWatcher) applicationChanged() error {
   938  	if err := w.application.Refresh(); err != nil {
   939  		return errors.Trace(err)
   940  	}
   941  	url, force, err := w.application.CharmURL()
   942  	if err != nil {
   943  		return errors.Trace(err)
   944  	}
   945  	required := false
   946  	if w.canApplyCharmProfile {
   947  		ch, err := w.st.Charm(url)
   948  		if err != nil {
   949  			return errors.Trace(err)
   950  		}
   951  		required, err = ch.LXDProfileRequired()
   952  		if err != nil {
   953  			return errors.Trace(err)
   954  		}
   955  	}
   956  	ver, err := w.application.CharmModifiedVersion()
   957  	if err != nil {
   958  		return errors.Trace(err)
   959  	}
   960  	// CAAS sidecar charms will wait for the provider to restart/recreate
   961  	// the unit before performing an upgrade.
   962  	if w.sidecar && ver != w.enforcedCharmModifiedVersion {
   963  		return nil
   964  	}
   965  	w.mu.Lock()
   966  	w.current.CharmURL = url
   967  	w.current.ForceCharmUpgrade = force
   968  	w.current.CharmModifiedVersion = ver
   969  	w.current.CharmProfileRequired = required
   970  	w.mu.Unlock()
   971  	return nil
   972  }
   973  
   974  // secretsChanged responds to changes in secrets.
   975  func (w *RemoteStateWatcher) secretsChanged(secretURIs []string) error {
   976  	w.mu.Lock()
   977  	defer w.mu.Unlock()
   978  	info, err := w.secretsClient.GetConsumerSecretsRevisionInfo(w.unit.Tag().Id(), secretURIs)
   979  	if err != nil {
   980  		return errors.Trace(err)
   981  	}
   982  	w.logger.Debugf("got latest secret info: %#v", info)
   983  	for _, uri := range secretURIs {
   984  		if latest, ok := info[uri]; ok {
   985  			w.current.ConsumedSecretInfo[uri] = latest
   986  		} else {
   987  			delete(w.current.ConsumedSecretInfo, uri)
   988  			deleted := set.NewStrings(w.current.DeletedSecrets...)
   989  			deleted.Add(uri)
   990  			w.current.DeletedSecrets = deleted.SortedValues()
   991  		}
   992  	}
   993  	w.logger.Debugf("deleted secrets: %v", w.current.DeletedSecrets)
   994  	w.logger.Debugf("obsolete secrets: %v", w.current.ObsoleteSecretRevisions)
   995  	return nil
   996  }
   997  
   998  func (w *RemoteStateWatcher) secretObsoleteRevisionsChanged(secretRevisions []string) error {
   999  	w.mu.Lock()
  1000  	defer w.mu.Unlock()
  1001  	for _, revInfo := range secretRevisions {
  1002  		parts := strings.Split(revInfo, "/")
  1003  		uri := parts[0]
  1004  		if len(parts) < 2 {
  1005  			deleted := set.NewStrings(w.current.DeletedSecrets...)
  1006  			deleted.Add(uri)
  1007  			w.current.DeletedSecrets = deleted.SortedValues()
  1008  			continue
  1009  		}
  1010  		rev, err := strconv.Atoi(parts[1])
  1011  		if err != nil {
  1012  			return errors.NotValidf("secret revision %q for %q", parts[1], uri)
  1013  		}
  1014  		obsolete := set.NewInts(w.current.ObsoleteSecretRevisions[uri]...)
  1015  		obsolete.Add(rev)
  1016  		w.current.ObsoleteSecretRevisions[uri] = obsolete.SortedValues()
  1017  	}
  1018  	w.logger.Debugf("obsolete secret revisions: %v", w.current.ObsoleteSecretRevisions)
  1019  	w.logger.Debugf("deleted secrets: %v", w.current.DeletedSecrets)
  1020  	return nil
  1021  }
  1022  
  1023  func (w *RemoteStateWatcher) instanceDataChanged() error {
  1024  	name, err := w.unit.LXDProfileName()
  1025  	if err != nil {
  1026  		return errors.Trace(err)
  1027  	}
  1028  	w.mu.Lock()
  1029  	w.current.LXDProfileName = name
  1030  	w.mu.Unlock()
  1031  	w.logger.Debugf("LXDProfileName changed to %q", name)
  1032  	return nil
  1033  }
  1034  
  1035  func (w *RemoteStateWatcher) configHashChanged(value string) {
  1036  	w.mu.Lock()
  1037  	w.current.ConfigHash = value
  1038  	w.mu.Unlock()
  1039  }
  1040  
  1041  func (w *RemoteStateWatcher) trustHashChanged(value string) {
  1042  	w.mu.Lock()
  1043  	w.current.TrustHash = value
  1044  	w.mu.Unlock()
  1045  }
  1046  
  1047  func (w *RemoteStateWatcher) addressesHashChanged(value string) {
  1048  	w.mu.Lock()
  1049  	w.current.AddressesHash = value
  1050  	w.mu.Unlock()
  1051  }
  1052  
  1053  func (w *RemoteStateWatcher) leaderSettingsChanged() error {
  1054  	w.mu.Lock()
  1055  	w.current.LeaderSettingsVersion++
  1056  	w.mu.Unlock()
  1057  	return nil
  1058  }
  1059  
  1060  func (w *RemoteStateWatcher) leadershipChanged(isLeader bool) error {
  1061  	w.mu.Lock()
  1062  	defer w.mu.Unlock()
  1063  
  1064  	w.current.Leader = isLeader
  1065  	if w.secretRotateWatcher != nil {
  1066  		_ = worker.Stop(w.secretRotateWatcher)
  1067  	}
  1068  	w.secretRotateWatcher = nil
  1069  	w.rotateSecretsChanges = nil
  1070  	w.current.SecretRotations = nil
  1071  
  1072  	if w.secretExpiryWatcher != nil {
  1073  		_ = worker.Stop(w.secretExpiryWatcher)
  1074  	}
  1075  	w.secretExpiryWatcher = nil
  1076  	w.expireSecretsChanges = nil
  1077  	w.current.ExpiredSecretRevisions = nil
  1078  
  1079  	if w.obsoleteRevisionWatcher != nil {
  1080  		_ = worker.Stop(w.obsoleteRevisionWatcher)
  1081  	}
  1082  	w.obsoleteRevisionWatcher = nil
  1083  	w.obsoleteRevisionChanges = nil
  1084  
  1085  	// Allow a generous buffer so a slow unit agent does not
  1086  	// block the upstream worker.
  1087  	w.rotateSecretsChanges = make(chan []string, 100)
  1088  	w.logger.Debugf("starting secrets rotation watcher")
  1089  	rotateWatcher, err := w.secretRotateWatcherFunc(w.unit.Tag(), isLeader, w.rotateSecretsChanges)
  1090  	if err != nil {
  1091  		return errors.Trace(err)
  1092  	}
  1093  	if err := w.catacomb.Add(rotateWatcher); err != nil {
  1094  		return errors.Trace(err)
  1095  	}
  1096  	w.secretRotateWatcher = rotateWatcher
  1097  
  1098  	// Allow a generous buffer so a slow unit agent does not
  1099  	// block the upstream worker.
  1100  	w.expireSecretsChanges = make(chan []string, 100)
  1101  	w.logger.Debugf("starting secret revisions expiry watcher")
  1102  	expiryWatcher, err := w.secretExpiryWatcherFunc(w.unit.Tag(), isLeader, w.expireSecretsChanges)
  1103  	if err != nil {
  1104  		return errors.Trace(err)
  1105  	}
  1106  	if err := w.catacomb.Add(expiryWatcher); err != nil {
  1107  		return errors.Trace(err)
  1108  	}
  1109  	w.secretExpiryWatcher = expiryWatcher
  1110  
  1111  	// Allow a generous buffer so a slow unit agent does not
  1112  	// block the upstream worker.
  1113  	w.obsoleteRevisionChanges = make(chan []string, 100)
  1114  	w.logger.Debugf("starting obsolete secret revisions watcher")
  1115  	owners := []names.Tag{w.unit.Tag()}
  1116  	if isLeader {
  1117  		appName, _ := names.UnitApplication(w.unit.Tag().Id())
  1118  		owners = append(owners, names.NewApplicationTag(appName))
  1119  	}
  1120  	obsoleteRevisionsWatcher, err := w.secretsClient.WatchObsolete(owners...)
  1121  	if err != nil {
  1122  		return errors.Trace(err)
  1123  	}
  1124  	if err := w.catacomb.Add(obsoleteRevisionsWatcher); err != nil {
  1125  		return errors.Trace(err)
  1126  	}
  1127  	w.obsoleteRevisionWatcher = obsoleteRevisionsWatcher
  1128  	w.obsoleteRevisionChanges = obsoleteRevisionsWatcher.Changes()
  1129  
  1130  	return nil
  1131  }
  1132  
  1133  // rotateSecretURIs adds the specified URLs to those that need
  1134  // to be rotated.
  1135  func (w *RemoteStateWatcher) rotateSecretURIs(uris []string) {
  1136  	w.mu.Lock()
  1137  	defer w.mu.Unlock()
  1138  
  1139  	pending := set.NewStrings(w.current.SecretRotations...)
  1140  	for _, uri := range uris {
  1141  		if !pending.Contains(uri) {
  1142  			pending.Add(uri)
  1143  			w.current.SecretRotations = append(w.current.SecretRotations, uri)
  1144  		}
  1145  	}
  1146  }
  1147  
  1148  // expireSecretRevisions adds the specified secret revisions
  1149  // to those that need to be expired.
  1150  func (w *RemoteStateWatcher) expireSecretRevisions(revisions []string) {
  1151  	w.mu.Lock()
  1152  	defer w.mu.Unlock()
  1153  
  1154  	pending := set.NewStrings(w.current.ExpiredSecretRevisions...)
  1155  	for _, rev := range revisions {
  1156  		if !pending.Contains(rev) {
  1157  			pending.Add(rev)
  1158  			w.current.ExpiredSecretRevisions = append(w.current.ExpiredSecretRevisions, rev)
  1159  		}
  1160  	}
  1161  }
  1162  
  1163  // relationsChanged responds to application relation changes.
  1164  func (w *RemoteStateWatcher) relationsChanged(keys []string) error {
  1165  	w.mu.Lock()
  1166  	defer w.mu.Unlock()
  1167  
  1168  	// NOTE (stickupkid): Any return nil or early exit during the iteration of
  1169  	// the keys that is non-exhaustive can cause units (subordinates) to
  1170  	// commit suicide.
  1171  
  1172  	for _, key := range keys {
  1173  		relationTag := names.NewRelationTag(key)
  1174  		rel, err := w.st.Relation(relationTag)
  1175  		if params.IsCodeNotFoundOrCodeUnauthorized(err) {
  1176  			// If it's actually gone, this unit cannot have entered
  1177  			// scope, and therefore never needs to know about it.
  1178  			if ruw, ok := w.relations[relationTag]; ok {
  1179  				_ = worker.Stop(ruw)
  1180  				delete(w.relations, relationTag)
  1181  				delete(w.current.Relations, ruw.relationId)
  1182  			}
  1183  		} else if err != nil {
  1184  			return errors.Trace(err)
  1185  		} else if relErr := w.ensureRelationUnits(rel); relErr != nil {
  1186  			return errors.Trace(relErr)
  1187  		}
  1188  	}
  1189  	return nil
  1190  }
  1191  
  1192  func (w *RemoteStateWatcher) ensureRelationUnits(rel Relation) error {
  1193  	relationTag := rel.Tag()
  1194  	if _, ok := w.relations[relationTag]; ok {
  1195  		// We're already watching this one, so just update life/suspension status
  1196  		relationSnapshot := w.current.Relations[rel.Id()]
  1197  		relationSnapshot.Life = rel.Life()
  1198  		relationSnapshot.Suspended = rel.Suspended()
  1199  		w.current.Relations[rel.Id()] = relationSnapshot
  1200  		if rel.Suspended() {
  1201  			// Relation has been suspended, so stop the listeners here.
  1202  			// The relation itself is retained in the current relations
  1203  			// in the suspended state so that departed/broken hooks can run.
  1204  			if ruw, ok := w.relations[relationTag]; ok {
  1205  				err := worker.Stop(ruw)
  1206  				if err != nil {
  1207  					// This was always silently ignored, so it can't be
  1208  					// particularly useful, but avoid suppressing errors entirely.
  1209  					w.logger.Debugf("error stopping relation watcher for %s: %v", w.unit.Tag().Id(), err)
  1210  				}
  1211  				delete(w.relations, relationTag)
  1212  			}
  1213  		}
  1214  		return nil
  1215  	}
  1216  	// We weren't watching it already, but if the relation is suspended,
  1217  	// we don't need to start watching it.
  1218  	if rel.Suspended() {
  1219  		return nil
  1220  	}
  1221  	return errors.Trace(w.watchRelationUnits(rel))
  1222  }
  1223  
  1224  // watchRelationUnits starts watching the relation units for the given
  1225  // relation, waits for its first event, and records the information in
  1226  // the current snapshot.
  1227  func (w *RemoteStateWatcher) watchRelationUnits(rel Relation) error {
  1228  	ruw, err := w.st.WatchRelationUnits(rel.Tag(), w.unit.Tag())
  1229  	// Deal with the race where Relation returned a valid, perhaps dying
  1230  	// relation, but by the time we ask to watch it, we get unauthorized
  1231  	// because it is no longer around.
  1232  	if params.IsCodeNotFoundOrCodeUnauthorized(err) {
  1233  		return nil
  1234  	} else if err != nil {
  1235  		return errors.Trace(err)
  1236  	}
  1237  	// Because of the delay before handing off responsibility to
  1238  	// wrapRelationUnitsWatcher below, add to our own catacomb to
  1239  	// ensure errors get picked up if they happen.
  1240  	if err := w.catacomb.Add(ruw); err != nil {
  1241  		return errors.Trace(err)
  1242  	}
  1243  	relationSnapshot := RelationSnapshot{
  1244  		Life:               rel.Life(),
  1245  		Suspended:          rel.Suspended(),
  1246  		Members:            make(map[string]int64),
  1247  		ApplicationMembers: make(map[string]int64),
  1248  	}
  1249  	// Handle the first change to populate the Members map.
  1250  	select {
  1251  	case <-w.catacomb.Dying():
  1252  		return w.catacomb.ErrDying()
  1253  	case change, ok := <-ruw.Changes():
  1254  		if !ok {
  1255  			return errors.New("relation units watcher closed")
  1256  		}
  1257  		for unit, settings := range change.Changed {
  1258  			relationSnapshot.Members[unit] = settings.Version
  1259  		}
  1260  		for app, settingsVersion := range change.AppChanged {
  1261  			relationSnapshot.ApplicationMembers[app] = settingsVersion
  1262  		}
  1263  	}
  1264  	// Wrap the Changes() with the relationId so we can process all changes
  1265  	// via the same channel.
  1266  	innerRUW, err := wrapRelationUnitsWatcher(rel.Id(), ruw, w.relationUnitsChanges)
  1267  	if err != nil {
  1268  		return errors.Trace(err)
  1269  	}
  1270  	if err := w.catacomb.Add(innerRUW); err != nil {
  1271  		return errors.Trace(err)
  1272  	}
  1273  	w.current.Relations[rel.Id()] = relationSnapshot
  1274  	w.relations[rel.Tag()] = innerRUW
  1275  	return nil
  1276  }
  1277  
  1278  // relationUnitsChanged responds to relation units changes.
  1279  func (w *RemoteStateWatcher) relationUnitsChanged(change relationUnitsChange) error {
  1280  	w.mu.Lock()
  1281  	defer w.mu.Unlock()
  1282  	snapshot, ok := w.current.Relations[change.relationId]
  1283  	if !ok {
  1284  		return nil
  1285  	}
  1286  	for unit, settings := range change.Changed {
  1287  		snapshot.Members[unit] = settings.Version
  1288  	}
  1289  	for app, settingsVersion := range change.AppChanged {
  1290  		snapshot.ApplicationMembers[app] = settingsVersion
  1291  	}
  1292  	for _, unit := range change.Departed {
  1293  		delete(snapshot.Members, unit)
  1294  	}
  1295  	return nil
  1296  }
  1297  
  1298  // storageAttachmentChanged responds to storage attachment changes.
  1299  func (w *RemoteStateWatcher) storageAttachmentChanged(change storageAttachmentChange) {
  1300  	w.mu.Lock()
  1301  	w.current.Storage[change.Tag] = change.Snapshot
  1302  	w.mu.Unlock()
  1303  }
  1304  
  1305  func (w *RemoteStateWatcher) actionsChanged(actions []string) {
  1306  	w.mu.Lock()
  1307  	defer w.mu.Unlock()
  1308  	for _, action := range actions {
  1309  		// If we already have the action, signal a change.
  1310  		if r, ok := w.current.ActionChanged[action]; ok {
  1311  			w.current.ActionChanged[action] = r + 1
  1312  		} else {
  1313  			w.current.ActionsPending = append(w.current.ActionsPending, action)
  1314  			w.current.ActionChanged[action] = 0
  1315  		}
  1316  	}
  1317  }
  1318  
  1319  func (w *RemoteStateWatcher) containerRunningStatus(runningStatus ContainerRunningStatus) {
  1320  	w.mu.Lock()
  1321  	w.logger.Debugf("running status update for %s(provider-id=%s): %+v", w.unit.Tag(), w.current.ProviderID, runningStatus)
  1322  	w.current.ActionsBlocked = !runningStatus.Running
  1323  	w.current.ContainerRunningStatus = &runningStatus
  1324  	w.mu.Unlock()
  1325  }
  1326  
  1327  // storageChanged responds to unit storage changes.
  1328  func (w *RemoteStateWatcher) storageChanged(keys []string) error {
  1329  	tags := make([]names.StorageTag, len(keys))
  1330  	for i, key := range keys {
  1331  		tags[i] = names.NewStorageTag(key)
  1332  	}
  1333  	ids := make([]params.StorageAttachmentId, len(keys))
  1334  	for i, tag := range tags {
  1335  		ids[i] = params.StorageAttachmentId{
  1336  			StorageTag: tag.String(),
  1337  			UnitTag:    w.unit.Tag().String(),
  1338  		}
  1339  	}
  1340  	results, err := w.st.StorageAttachmentLife(ids)
  1341  	if err != nil {
  1342  		return errors.Trace(err)
  1343  	}
  1344  
  1345  	w.mu.Lock()
  1346  	defer w.mu.Unlock()
  1347  
  1348  	for i, result := range results {
  1349  		tag := tags[i]
  1350  		if result.Error == nil {
  1351  			if storageSnapshot, ok := w.current.Storage[tag]; ok {
  1352  				// We've previously started a watcher for this storage
  1353  				// attachment, so all we needed to do was update the
  1354  				// lifecycle state.
  1355  				storageSnapshot.Life = result.Life
  1356  				w.current.Storage[tag] = storageSnapshot
  1357  				continue
  1358  			}
  1359  			// We haven't seen this storage attachment before, so start
  1360  			// a watcher now; add it to our catacomb in case of mishap;
  1361  			// and wait for the initial event.
  1362  			saw, err := w.st.WatchStorageAttachment(tag, w.unit.Tag())
  1363  			if err != nil {
  1364  				return errors.Annotate(err, "watching storage attachment")
  1365  			}
  1366  			if err := w.catacomb.Add(saw); err != nil {
  1367  				return errors.Trace(err)
  1368  			}
  1369  			if err := w.watchStorageAttachment(tag, result.Life, saw); err != nil {
  1370  				return errors.Trace(err)
  1371  			}
  1372  		} else if params.IsCodeNotFound(result.Error) {
  1373  			if watcher, ok := w.storageAttachmentWatchers[tag]; ok {
  1374  				// already under catacomb management, any error tracked already
  1375  				_ = worker.Stop(watcher)
  1376  				delete(w.storageAttachmentWatchers, tag)
  1377  			}
  1378  			delete(w.current.Storage, tag)
  1379  		} else {
  1380  			return errors.Annotatef(
  1381  				result.Error, "getting life of %s attachment for %s",
  1382  				names.ReadableString(tag), w.unit.Tag().Id(),
  1383  			)
  1384  		}
  1385  	}
  1386  	return nil
  1387  }
  1388  
  1389  // watchStorageAttachment starts watching the storage attachment with
  1390  // the specified storage tag, waits for its first event, and records
  1391  // the information in the current snapshot.
  1392  func (w *RemoteStateWatcher) watchStorageAttachment(
  1393  	tag names.StorageTag,
  1394  	life life.Value,
  1395  	saw watcher.NotifyWatcher,
  1396  ) error {
  1397  	var storageSnapshot StorageSnapshot
  1398  	select {
  1399  	case <-w.catacomb.Dying():
  1400  		return w.catacomb.ErrDying()
  1401  	case _, ok := <-saw.Changes():
  1402  		if !ok {
  1403  			return errors.Errorf("storage attachment watcher closed for %s", w.unit.Tag().Id())
  1404  		}
  1405  		var err error
  1406  		storageSnapshot, err = getStorageSnapshot(w.st, tag, w.unit.Tag())
  1407  		if errors.Is(err, errors.NotProvisioned) {
  1408  			// If the storage is unprovisioned, we still want to
  1409  			// record the attachment, but we'll mark it as
  1410  			// unattached. This allows the uniter to wait for
  1411  			// pending storage attachments to be provisioned.
  1412  			storageSnapshot = StorageSnapshot{Life: life}
  1413  		} else if err != nil {
  1414  			return errors.Annotatef(err, "processing initial storage attachment change for %s", w.unit.Tag().Id())
  1415  		}
  1416  	}
  1417  	innerSAW, err := newStorageAttachmentWatcher(
  1418  		w.st, saw, w.unit.Tag(), tag, w.storageAttachmentChanges,
  1419  	)
  1420  	if err != nil {
  1421  		return errors.Trace(err)
  1422  	}
  1423  	w.current.Storage[tag] = storageSnapshot
  1424  	w.storageAttachmentWatchers[tag] = innerSAW
  1425  	return nil
  1426  }
  1427  
  1428  // markShutdown is called when Shutdown is called on remote state.
  1429  func (w *RemoteStateWatcher) markShutdown() {
  1430  	w.mu.Lock()
  1431  	w.current.Shutdown = true
  1432  	w.mu.Unlock()
  1433  }