github.com/mhilton/juju-juju@v0.0.0-20150901100907-a94dd2c73455/worker/machiner/machiner.go (about) 1 // Copyright 2012, 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 package machiner 4 5 import ( 6 "net" 7 8 "github.com/juju/errors" 9 "github.com/juju/loggo" 10 "github.com/juju/names" 11 12 "github.com/juju/juju/agent" 13 "github.com/juju/juju/api/watcher" 14 "github.com/juju/juju/apiserver/params" 15 "github.com/juju/juju/network" 16 "github.com/juju/juju/worker" 17 ) 18 19 var logger = loggo.GetLogger("juju.worker.machiner") 20 21 // Machiner is responsible for a machine agent's lifecycle. 22 type Machiner struct { 23 st MachineAccessor 24 tag names.MachineTag 25 machine Machine 26 ignoreAddressesOnStart bool 27 } 28 29 // NewMachiner returns a Worker that will wait for the identified machine 30 // to become Dying and make it Dead; or until the machine becomes Dead by 31 // other means. 32 func NewMachiner(st MachineAccessor, agentConfig agent.Config, ignoreAddressesOnStart bool) worker.Worker { 33 mr := &Machiner{st: st, tag: agentConfig.Tag().(names.MachineTag), ignoreAddressesOnStart: ignoreAddressesOnStart} 34 return worker.NewNotifyWorker(mr) 35 } 36 37 func (mr *Machiner) SetUp() (watcher.NotifyWatcher, error) { 38 // Find which machine we're responsible for. 39 m, err := mr.st.Machine(mr.tag) 40 if params.IsCodeNotFoundOrCodeUnauthorized(err) { 41 return nil, worker.ErrTerminateAgent 42 } else if err != nil { 43 return nil, errors.Trace(err) 44 } 45 mr.machine = m 46 47 if mr.ignoreAddressesOnStart { 48 logger.Debugf("machine addresses ignored on start - resetting machine addresses") 49 if err := m.SetMachineAddresses(nil); err != nil { 50 return nil, errors.Annotate(err, "reseting machine addresses") 51 } 52 } else { 53 // Set the addresses in state to the host's addresses. 54 if err := setMachineAddresses(mr.tag, m); err != nil { 55 return nil, errors.Annotate(err, "setting machine addresses") 56 } 57 } 58 59 // Mark the machine as started and log it. 60 if err := m.SetStatus(params.StatusStarted, "", nil); err != nil { 61 return nil, errors.Annotatef(err, "%s failed to set status started", mr.tag) 62 } 63 logger.Infof("%q started", mr.tag) 64 65 return m.Watch() 66 } 67 68 var interfaceAddrs = net.InterfaceAddrs 69 70 // setMachineAddresses sets the addresses for this machine to all of the 71 // host's non-loopback interface IP addresses. 72 func setMachineAddresses(tag names.MachineTag, m Machine) error { 73 addrs, err := interfaceAddrs() 74 if err != nil { 75 return err 76 } 77 var hostAddresses []network.Address 78 for _, addr := range addrs { 79 var ip net.IP 80 switch addr := addr.(type) { 81 case *net.IPAddr: 82 ip = addr.IP 83 case *net.IPNet: 84 ip = addr.IP 85 default: 86 continue 87 } 88 address := network.NewAddress(ip.String()) 89 // Filter out link-local addresses as we cannot reliably use them. 90 if address.Scope == network.ScopeLinkLocal { 91 continue 92 } 93 hostAddresses = append(hostAddresses, address) 94 } 95 if len(hostAddresses) == 0 { 96 return nil 97 } 98 // Filter out any LXC bridge addresses. 99 hostAddresses = network.FilterLXCAddresses(hostAddresses) 100 logger.Infof("setting addresses for %v to %q", tag, hostAddresses) 101 return m.SetMachineAddresses(hostAddresses) 102 } 103 104 func (mr *Machiner) Handle(_ <-chan struct{}) error { 105 if err := mr.machine.Refresh(); params.IsCodeNotFoundOrCodeUnauthorized(err) { 106 return worker.ErrTerminateAgent 107 } else if err != nil { 108 return err 109 } 110 life := mr.machine.Life() 111 if life == params.Alive { 112 return nil 113 } 114 logger.Debugf("%q is now %s", mr.tag, life) 115 if err := mr.machine.SetStatus(params.StatusStopped, "", nil); err != nil { 116 return errors.Annotatef(err, "%s failed to set status stopped", mr.tag) 117 } 118 119 // Attempt to mark the machine Dead. If the machine still has units 120 // assigned, or storage attached, this will fail with 121 // CodeHasAssignedUnits or CodeMachineHasAttachedStorage respectively. 122 // Once units or storage are removed, the watcher will trigger again 123 // and we'll reattempt. 124 if err := mr.machine.EnsureDead(); err != nil { 125 if params.IsCodeHasAssignedUnits(err) { 126 return nil 127 } 128 if params.IsCodeMachineHasAttachedStorage(err) { 129 logger.Tracef("machine still has storage attached") 130 return nil 131 } 132 return errors.Annotatef(err, "%s failed to set machine to dead", mr.tag) 133 } 134 return worker.ErrTerminateAgent 135 } 136 137 func (mr *Machiner) TearDown() error { 138 // Nothing to do here. 139 return nil 140 }