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