launchpad.net/~rogpeppe/juju-core/500-errgo-fix@v0.0.0-20140213181702-000000002356/worker/instancepoller/observer.go (about)

     1  // Copyright 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package instancepoller
     5  
     6  import (
     7  	"sync"
     8  
     9  	"launchpad.net/tomb"
    10  
    11  	"launchpad.net/juju-core/environs"
    12  	"launchpad.net/juju-core/state"
    13  	"launchpad.net/juju-core/state/watcher"
    14  	"launchpad.net/juju-core/worker"
    15  )
    16  
    17  // TODO(rog) 2013-10-02
    18  // Put this somewhere generally available and
    19  // refactor other workers to use it.
    20  
    21  // environObserver watches the current environment configuration
    22  // and makes it available. It discards invalid environment
    23  // configurations.
    24  type environObserver struct {
    25  	tomb           tomb.Tomb
    26  	environWatcher state.NotifyWatcher
    27  	st             *state.State
    28  	mu             sync.Mutex
    29  	environ        environs.Environ
    30  }
    31  
    32  // newEnvironObserver waits for the state to have a valid environment
    33  // configuration and returns a new environment observer. While waiting
    34  // for the first environment configuration, it will return with
    35  // tomb.ErrDying if it receives a value on dying.
    36  func newEnvironObserver(st *state.State, dying <-chan struct{}) (*environObserver, error) {
    37  	environWatcher := st.WatchForEnvironConfigChanges()
    38  	environ, err := worker.WaitForEnviron(environWatcher, st, dying)
    39  	if err != nil {
    40  		return nil, mask(err)
    41  	}
    42  	obs := &environObserver{
    43  		st:             st,
    44  		environ:        environ,
    45  		environWatcher: environWatcher,
    46  	}
    47  	go func() {
    48  		defer obs.tomb.Done()
    49  		defer watcher.Stop(environWatcher, &obs.tomb)
    50  		obs.tomb.Kill(obs.loop())
    51  	}()
    52  	return obs, nil
    53  }
    54  
    55  func (obs *environObserver) loop() error {
    56  	for {
    57  		select {
    58  		case <-obs.tomb.Dying():
    59  			return nil
    60  		case _, ok := <-obs.environWatcher.Changes():
    61  			if !ok {
    62  				return watcher.MustErr(obs.environWatcher)
    63  			}
    64  		}
    65  		config, err := obs.st.EnvironConfig()
    66  		if err != nil {
    67  			logger.Warningf("error reading environment config: %v", err)
    68  			continue
    69  		}
    70  		environ, err := environs.New(config)
    71  		if err != nil {
    72  			logger.Warningf("error creating Environ: %v", err)
    73  			continue
    74  		}
    75  		obs.mu.Lock()
    76  		obs.environ = environ
    77  		obs.mu.Unlock()
    78  	}
    79  }
    80  
    81  // Environ returns the most recent valid Environ.
    82  func (obs *environObserver) Environ() environs.Environ {
    83  	obs.mu.Lock()
    84  	defer obs.mu.Unlock()
    85  	return obs.environ
    86  }
    87  
    88  func (obs *environObserver) Kill() {
    89  	obs.tomb.Kill(nil)
    90  }
    91  
    92  func (obs *environObserver) Wait() error {
    93  	return obs.tomb.Wait()
    94  }