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

     1  // Copyright 2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package addresser
     5  
     6  import (
     7  	"github.com/juju/errors"
     8  	"github.com/juju/loggo"
     9  
    10  	apiWatcher "github.com/juju/juju/api/watcher"
    11  	"github.com/juju/juju/environs"
    12  	"github.com/juju/juju/environs/config"
    13  	"github.com/juju/juju/instance"
    14  	"github.com/juju/juju/network"
    15  	"github.com/juju/juju/provider/common"
    16  	"github.com/juju/juju/state"
    17  	"github.com/juju/juju/worker"
    18  )
    19  
    20  var logger = loggo.GetLogger("juju.worker.addresser")
    21  
    22  type releaser interface {
    23  	// ReleaseAddress has the same signature as the same method in the
    24  	// environs.Networking interface.
    25  	ReleaseAddress(instance.Id, network.Id, network.Address) error
    26  }
    27  
    28  // stateAddresser defines the State methods used by the addresserHandler
    29  type stateAddresser interface {
    30  	DeadIPAddresses() ([]*state.IPAddress, error)
    31  	EnvironConfig() (*config.Config, error)
    32  	IPAddress(string) (*state.IPAddress, error)
    33  	Machine(string) (*state.Machine, error)
    34  	WatchIPAddresses() state.StringsWatcher
    35  }
    36  
    37  type addresserHandler struct {
    38  	st       stateAddresser
    39  	releaser releaser
    40  }
    41  
    42  // NewWorker returns a worker that keeps track of
    43  // IP address lifecycles, releaseing and removing Dead addresses.
    44  func NewWorker(st stateAddresser) (worker.Worker, error) {
    45  	config, err := st.EnvironConfig()
    46  	if err != nil {
    47  		return nil, errors.Trace(err)
    48  	}
    49  	environ, err := environs.New(config)
    50  	if err != nil {
    51  		return nil, errors.Trace(err)
    52  	}
    53  	// If netEnviron is nil the worker will start but won't do anything as
    54  	// no IP addresses will be created or destroyed.
    55  	netEnviron, _ := environs.SupportsNetworking(environ)
    56  	a := newWorkerWithReleaser(st, netEnviron)
    57  	return a, nil
    58  }
    59  
    60  func newWorkerWithReleaser(st stateAddresser, releaser releaser) worker.Worker {
    61  	a := &addresserHandler{
    62  		st:       st,
    63  		releaser: releaser,
    64  	}
    65  	w := worker.NewStringsWorker(a)
    66  	return w
    67  }
    68  
    69  // Handle is part of the StringsWorker interface.
    70  func (a *addresserHandler) Handle(ids []string) error {
    71  	if a.releaser == nil {
    72  		return nil
    73  	}
    74  	for _, id := range ids {
    75  		logger.Debugf("received notification about address %v", id)
    76  		addr, err := a.st.IPAddress(id)
    77  		if err != nil {
    78  			if errors.IsNotFound(err) {
    79  				logger.Debugf("address %v was removed; skipping", id)
    80  				continue
    81  			}
    82  			return err
    83  		}
    84  		if addr.Life() != state.Dead {
    85  			logger.Debugf("address %v is not Dead (life %q); skipping", id, addr.Life())
    86  			continue
    87  		}
    88  		err = a.releaseIPAddress(addr)
    89  		if err != nil {
    90  			return err
    91  		}
    92  		logger.Debugf("address %v released", id)
    93  		err = addr.Remove()
    94  		if err != nil {
    95  			return err
    96  		}
    97  		logger.Debugf("address %v removed", id)
    98  	}
    99  	return nil
   100  }
   101  
   102  func (a *addresserHandler) releaseIPAddress(addr *state.IPAddress) (err error) {
   103  	defer errors.DeferredAnnotatef(&err, "failed to release address %v", addr.Value())
   104  	logger.Debugf("attempting to release dead address %#v", addr.Value())
   105  
   106  	subnetId := network.Id(addr.SubnetId())
   107  	for attempt := common.ShortAttempt.Start(); attempt.Next(); {
   108  		err = a.releaser.ReleaseAddress(addr.InstanceId(), subnetId, addr.Address())
   109  		if err == nil {
   110  			return nil
   111  		}
   112  	}
   113  	// Don't remove the address from state so we
   114  	// can retry releasing the address later.
   115  	logger.Warningf("cannot release address %q: %v (will retry)", addr.Value(), err)
   116  	return errors.Trace(err)
   117  }
   118  
   119  // SetUp is part of the StringsWorker interface.
   120  func (a *addresserHandler) SetUp() (apiWatcher.StringsWatcher, error) {
   121  	return a.st.WatchIPAddresses(), nil
   122  }
   123  
   124  // TearDown is part of the StringsWorker interface.
   125  func (a *addresserHandler) TearDown() error {
   126  	return nil
   127  }