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 }