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 }