github.com/Pankov404/juju@v0.0.0-20150703034450-be266991dceb/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/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  }
    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 MachineAccessor, agentConfig agent.Config) worker.Worker {
    32  	mr := &Machiner{st: st, tag: agentConfig.Tag().(names.MachineTag)}
    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(mr.tag, 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(tag names.MachineTag, m Machine) error {
    65  	addrs, err := interfaceAddrs()
    66  	if err != nil {
    67  		return err
    68  	}
    69  	var hostAddresses []network.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  		address := network.NewAddress(ip.String())
    81  		// Filter out link-local addresses as we cannot reliably use them.
    82  		if address.Scope == network.ScopeLinkLocal {
    83  			continue
    84  		}
    85  		hostAddresses = append(hostAddresses, address)
    86  	}
    87  	if len(hostAddresses) == 0 {
    88  		return nil
    89  	}
    90  	// Filter out any LXC bridge addresses.
    91  	hostAddresses = network.FilterLXCAddresses(hostAddresses)
    92  	logger.Infof("setting addresses for %v to %q", tag, hostAddresses)
    93  	return m.SetMachineAddresses(hostAddresses)
    94  }
    95  
    96  func (mr *Machiner) Handle(_ <-chan struct{}) error {
    97  	if err := mr.machine.Refresh(); params.IsCodeNotFoundOrCodeUnauthorized(err) {
    98  		return worker.ErrTerminateAgent
    99  	} else if err != nil {
   100  		return err
   101  	}
   102  	life := mr.machine.Life()
   103  	if life == params.Alive {
   104  		return nil
   105  	}
   106  	logger.Debugf("%q is now %s", mr.tag, life)
   107  	if err := mr.machine.SetStatus(params.StatusStopped, "", nil); err != nil {
   108  		return fmt.Errorf("%s failed to set status stopped: %v", mr.tag, err)
   109  	}
   110  
   111  	// Attempt to mark the machine Dead. If the machine still has units
   112  	// assigned, or storage attached, this will fail with
   113  	// CodeHasAssignedUnits or CodeMachineHasAttachedStorage respectively.
   114  	// Once units or storage are removed, the watcher will trigger again
   115  	// and we'll reattempt.
   116  	if err := mr.machine.EnsureDead(); err != nil {
   117  		if params.IsCodeHasAssignedUnits(err) {
   118  			return nil
   119  		}
   120  		if params.IsCodeMachineHasAttachedStorage(err) {
   121  			logger.Tracef("machine still has storage attached")
   122  			return nil
   123  		}
   124  		return fmt.Errorf("%s failed to set machine to dead: %v", mr.tag, err)
   125  	}
   126  	return worker.ErrTerminateAgent
   127  }
   128  
   129  func (mr *Machiner) TearDown() error {
   130  	// Nothing to do here.
   131  	return nil
   132  }