github.com/Pankov404/juju@v0.0.0-20150703034450-be266991dceb/worker/uniter/filter/filter.go (about)

     1  // Copyright 2012-2014 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package filter
     5  
     6  import (
     7  	"github.com/juju/errors"
     8  	"github.com/juju/loggo"
     9  	"github.com/juju/names"
    10  	"github.com/juju/utils/set"
    11  	"gopkg.in/juju/charm.v5"
    12  	"launchpad.net/tomb"
    13  
    14  	"github.com/juju/juju/api/uniter"
    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  )
    20  
    21  var filterLogger = loggo.GetLogger("juju.worker.uniter.filter")
    22  
    23  // filter collects unit, service, and service config information from separate
    24  // state watchers, and presents it as events on channels designed specifically
    25  // for the convenience of the uniter.
    26  type filter struct {
    27  	st   *uniter.State
    28  	tomb tomb.Tomb
    29  
    30  	// outUnitDying is closed when the unit's life becomes Dying.
    31  	outUnitDying chan struct{}
    32  
    33  	// The out*On chans are used to deliver events to clients.
    34  	// The out* chans, when set to the corresponding out*On chan (rather than
    35  	// nil) indicate that an event of the appropriate type is ready to send
    36  	// to the client.
    37  	outConfig           chan struct{}
    38  	outConfigOn         chan struct{}
    39  	outAction           chan string
    40  	outActionOn         chan string
    41  	outLeaderSettings   chan struct{}
    42  	outLeaderSettingsOn chan struct{}
    43  	outUpgrade          chan *charm.URL
    44  	outUpgradeOn        chan *charm.URL
    45  	outResolved         chan params.ResolvedMode
    46  	outResolvedOn       chan params.ResolvedMode
    47  	outRelations        chan []int
    48  	outRelationsOn      chan []int
    49  	outMeterStatus      chan struct{}
    50  	outMeterStatusOn    chan struct{}
    51  	outStorage          chan []names.StorageTag
    52  	outStorageOn        chan []names.StorageTag
    53  	// The want* chans are used to indicate that the filter should send
    54  	// events if it has them available.
    55  	wantForcedUpgrade  chan bool
    56  	wantResolved       chan struct{}
    57  	wantLeaderSettings chan bool
    58  
    59  	// discardConfig is used to indicate that any pending config event
    60  	// should be discarded.
    61  	discardConfig chan struct{}
    62  
    63  	// discardLeaderSettings is used to indicate any pending Leader
    64  	// Settings event should be discarded.
    65  	discardLeaderSettings chan struct{}
    66  
    67  	// setCharm is used to request that the unit's charm URL be set to
    68  	// a new value. This must be done in the filter's goroutine, so
    69  	// that config watches can be stopped and restarted pointing to
    70  	// the new charm URL. If we don't stop the watch before the
    71  	// (potentially) last reference to that settings document is
    72  	// removed, we'll see spurious errors (and even in the best case,
    73  	// we risk getting notifications for the wrong settings version).
    74  	setCharm chan *charm.URL
    75  
    76  	// didSetCharm is used to report back after setting a charm URL.
    77  	didSetCharm chan struct{}
    78  
    79  	// clearResolved is used to request that the unit's resolved flag
    80  	// be cleared. This must be done on the filter's goroutine so that
    81  	// it can immediately trigger the unit change handler, and thus
    82  	// ensure that subsquent requests for resolved events -- that land
    83  	// before the next watcher update for the unit -- do not erroneously
    84  	// send out stale values.
    85  	clearResolved chan struct{}
    86  
    87  	// didClearResolved is used to report back after clearing the resolved
    88  	// flag.
    89  	didClearResolved chan struct{}
    90  
    91  	// The following fields hold state that is collected while running,
    92  	// and used to detect interesting changes to express as events.
    93  	unit             *uniter.Unit
    94  	life             params.Life
    95  	resolved         params.ResolvedMode
    96  	service          *uniter.Service
    97  	upgradeFrom      serviceCharm
    98  	upgradeAvailable serviceCharm
    99  	upgrade          *charm.URL
   100  	relations        []int
   101  	storage          []names.StorageTag
   102  	actionsPending   []string
   103  	nextAction       string
   104  
   105  	// meterStatusCode and meterStatusInfo reflect the meter status values of the unit.
   106  	meterStatusCode string
   107  	meterStatusInfo string
   108  }
   109  
   110  // NewFilter returns a filter that handles state changes pertaining to the
   111  // supplied unit.
   112  func NewFilter(st *uniter.State, unitTag names.UnitTag) (Filter, error) {
   113  	f := &filter{
   114  		st:                    st,
   115  		outUnitDying:          make(chan struct{}),
   116  		outConfigOn:           make(chan struct{}),
   117  		outActionOn:           make(chan string),
   118  		outLeaderSettingsOn:   make(chan struct{}),
   119  		outUpgradeOn:          make(chan *charm.URL),
   120  		outResolvedOn:         make(chan params.ResolvedMode),
   121  		outRelationsOn:        make(chan []int),
   122  		outMeterStatusOn:      make(chan struct{}),
   123  		outStorageOn:          make(chan []names.StorageTag),
   124  		wantForcedUpgrade:     make(chan bool),
   125  		wantResolved:          make(chan struct{}),
   126  		wantLeaderSettings:    make(chan bool),
   127  		discardConfig:         make(chan struct{}),
   128  		discardLeaderSettings: make(chan struct{}),
   129  		setCharm:              make(chan *charm.URL),
   130  		didSetCharm:           make(chan struct{}),
   131  		clearResolved:         make(chan struct{}),
   132  		didClearResolved:      make(chan struct{}),
   133  	}
   134  	go func() {
   135  		defer f.tomb.Done()
   136  		err := f.loop(unitTag)
   137  		filterLogger.Errorf("%v", err)
   138  		f.tomb.Kill(err)
   139  	}()
   140  	return f, nil
   141  }
   142  
   143  func (f *filter) Stop() error {
   144  	f.tomb.Kill(nil)
   145  	return f.tomb.Wait()
   146  }
   147  
   148  func (f *filter) Dead() <-chan struct{} {
   149  	return f.tomb.Dead()
   150  }
   151  
   152  func (f *filter) Wait() error {
   153  	return f.tomb.Wait()
   154  }
   155  
   156  func (f *filter) Kill() {
   157  	f.tomb.Kill(nil)
   158  }
   159  
   160  // UnitDying returns a channel which is closed when the Unit enters a Dying state.
   161  func (f *filter) UnitDying() <-chan struct{} {
   162  	return f.outUnitDying
   163  }
   164  
   165  // UpgradeEvents returns a channel that will receive a new charm URL whenever an
   166  // upgrade is indicated. Events should not be read until the baseline state
   167  // has been specified by calling WantUpgradeEvent.
   168  func (f *filter) UpgradeEvents() <-chan *charm.URL {
   169  	return f.outUpgradeOn
   170  }
   171  
   172  // ResolvedEvents returns a channel that may receive a ResolvedMode when the
   173  // unit's Resolved value changes, or when an event is explicitly requested.
   174  // A ResolvedNone state will never generate events, but ResolvedRetryHooks and
   175  // ResolvedNoHooks will always be delivered as described.
   176  func (f *filter) ResolvedEvents() <-chan params.ResolvedMode {
   177  	return f.outResolvedOn
   178  }
   179  
   180  // MeterStatusEvents returns a channel that will receive a signal when the unit's
   181  // meter status changes.
   182  func (f *filter) MeterStatusEvents() <-chan struct{} {
   183  	return f.outMeterStatusOn
   184  }
   185  
   186  // ConfigEvents returns a channel that will receive a signal whenever the service's
   187  // configuration changes, or when an event is explicitly requested.
   188  func (f *filter) ConfigEvents() <-chan struct{} {
   189  	return f.outConfigOn
   190  }
   191  
   192  // ActionEvents returns a channel that will receive a signal whenever the unit
   193  // receives new Actions.
   194  func (f *filter) ActionEvents() <-chan string {
   195  	return f.outActionOn
   196  }
   197  
   198  // RelationsEvents returns a channel that will receive the ids of all the service's
   199  // relations whose Life status has changed.
   200  func (f *filter) RelationsEvents() <-chan []int {
   201  	return f.outRelationsOn
   202  }
   203  
   204  // StorageEvents returns a channel that will receive the tags of all the unit's
   205  // associated storage instances.
   206  func (f *filter) StorageEvents() <-chan []names.StorageTag {
   207  	return f.outStorageOn
   208  }
   209  
   210  // WantUpgradeEvent controls whether the filter will generate upgrade
   211  // events for unforced service charm changes.
   212  func (f *filter) WantUpgradeEvent(mustForce bool) {
   213  	select {
   214  	case <-f.tomb.Dying():
   215  	case f.wantForcedUpgrade <- mustForce:
   216  	}
   217  }
   218  
   219  // SetCharm notifies the filter that the unit is running a new
   220  // charm. It causes the unit's charm URL to be set in state, and the
   221  // following changes to the filter's behaviour:
   222  //
   223  // * Upgrade events will only be generated for charms different to
   224  //   that supplied;
   225  // * A fresh relations event will be generated containing every relation
   226  //   the service is participating in;
   227  // * A fresh configuration event will be generated, and subsequent
   228  //   events will only be sent in response to changes in the version
   229  //   of the service's settings that is specific to that charm.
   230  //
   231  // SetCharm blocks until the charm URL is set in state, returning any
   232  // error that occurred.
   233  func (f *filter) SetCharm(curl *charm.URL) error {
   234  	select {
   235  	case <-f.tomb.Dying():
   236  		return tomb.ErrDying
   237  	case f.setCharm <- curl:
   238  	}
   239  	select {
   240  	case <-f.tomb.Dying():
   241  		return tomb.ErrDying
   242  	case <-f.didSetCharm:
   243  		return nil
   244  	}
   245  }
   246  
   247  // WantResolvedEvent indicates that the filter should send a resolved event
   248  // if one is available.
   249  func (f *filter) WantResolvedEvent() {
   250  	select {
   251  	case <-f.tomb.Dying():
   252  	case f.wantResolved <- nothing:
   253  	}
   254  }
   255  
   256  // ClearResolved notifies the filter that a resolved event has been handled
   257  // and should not be reported again.
   258  func (f *filter) ClearResolved() error {
   259  	select {
   260  	case <-f.tomb.Dying():
   261  		return tomb.ErrDying
   262  	case f.clearResolved <- nothing:
   263  	}
   264  	select {
   265  	case <-f.tomb.Dying():
   266  		return tomb.ErrDying
   267  	case <-f.didClearResolved:
   268  		filterLogger.Debugf("resolved clear completed")
   269  		return nil
   270  	}
   271  }
   272  
   273  // LeaderSettingsEvents returns a channel that will receive an event whenever
   274  // there is a leader settings change. Events can be temporarily suspended by
   275  // calling WantLeaderSettingsEvents(false), and then reenabled by calling
   276  // WantLeaderSettingsEvents(true)
   277  func (f *filter) LeaderSettingsEvents() <-chan struct{} {
   278  	return f.outLeaderSettingsOn
   279  }
   280  
   281  // DiscardLeaderSettingsEvent can be called to discard any pending
   282  // LeaderSettingsEvents. This is used by code that saw a LeaderSettings change,
   283  // and has been prepping for a response. Just before they request the current
   284  // LeaderSettings, they can discard any other pending changes, since they know
   285  // they will be handling all changes that have occurred before right now.
   286  func (f *filter) DiscardLeaderSettingsEvent() {
   287  	select {
   288  	case <-f.tomb.Dying():
   289  	case f.discardLeaderSettings <- nothing:
   290  	}
   291  }
   292  
   293  // WantLeaderSettingsEvents can be used to enable/disable events being sent on
   294  // the LeaderSettingsEvents() channel. This is used when an agent notices that
   295  // it is the leader, it wants to disable getting events for changes that it is
   296  // generating. Calling this with sendEvents=false disables getting change
   297  // events. Calling this with sendEvents=true will enable future changes, and
   298  // queues up an immediate event so that the agent will refresh its information
   299  // for any events it might have missed while it thought it was the leader.
   300  func (f *filter) WantLeaderSettingsEvents(sendEvents bool) {
   301  	select {
   302  	case <-f.tomb.Dying():
   303  	case f.wantLeaderSettings <- sendEvents:
   304  	}
   305  }
   306  
   307  // DiscardConfigEvent indicates that the filter should discard any pending
   308  // config event.
   309  func (f *filter) DiscardConfigEvent() {
   310  	select {
   311  	case <-f.tomb.Dying():
   312  	case f.discardConfig <- nothing:
   313  	}
   314  }
   315  
   316  func (f *filter) maybeStopWatcher(w watcher.Stopper) {
   317  	if w != nil {
   318  		watcher.Stop(w, &f.tomb)
   319  	}
   320  }
   321  
   322  func (f *filter) loop(unitTag names.UnitTag) (err error) {
   323  	// TODO(dfc) named return value is a time bomb
   324  	defer func() {
   325  		if params.IsCodeNotFoundOrCodeUnauthorized(err) {
   326  			err = worker.ErrTerminateAgent
   327  		}
   328  	}()
   329  	if f.unit, err = f.st.Unit(unitTag); err != nil {
   330  		return err
   331  	}
   332  	if err = f.unitChanged(); err != nil {
   333  		return err
   334  	}
   335  	if err = f.meterStatusChanged(); err != nil {
   336  		return err
   337  	}
   338  	f.service, err = f.unit.Service()
   339  	if err != nil {
   340  		return err
   341  	}
   342  	if err = f.serviceChanged(); err != nil {
   343  		return err
   344  	}
   345  	unitw, err := f.unit.Watch()
   346  	if err != nil {
   347  		return err
   348  	}
   349  	defer f.maybeStopWatcher(unitw)
   350  	servicew, err := f.service.Watch()
   351  	if err != nil {
   352  		return err
   353  	}
   354  	defer f.maybeStopWatcher(servicew)
   355  	// configw and relationsw can get restarted, so we need to use
   356  	// their eventual values in the defer calls.
   357  	var configw apiwatcher.NotifyWatcher
   358  	var configChanges <-chan struct{}
   359  	curl, err := f.unit.CharmURL()
   360  	if err == nil {
   361  		configw, err = f.unit.WatchConfigSettings()
   362  		if err != nil {
   363  			return err
   364  		}
   365  		configChanges = configw.Changes()
   366  		f.upgradeFrom.url = curl
   367  	} else if err != uniter.ErrNoCharmURLSet {
   368  		filterLogger.Errorf("unit charm: %v", err)
   369  		return err
   370  	}
   371  	defer f.maybeStopWatcher(configw)
   372  	actionsw, err := f.unit.WatchActionNotifications()
   373  	if err != nil {
   374  		return err
   375  	}
   376  	f.actionsPending = make([]string, 0)
   377  	defer f.maybeStopWatcher(actionsw)
   378  	relationsw, err := f.service.WatchRelations()
   379  	if err != nil {
   380  		return err
   381  	}
   382  	defer f.maybeStopWatcher(relationsw)
   383  	meterStatusw, err := f.unit.WatchMeterStatus()
   384  	if err != nil {
   385  		return err
   386  	}
   387  	defer f.maybeStopWatcher(meterStatusw)
   388  	addressesw, err := f.unit.WatchAddresses()
   389  	if err != nil {
   390  		return err
   391  	}
   392  	defer watcher.Stop(addressesw, &f.tomb)
   393  	storagew, err := f.unit.WatchStorage()
   394  	if err != nil {
   395  		return err
   396  	}
   397  	defer watcher.Stop(storagew, &f.tomb)
   398  	leaderSettingsw, err := f.st.LeadershipSettings.WatchLeadershipSettings(f.service.Tag().Id())
   399  	if err != nil {
   400  		return err
   401  	}
   402  	defer watcher.Stop(leaderSettingsw, &f.tomb)
   403  
   404  	// Ignore external requests for leader settings behaviour until we see the first change.
   405  	var discardLeaderSettings <-chan struct{}
   406  	var wantLeaderSettings <-chan bool
   407  	// By default we send all leaderSettings onwards.
   408  	sendLeaderSettings := true
   409  
   410  	// Config events cannot be meaningfully discarded until one is available;
   411  	// once we receive the initial config and address changes, we unblock
   412  	// discard requests by setting this channel to its namesake on f.
   413  	var discardConfig chan struct{}
   414  	var seenConfigChange bool
   415  	var seenAddressChange bool
   416  	maybePrepareConfigEvent := func() {
   417  		if !seenAddressChange {
   418  			filterLogger.Debugf("no address change seen yet, skipping config event")
   419  			return
   420  		}
   421  		if !seenConfigChange {
   422  			filterLogger.Debugf("no config change seen yet, skipping config event")
   423  			return
   424  		}
   425  		filterLogger.Debugf("preparing new config event")
   426  		f.outConfig = f.outConfigOn
   427  		discardConfig = f.discardConfig
   428  	}
   429  
   430  	for {
   431  		var ok bool
   432  		select {
   433  		case <-f.tomb.Dying():
   434  			return tomb.ErrDying
   435  
   436  		// Handle watcher changes.
   437  		case _, ok = <-unitw.Changes():
   438  			filterLogger.Debugf("got unit change")
   439  			if !ok {
   440  				return watcher.EnsureErr(unitw)
   441  			}
   442  			if err = f.unitChanged(); err != nil {
   443  				return err
   444  			}
   445  		case _, ok = <-servicew.Changes():
   446  			filterLogger.Debugf("got service change")
   447  			if !ok {
   448  				return watcher.EnsureErr(servicew)
   449  			}
   450  			if err = f.serviceChanged(); err != nil {
   451  				return err
   452  			}
   453  		case _, ok = <-configChanges:
   454  			filterLogger.Debugf("got config change")
   455  			if !ok {
   456  				return watcher.EnsureErr(configw)
   457  			}
   458  			seenConfigChange = true
   459  			maybePrepareConfigEvent()
   460  		case _, ok = <-addressesw.Changes():
   461  			filterLogger.Debugf("got address change")
   462  			if !ok {
   463  				return watcher.EnsureErr(addressesw)
   464  			}
   465  			seenAddressChange = true
   466  			maybePrepareConfigEvent()
   467  		case _, ok = <-meterStatusw.Changes():
   468  			filterLogger.Debugf("got meter status change")
   469  			if !ok {
   470  				return watcher.EnsureErr(meterStatusw)
   471  			}
   472  			if err = f.meterStatusChanged(); err != nil {
   473  				return errors.Trace(err)
   474  			}
   475  		case ids, ok := <-actionsw.Changes():
   476  			filterLogger.Debugf("got %d actions", len(ids))
   477  			if !ok {
   478  				return watcher.EnsureErr(actionsw)
   479  			}
   480  			f.actionsPending = append(f.actionsPending, ids...)
   481  			f.nextAction = f.getNextAction()
   482  		case keys, ok := <-relationsw.Changes():
   483  			filterLogger.Debugf("got relations change")
   484  			if !ok {
   485  				return watcher.EnsureErr(relationsw)
   486  			}
   487  			var ids []int
   488  			for _, key := range keys {
   489  				relationTag := names.NewRelationTag(key)
   490  				rel, err := f.st.Relation(relationTag)
   491  				if params.IsCodeNotFoundOrCodeUnauthorized(err) {
   492  					// If it's actually gone, this unit cannot have entered
   493  					// scope, and therefore never needs to know about it.
   494  				} else if err != nil {
   495  					return err
   496  				} else {
   497  					ids = append(ids, rel.Id())
   498  				}
   499  			}
   500  			f.relationsChanged(ids)
   501  		case ids, ok := <-storagew.Changes():
   502  			filterLogger.Debugf("got storage change")
   503  			if !ok {
   504  				return watcher.EnsureErr(storagew)
   505  			}
   506  			tags := make([]names.StorageTag, len(ids))
   507  			for i, id := range ids {
   508  				tag := names.NewStorageTag(id)
   509  				tags[i] = tag
   510  			}
   511  			f.storageChanged(tags)
   512  		case _, ok = <-leaderSettingsw.Changes():
   513  			filterLogger.Debugf("got leader settings change: ok=%t", ok)
   514  			if !ok {
   515  				return watcher.EnsureErr(leaderSettingsw)
   516  			}
   517  			if sendLeaderSettings {
   518  				// only send the leader settings changed event
   519  				// if it hasn't been explicitly disabled
   520  				f.outLeaderSettings = f.outLeaderSettingsOn
   521  			} else {
   522  				filterLogger.Debugf("not sending leader settings change (want=false)")
   523  			}
   524  			discardLeaderSettings = f.discardLeaderSettings
   525  			wantLeaderSettings = f.wantLeaderSettings
   526  
   527  		// Send events on active out chans.
   528  		case f.outUpgrade <- f.upgrade:
   529  			filterLogger.Debugf("sent upgrade event")
   530  			f.outUpgrade = nil
   531  		case f.outResolved <- f.resolved:
   532  			filterLogger.Debugf("sent resolved event")
   533  			f.outResolved = nil
   534  		case f.outConfig <- nothing:
   535  			filterLogger.Debugf("sent config event")
   536  			f.outConfig = nil
   537  		case f.outLeaderSettings <- nothing:
   538  			filterLogger.Debugf("sent leader settings event")
   539  			f.outLeaderSettings = nil
   540  		case f.outAction <- f.nextAction:
   541  			f.nextAction = f.getNextAction()
   542  			filterLogger.Debugf("sent action event")
   543  		case f.outRelations <- f.relations:
   544  			filterLogger.Debugf("sent relations event")
   545  			f.outRelations = nil
   546  			f.relations = nil
   547  		case f.outMeterStatus <- nothing:
   548  			filterLogger.Debugf("sent meter status change event")
   549  			f.outMeterStatus = nil
   550  		case f.outStorage <- f.storage:
   551  			filterLogger.Debugf("sent storage event")
   552  			f.outStorage = nil
   553  			f.storage = nil
   554  
   555  		// Handle explicit requests.
   556  		case curl := <-f.setCharm:
   557  			filterLogger.Debugf("changing charm to %q", curl)
   558  			// We need to restart the config watcher after setting the
   559  			// charm, because service config settings are distinct for
   560  			// different service charms.
   561  			if configw != nil {
   562  				if err := configw.Stop(); err != nil {
   563  					return err
   564  				}
   565  			}
   566  			if err := f.unit.SetCharmURL(curl); err != nil {
   567  				filterLogger.Debugf("failed setting charm url %q: %v", curl, err)
   568  				return err
   569  			}
   570  			select {
   571  			case <-f.tomb.Dying():
   572  				return tomb.ErrDying
   573  			case f.didSetCharm <- nothing:
   574  			}
   575  			configw, err = f.unit.WatchConfigSettings()
   576  			if err != nil {
   577  				return err
   578  			}
   579  			configChanges = configw.Changes()
   580  
   581  			// Restart the relations watcher.
   582  			if err := relationsw.Stop(); err != nil {
   583  				return err
   584  			}
   585  			relationsw, err = f.service.WatchRelations()
   586  			if err != nil {
   587  				return err
   588  			}
   589  
   590  			f.upgradeFrom.url = curl
   591  			if err = f.upgradeChanged(); err != nil {
   592  				return err
   593  			}
   594  		case force := <-f.wantForcedUpgrade:
   595  			filterLogger.Debugf("want forced upgrade %v", force)
   596  			f.upgradeFrom.force = force
   597  			if err = f.upgradeChanged(); err != nil {
   598  				return err
   599  			}
   600  		case <-f.wantResolved:
   601  			filterLogger.Debugf("want resolved event")
   602  			if f.resolved != params.ResolvedNone {
   603  				f.outResolved = f.outResolvedOn
   604  			}
   605  		case sendEvents := <-wantLeaderSettings:
   606  			filterLogger.Debugf("want leader settings event: %t", sendEvents)
   607  			sendLeaderSettings = sendEvents
   608  			if sendEvents {
   609  				// go ahead and send an event right now,
   610  				// they're waiting for us
   611  				f.outLeaderSettings = f.outLeaderSettingsOn
   612  			} else {
   613  				// Make sure we don't have a pending event
   614  				f.outLeaderSettings = nil
   615  			}
   616  		case <-f.clearResolved:
   617  			filterLogger.Debugf("resolved event handled")
   618  			f.outResolved = nil
   619  			if err := f.unit.ClearResolved(); err != nil {
   620  				return err
   621  			}
   622  			if err := f.unitChanged(); err != nil {
   623  				return err
   624  			}
   625  			select {
   626  			case <-f.tomb.Dying():
   627  				return tomb.ErrDying
   628  			case f.didClearResolved <- nothing:
   629  			}
   630  		case <-discardConfig:
   631  			filterLogger.Debugf("discarded config event")
   632  			f.outConfig = nil
   633  		case <-discardLeaderSettings:
   634  			filterLogger.Debugf("discarded leader settings event")
   635  			f.outLeaderSettings = nil
   636  		}
   637  	}
   638  }
   639  
   640  // meterStatusChanges respondes to changes in the unit's meter status.
   641  func (f *filter) meterStatusChanged() error {
   642  	code, info, err := f.unit.MeterStatus()
   643  	if err != nil {
   644  		return errors.Trace(err)
   645  	}
   646  	if f.meterStatusCode != code || f.meterStatusInfo != info {
   647  		if f.meterStatusCode != "" {
   648  			f.outMeterStatus = f.outMeterStatusOn
   649  		}
   650  		f.meterStatusCode = code
   651  		f.meterStatusInfo = info
   652  	}
   653  	return nil
   654  }
   655  
   656  // unitChanged responds to changes in the unit.
   657  func (f *filter) unitChanged() error {
   658  	if err := f.unit.Refresh(); err != nil {
   659  		return err
   660  	}
   661  	if f.life != f.unit.Life() {
   662  		switch f.life = f.unit.Life(); f.life {
   663  		case params.Dying:
   664  			filterLogger.Infof("unit is dying")
   665  			close(f.outUnitDying)
   666  			f.outUpgrade = nil
   667  		case params.Dead:
   668  			filterLogger.Infof("unit is dead")
   669  			return worker.ErrTerminateAgent
   670  		}
   671  	}
   672  	resolved, err := f.unit.Resolved()
   673  	if err != nil {
   674  		return err
   675  	}
   676  	if resolved != f.resolved {
   677  		f.resolved = resolved
   678  		if f.resolved != params.ResolvedNone {
   679  			f.outResolved = f.outResolvedOn
   680  		}
   681  	}
   682  	return nil
   683  }
   684  
   685  // serviceChanged responds to changes in the service.
   686  func (f *filter) serviceChanged() error {
   687  	if err := f.service.Refresh(); err != nil {
   688  		return err
   689  	}
   690  	url, force, err := f.service.CharmURL()
   691  	if err != nil {
   692  		return err
   693  	}
   694  	f.upgradeAvailable = serviceCharm{url, force}
   695  	switch f.service.Life() {
   696  	case params.Dying:
   697  		if err := f.unit.Destroy(); err != nil {
   698  			return err
   699  		}
   700  	case params.Dead:
   701  		filterLogger.Infof("service is dead")
   702  		return worker.ErrTerminateAgent
   703  	}
   704  	return f.upgradeChanged()
   705  }
   706  
   707  // upgradeChanged responds to changes in the service or in the
   708  // upgrade requests that defines which charm changes should be
   709  // delivered as upgrades.
   710  func (f *filter) upgradeChanged() (err error) {
   711  	if f.life != params.Alive {
   712  		filterLogger.Debugf("charm check skipped, unit is dying")
   713  		f.outUpgrade = nil
   714  		return nil
   715  	}
   716  	if f.upgradeFrom.url == nil {
   717  		filterLogger.Debugf("charm check skipped, not yet installed.")
   718  		f.outUpgrade = nil
   719  		return nil
   720  	}
   721  	if *f.upgradeAvailable.url != *f.upgradeFrom.url {
   722  		if f.upgradeAvailable.force || !f.upgradeFrom.force {
   723  			filterLogger.Debugf("preparing new upgrade event")
   724  			if f.upgrade == nil || *f.upgrade != *f.upgradeAvailable.url {
   725  				f.upgrade = f.upgradeAvailable.url
   726  			}
   727  			f.outUpgrade = f.outUpgradeOn
   728  			return nil
   729  		}
   730  	}
   731  	filterLogger.Debugf("no new charm event")
   732  	f.outUpgrade = nil
   733  	return nil
   734  }
   735  
   736  // relationsChanged responds to service relation changes.
   737  func (f *filter) relationsChanged(changed []int) {
   738  	ids := set.NewInts(f.relations...)
   739  	for _, id := range changed {
   740  		ids.Add(id)
   741  	}
   742  	if len(f.relations) != len(ids) {
   743  		f.relations = ids.SortedValues()
   744  		f.outRelations = f.outRelationsOn
   745  	}
   746  }
   747  
   748  // storageChanged responds to unit storage changes.
   749  func (f *filter) storageChanged(changed []names.StorageTag) {
   750  	tags := set.NewTags() // f.storage is []StorageTag, not []Tag
   751  	for _, tag := range f.storage {
   752  		tags.Add(tag)
   753  	}
   754  	for _, tag := range changed {
   755  		tags.Add(tag)
   756  	}
   757  	if len(f.storage) != len(tags) {
   758  		storage := make([]names.StorageTag, len(tags))
   759  		for i, tag := range tags.SortedValues() {
   760  			storage[i] = tag.(names.StorageTag)
   761  		}
   762  		f.storage = storage
   763  		f.outStorage = f.outStorageOn
   764  	}
   765  }
   766  
   767  func (f *filter) getNextAction() string {
   768  	if len(f.actionsPending) > 0 {
   769  		actionId := f.actionsPending[0]
   770  
   771  		f.outAction = f.outActionOn
   772  		f.actionsPending = f.actionsPending[1:]
   773  
   774  		return actionId
   775  	} else {
   776  		f.outAction = nil
   777  	}
   778  
   779  	return ""
   780  }
   781  
   782  // serviceCharm holds information about a charm.
   783  type serviceCharm struct {
   784  	url   *charm.URL
   785  	force bool
   786  }
   787  
   788  // nothing is marginally more pleasant to read than "struct{}{}".
   789  var nothing = struct{}{}