123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256 |
- package power
- import (
- "bufio"
- "errors"
- "os"
- "path/filepath"
- "strconv"
- "strings"
- "syscall"
- log "github.com/Sirupsen/logrus"
- dockerClient "github.com/fsouza/go-dockerclient"
- "github.com/rancherio/os/docker"
- )
- const (
- DOCKER_CGROUPS_FILE = "/proc/self/cgroup"
- )
- func runDocker(name string) error {
- if os.ExpandEnv("${IN_DOCKER}") == "true" {
- return nil
- }
- client, err := docker.NewSystemClient()
- if err != nil {
- return err
- }
- cmd := []string{name}
- if name == "" {
- name = filepath.Base(os.Args[0])
- cmd = os.Args
- }
- 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: cmd,
- 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(name string) {
- if os.Geteuid() != 0 {
- log.Fatalf("%s: Need to be root", os.Args[0])
- }
- if err := runDocker(name); err != nil {
- log.Fatal(err)
- }
- }
- func PowerOff() {
- common("poweroff")
- reboot(syscall.LINUX_REBOOT_CMD_POWER_OFF)
- }
- func Reboot() {
- common("reboot")
- reboot(syscall.LINUX_REBOOT_CMD_RESTART)
- }
- func Halt() {
- common("halt")
- reboot(syscall.LINUX_REBOOT_CMD_HALT)
- }
- func reboot(code int) {
- err := shutDownContainers()
- if err != nil {
- log.Error(err)
- }
- syscall.Sync()
- err = syscall.Reboot(code)
- if err != nil {
- log.Fatal(err)
- }
- }
- func shutDownContainers() error {
- var err error
- shutDown := true
- timeout := 2
- for i, arg := range os.Args {
- if arg == "-f" || arg == "--f" || arg == "--force" {
- shutDown = false
- }
- if arg == "-t" || arg == "--t" || arg == "--timeout" {
- if len(os.Args) > i+1 {
- t, err := strconv.Atoi(os.Args[i+1])
- if err != nil {
- return err
- }
- timeout = t
- } else {
- log.Error("please specify a timeout")
- }
- }
- }
- if !shutDown {
- return nil
- }
- client, err := docker.NewSystemClient()
- if err != nil {
- return err
- }
- opts := dockerClient.ListContainersOptions{
- All: true,
- Filters: map[string][]string{
- "status": {"running"},
- },
- }
- containers, err := client.ListContainers(opts)
- if err != nil {
- return err
- }
- currentContainerId, err := getCurrentContainerId()
- if err != nil {
- return err
- }
- var stopErrorStrings []string
- for _, container := range containers {
- if container.ID == currentContainerId {
- continue
- }
- log.Infof("Stopping %s : %v", container.ID[:12], container.Names)
- stopErr := client.StopContainer(container.ID, uint(timeout))
- if stopErr != nil {
- stopErrorStrings = append(stopErrorStrings, " ["+container.ID+"] "+stopErr.Error())
- }
- }
- var waitErrorStrings []string
- for _, container := range containers {
- if container.ID == currentContainerId {
- continue
- }
- _, waitErr := client.WaitContainer(container.ID)
- if waitErr != nil {
- waitErrorStrings = append(waitErrorStrings, " ["+container.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(DOCKER_CGROUPS_FILE)
- 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, "/")
- for 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
- }
|