1
0
mirror of https://github.com/rancher/os.git synced 2025-09-01 06:40:31 +00:00

More graceful shutdown and sync before syscall

This commit is contained in:
Darren Shepherd
2015-03-14 21:31:11 -07:00
parent ac2459ba37
commit c0b02ca361
2 changed files with 139 additions and 56 deletions

View File

@@ -4,40 +4,122 @@ import (
"bufio" "bufio"
"errors" "errors"
"os" "os"
"path/filepath"
"strconv" "strconv"
"strings" "strings"
"syscall" "syscall"
log "github.com/Sirupsen/logrus" log "github.com/Sirupsen/logrus"
"github.com/fsouza/go-dockerclient" dockerClient "github.com/fsouza/go-dockerclient"
"github.com/rancherio/os/docker"
) )
const ( const (
dockerPath = "unix:///var/run/system-docker.sock" DOCKER_CGROUPS_FILE = "/proc/self/cgroup"
dockerCGroupsFile = "/proc/self/cgroup"
) )
func PowerOff() { func runDocker() error {
if os.Geteuid() != 0 { if os.ExpandEnv("${IN_DOCKER}") == "true" {
log.Fatalf("%s: Permission Denied", os.Args[0]) return nil
} }
syscall.Sync()
client, err := docker.NewSystemClient()
if err != nil {
return err
}
name := filepath.Base(os.Args[0])
exiting, err := client.InspectContainer(name)
if exiting != nil {
err := client.RemoveContainer(dockerClient.RemoveContainerOptions{
ID: exiting.ID,
Force: true,
})
if err != nil {
return err
}
}
currentContainerId, err := getCurrentContainerId()
if err != nil {
return err
}
currentContainer, err := client.InspectContainer(currentContainerId)
if err != nil {
return err
}
powerContainer, err := client.CreateContainer(dockerClient.CreateContainerOptions{
Name: name,
Config: &dockerClient.Config{
Image: currentContainer.Config.Image,
Cmd: os.Args,
Env: []string{
"IN_DOCKER=true",
},
},
HostConfig: &dockerClient.HostConfig{
PidMode: "host",
VolumesFrom: []string{
currentContainer.ID,
},
Privileged: true,
},
})
if err != nil {
return err
}
go func() {
client.AttachToContainer(dockerClient.AttachToContainerOptions{
Container: powerContainer.ID,
OutputStream: os.Stdout,
ErrorStream: os.Stderr,
Stderr: true,
Stdout: true,
})
}()
err = client.StartContainer(powerContainer.ID, powerContainer.HostConfig)
if err != nil {
return err
}
_, err = client.WaitContainer(powerContainer.ID)
if err != nil {
log.Fatal(err)
}
os.Exit(0)
return nil
}
func common() {
if os.Geteuid() != 0 {
log.Fatalf("%s: Need to be root", os.Args[0])
}
if err := runDocker(); err != nil {
log.Fatal(err)
}
}
func PowerOff() {
common()
reboot(syscall.LINUX_REBOOT_CMD_POWER_OFF) reboot(syscall.LINUX_REBOOT_CMD_POWER_OFF)
} }
func Reboot() { func Reboot() {
if os.Geteuid() != 0 { common()
log.Fatalf("%s: Permission Denied", os.Args[0])
}
syscall.Sync()
reboot(syscall.LINUX_REBOOT_CMD_RESTART) reboot(syscall.LINUX_REBOOT_CMD_RESTART)
} }
func Halt() { func Halt() {
if os.Geteuid() != 0 { common()
log.Fatalf("%s: Permission Denied", os.Args[0])
}
syscall.Sync()
reboot(syscall.LINUX_REBOOT_CMD_HALT) reboot(syscall.LINUX_REBOOT_CMD_HALT)
} }
@@ -46,6 +128,9 @@ func reboot(code int) {
if err != nil { if err != nil {
log.Error(err) log.Error(err)
} }
syscall.Sync()
err = syscall.Reboot(code) err = syscall.Reboot(code)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
@@ -55,69 +140,72 @@ func reboot(code int) {
func shutDownContainers() error { func shutDownContainers() error {
var err error var err error
shutDown := true shutDown := true
timeout := uint(2) timeout := 2
for i := range os.Args { for i, arg := range os.Args {
arg := os.Args[i]
if arg == "-f" || arg == "--f" || arg == "--force" { if arg == "-f" || arg == "--f" || arg == "--force" {
shutDown = false shutDown = false
} }
if arg == "-t" || arg == "--t" || arg == "--timeout" { if arg == "-t" || arg == "--t" || arg == "--timeout" {
if len(os.Args) > i+1 { if len(os.Args) > i+1 {
t, er := strconv.Atoi(os.Args[i+1]) t, err := strconv.Atoi(os.Args[i+1])
if er != nil { if err != nil {
return err return err
} }
timeout = uint(t) timeout = t
} else { } else {
log.Info("please specify a timeout") log.Error("please specify a timeout")
} }
} }
} }
if !shutDown { if !shutDown {
return nil return nil
} }
client, err := docker.NewClient(dockerPath) client, err := docker.NewSystemClient()
if err != nil { if err != nil {
return err return err
} }
opts := docker.ListContainersOptions{All: true, Filters: map[string][]string{"status": []string{"running"}}} opts := dockerClient.ListContainersOptions{
var containers []docker.APIContainers All: true,
Filters: map[string][]string{
containers, err = client.ListContainers(opts) "status": []string{"running"},
},
}
containers, err := client.ListContainers(opts)
if err != nil { if err != nil {
return err return err
} }
currentContainerId, err := getCurrentContainerId() currentContainerId, err := getCurrentContainerId()
if err != nil { if err != nil {
return err return err
} }
var stopErrorStrings []string var stopErrorStrings []string
for i := range containers { for _, container := range containers {
if containers[i].ID == currentContainerId { if container.ID == currentContainerId {
continue continue
} }
stopErr := client.StopContainer(containers[i].ID, timeout)
log.Infof("Stopping %s : %v", container.ID[:12], container.Names)
stopErr := client.StopContainer(container.ID, uint(timeout))
if stopErr != nil { if stopErr != nil {
stopErrorStrings = append(stopErrorStrings, " ["+containers[i].ID+"] "+stopErr.Error()) stopErrorStrings = append(stopErrorStrings, " ["+container.ID+"] "+stopErr.Error())
} }
} }
var waitErrorStrings []string var waitErrorStrings []string
for i := range containers { for _, container := range containers {
if containers[i].ID == currentContainerId { if container.ID == currentContainerId {
continue continue
} }
_, waitErr := client.WaitContainer(containers[i].ID) _, waitErr := client.WaitContainer(container.ID)
if waitErr != nil { if waitErr != nil {
waitErrorStrings = append(waitErrorStrings, " ["+containers[i].ID+"] "+waitErr.Error()) waitErrorStrings = append(waitErrorStrings, " ["+container.ID+"] "+waitErr.Error())
} }
} }
@@ -129,7 +217,7 @@ func shutDownContainers() error {
} }
func getCurrentContainerId() (string, error) { func getCurrentContainerId() (string, error) {
file, err := os.Open(dockerCGroupsFile) file, err := os.Open(DOCKER_CGROUPS_FILE)
if err != nil { if err != nil {
return "", err return "", err

View File

@@ -1,10 +1,9 @@
package power package power
import( import (
"fmt"
"os" "os"
"github.com/codegangsta/cli" "github.com/codegangsta/cli"
"github.com/rancherio/os/config" "github.com/rancherio/os/config"
) )
@@ -18,27 +17,24 @@ func Main() {
app.Email = "sid@rancher.com" app.Email = "sid@rancher.com"
app.EnableBashCompletion = true app.EnableBashCompletion = true
app.Action = shutdown app.Action = shutdown
app.Flags = []cli.Flag{ app.Flags = []cli.Flag{
cli.StringFlag { cli.StringFlag{
Name: "r, R", Name: "r, R",
Usage: "reboot after shutdown", Usage: "reboot after shutdown",
}, },
cli.StringFlag { cli.StringFlag{
Name: "h", Name: "h",
Usage: "halt the system", Usage: "halt the system",
}, },
} }
app.HideHelp = true app.HideHelp = true
app.Run(os.Args) app.Run(os.Args)
} }
func shutdown(c *cli.Context) { func shutdown(c *cli.Context) {
common()
reboot := c.String("r") reboot := c.String("r")
poweroff := c.String("h") poweroff := c.String("h")
fmt.Println(reboot)
fmt.Println(poweroff)
if reboot == "now" { if reboot == "now" {
Reboot() Reboot()
@@ -46,4 +42,3 @@ func shutdown(c *cli.Context) {
PowerOff() PowerOff()
} }
} }