github.com/cloud-green/juju@v0.0.0-20151002100041-a00291338d3d/cmd/jujud/reboot/reboot.go (about)

     1  package reboot
     2  
     3  import (
     4  	"io/ioutil"
     5  	"os"
     6  	"os/exec"
     7  	"time"
     8  
     9  	"github.com/juju/errors"
    10  	"github.com/juju/loggo"
    11  	"github.com/juju/names"
    12  
    13  	"github.com/juju/juju/agent"
    14  	"github.com/juju/juju/api"
    15  	"github.com/juju/juju/api/reboot"
    16  	"github.com/juju/juju/apiserver/params"
    17  	"github.com/juju/juju/container"
    18  	"github.com/juju/juju/container/factory"
    19  	"github.com/juju/juju/instance"
    20  )
    21  
    22  var logger = loggo.GetLogger("juju.cmd.jujud.reboot")
    23  var timeout = time.Duration(10 * time.Minute)
    24  var rebootAfter = 15
    25  
    26  func runCommand(args []string) error {
    27  	_, err := exec.Command(args[0], args[1:]...).Output()
    28  	if err != nil {
    29  		return errors.Trace(err)
    30  	}
    31  	return nil
    32  }
    33  
    34  var tmpFile = func() (*os.File, error) {
    35  	f, err := ioutil.TempFile(os.TempDir(), "juju-reboot")
    36  	if err != nil {
    37  		return nil, errors.Trace(err)
    38  	}
    39  	return f, nil
    40  }
    41  
    42  // Reboot implements the ExecuteReboot command which will reboot a machine
    43  // once all containers have shut down, or a timeout is reached
    44  type Reboot struct {
    45  	acfg     agent.Config
    46  	apistate api.Connection
    47  	tag      names.MachineTag
    48  	st       *reboot.State
    49  }
    50  
    51  func NewRebootWaiter(apistate api.Connection, acfg agent.Config) (*Reboot, error) {
    52  	rebootState, err := apistate.Reboot()
    53  	if err != nil {
    54  		return nil, errors.Trace(err)
    55  	}
    56  	tag, ok := acfg.Tag().(names.MachineTag)
    57  	if !ok {
    58  		return nil, errors.Errorf("Expected names.MachineTag, got: %T --> %v", acfg.Tag(), acfg.Tag())
    59  	}
    60  	return &Reboot{
    61  		acfg:     acfg,
    62  		st:       rebootState,
    63  		tag:      tag,
    64  		apistate: apistate,
    65  	}, nil
    66  }
    67  
    68  // ExecuteReboot will wait for all running containers to stop, and then execute
    69  // a shutdown or a reboot (based on the action param)
    70  func (r *Reboot) ExecuteReboot(action params.RebootAction) error {
    71  	err := r.waitForContainersOrTimeout()
    72  	if err != nil {
    73  		return errors.Trace(err)
    74  	}
    75  
    76  	err = scheduleAction(action, rebootAfter)
    77  	if err != nil {
    78  		return errors.Trace(err)
    79  	}
    80  
    81  	err = r.st.ClearReboot()
    82  	if err != nil {
    83  		return errors.Trace(err)
    84  	}
    85  	return nil
    86  }
    87  
    88  func (r *Reboot) runningContainers() ([]instance.Instance, error) {
    89  	runningInstances := []instance.Instance{}
    90  
    91  	for _, val := range instance.ContainerTypes {
    92  		managerConfig := container.ManagerConfig{container.ConfigName: container.DefaultNamespace}
    93  		if namespace := r.acfg.Value(agent.Namespace); namespace != "" {
    94  			managerConfig[container.ConfigName] = namespace
    95  		}
    96  		cfg := container.ManagerConfig(managerConfig)
    97  		manager, err := factory.NewContainerManager(val, cfg, nil)
    98  		if err != nil {
    99  			logger.Warningf("Failed to get manager for container type %v: %v", val, err)
   100  			continue
   101  		}
   102  		if !manager.IsInitialized() {
   103  			continue
   104  		}
   105  		instances, err := manager.ListContainers()
   106  		if err != nil {
   107  			logger.Warningf("Failed to list containers: %v", err)
   108  		}
   109  		runningInstances = append(runningInstances, instances...)
   110  	}
   111  	return runningInstances, nil
   112  }
   113  
   114  func (r *Reboot) waitForContainersOrTimeout() error {
   115  	c := make(chan error, 1)
   116  	quit := make(chan bool, 1)
   117  	go func() {
   118  		for {
   119  			select {
   120  			case <-quit:
   121  				c <- nil
   122  				return
   123  			default:
   124  				containers, err := r.runningContainers()
   125  				if err != nil {
   126  					c <- err
   127  					return
   128  				}
   129  				if len(containers) == 0 {
   130  					c <- nil
   131  					return
   132  				}
   133  				logger.Warningf("Waiting for containers to shutdown: %v", containers)
   134  				time.Sleep(1 * time.Second)
   135  			}
   136  		}
   137  	}()
   138  
   139  	select {
   140  	case <-time.After(timeout):
   141  
   142  		// Containers are still up after timeout. C'est la vie
   143  		logger.Infof("Timeout reached waiting for containers to shutdown")
   144  		quit <- true
   145  	case err := <-c:
   146  		return errors.Trace(err)
   147  
   148  	}
   149  	return nil
   150  }