github.com/cloud-green/juju@v0.0.0-20151002100041-a00291338d3d/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  	"github.com/juju/names"
    13  	"launchpad.net/tomb"
    14  
    15  	apiwatcher "github.com/juju/juju/api/watcher"
    16  	"github.com/juju/juju/apiserver/params"
    17  	"github.com/juju/juju/state/watcher"
    18  	"github.com/juju/juju/worker"
    19  	"github.com/juju/juju/worker/leadership"
    20  )
    21  
    22  var logger = loggo.GetLogger("juju.worker.uniter.remotestate")
    23  
    24  // RemoteStateWatcher collects unit, service, and service config information
    25  // from separate state watchers, and updates a Snapshot which is sent on a
    26  // channel upon change.
    27  type RemoteStateWatcher struct {
    28  	st                        State
    29  	unit                      Unit
    30  	service                   Service
    31  	relations                 map[names.RelationTag]*relationUnitsWatcher
    32  	relationUnitsChanges      chan relationUnitsChange
    33  	storageAttachmentWatchers map[names.StorageTag]*storageAttachmentWatcher
    34  	storageAttachmentChanges  chan storageAttachmentChange
    35  	leadershipTracker         leadership.Tracker
    36  	updateStatusChannel       func() <-chan time.Time
    37  
    38  	tomb tomb.Tomb
    39  
    40  	out     chan struct{}
    41  	mu      sync.Mutex
    42  	current Snapshot
    43  }
    44  
    45  // WatcherConfig holds configuration parameters for the
    46  // remote state watcher.
    47  type WatcherConfig struct {
    48  	State               State
    49  	LeadershipTracker   leadership.Tracker
    50  	UpdateStatusChannel func() <-chan time.Time
    51  	UnitTag             names.UnitTag
    52  }
    53  
    54  // NewWatcher returns a RemoteStateWatcher that handles state changes pertaining to the
    55  // supplied unit.
    56  func NewWatcher(config WatcherConfig) (*RemoteStateWatcher, error) {
    57  	w := &RemoteStateWatcher{
    58  		st:                        config.State,
    59  		relations:                 make(map[names.RelationTag]*relationUnitsWatcher),
    60  		relationUnitsChanges:      make(chan relationUnitsChange),
    61  		storageAttachmentWatchers: make(map[names.StorageTag]*storageAttachmentWatcher),
    62  		storageAttachmentChanges:  make(chan storageAttachmentChange),
    63  		leadershipTracker:         config.LeadershipTracker,
    64  		updateStatusChannel:       config.UpdateStatusChannel,
    65  		// Note: it is important that the out channel be buffered!
    66  		// The remote state watcher will perform a non-blocking send
    67  		// on the channel to wake up the observer. It is non-blocking
    68  		// so that we coalesce events while the observer is busy.
    69  		out: make(chan struct{}, 1),
    70  		current: Snapshot{
    71  			Relations: make(map[int]RelationSnapshot),
    72  			Storage:   make(map[names.StorageTag]StorageSnapshot),
    73  		},
    74  	}
    75  	if err := w.init(config.UnitTag); err != nil {
    76  		return nil, errors.Trace(err)
    77  	}
    78  	go func() {
    79  		defer w.tomb.Done()
    80  		err := w.loop(config.UnitTag)
    81  		logger.Errorf("remote state watcher exited: %v", err)
    82  		w.tomb.Kill(errors.Cause(err))
    83  
    84  		// Stop all remaining sub-watchers.
    85  		for _, w := range w.storageAttachmentWatchers {
    86  			watcher.Stop(w, &w.tomb)
    87  		}
    88  		for _, w := range w.relations {
    89  			watcher.Stop(w, &w.tomb)
    90  		}
    91  	}()
    92  	return w, nil
    93  }
    94  
    95  func (w *RemoteStateWatcher) Stop() error {
    96  	w.tomb.Kill(nil)
    97  	return w.tomb.Wait()
    98  }
    99  
   100  func (w *RemoteStateWatcher) Dead() <-chan struct{} {
   101  	return w.tomb.Dead()
   102  }
   103  
   104  func (w *RemoteStateWatcher) Wait() error {
   105  	return w.tomb.Wait()
   106  }
   107  
   108  func (w *RemoteStateWatcher) Kill() {
   109  	w.tomb.Kill(nil)
   110  }
   111  
   112  func (w *RemoteStateWatcher) RemoteStateChanged() <-chan struct{} {
   113  	return w.out
   114  }
   115  
   116  func (w *RemoteStateWatcher) Snapshot() Snapshot {
   117  	w.mu.Lock()
   118  	defer w.mu.Unlock()
   119  	snapshot := w.current
   120  	snapshot.Relations = make(map[int]RelationSnapshot)
   121  	for id, relationSnapshot := range w.current.Relations {
   122  		snapshot.Relations[id] = relationSnapshot
   123  	}
   124  	snapshot.Storage = make(map[names.StorageTag]StorageSnapshot)
   125  	for tag, storageSnapshot := range w.current.Storage {
   126  		snapshot.Storage[tag] = storageSnapshot
   127  	}
   128  	snapshot.Actions = make([]string, len(w.current.Actions))
   129  	for i, action := range w.current.Actions {
   130  		snapshot.Actions[i] = action
   131  	}
   132  	return snapshot
   133  }
   134  
   135  func (w *RemoteStateWatcher) ClearResolvedMode() {
   136  	w.mu.Lock()
   137  	w.current.ResolvedMode = params.ResolvedNone
   138  	w.mu.Unlock()
   139  }
   140  
   141  func (w *RemoteStateWatcher) init(unitTag names.UnitTag) (err error) {
   142  	// TODO(dfc) named return value is a time bomb
   143  	// TODO(axw) move this logic.
   144  	defer func() {
   145  		if params.IsCodeNotFoundOrCodeUnauthorized(err) {
   146  			err = worker.ErrTerminateAgent
   147  		}
   148  	}()
   149  	if w.unit, err = w.st.Unit(unitTag); err != nil {
   150  		return err
   151  	}
   152  	w.service, err = w.unit.Service()
   153  	if err != nil {
   154  		return err
   155  	}
   156  	return nil
   157  }
   158  
   159  func (w *RemoteStateWatcher) loop(unitTag names.UnitTag) (err error) {
   160  	var requiredEvents int
   161  
   162  	var seenUnitChange bool
   163  	unitw, err := w.unit.Watch()
   164  	if err != nil {
   165  		return err
   166  	}
   167  	defer watcher.Stop(unitw, &w.tomb)
   168  	requiredEvents++
   169  
   170  	var seenServiceChange bool
   171  	servicew, err := w.service.Watch()
   172  	if err != nil {
   173  		return err
   174  	}
   175  	defer watcher.Stop(servicew, &w.tomb)
   176  	requiredEvents++
   177  
   178  	var seenConfigChange bool
   179  	configw, err := w.unit.WatchConfigSettings()
   180  	if err != nil {
   181  		return err
   182  	}
   183  	defer watcher.Stop(configw, &w.tomb)
   184  	requiredEvents++
   185  
   186  	var seenRelationsChange bool
   187  	relationsw, err := w.service.WatchRelations()
   188  	if err != nil {
   189  		return err
   190  	}
   191  	defer watcher.Stop(relationsw, &w.tomb)
   192  	requiredEvents++
   193  
   194  	var seenAddressesChange bool
   195  	addressesw, err := w.unit.WatchAddresses()
   196  	if err != nil {
   197  		return err
   198  	}
   199  	defer watcher.Stop(addressesw, &w.tomb)
   200  	requiredEvents++
   201  
   202  	var seenStorageChange bool
   203  	storagew, err := w.unit.WatchStorage()
   204  	if err != nil {
   205  		return err
   206  	}
   207  	defer watcher.Stop(storagew, &w.tomb)
   208  	requiredEvents++
   209  
   210  	var seenLeaderSettingsChange bool
   211  	leaderSettingsw, err := w.service.WatchLeadershipSettings()
   212  	if err != nil {
   213  		return err
   214  	}
   215  	defer watcher.Stop(leaderSettingsw, &w.tomb)
   216  	requiredEvents++
   217  
   218  	var seenActionsChange bool
   219  	actionsw, err := w.unit.WatchActionNotifications()
   220  	if err != nil {
   221  		return err
   222  	}
   223  	defer watcher.Stop(actionsw, &w.tomb)
   224  	requiredEvents++
   225  
   226  	var seenLeadershipChange bool
   227  	// There's no watcher for this per se; we wait on a channel
   228  	// returned by the leadership tracker.
   229  	requiredEvents++
   230  
   231  	var eventsObserved int
   232  	observedEvent := func(flag *bool) {
   233  		if !*flag {
   234  			*flag = true
   235  			eventsObserved++
   236  		}
   237  	}
   238  
   239  	// fire will, once the first event for each watcher has
   240  	// been observed, send a signal on the out channel.
   241  	fire := func() {
   242  		if eventsObserved != requiredEvents {
   243  			return
   244  		}
   245  		select {
   246  		case w.out <- struct{}{}:
   247  		default:
   248  		}
   249  	}
   250  
   251  	defer func() {
   252  		for _, ruw := range w.relations {
   253  			watcher.Stop(ruw, &w.tomb)
   254  		}
   255  	}()
   256  
   257  	// Check the initial leadership status, and then we can flip-flop
   258  	// waiting on leader or minion to trigger the changed event.
   259  	var waitLeader, waitMinion <-chan struct{}
   260  	claimLeader := w.leadershipTracker.ClaimLeader()
   261  	select {
   262  	case <-w.tomb.Dying():
   263  		return tomb.ErrDying
   264  	case <-claimLeader.Ready():
   265  		isLeader := claimLeader.Wait()
   266  		w.leadershipChanged(isLeader)
   267  		if isLeader {
   268  			waitMinion = w.leadershipTracker.WaitMinion().Ready()
   269  		} else {
   270  			waitLeader = w.leadershipTracker.WaitLeader().Ready()
   271  		}
   272  		observedEvent(&seenLeadershipChange)
   273  	}
   274  
   275  	for {
   276  		select {
   277  		case <-w.tomb.Dying():
   278  			return tomb.ErrDying
   279  
   280  		case _, ok := <-unitw.Changes():
   281  			logger.Debugf("got unit change")
   282  			if !ok {
   283  				return watcher.EnsureErr(unitw)
   284  			}
   285  			if err := w.unitChanged(); err != nil {
   286  				return err
   287  			}
   288  			observedEvent(&seenUnitChange)
   289  
   290  		case _, ok := <-servicew.Changes():
   291  			logger.Debugf("got service change")
   292  			if !ok {
   293  				return watcher.EnsureErr(servicew)
   294  			}
   295  			if err := w.serviceChanged(); err != nil {
   296  				return err
   297  			}
   298  			observedEvent(&seenServiceChange)
   299  
   300  		case _, ok := <-configw.Changes():
   301  			logger.Debugf("got config change: ok=%t", ok)
   302  			if !ok {
   303  				return watcher.EnsureErr(configw)
   304  			}
   305  			if err := w.configChanged(); err != nil {
   306  				return err
   307  			}
   308  			observedEvent(&seenConfigChange)
   309  
   310  		case _, ok := <-addressesw.Changes():
   311  			logger.Debugf("got address change: ok=%t", ok)
   312  			if !ok {
   313  				return watcher.EnsureErr(addressesw)
   314  			}
   315  			if err := w.addressesChanged(); err != nil {
   316  				return err
   317  			}
   318  			observedEvent(&seenAddressesChange)
   319  
   320  		case _, ok := <-leaderSettingsw.Changes():
   321  			logger.Debugf("got leader settings change: ok=%t", ok)
   322  			if !ok {
   323  				return watcher.EnsureErr(leaderSettingsw)
   324  			}
   325  			if err := w.leaderSettingsChanged(); err != nil {
   326  				return err
   327  			}
   328  			observedEvent(&seenLeaderSettingsChange)
   329  
   330  		case actions, ok := <-actionsw.Changes():
   331  			logger.Debugf("got action change: %v ok=%t", actions, ok)
   332  			if !ok {
   333  				return watcher.EnsureErr(actionsw)
   334  			}
   335  			if err := w.actionsChanged(actions); err != nil {
   336  				return err
   337  			}
   338  			observedEvent(&seenActionsChange)
   339  
   340  		case keys, ok := <-relationsw.Changes():
   341  			logger.Debugf("got relations change: ok=%t", ok)
   342  			if !ok {
   343  				return watcher.EnsureErr(relationsw)
   344  			}
   345  			if err := w.relationsChanged(keys); err != nil {
   346  				return err
   347  			}
   348  			observedEvent(&seenRelationsChange)
   349  
   350  		case keys, ok := <-storagew.Changes():
   351  			logger.Debugf("got storage change: %v ok=%t", keys, ok)
   352  			if !ok {
   353  				return watcher.EnsureErr(storagew)
   354  			}
   355  			if err := w.storageChanged(keys); err != nil {
   356  				return err
   357  			}
   358  			observedEvent(&seenStorageChange)
   359  
   360  		case <-waitMinion:
   361  			logger.Debugf("got leadership change: minion")
   362  			if err := w.leadershipChanged(false); err != nil {
   363  				return err
   364  			}
   365  			waitMinion = nil
   366  			waitLeader = w.leadershipTracker.WaitLeader().Ready()
   367  
   368  		case <-waitLeader:
   369  			logger.Debugf("got leadership change: leader")
   370  			if err := w.leadershipChanged(true); err != nil {
   371  				return err
   372  			}
   373  			waitLeader = nil
   374  			waitMinion = w.leadershipTracker.WaitMinion().Ready()
   375  
   376  		case change := <-w.storageAttachmentChanges:
   377  			logger.Debugf("storage attachment change %v", change)
   378  			if err := w.storageAttachmentChanged(change); err != nil {
   379  				return err
   380  			}
   381  
   382  		case change := <-w.relationUnitsChanges:
   383  			logger.Debugf("got a relation units change: %v", change)
   384  			if err := w.relationUnitsChanged(change); err != nil {
   385  				return err
   386  			}
   387  
   388  		case <-w.updateStatusChannel():
   389  			logger.Debugf("update status timer triggered")
   390  			if err := w.updateStatusChanged(); err != nil {
   391  				return err
   392  			}
   393  		}
   394  
   395  		// Something changed.
   396  		fire()
   397  	}
   398  }
   399  
   400  // updateStatusChanged is called when the update status timer expires.
   401  func (w *RemoteStateWatcher) updateStatusChanged() error {
   402  	w.mu.Lock()
   403  	w.current.UpdateStatusVersion++
   404  	w.mu.Unlock()
   405  	return nil
   406  }
   407  
   408  // unitChanged responds to changes in the unit.
   409  func (w *RemoteStateWatcher) unitChanged() error {
   410  	if err := w.unit.Refresh(); err != nil {
   411  		return err
   412  	}
   413  	resolved, err := w.unit.Resolved()
   414  	if err != nil {
   415  		return err
   416  	}
   417  	w.mu.Lock()
   418  	defer w.mu.Unlock()
   419  	w.current.Life = w.unit.Life()
   420  	w.current.ResolvedMode = resolved
   421  	return nil
   422  }
   423  
   424  // serviceChanged responds to changes in the service.
   425  func (w *RemoteStateWatcher) serviceChanged() error {
   426  	if err := w.service.Refresh(); err != nil {
   427  		return err
   428  	}
   429  	url, force, err := w.service.CharmURL()
   430  	if err != nil {
   431  		return err
   432  	}
   433  	w.mu.Lock()
   434  	w.current.CharmURL = url
   435  	w.current.ForceCharmUpgrade = force
   436  	w.mu.Unlock()
   437  	return nil
   438  }
   439  
   440  func (w *RemoteStateWatcher) configChanged() error {
   441  	w.mu.Lock()
   442  	w.current.ConfigVersion++
   443  	w.mu.Unlock()
   444  	return nil
   445  }
   446  
   447  func (w *RemoteStateWatcher) addressesChanged() error {
   448  	w.mu.Lock()
   449  	w.current.ConfigVersion++
   450  	w.mu.Unlock()
   451  	return nil
   452  }
   453  
   454  func (w *RemoteStateWatcher) leaderSettingsChanged() error {
   455  	w.mu.Lock()
   456  	w.current.LeaderSettingsVersion++
   457  	w.mu.Unlock()
   458  	return nil
   459  }
   460  
   461  func (w *RemoteStateWatcher) leadershipChanged(isLeader bool) error {
   462  	w.mu.Lock()
   463  	w.current.Leader = isLeader
   464  	w.mu.Unlock()
   465  	return nil
   466  }
   467  
   468  // relationsChanged responds to service relation changes.
   469  func (w *RemoteStateWatcher) relationsChanged(keys []string) error {
   470  	w.mu.Lock()
   471  	defer w.mu.Unlock()
   472  	for _, key := range keys {
   473  		relationTag := names.NewRelationTag(key)
   474  		rel, err := w.st.Relation(relationTag)
   475  		if params.IsCodeNotFoundOrCodeUnauthorized(err) {
   476  			// If it's actually gone, this unit cannot have entered
   477  			// scope, and therefore never needs to know about it.
   478  			if ruw, ok := w.relations[relationTag]; ok {
   479  				if err := ruw.Stop(); err != nil {
   480  					return errors.Trace(err)
   481  				}
   482  				delete(w.relations, relationTag)
   483  				delete(w.current.Relations, ruw.relationId)
   484  			}
   485  		} else if err != nil {
   486  			return err
   487  		} else {
   488  			if _, ok := w.relations[relationTag]; ok {
   489  				relationSnapshot := w.current.Relations[rel.Id()]
   490  				relationSnapshot.Life = rel.Life()
   491  				w.current.Relations[rel.Id()] = relationSnapshot
   492  				continue
   493  			}
   494  			in, err := w.st.WatchRelationUnits(relationTag, w.unit.Tag())
   495  			if err != nil {
   496  				return errors.Trace(err)
   497  			}
   498  			if err := w.watchRelationUnits(rel, relationTag, in); err != nil {
   499  				watcher.Stop(in, &w.tomb)
   500  				return errors.Trace(err)
   501  			}
   502  		}
   503  	}
   504  	return nil
   505  }
   506  
   507  // watchRelationUnits starts watching the relation units for the given
   508  // relation, waits for its first event, and records the information in
   509  // the current snapshot.
   510  func (w *RemoteStateWatcher) watchRelationUnits(
   511  	rel Relation, relationTag names.RelationTag, in apiwatcher.RelationUnitsWatcher,
   512  ) error {
   513  	relationSnapshot := RelationSnapshot{
   514  		Life:    rel.Life(),
   515  		Members: make(map[string]int64),
   516  	}
   517  	select {
   518  	case <-w.tomb.Dying():
   519  		return tomb.ErrDying
   520  	case change, ok := <-in.Changes():
   521  		if !ok {
   522  			return watcher.EnsureErr(in)
   523  		}
   524  		for unit, settings := range change.Changed {
   525  			relationSnapshot.Members[unit] = settings.Version
   526  		}
   527  	}
   528  	w.current.Relations[rel.Id()] = relationSnapshot
   529  	w.relations[relationTag] = newRelationUnitsWatcher(
   530  		rel.Id(), in, w.relationUnitsChanges,
   531  	)
   532  	return nil
   533  }
   534  
   535  // relationUnitsChanged responds to relation units changes.
   536  func (w *RemoteStateWatcher) relationUnitsChanged(change relationUnitsChange) error {
   537  	w.mu.Lock()
   538  	defer w.mu.Unlock()
   539  	snapshot, ok := w.current.Relations[change.relationId]
   540  	if !ok {
   541  		return nil
   542  	}
   543  	for unit, settings := range change.Changed {
   544  		snapshot.Members[unit] = settings.Version
   545  	}
   546  	for _, unit := range change.Departed {
   547  		delete(snapshot.Members, unit)
   548  	}
   549  	return nil
   550  }
   551  
   552  // storageAttachmentChanged responds to storage attachment changes.
   553  func (w *RemoteStateWatcher) storageAttachmentChanged(change storageAttachmentChange) error {
   554  	w.mu.Lock()
   555  	w.current.Storage[change.Tag] = change.Snapshot
   556  	w.mu.Unlock()
   557  	return nil
   558  }
   559  
   560  func (w *RemoteStateWatcher) actionsChanged(actions []string) error {
   561  	w.mu.Lock()
   562  	defer w.mu.Unlock()
   563  	w.current.Actions = append(w.current.Actions, actions...)
   564  	return nil
   565  }
   566  
   567  // storageChanged responds to unit storage changes.
   568  func (w *RemoteStateWatcher) storageChanged(keys []string) error {
   569  	tags := make([]names.StorageTag, len(keys))
   570  	for i, key := range keys {
   571  		tags[i] = names.NewStorageTag(key)
   572  	}
   573  	ids := make([]params.StorageAttachmentId, len(keys))
   574  	for i, tag := range tags {
   575  		ids[i] = params.StorageAttachmentId{
   576  			StorageTag: tag.String(),
   577  			UnitTag:    w.unit.Tag().String(),
   578  		}
   579  	}
   580  	results, err := w.st.StorageAttachmentLife(ids)
   581  	if err != nil {
   582  		return errors.Trace(err)
   583  	}
   584  
   585  	w.mu.Lock()
   586  	defer w.mu.Unlock()
   587  
   588  	for i, result := range results {
   589  		tag := tags[i]
   590  		if result.Error == nil {
   591  			if storageSnapshot, ok := w.current.Storage[tag]; ok {
   592  				// We've previously started a watcher for this storage
   593  				// attachment, so all we needed to do was update the
   594  				// lifecycle state.
   595  				storageSnapshot.Life = result.Life
   596  				w.current.Storage[tag] = storageSnapshot
   597  				continue
   598  			}
   599  			// We haven't seen this storage attachment before, so start
   600  			// a watcher now and wait for the initial event.
   601  			in, err := w.st.WatchStorageAttachment(tag, w.unit.Tag())
   602  			if err != nil {
   603  				return errors.Annotate(err, "watching storage attachment")
   604  			}
   605  			if err := w.watchStorageAttachment(tag, result.Life, in); err != nil {
   606  				watcher.Stop(in, &w.tomb)
   607  				return errors.Trace(err)
   608  			}
   609  		} else if params.IsCodeNotFound(result.Error) {
   610  			if watcher, ok := w.storageAttachmentWatchers[tag]; ok {
   611  				if err := watcher.Stop(); err != nil {
   612  					return errors.Annotatef(
   613  						err, "stopping watcher of %s attachment",
   614  						names.ReadableString(tag),
   615  					)
   616  				}
   617  				delete(w.storageAttachmentWatchers, tag)
   618  			}
   619  			delete(w.current.Storage, tag)
   620  		} else {
   621  			return errors.Annotatef(
   622  				result.Error, "getting life of %s attachment",
   623  				names.ReadableString(tag),
   624  			)
   625  		}
   626  	}
   627  	return nil
   628  }
   629  
   630  // watchStorageAttachment starts watching the storage attachment with
   631  // the specified storage tag, waits for its first event, and records
   632  // the information in the current snapshot.
   633  func (w *RemoteStateWatcher) watchStorageAttachment(
   634  	tag names.StorageTag,
   635  	life params.Life,
   636  	in apiwatcher.NotifyWatcher,
   637  ) error {
   638  	var storageSnapshot StorageSnapshot
   639  	select {
   640  	case <-w.tomb.Dying():
   641  		return tomb.ErrDying
   642  	case _, ok := <-in.Changes():
   643  		if !ok {
   644  			return watcher.EnsureErr(in)
   645  		}
   646  		var err error
   647  		storageSnapshot, err = getStorageSnapshot(w.st, tag, w.unit.Tag())
   648  		if params.IsCodeNotProvisioned(err) {
   649  			// If the storage is unprovisioned, we still want to
   650  			// record the attachment, but we'll mark it as
   651  			// unattached. This allows the uniter to wait for
   652  			// pending storage attachments to be provisioned.
   653  			storageSnapshot = StorageSnapshot{Life: life}
   654  		} else if err != nil {
   655  			return errors.Annotatef(err, "processing initial storage attachment change")
   656  		}
   657  	}
   658  	w.current.Storage[tag] = storageSnapshot
   659  	w.storageAttachmentWatchers[tag] = newStorageAttachmentWatcher(
   660  		w.st, in, w.unit.Tag(), tag, w.storageAttachmentChanges,
   661  	)
   662  	return nil
   663  }