2015-02-23 05:07:59 +00:00
|
|
|
package power
|
|
|
|
|
2015-03-15 04:31:11 +00:00
|
|
|
import (
|
2017-07-05 04:14:22 +00:00
|
|
|
"fmt"
|
2015-02-23 05:07:59 +00:00
|
|
|
"os"
|
2017-07-05 04:14:22 +00:00
|
|
|
"os/exec"
|
|
|
|
"path/filepath"
|
|
|
|
"syscall"
|
2015-02-23 05:07:59 +00:00
|
|
|
|
2015-03-15 04:31:11 +00:00
|
|
|
"github.com/codegangsta/cli"
|
2017-07-05 04:14:22 +00:00
|
|
|
"github.com/rancher/os/cmd/control/install"
|
2015-10-12 11:50:17 +00:00
|
|
|
"github.com/rancher/os/config"
|
2018-09-16 04:55:26 +00:00
|
|
|
"github.com/rancher/os/pkg/log"
|
2015-02-23 05:07:59 +00:00
|
|
|
)
|
|
|
|
|
2017-07-05 04:14:22 +00:00
|
|
|
var (
|
2017-07-06 01:37:18 +00:00
|
|
|
haltFlag bool
|
|
|
|
poweroffFlag bool
|
|
|
|
rebootFlag bool
|
|
|
|
forceFlag bool
|
|
|
|
kexecFlag bool
|
|
|
|
previouskexecFlag bool
|
|
|
|
kexecAppendFlag string
|
2017-07-05 04:14:22 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
func Shutdown() {
|
2016-11-23 10:49:35 +00:00
|
|
|
log.InitLogger()
|
2015-02-23 05:07:59 +00:00
|
|
|
app := cli.NewApp()
|
|
|
|
|
2018-03-06 22:00:27 +00:00
|
|
|
app.Name = filepath.Base(os.Args[0])
|
2017-07-28 01:50:07 +00:00
|
|
|
app.Usage = fmt.Sprintf("%s RancherOS\nbuilt: %s", app.Name, config.BuildDate)
|
2016-11-28 08:06:00 +00:00
|
|
|
app.Version = config.Version
|
2015-02-23 05:07:59 +00:00
|
|
|
app.Author = "Rancher Labs, Inc."
|
|
|
|
app.EnableBashCompletion = true
|
|
|
|
app.Action = shutdown
|
2015-03-15 04:31:11 +00:00
|
|
|
app.Flags = []cli.Flag{
|
2017-07-05 04:14:22 +00:00
|
|
|
// --no-wall
|
|
|
|
// Do not send wall message before halt, power-off,
|
|
|
|
// reboot.
|
|
|
|
|
|
|
|
// halt, poweroff, reboot ONLY
|
|
|
|
// -f, --force
|
|
|
|
// Force immediate halt, power-off, reboot. Do not
|
|
|
|
// contact the init system.
|
|
|
|
cli.BoolFlag{
|
|
|
|
Name: "f, force",
|
|
|
|
Usage: "Force immediate halt, power-off, reboot. Do not contact the init system.",
|
|
|
|
Destination: &forceFlag,
|
2015-03-15 04:31:11 +00:00
|
|
|
},
|
2017-07-05 04:14:22 +00:00
|
|
|
|
|
|
|
// -w, --wtmp-only
|
|
|
|
// Only write wtmp shutdown entry, do not actually
|
|
|
|
// halt, power-off, reboot.
|
|
|
|
|
|
|
|
// -d, --no-wtmp
|
|
|
|
// Do not write wtmp shutdown entry.
|
|
|
|
|
|
|
|
// -n, --no-sync
|
|
|
|
// Don't sync hard disks/storage media before halt,
|
|
|
|
// power-off, reboot.
|
|
|
|
|
|
|
|
// shutdown ONLY
|
|
|
|
// -h
|
|
|
|
// Equivalent to --poweroff, unless --halt is
|
|
|
|
// specified.
|
|
|
|
|
|
|
|
// -k
|
|
|
|
// Do not halt, power-off, reboot, just write wall
|
|
|
|
// message.
|
|
|
|
|
|
|
|
// -c
|
|
|
|
// Cancel a pending shutdown. This may be used
|
|
|
|
// cancel the effect of an invocation of shutdown
|
|
|
|
// with a time argument that is not "+0" or "now".
|
|
|
|
|
|
|
|
}
|
|
|
|
// -H, --halt
|
|
|
|
// Halt the machine.
|
|
|
|
if app.Name == "halt" {
|
|
|
|
app.Flags = append(app.Flags, cli.BoolTFlag{
|
|
|
|
Name: "H, halt",
|
|
|
|
Usage: "halt the machine",
|
|
|
|
Destination: &haltFlag,
|
|
|
|
})
|
|
|
|
} else {
|
|
|
|
app.Flags = append(app.Flags, cli.BoolFlag{
|
2018-01-24 09:53:52 +00:00
|
|
|
Name: "H, halt",
|
2017-07-05 04:14:22 +00:00
|
|
|
Usage: "halt the machine",
|
|
|
|
Destination: &haltFlag,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
// -P, --poweroff
|
|
|
|
// Power-off the machine (the default for shutdown cmd).
|
|
|
|
if app.Name == "poweroff" {
|
|
|
|
app.Flags = append(app.Flags, cli.BoolTFlag{
|
|
|
|
Name: "P, poweroff",
|
2018-01-24 09:53:52 +00:00
|
|
|
Usage: "poweroff the machine",
|
2017-07-05 04:14:22 +00:00
|
|
|
Destination: &poweroffFlag,
|
|
|
|
})
|
|
|
|
} else {
|
2018-01-24 09:53:52 +00:00
|
|
|
// shutdown -h
|
|
|
|
// Equivalent to --poweroff
|
|
|
|
if app.Name == "shutdown" {
|
|
|
|
app.Flags = append(app.Flags, cli.BoolFlag{
|
|
|
|
Name: "h",
|
|
|
|
Usage: "poweroff the machine",
|
|
|
|
Destination: &poweroffFlag,
|
|
|
|
})
|
|
|
|
}
|
2017-07-05 04:14:22 +00:00
|
|
|
app.Flags = append(app.Flags, cli.BoolFlag{
|
|
|
|
Name: "P, poweroff",
|
2018-01-24 09:53:52 +00:00
|
|
|
Usage: "poweroff the machine",
|
2017-07-05 04:14:22 +00:00
|
|
|
Destination: &poweroffFlag,
|
|
|
|
})
|
2015-03-15 04:31:11 +00:00
|
|
|
}
|
2017-07-05 04:14:22 +00:00
|
|
|
// -r, --reboot
|
|
|
|
// Reboot the machine.
|
|
|
|
if app.Name == "reboot" {
|
|
|
|
app.Flags = append(app.Flags, cli.BoolTFlag{
|
|
|
|
Name: "r, reboot",
|
|
|
|
Usage: "reboot after shutdown",
|
|
|
|
Destination: &rebootFlag,
|
|
|
|
})
|
|
|
|
// OR? maybe implement it as a `kexec` cli tool?
|
|
|
|
app.Flags = append(app.Flags, cli.BoolFlag{
|
|
|
|
Name: "kexec",
|
2017-07-06 01:37:18 +00:00
|
|
|
Usage: "kexec the default RancherOS cfg",
|
2017-07-05 04:14:22 +00:00
|
|
|
Destination: &kexecFlag,
|
|
|
|
})
|
2017-07-06 01:37:18 +00:00
|
|
|
app.Flags = append(app.Flags, cli.BoolFlag{
|
|
|
|
Name: "kexec-previous",
|
|
|
|
Usage: "kexec the previous RancherOS cfg",
|
|
|
|
Destination: &previouskexecFlag,
|
|
|
|
})
|
|
|
|
app.Flags = append(app.Flags, cli.StringFlag{
|
|
|
|
Name: "kexec-append",
|
|
|
|
Usage: "kexec using the specified kernel boot params (ignores global.cfg)",
|
|
|
|
Destination: &kexecAppendFlag,
|
|
|
|
})
|
2017-07-05 04:14:22 +00:00
|
|
|
} else {
|
|
|
|
app.Flags = append(app.Flags, cli.BoolFlag{
|
|
|
|
Name: "r, reboot",
|
|
|
|
Usage: "reboot after shutdown",
|
|
|
|
Destination: &rebootFlag,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
//TODO: add the time and msg flags...
|
2017-07-28 01:50:07 +00:00
|
|
|
app.HideHelp = true
|
|
|
|
|
2015-02-23 05:07:59 +00:00
|
|
|
app.Run(os.Args)
|
|
|
|
}
|
|
|
|
|
2017-07-06 01:37:18 +00:00
|
|
|
func Kexec(previous bool, bootDir, append string) error {
|
|
|
|
cfg := "linux-current.cfg"
|
|
|
|
if previous {
|
|
|
|
cfg = "linux-previous.cfg"
|
|
|
|
}
|
|
|
|
cfgFile := filepath.Join(bootDir, cfg)
|
2017-07-05 04:14:22 +00:00
|
|
|
vmlinuzFile, initrdFile, err := install.ReadSyslinuxCfg(cfgFile)
|
|
|
|
if err != nil {
|
|
|
|
log.Errorf("%s", err)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
globalCfgFile := filepath.Join(bootDir, "global.cfg")
|
|
|
|
if append == "" {
|
|
|
|
append, err = install.ReadGlobalCfg(globalCfgFile)
|
|
|
|
if err != nil {
|
|
|
|
log.Errorf("%s", err)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// TODO: read global.cfg if append == ""
|
|
|
|
// kexec -l ${DIST}/vmlinuz --initrd=${DIST}/initrd --append="${kernelArgs} ${APPEND}" -f
|
|
|
|
cmd := exec.Command(
|
|
|
|
"kexec",
|
|
|
|
"-l", vmlinuzFile,
|
|
|
|
"--initrd", initrdFile,
|
2017-07-06 01:37:18 +00:00
|
|
|
"--append", append,
|
2017-07-05 04:14:22 +00:00
|
|
|
"-f")
|
|
|
|
log.Debugf("Run(%#v)", cmd)
|
|
|
|
cmd.Stderr = os.Stderr
|
|
|
|
if _, err := cmd.Output(); err != nil {
|
|
|
|
log.Errorf("Failed to kexec: %s", err)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
log.Infof("kexec'd to new install")
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Reboot is used by installation / upgrade
|
|
|
|
// TODO: add kexec option
|
|
|
|
func Reboot() {
|
2018-01-25 08:25:09 +00:00
|
|
|
os.Args = []string{"reboot"}
|
2017-07-05 04:14:22 +00:00
|
|
|
reboot("reboot", false, syscall.LINUX_REBOOT_CMD_RESTART)
|
|
|
|
}
|
|
|
|
|
2016-05-17 03:36:08 +00:00
|
|
|
func shutdown(c *cli.Context) error {
|
2017-07-05 04:14:22 +00:00
|
|
|
// the shutdown command's default is poweroff
|
|
|
|
var powerCmd uint
|
|
|
|
powerCmd = syscall.LINUX_REBOOT_CMD_POWER_OFF
|
|
|
|
if rebootFlag {
|
|
|
|
powerCmd = syscall.LINUX_REBOOT_CMD_RESTART
|
|
|
|
} else if poweroffFlag {
|
|
|
|
powerCmd = syscall.LINUX_REBOOT_CMD_POWER_OFF
|
|
|
|
} else if haltFlag {
|
|
|
|
powerCmd = syscall.LINUX_REBOOT_CMD_HALT
|
|
|
|
}
|
2015-02-23 05:07:59 +00:00
|
|
|
|
2017-07-05 04:14:22 +00:00
|
|
|
timeArg := c.Args().Get(0)
|
cmd/power: Set correct container name and ensure full command executed
This fixes a few issues that are preventing shutdown and friends from
behaving correctly:
* The command name, which is being used to determine via what command it
was being called (ie: shutdown, reboot, or halt) was not being parsed
for absolute paths. This was preventing certain logic from being handled
(example: enforcing a static time value of "now" for shutdown), but more
problematically was the fact that it was being used as the container
name being passed to runDocker, the function that launches the
independent shutdown container. This was causing the shutdown container
to fail as something like "/sbin/shutdown" is not a valid name for a
container. The logic to parse out the base command being run is actually
present in runDocker, but does not run if a name is supplied to the
function.
* Further, the command line was not being parsed in the shutdown
container if the name supplied to runDocker was non-empty. Rather, the
full command to run just became the name of the container. Hence,
something like "/sbin/shutdown -h now" became just "shutdown", executing
the default power off behaviour for all actions (including reboots).
* Further to this, open-vm-tools expects "/sbin/shutdown -h now" to be a
valid command to halt the system, which was not being recognized as the
only recognized short-form halt flag in shutdown was its capital version
(-H).
This fixes these three issues by parsing out the base of the called
command before sending it to reboot, using all of os.Argv as the command
line to run regardless of if a name was set for the container or not,
and finally adding the lowercase -h switch to the "shutdown" form of
this command ("halt" is still uppercase only).
Fixes rancher/os#2121.
Fixes rancher/os#2074.
2017-10-21 00:09:13 +00:00
|
|
|
// We may be called via an absolute path, so check that now and make sure we
|
|
|
|
// don't pass the wrong app name down. Aside from the logic in the immediate
|
|
|
|
// context here, the container name is derived from how we were called and
|
|
|
|
// cannot contain slashes.
|
|
|
|
appName := filepath.Base(c.App.Name)
|
|
|
|
if appName == "shutdown" && timeArg != "" {
|
2017-07-05 04:14:22 +00:00
|
|
|
if timeArg != "now" {
|
|
|
|
err := fmt.Errorf("Sorry, can't parse '%s' as time value (only 'now' supported)", timeArg)
|
|
|
|
log.Error(err)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
// TODO: if there are more params, LOG them
|
2015-02-23 05:07:59 +00:00
|
|
|
}
|
2016-05-17 03:36:08 +00:00
|
|
|
|
cmd/power: Set correct container name and ensure full command executed
This fixes a few issues that are preventing shutdown and friends from
behaving correctly:
* The command name, which is being used to determine via what command it
was being called (ie: shutdown, reboot, or halt) was not being parsed
for absolute paths. This was preventing certain logic from being handled
(example: enforcing a static time value of "now" for shutdown), but more
problematically was the fact that it was being used as the container
name being passed to runDocker, the function that launches the
independent shutdown container. This was causing the shutdown container
to fail as something like "/sbin/shutdown" is not a valid name for a
container. The logic to parse out the base command being run is actually
present in runDocker, but does not run if a name is supplied to the
function.
* Further, the command line was not being parsed in the shutdown
container if the name supplied to runDocker was non-empty. Rather, the
full command to run just became the name of the container. Hence,
something like "/sbin/shutdown -h now" became just "shutdown", executing
the default power off behaviour for all actions (including reboots).
* Further to this, open-vm-tools expects "/sbin/shutdown -h now" to be a
valid command to halt the system, which was not being recognized as the
only recognized short-form halt flag in shutdown was its capital version
(-H).
This fixes these three issues by parsing out the base of the called
command before sending it to reboot, using all of os.Argv as the command
line to run regardless of if a name was set for the container or not,
and finally adding the lowercase -h switch to the "shutdown" form of
this command ("halt" is still uppercase only).
Fixes rancher/os#2121.
Fixes rancher/os#2074.
2017-10-21 00:09:13 +00:00
|
|
|
reboot(appName, forceFlag, powerCmd)
|
2017-07-05 04:14:22 +00:00
|
|
|
|
2016-05-17 03:36:08 +00:00
|
|
|
return nil
|
2015-02-23 05:07:59 +00:00
|
|
|
}
|