From 56a4f96b247bb863143b028d6cb880840e86a03e Mon Sep 17 00:00:00 2001 From: sidharthamani Date: Thu, 12 Feb 2015 15:22:48 -0800 Subject: [PATCH] add power functions - down, restart, halt --- config/config.go | 11 ++-- init/init.go | 7 ++- main.go | 5 +- power/power.go | 151 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 167 insertions(+), 7 deletions(-) create mode 100644 power/power.go diff --git a/config/config.go b/config/config.go index 26ba1fd2..a571693e 100644 --- a/config/config.go +++ b/config/config.go @@ -78,11 +78,11 @@ func NewConfig() *Config { "8.8.8.8", "8.8.4.4", }, - ImagesPath: "/", - ImagesPattern: "images*.tar", - StateRequired: false, + ImagesPath: "/", + ImagesPattern: "images*.tar", + StateRequired: false, StateDev: "LABEL=RANCHER_STATE", - StateDevFSType: "auto", + StateDevFSType: "ext4", SysInit: "/sbin/init-sys", SystemDockerArgs: []string{"docker", "-d", "-s", "overlay", "-b", "none"}, UserInit: "/sbin/init-user", @@ -143,6 +143,9 @@ func NewConfig() *Config { "--volume", "/init:/usr/bin/system-docker:ro", "--volume", "/init:/usr/bin/respawn:ro", "--volume", "/var/run/docker.sock:/var/run/system-docker.sock:ro", + "--volume", "/sbin/poweroff:/sbin/poweroff:ro", + "--volume", "/sbin/reboot:/sbin/reboot:ro", + "--volume", "/sbin/halt:/sbin/halt:ro", "--volumes-from", "system-state", "--net", "host", "--pid", "host", diff --git a/init/init.go b/init/init.go index 5025d979..3d9d0c65 100644 --- a/init/init.go +++ b/init/init.go @@ -55,6 +55,9 @@ var ( "/sbin/modprobe": "/busybox", "/var/run": "/run", DOCKER: "/docker", + "/sbin/poweroff": "/init", + "/sbin/halt": "/init", + "/sbin/reboot": "/init", } ) @@ -215,10 +218,10 @@ func mountState(cfg *config.Config) error { var err error dev := util.ResolveDevice(cfg.StateDev) - log.Debugf("Mounting state device %s", dev) + log.Debugf("Mounting state device %s", dev) fsType := cfg.StateDevFSType - log.Debugf("FsType has been set to %s", fsType) + log.Debugf("FsType has been set to %s", fsType) if fsType == "auto" { actualFsType, fsErr := util.GetFsType(dev) if fsErr != nil { diff --git a/main.go b/main.go index ef6bb34b..42963ea8 100644 --- a/main.go +++ b/main.go @@ -6,6 +6,7 @@ import ( log "github.com/Sirupsen/logrus" "github.com/docker/docker/pkg/reexec" osInit "github.com/rancherio/os/init" + "github.com/rancherio/os/power" "github.com/rancherio/os/respawn" "github.com/rancherio/os/sysinit" "github.com/rancherio/os/user" @@ -18,8 +19,10 @@ func main() { reexec.Register("/sbin/init-sys", sysinit.SysInit) reexec.Register("/usr/bin/system-docker", user.SystemDocker) reexec.Register("system-docker", user.SystemDocker) + reexec.Register("poweroff", power.PowerOff) + reexec.Register("reboot", power.Reboot) + reexec.Register("halt", power.Halt) reexec.Register("respawn", respawn.Main) - if !reexec.Init() { log.Fatalf("Failed to find an entry point for %s", os.Args[0]) } diff --git a/power/power.go b/power/power.go new file mode 100644 index 00000000..58409941 --- /dev/null +++ b/power/power.go @@ -0,0 +1,151 @@ +package power + +import ( + "bufio" + "errors" + "os" + "strconv" + "syscall" + "strings" + + "github.com/fsouza/go-dockerclient" +) + + +const ( + dockerPath = "unix:///var/run/system-docker.sock" + dockerCGroupsFile = "/proc/self/cgroup" +) + +func PowerOff() { + reboot(syscall.LINUX_REBOOT_CMD_POWER_OFF) +} + +func Reboot() { + reboot(syscall.LINUX_REBOOT_CMD_RESTART) +} + +func Halt() { + reboot(syscall.LINUX_REBOOT_CMD_HALT) +} + +func reboot(code int) { + err := shutDownContainers() + if err != nil { + panic(err) + } + err = syscall.Reboot(code) + if err != nil { + panic(err) + } +} + +func shutDownContainers() error { + var err error + shutDown := true + timeout := uint(0) + for i := range os.Args { + arg := os.Args[i] + if arg == "-f" || arg == "--f" || arg == "--force" { + shutDown = false + } + if arg == "-t" || arg == "--t" || arg == "--timeout" { + if len(os.Args) > i+1 { + t, er := strconv.Atoi(os.Args[i+1]) + if er != nil { + return err + } + timeout = uint(t) + } else { + panic("please specify a timeout") + } + } + } + if !shutDown { + return nil + } + client, err := docker.NewClient(dockerPath) + + if err != nil { + return err + } + + opts := docker.ListContainersOptions{All: true, Filters: map[string][]string{"status": []string{"running"}}} + var containers []docker.APIContainers + + containers, err = client.ListContainers(opts) + + if err != nil { + return err + } + + currentContainerId, err := getCurrentContainerId() + + if err != nil { + return err + } + + var stopErrorStrings []string + + for i := range containers { + if containers[i].ID == currentContainerId { + continue + } + stopErr := client.StopContainer(containers[i].ID, timeout) + if stopErr != nil { + stopErrorStrings = append(stopErrorStrings, " [" + containers[i].ID + "] " +stopErr.Error()) + } + } + + var waitErrorStrings []string + + for i := range containers { + if containers[i].ID == currentContainerId { + continue + } + _, waitErr := client.WaitContainer(containers[i].ID) + if waitErr != nil { + waitErrorStrings = append(waitErrorStrings, " [" + containers[i].ID + "] " + waitErr.Error()) + } + } + + if len(waitErrorStrings) != 0 || len(stopErrorStrings) != 0 { + return errors.New("error while stopping \n1. STOP Errors [" + strings.Join(stopErrorStrings, ",") + "] \n2. WAIT Errors [" + strings.Join(waitErrorStrings, ",") + "]") + } + + return nil +} + + +func getCurrentContainerId() (string, error) { + file, err := os.Open(dockerCGroupsFile) + + if err != nil { + return "", err + } + + fileReader := bufio.NewScanner(file) + if !fileReader.Scan() { + return "", errors.New("Empty file /proc/self/cgroup") + } + line := fileReader.Text() + parts := strings.Split(line, "/") + + while len(parts) != 3 { + if !fileReader.Scan() { + return "", errors.New("Found no docker cgroups") + } + line = fileReader.Text() + parts = strings.Split(line, "/") + if len(parts) == 3 { + if strings.HasSuffix(parts[1], "docker") { + break + } else { + parts = nil + } + } + } + + return parts[len(parts)-1:][0], nil +} +