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:
@@ -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
|
||||||
|
@@ -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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user