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