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