github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/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  	"github.com/juju/clock"
     8  	"github.com/juju/errors"
     9  	"github.com/juju/loggo"
    10  	"gopkg.in/juju/names.v2"
    11  	"gopkg.in/juju/worker.v1"
    12  	"gopkg.in/tomb.v2"
    13  
    14  	"github.com/juju/juju/agent"
    15  	"github.com/juju/juju/api/reboot"
    16  	"github.com/juju/juju/apiserver/params"
    17  	"github.com/juju/juju/core/machinelock"
    18  	"github.com/juju/juju/core/watcher"
    19  	jworker "github.com/juju/juju/worker"
    20  )
    21  
    22  var logger = loggo.GetLogger("juju.worker.reboot")
    23  
    24  // The reboot worker listens for changes to the reboot flag and
    25  // exists with worker.ErrRebootMachine if the machine should reboot or
    26  // with worker.ErrShutdownMachine if it should shutdown. This will be picked
    27  // up by the machine agent as a fatal error and will do the
    28  // right thing (reboot or shutdown)
    29  type Reboot struct {
    30  	tomb        tomb.Tomb
    31  	st          reboot.State
    32  	tag         names.MachineTag
    33  	machineLock machinelock.Lock
    34  	clock       clock.Clock
    35  }
    36  
    37  func NewReboot(st reboot.State, agentConfig agent.Config, machineLock machinelock.Lock, clock clock.Clock) (worker.Worker, error) {
    38  	tag, ok := agentConfig.Tag().(names.MachineTag)
    39  	if !ok {
    40  		return nil, errors.Errorf("Expected names.MachineTag, got %T: %v", agentConfig.Tag(), agentConfig.Tag())
    41  	}
    42  	r := &Reboot{
    43  		st:          st,
    44  		tag:         tag,
    45  		machineLock: machineLock,
    46  		clock:       clock,
    47  	}
    48  	w, err := watcher.NewNotifyWorker(watcher.NotifyConfig{
    49  		Handler: r,
    50  	})
    51  	return w, errors.Trace(err)
    52  }
    53  
    54  func (r *Reboot) SetUp() (watcher.NotifyWatcher, error) {
    55  	watcher, err := r.st.WatchForRebootEvent()
    56  	return watcher, errors.Trace(err)
    57  }
    58  
    59  func (r *Reboot) Handle(_ <-chan struct{}) error {
    60  	rAction, err := r.st.GetRebootAction()
    61  	if err != nil {
    62  		return errors.Trace(err)
    63  	}
    64  	logger.Debugf("Reboot worker got action: %v", rAction)
    65  
    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 := machinelock.Spec{
    70  		Worker:   "reboot",
    71  		NoCancel: true,
    72  	}
    73  
    74  	switch rAction {
    75  	case params.ShouldReboot:
    76  		spec.Comment = "reboot"
    77  		if _, err := r.machineLock.Acquire(spec); err != nil {
    78  			return errors.Trace(err)
    79  		}
    80  		logger.Debugf("machine lock will not be released manually")
    81  		err = jworker.ErrRebootMachine
    82  	case params.ShouldShutdown:
    83  		spec.Comment = "shutdown"
    84  		if _, err := r.machineLock.Acquire(spec); err != nil {
    85  			return errors.Trace(err)
    86  		}
    87  		logger.Debugf("machine lock will not be released manually")
    88  		err = jworker.ErrShutdownMachine
    89  	}
    90  
    91  	if err != nil {
    92  		// We clear the reboot flag here rather than when we are attempting to
    93  		// handle the reboot error in the machine agent code as it is possible
    94  		// that the machine agent is also a controller, and the apiserver has been
    95  		// shut down. It is better to clear the flag and not reboot on a weird
    96  		// error rather than get into a reboot loop because we can't shutdown.
    97  		if err := r.st.ClearReboot(); err != nil {
    98  			logger.Infof("unable to clear reboot flag: %v", err)
    99  		}
   100  	}
   101  	return err
   102  }
   103  
   104  func (r *Reboot) TearDown() error {
   105  	// nothing to teardown.
   106  	return nil
   107  }