github.com/cloudbase/juju-core@v0.0.0-20140504232958-a7271ac7912f/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 11 "launchpad.net/juju-core/agent" 12 "launchpad.net/juju-core/instance" 13 "launchpad.net/juju-core/state/api/machiner" 14 "launchpad.net/juju-core/state/api/params" 15 "launchpad.net/juju-core/state/api/watcher" 16 "launchpad.net/juju-core/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 *machiner.State 24 tag string 25 machine *machiner.Machine 26 } 27 28 // NewMachiner returns a Worker that will wait for the identified machine 29 // to become Dying and make it Dead; or until the machine becomes Dead by 30 // other means. 31 func NewMachiner(st *machiner.State, agentConfig agent.Config) worker.Worker { 32 mr := &Machiner{st: st, tag: agentConfig.Tag()} 33 return worker.NewNotifyWorker(mr) 34 } 35 36 func (mr *Machiner) SetUp() (watcher.NotifyWatcher, error) { 37 // Find which machine we're responsible for. 38 m, err := mr.st.Machine(mr.tag) 39 if params.IsCodeNotFoundOrCodeUnauthorized(err) { 40 return nil, worker.ErrTerminateAgent 41 } else if err != nil { 42 return nil, err 43 } 44 mr.machine = m 45 46 // Set the addresses in state to the host's addresses. 47 if err := setMachineAddresses(m); err != nil { 48 return nil, err 49 } 50 51 // Mark the machine as started and log it. 52 if err := m.SetStatus(params.StatusStarted, "", nil); err != nil { 53 return nil, fmt.Errorf("%s failed to set status started: %v", mr.tag, err) 54 } 55 logger.Infof("%q started", mr.tag) 56 57 return m.Watch() 58 } 59 60 var interfaceAddrs = net.InterfaceAddrs 61 62 // setMachineAddresses sets the addresses for this machine to all of the 63 // host's non-loopback interface IP addresses. 64 func setMachineAddresses(m *machiner.Machine) error { 65 addrs, err := interfaceAddrs() 66 if err != nil { 67 return err 68 } 69 var hostAddresses []instance.Address 70 for _, addr := range addrs { 71 var ip net.IP 72 switch addr := addr.(type) { 73 case *net.IPAddr: 74 ip = addr.IP 75 case *net.IPNet: 76 ip = addr.IP 77 default: 78 continue 79 } 80 if ip.IsLoopback() { 81 continue 82 } 83 hostAddresses = append(hostAddresses, instance.NewAddress(ip.String())) 84 } 85 if len(hostAddresses) == 0 { 86 return nil 87 } 88 logger.Infof("setting addresses for %v to %q", m.Tag(), hostAddresses) 89 return m.SetMachineAddresses(hostAddresses) 90 } 91 92 func (mr *Machiner) Handle() error { 93 if err := mr.machine.Refresh(); params.IsCodeNotFoundOrCodeUnauthorized(err) { 94 return worker.ErrTerminateAgent 95 } else if err != nil { 96 return err 97 } 98 if mr.machine.Life() == params.Alive { 99 return nil 100 } 101 logger.Debugf("%q is now %s", mr.tag, mr.machine.Life()) 102 if err := mr.machine.SetStatus(params.StatusStopped, "", nil); err != nil { 103 return fmt.Errorf("%s failed to set status stopped: %v", mr.tag, err) 104 } 105 106 // If the machine is Dying, it has no units, 107 // and can be safely set to Dead. 108 if err := mr.machine.EnsureDead(); err != nil { 109 return fmt.Errorf("%s failed to set machine to dead: %v", mr.tag, err) 110 } 111 return worker.ErrTerminateAgent 112 } 113 114 func (mr *Machiner) TearDown() error { 115 // Nothing to do here. 116 return nil 117 }