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 }