github.com/Pankov404/juju@v0.0.0-20150703034450-be266991dceb/worker/addresser/worker.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package addresser 5 6 import ( 7 "github.com/juju/errors" 8 "github.com/juju/loggo" 9 10 apiWatcher "github.com/juju/juju/api/watcher" 11 "github.com/juju/juju/environs" 12 "github.com/juju/juju/environs/config" 13 "github.com/juju/juju/instance" 14 "github.com/juju/juju/network" 15 "github.com/juju/juju/provider/common" 16 "github.com/juju/juju/state" 17 "github.com/juju/juju/worker" 18 ) 19 20 var logger = loggo.GetLogger("juju.worker.addresser") 21 22 type releaser interface { 23 // ReleaseAddress has the same signature as the same method in the 24 // environs.Networking interface. 25 ReleaseAddress(instance.Id, network.Id, network.Address) error 26 } 27 28 // stateAddresser defines the State methods used by the addresserHandler 29 type stateAddresser interface { 30 DeadIPAddresses() ([]*state.IPAddress, error) 31 EnvironConfig() (*config.Config, error) 32 IPAddress(string) (*state.IPAddress, error) 33 Machine(string) (*state.Machine, error) 34 WatchIPAddresses() state.StringsWatcher 35 } 36 37 type addresserHandler struct { 38 st stateAddresser 39 releaser releaser 40 } 41 42 // NewWorker returns a worker that keeps track of 43 // IP address lifecycles, releaseing and removing Dead addresses. 44 func NewWorker(st stateAddresser) (worker.Worker, error) { 45 config, err := st.EnvironConfig() 46 if err != nil { 47 return nil, errors.Trace(err) 48 } 49 environ, err := environs.New(config) 50 if err != nil { 51 return nil, errors.Trace(err) 52 } 53 // If netEnviron is nil the worker will start but won't do anything as 54 // no IP addresses will be created or destroyed. 55 netEnviron, _ := environs.SupportsNetworking(environ) 56 a := newWorkerWithReleaser(st, netEnviron) 57 return a, nil 58 } 59 60 func newWorkerWithReleaser(st stateAddresser, releaser releaser) worker.Worker { 61 a := &addresserHandler{ 62 st: st, 63 releaser: releaser, 64 } 65 w := worker.NewStringsWorker(a) 66 return w 67 } 68 69 // Handle is part of the StringsWorker interface. 70 func (a *addresserHandler) Handle(ids []string) error { 71 if a.releaser == nil { 72 return nil 73 } 74 for _, id := range ids { 75 logger.Debugf("received notification about address %v", id) 76 addr, err := a.st.IPAddress(id) 77 if err != nil { 78 if errors.IsNotFound(err) { 79 logger.Debugf("address %v was removed; skipping", id) 80 continue 81 } 82 return err 83 } 84 if addr.Life() != state.Dead { 85 logger.Debugf("address %v is not Dead (life %q); skipping", id, addr.Life()) 86 continue 87 } 88 err = a.releaseIPAddress(addr) 89 if err != nil { 90 return err 91 } 92 logger.Debugf("address %v released", id) 93 err = addr.Remove() 94 if err != nil { 95 return err 96 } 97 logger.Debugf("address %v removed", id) 98 } 99 return nil 100 } 101 102 func (a *addresserHandler) releaseIPAddress(addr *state.IPAddress) (err error) { 103 defer errors.DeferredAnnotatef(&err, "failed to release address %v", addr.Value()) 104 logger.Debugf("attempting to release dead address %#v", addr.Value()) 105 106 subnetId := network.Id(addr.SubnetId()) 107 for attempt := common.ShortAttempt.Start(); attempt.Next(); { 108 err = a.releaser.ReleaseAddress(addr.InstanceId(), subnetId, addr.Address()) 109 if err == nil { 110 return nil 111 } 112 } 113 // Don't remove the address from state so we 114 // can retry releasing the address later. 115 logger.Warningf("cannot release address %q: %v (will retry)", addr.Value(), err) 116 return errors.Trace(err) 117 } 118 119 // SetUp is part of the StringsWorker interface. 120 func (a *addresserHandler) SetUp() (apiWatcher.StringsWatcher, error) { 121 return a.st.WatchIPAddresses(), nil 122 } 123 124 // TearDown is part of the StringsWorker interface. 125 func (a *addresserHandler) TearDown() error { 126 return nil 127 }