github.com/altoros/juju-vmware@v0.0.0-20150312064031-f19ae857ccca/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 "fmt" 7 "net" 8 9 "github.com/juju/loggo" 10 "github.com/juju/names" 11 12 "github.com/juju/juju/agent" 13 "github.com/juju/juju/api/machiner" 14 "github.com/juju/juju/api/watcher" 15 "github.com/juju/juju/apiserver/params" 16 "github.com/juju/juju/network" 17 "github.com/juju/juju/worker" 18 ) 19 20 var logger = loggo.GetLogger("juju.worker.machiner") 21 22 // Machiner is responsible for a machine agent's lifecycle. 23 type Machiner struct { 24 st *machiner.State 25 tag names.MachineTag 26 machine *machiner.Machine 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 *machiner.State, agentConfig agent.Config) worker.Worker { 33 // TODO(dfc) clearly agentConfig.Tag() can _only_ return a machine tag 34 mr := &Machiner{st: st, tag: agentConfig.Tag().(names.MachineTag)} 35 return worker.NewNotifyWorker(mr) 36 } 37 38 func (mr *Machiner) SetUp() (watcher.NotifyWatcher, error) { 39 // Find which machine we're responsible for. 40 m, err := mr.st.Machine(mr.tag) 41 if params.IsCodeNotFoundOrCodeUnauthorized(err) { 42 return nil, worker.ErrTerminateAgent 43 } else if err != nil { 44 return nil, err 45 } 46 mr.machine = m 47 48 // Set the addresses in state to the host's addresses. 49 if err := setMachineAddresses(m); err != nil { 50 return nil, err 51 } 52 53 // Mark the machine as started and log it. 54 if err := m.SetStatus(params.StatusStarted, "", nil); err != nil { 55 return nil, fmt.Errorf("%s failed to set status started: %v", mr.tag, err) 56 } 57 logger.Infof("%q started", mr.tag) 58 59 return m.Watch() 60 } 61 62 var interfaceAddrs = net.InterfaceAddrs 63 64 // setMachineAddresses sets the addresses for this machine to all of the 65 // host's non-loopback interface IP addresses. 66 func setMachineAddresses(m *machiner.Machine) error { 67 addrs, err := interfaceAddrs() 68 if err != nil { 69 return err 70 } 71 var hostAddresses []network.Address 72 for _, addr := range addrs { 73 var ip net.IP 74 switch addr := addr.(type) { 75 case *net.IPAddr: 76 ip = addr.IP 77 case *net.IPNet: 78 ip = addr.IP 79 default: 80 continue 81 } 82 address := network.NewAddress(ip.String(), network.ScopeUnknown) 83 // Filter out link-local addresses as we cannot reliably use them. 84 if address.Scope == network.ScopeLinkLocal { 85 continue 86 } 87 hostAddresses = append(hostAddresses, address) 88 } 89 if len(hostAddresses) == 0 { 90 return nil 91 } 92 logger.Infof("setting addresses for %v to %q", m.Tag(), hostAddresses) 93 return m.SetMachineAddresses(hostAddresses) 94 } 95 96 func (mr *Machiner) Handle() error { 97 if err := mr.machine.Refresh(); params.IsCodeNotFoundOrCodeUnauthorized(err) { 98 return worker.ErrTerminateAgent 99 } else if err != nil { 100 return err 101 } 102 if mr.machine.Life() == params.Alive { 103 return nil 104 } 105 logger.Debugf("%q is now %s", mr.tag, mr.machine.Life()) 106 if err := mr.machine.SetStatus(params.StatusStopped, "", nil); err != nil { 107 return fmt.Errorf("%s failed to set status stopped: %v", mr.tag, err) 108 } 109 110 // If the machine is Dying, it has no units, 111 // and can be safely set to Dead. 112 if err := mr.machine.EnsureDead(); err != nil { 113 return fmt.Errorf("%s failed to set machine to dead: %v", mr.tag, err) 114 } 115 return worker.ErrTerminateAgent 116 } 117 118 func (mr *Machiner) TearDown() error { 119 // Nothing to do here. 120 return nil 121 }