github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/worker/machineundertaker/undertaker.go (about)

     1  // Copyright 2016 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package machineundertaker
     5  
     6  import (
     7  	"github.com/juju/errors"
     8  	"github.com/juju/loggo"
     9  	"gopkg.in/juju/names.v2"
    10  
    11  	"github.com/juju/juju/environs"
    12  	"github.com/juju/juju/network"
    13  	"github.com/juju/juju/watcher"
    14  	"github.com/juju/juju/worker"
    15  )
    16  
    17  var logger = loggo.GetLogger("juju.worker.machineundertaker")
    18  
    19  // Facade defines the interface we require from the machine undertaker
    20  // facade.
    21  type Facade interface {
    22  	WatchMachineRemovals() (watcher.NotifyWatcher, error)
    23  	AllMachineRemovals() ([]names.MachineTag, error)
    24  	GetProviderInterfaceInfo(names.MachineTag) ([]network.ProviderInterfaceInfo, error)
    25  	CompleteRemoval(names.MachineTag) error
    26  }
    27  
    28  // AddressReleaser defines the interface we need from the environment
    29  // networking.
    30  type AddressReleaser interface {
    31  	ReleaseContainerAddresses([]network.ProviderInterfaceInfo) error
    32  }
    33  
    34  // MachineUndertaker is responsible for doing any provider-level
    35  // cleanup needed and then removing the machine.
    36  type Undertaker struct {
    37  	API      Facade
    38  	Releaser AddressReleaser
    39  }
    40  
    41  // NewWorker returns a machine undertaker worker that will watch for
    42  // machines that need to be removed and remove them, cleaning up any
    43  // necessary provider-level resources first.
    44  func NewWorker(api Facade, env environs.Environ) (worker.Worker, error) {
    45  	envNetworking, _ := environs.SupportsNetworking(env)
    46  	w, err := watcher.NewNotifyWorker(watcher.NotifyConfig{
    47  		Handler: &Undertaker{API: api, Releaser: envNetworking},
    48  	})
    49  	if err != nil {
    50  		return nil, errors.Trace(err)
    51  	}
    52  	return w, nil
    53  }
    54  
    55  // Setup (part of watcher.NotifyHandler) starts watching for machine
    56  // removals.
    57  func (u *Undertaker) SetUp() (watcher.NotifyWatcher, error) {
    58  	logger.Infof("setting up machine undertaker")
    59  	return u.API.WatchMachineRemovals()
    60  }
    61  
    62  // Handle (part of watcher.NotifyHandler) cleans up provider resources
    63  // and removes machines that have been marked for removal.
    64  func (u *Undertaker) Handle(<-chan struct{}) error {
    65  	removals, err := u.API.AllMachineRemovals()
    66  	if err != nil {
    67  		return errors.Trace(err)
    68  	}
    69  	logger.Debugf("handling removals: %v", removals)
    70  	// TODO(babbageclunk): shuffle the removals so if there's a
    71  	// problem with one others can still get past?
    72  	for _, machine := range removals {
    73  		err := u.MaybeReleaseAddresses(machine)
    74  		if err != nil {
    75  			logger.Errorf("couldn't release addresses for %s: %s", machine, err)
    76  			continue
    77  		}
    78  		err = u.API.CompleteRemoval(machine)
    79  		if err != nil {
    80  			logger.Errorf("couldn't complete removal for %s: %s", machine, err)
    81  		} else {
    82  			logger.Debugf("completed removal: %s", machine)
    83  		}
    84  	}
    85  	return nil
    86  }
    87  
    88  // MaybeReleaseAddresses releases any addresses that have been
    89  // allocated to this machine by the provider (if the provider supports
    90  // that).
    91  func (u *Undertaker) MaybeReleaseAddresses(machine names.MachineTag) error {
    92  	if u.Releaser == nil {
    93  		// This environ doesn't support releasing addresses.
    94  		return nil
    95  	}
    96  	if !names.IsContainerMachine(machine.Id()) {
    97  		// At the moment, only containers need their addresses releasing.
    98  		return nil
    99  	}
   100  	interfaceInfos, err := u.API.GetProviderInterfaceInfo(machine)
   101  	if err != nil {
   102  		return errors.Trace(err)
   103  	}
   104  	if len(interfaceInfos) == 0 {
   105  		logger.Debugf("%s has no addresses to release", machine)
   106  		return nil
   107  	}
   108  	err = u.Releaser.ReleaseContainerAddresses(interfaceInfos)
   109  	// Some providers say they support networking but don't
   110  	// actually support container addressing; don't freak out
   111  	// about those.
   112  	if errors.IsNotSupported(err) {
   113  		logger.Debugf("%s has addresses but provider doesn't support releasing them", machine)
   114  	} else if err != nil {
   115  		return errors.Trace(err)
   116  	}
   117  	return nil
   118  }
   119  
   120  // Teardown (part of watcher.NotifyHandler) is an opportunity to stop
   121  // or release any resources created in SetUp other than the watcher,
   122  // which watcher.NotifyWorker takes care of for us.
   123  func (u *Undertaker) TearDown() error {
   124  	logger.Infof("tearing down machine undertaker")
   125  	return nil
   126  }