github.com/wallyworld/juju@v0.0.0-20161013125918-6cf1bc9d917a/worker/reboot/reboot.go (about)

     1  // Copyright 2014 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package reboot
     5  
     6  import (
     7  	"time"
     8  
     9  	"github.com/juju/errors"
    10  	"github.com/juju/loggo"
    11  	"github.com/juju/mutex"
    12  	"github.com/juju/utils/clock"
    13  	"gopkg.in/juju/names.v2"
    14  	"gopkg.in/tomb.v1"
    15  
    16  	"github.com/juju/juju/agent"
    17  	"github.com/juju/juju/api/reboot"
    18  	"github.com/juju/juju/apiserver/params"
    19  	"github.com/juju/juju/watcher"
    20  	"github.com/juju/juju/worker"
    21  )
    22  
    23  var logger = loggo.GetLogger("juju.worker.reboot")
    24  
    25  // The reboot worker listens for changes to the reboot flag and
    26  // exists with worker.ErrRebootMachine if the machine should reboot or
    27  // with worker.ErrShutdownMachine if it should shutdown. This will be picked
    28  // up by the machine agent as a fatal error and will do the
    29  // right thing (reboot or shutdown)
    30  type Reboot struct {
    31  	tomb            tomb.Tomb
    32  	st              reboot.State
    33  	tag             names.MachineTag
    34  	machineLockName string
    35  	clock           clock.Clock
    36  }
    37  
    38  func NewReboot(st reboot.State, agentConfig agent.Config, machineLockName string, clock clock.Clock) (worker.Worker, error) {
    39  	tag, ok := agentConfig.Tag().(names.MachineTag)
    40  	if !ok {
    41  		return nil, errors.Errorf("Expected names.MachineTag, got %T: %v", agentConfig.Tag(), agentConfig.Tag())
    42  	}
    43  	r := &Reboot{
    44  		st:              st,
    45  		tag:             tag,
    46  		machineLockName: machineLockName,
    47  		clock:           clock,
    48  	}
    49  	w, err := watcher.NewNotifyWorker(watcher.NotifyConfig{
    50  		Handler: r,
    51  	})
    52  	return w, errors.Trace(err)
    53  }
    54  
    55  func (r *Reboot) SetUp() (watcher.NotifyWatcher, error) {
    56  	watcher, err := r.st.WatchForRebootEvent()
    57  	return watcher, errors.Trace(err)
    58  }
    59  
    60  func (r *Reboot) Handle(_ <-chan struct{}) error {
    61  	rAction, err := r.st.GetRebootAction()
    62  	if err != nil {
    63  		return errors.Trace(err)
    64  	}
    65  	logger.Debugf("Reboot worker got action: %v", rAction)
    66  	// NOTE: Here we explicitly avoid stopping on the abort channel as we are
    67  	// wanting to make sure that we grab the lock and return an error
    68  	// sufficiently heavyweight to get the agent to restart.
    69  	spec := mutex.Spec{
    70  		Name:  r.machineLockName,
    71  		Clock: r.clock,
    72  		Delay: 250 * time.Millisecond,
    73  	}
    74  
    75  	switch rAction {
    76  	case params.ShouldReboot:
    77  		logger.Debugf("acquiring mutex %q for reboot", r.machineLockName)
    78  		if _, err := mutex.Acquire(spec); err != nil {
    79  			return errors.Trace(err)
    80  		}
    81  		logger.Debugf("mutex %q acquired, won't release", r.machineLockName)
    82  		return worker.ErrRebootMachine
    83  	case params.ShouldShutdown:
    84  		logger.Debugf("acquiring mutex %q for shutdown", r.machineLockName)
    85  		if _, err := mutex.Acquire(spec); err != nil {
    86  			return errors.Trace(err)
    87  		}
    88  		logger.Debugf("mutex %q acquired, won't release", r.machineLockName)
    89  		return worker.ErrShutdownMachine
    90  	default:
    91  		return nil
    92  	}
    93  }
    94  
    95  func (r *Reboot) TearDown() error {
    96  	// nothing to teardown.
    97  	return nil
    98  }