1
0
mirror of https://github.com/rancher/os.git synced 2025-09-02 15:24:32 +00:00

reboot --kexec almost works

Signed-off-by: Sven Dowideit <SvenDowideit@home.org.au>
This commit is contained in:
Sven Dowideit
2017-07-05 14:14:22 +10:00
parent 5e4b5975a9
commit c5d4cb91c3
6 changed files with 356 additions and 204 deletions

View File

@@ -152,7 +152,7 @@ func installAction(c *cli.Context) error {
if cloudConfig == "" {
if installType != "upgrade" {
// TODO: I wonder if its plausible to merge a new cloud-config into an existing one on upgrade - so for now, i'm only turning off the warning
log.Warn("Cloud-config not provided: you might need to provide cloud-config on bootDir with ssh_authorized_keys")
log.Warn("Cloud-config not provided: you might need to provide cloud-config on boot with ssh_authorized_keys")
}
} else {
os.MkdirAll("/opt", 0755)
@@ -410,7 +410,6 @@ func layDownOS(image, installType, cloudConfig, device, partition, statedir, kap
//cloudConfig := SCRIPTS_DIR + "/conf/empty.yml" //${cloudConfig:-"${SCRIPTS_DIR}/conf/empty.yml"}
CONSOLE := "tty0"
baseName := "/mnt/new_img"
bootDir := "boot/"
kernelArgs := "printk.devkmsg=on rancher.state.dev=LABEL=RANCHER_STATE rancher.state.wait" // console="+CONSOLE
if statedir != "" {
kernelArgs = kernelArgs + " rancher.state.directory=" + statedir
@@ -432,12 +431,12 @@ func layDownOS(image, installType, cloudConfig, device, partition, statedir, kap
case "generic":
log.Debugf("formatAndMount")
var err error
device, partition, err = formatAndMount(baseName, bootDir, device, partition)
device, partition, err = formatAndMount(baseName, device, partition)
if err != nil {
log.Errorf("formatAndMount %s", err)
return err
}
err = installSyslinux(device, baseName, bootDir, diskType)
err = installSyslinux(device, baseName, diskType)
if err != nil {
log.Errorf("installSyslinux %s", err)
return err
@@ -449,7 +448,7 @@ func layDownOS(image, installType, cloudConfig, device, partition, statedir, kap
}
case "arm":
var err error
device, partition, err = formatAndMount(baseName, bootDir, device, partition)
device, partition, err = formatAndMount(baseName, device, partition)
if err != nil {
return err
}
@@ -459,45 +458,45 @@ func layDownOS(image, installType, cloudConfig, device, partition, statedir, kap
case "amazon-ebs-hvm":
CONSOLE = "ttyS0"
var err error
device, partition, err = formatAndMount(baseName, bootDir, device, partition)
device, partition, err = formatAndMount(baseName, device, partition)
if err != nil {
return err
}
if installType == "amazon-ebs-hvm" {
installSyslinux(device, baseName, bootDir, diskType)
installSyslinux(device, baseName, diskType)
}
//# AWS Networking recommends disabling.
seedData(baseName, cloudConfig, FILES)
case "googlecompute":
CONSOLE = "ttyS0"
var err error
device, partition, err = formatAndMount(baseName, bootDir, device, partition)
device, partition, err = formatAndMount(baseName, device, partition)
if err != nil {
return err
}
installSyslinux(device, baseName, bootDir, diskType)
installSyslinux(device, baseName, diskType)
seedData(baseName, cloudConfig, FILES)
case "noformat":
var err error
device, partition, err = mountdevice(baseName, bootDir, device, partition, false)
device, partition, err = install.MountDevice(baseName, device, partition, false)
if err != nil {
return err
}
installSyslinux(device, baseName, bootDir, diskType)
installSyslinux(device, baseName, diskType)
if err := os.MkdirAll(filepath.Join(baseName, statedir), 0755); err != nil {
return err
}
case "raid":
var err error
device, partition, err = mountdevice(baseName, bootDir, device, partition, false)
device, partition, err = install.MountDevice(baseName, device, partition, false)
if err != nil {
return err
}
installSyslinux(device, baseName, bootDir, diskType)
installSyslinux(device, baseName, diskType)
case "bootstrap":
CONSOLE = "ttyS0"
var err error
device, partition, err = mountdevice(baseName, bootDir, device, partition, true)
device, partition, err = install.MountDevice(baseName, device, partition, true)
if err != nil {
return err
}
@@ -507,39 +506,39 @@ func layDownOS(image, installType, cloudConfig, device, partition, statedir, kap
fallthrough
case "upgrade":
var err error
device, partition, err = mountdevice(baseName, bootDir, device, partition, false)
device, partition, err = install.MountDevice(baseName, device, partition, false)
if err != nil {
return err
}
log.Debugf("upgrading - %s, %s, %s, %s", device, baseName, bootDir, diskType)
log.Debugf("upgrading - %s, %s, %s, %s", device, baseName, diskType)
// TODO: detect pv-grub, and don't kill it with syslinux
upgradeBootloader(device, baseName, bootDir, diskType)
upgradeBootloader(device, baseName, diskType)
default:
return fmt.Errorf("unexpected install type %s", installType)
}
kernelArgs = kernelArgs + " console=" + CONSOLE
if kappend == "" {
preservedAppend, _ := ioutil.ReadFile(filepath.Join(baseName, bootDir+"append"))
preservedAppend, _ := ioutil.ReadFile(filepath.Join(baseName, install.BootDir+"append"))
kappend = string(preservedAppend)
} else {
ioutil.WriteFile(filepath.Join(baseName, bootDir+"append"), []byte(kappend), 0644)
ioutil.WriteFile(filepath.Join(baseName, install.BootDir+"append"), []byte(kappend), 0644)
}
if installType == "amazon-ebs-pv" {
menu := install.BootVars{
BaseName: baseName,
BootDir: bootDir,
BootDir: install.BootDir,
Timeout: 0,
Fallback: 0, // need to be conditional on there being a 'rollback'?
Entries: []install.MenuEntry{
install.MenuEntry{"RancherOS-current", bootDir, VERSION, kernelArgs, kappend},
install.MenuEntry{"RancherOS-current", install.BootDir, VERSION, kernelArgs, kappend},
},
}
install.PvGrubConfig(menu)
}
log.Debugf("installRancher")
currentCfg, err := installRancher(baseName, bootDir, VERSION, DIST, kernelArgs+" "+kappend)
currentCfg, err := installRancher(baseName, VERSION, DIST, kernelArgs+" "+kappend)
if err != nil {
log.Errorf("%s", err)
return err
@@ -548,55 +547,12 @@ func layDownOS(image, installType, cloudConfig, device, partition, statedir, kap
// Used by upgrade
if kexec {
vmlinuzFile, initrdFile, err := readSyslinuxCfg(currentCfg)
if err != nil {
log.Errorf("%s", err)
return err
}
// kexec -l ${DIST}/vmlinuz --initrd=${DIST}/initrd --append="${kernelArgs} ${APPEND}" -f
cmd := exec.Command(
"kexec",
"-l", DIST+"/"+vmlinuzFile,
"--initrd", DIST+"/"+initrdFile,
"--append", "'"+kernelArgs+" "+kappend+"'",
"-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")
power.Kexec(currentCfg, kernelArgs+" "+kappend)
}
return nil
}
func readSyslinuxCfg(currentCfg string) (string, string, error) {
vmlinuzFile := ""
initrdFile := ""
// Need to parse currentCfg for the lines:
// KERNEL ../vmlinuz-4.9.18-rancher^M
// INITRD ../initrd-41e02e6-dirty^M
buf, err := ioutil.ReadFile(currentCfg)
if err != nil {
return vmlinuzFile, initrdFile, err
}
s := bufio.NewScanner(bytes.NewReader(buf))
for s.Scan() {
line := strings.TrimSpace(s.Text())
if strings.HasPrefix(line, "KERNEL") {
vmlinuzFile = strings.TrimSpace(strings.TrimPrefix(line, "KERNEL"))
vmlinuzFile = filepath.Base(vmlinuzFile)
}
if strings.HasPrefix(line, "INITRD") {
initrdFile = strings.TrimSpace(strings.TrimPrefix(line, "INITRD"))
initrdFile = filepath.Base(initrdFile)
}
}
return vmlinuzFile, initrdFile, err
}
// files is an array of 'sourcefile:destination' - but i've not seen any examples of it being used.
func seedData(baseName, cloudData string, files []string) error {
log.Debugf("seedData")
@@ -772,59 +728,7 @@ func formatdevice(device, partition string) error {
return nil
}
func mountdevice(baseName, bootDir, device, partition string, raw bool) (string, string, error) {
log.Debugf("mountdevice %s, raw %v", partition, raw)
if partition == "" {
if raw {
log.Debugf("util.Mount (raw) %s, %s", partition, baseName)
cmd := exec.Command("lsblk", "-no", "pkname", partition)
log.Debugf("Run(%v)", cmd)
cmd.Stderr = os.Stderr
device := ""
// TODO: out can == "" - this is used to "detect software RAID" which is terrible
if out, err := cmd.Output(); err == nil {
device = "/dev/" + strings.TrimSpace(string(out))
}
log.Debugf("mountdevice return -> d: %s, p: %s", device, partition)
return device, partition, util.Mount(partition, baseName, "", "")
}
//rootfs := partition
// Don't use ResolveDevice - it can fail, whereas `blkid -L LABEL` works more often
cfg := config.LoadConfig()
if d, _ := util.Blkid("RANCHER_BOOT"); d != "" {
partition = d
baseName = filepath.Join(baseName, "boot")
} else {
if dev := util.ResolveDevice(cfg.Rancher.State.Dev); dev != "" {
// try the rancher.state.dev setting
partition = dev
} else {
if d, _ := util.Blkid("RANCHER_STATE"); d != "" {
partition = d
}
}
}
cmd := exec.Command("lsblk", "-no", "pkname", partition)
log.Debugf("Run(%v)", cmd)
cmd.Stderr = os.Stderr
// TODO: out can == "" - this is used to "detect software RAID" which is terrible
if out, err := cmd.Output(); err == nil {
device = "/dev/" + strings.TrimSpace(string(out))
}
}
os.MkdirAll(baseName, 0755)
cmd := exec.Command("mount", partition, baseName)
//cmd.Stdout, cmd.Stderr = os.Stdout, os.Stderr
log.Debugf("mountdevice return2 -> d: %s, p: %s", device, partition)
return device, partition, cmd.Run()
}
func formatAndMount(baseName, bootDir, device, partition string) (string, string, error) {
func formatAndMount(baseName, device, partition string) (string, string, error) {
log.Debugf("formatAndMount")
err := formatdevice(device, partition)
@@ -832,31 +736,14 @@ func formatAndMount(baseName, bootDir, device, partition string) (string, string
log.Errorf("formatdevice %s", err)
return device, partition, err
}
device, partition, err = mountdevice(baseName, bootDir, device, partition, false)
device, partition, err = install.MountDevice(baseName, device, partition, false)
if err != nil {
log.Errorf("mountdevice %s", err)
return device, partition, err
}
//err = createbootDirs(baseName, bootDir)
//if err != nil {
// log.Errorf("createbootDirs %s", err)
// return bootDir, err
//}
return device, partition, nil
}
func NOPEcreatebootDir(baseName, bootDir string) error {
log.Debugf("createbootDirs")
if err := os.MkdirAll(filepath.Join(baseName, bootDir+"grub"), 0755); err != nil {
return err
}
if err := os.MkdirAll(filepath.Join(baseName, bootDir+"syslinux"), 0755); err != nil {
return err
}
return nil
}
func setBootable(device, diskType string) error {
// TODO make conditional - if there is a bootable device already, don't break it
// TODO: make RANCHER_BOOT bootable - it might not be device 1
@@ -875,10 +762,10 @@ func setBootable(device, diskType string) error {
return nil
}
func upgradeBootloader(device, baseName, bootDir, diskType string) error {
func upgradeBootloader(device, baseName, diskType string) error {
log.Debugf("start upgradeBootloader")
grubDir := filepath.Join(baseName, bootDir+"grub")
grubDir := filepath.Join(baseName, install.BootDir+"grub")
if _, err := os.Stat(grubDir); os.IsNotExist(err) {
log.Debugf("%s does not exist - no need to upgrade bootloader", grubDir)
// we've already upgraded
@@ -886,12 +773,12 @@ func upgradeBootloader(device, baseName, bootDir, diskType string) error {
return nil
}
// deal with systems which were previously upgraded, then rolled back, and are now being re-upgraded
grubBackup := filepath.Join(baseName, bootDir+"grub_backup")
grubBackup := filepath.Join(baseName, install.BootDir+"grub_backup")
if err := os.RemoveAll(grubBackup); err != nil {
log.Errorf("RemoveAll (%s): %s", grubBackup, err)
return err
}
backupSyslinuxDir := filepath.Join(baseName, bootDir+"syslinux_backup")
backupSyslinuxDir := filepath.Join(baseName, install.BootDir+"syslinux_backup")
if _, err := os.Stat(backupSyslinuxDir); !os.IsNotExist(err) {
backupSyslinuxLdlinuxSys := filepath.Join(backupSyslinuxDir, "ldlinux.sys")
if _, err := os.Stat(backupSyslinuxLdlinuxSys); !os.IsNotExist(err) {
@@ -914,7 +801,7 @@ func upgradeBootloader(device, baseName, bootDir, diskType string) error {
return err
}
syslinuxDir := filepath.Join(baseName, bootDir+"syslinux")
syslinuxDir := filepath.Join(baseName, install.BootDir+"syslinux")
// it seems that v0.5.0 didn't have a syslinux dir, while 0.7 does
if _, err := os.Stat(syslinuxDir); !os.IsNotExist(err) {
if err := os.Rename(syslinuxDir, backupSyslinuxDir); err != nil {
@@ -935,15 +822,15 @@ func upgradeBootloader(device, baseName, bootDir, diskType string) error {
cfg = strings.Replace(cfg, "current", "previous", -1)
// TODO consider removing the APPEND line - as the global.cfg should have the same result
ioutil.WriteFile(filepath.Join(baseName, bootDir, "linux-current.cfg"), []byte(cfg), 0644)
ioutil.WriteFile(filepath.Join(baseName, install.BootDir, "linux-current.cfg"), []byte(cfg), 0644)
lines := strings.Split(cfg, "\n")
for _, line := range lines {
line = strings.TrimSpace(line)
if strings.HasPrefix(line, "APPEND") {
log.Errorf("write new (%s) %s", filepath.Join(baseName, bootDir, "global.cfg"), err)
log.Errorf("write new (%s) %s", filepath.Join(baseName, install.BootDir, "global.cfg"), err)
// TODO: need to append any extra's the user specified
ioutil.WriteFile(filepath.Join(baseName, bootDir, "global.cfg"), []byte(cfg), 0644)
ioutil.WriteFile(filepath.Join(baseName, install.BootDir, "global.cfg"), []byte(cfg), 0644)
break
}
}
@@ -951,10 +838,10 @@ func upgradeBootloader(device, baseName, bootDir, diskType string) error {
}
}
return installSyslinux(device, baseName, bootDir, diskType)
return installSyslinux(device, baseName, diskType)
}
func installSyslinux(device, baseName, bootDir, diskType string) error {
func installSyslinux(device, baseName, diskType string) error {
log.Debugf("installSyslinux(%s)", device)
mbrFile := "mbr.bin"
@@ -1004,7 +891,7 @@ func installSyslinux(device, baseName, bootDir, diskType string) error {
}
}
sysLinuxDir := filepath.Join(baseName, bootDir, "syslinux")
sysLinuxDir := filepath.Join(baseName, install.BootDir, "syslinux")
if err := os.MkdirAll(sysLinuxDir, 0755); err != nil {
log.Errorf("MkdirAll(%s)): %s", sysLinuxDir, err)
//return err
@@ -1037,13 +924,13 @@ func installSyslinux(device, baseName, bootDir, diskType string) error {
return nil
}
func installRancher(baseName, bootDir, VERSION, DIST, kappend string) (string, error) {
func installRancher(baseName, VERSION, DIST, kappend string) (string, error) {
log.Debugf("installRancher")
// detect if there already is a linux-current.cfg, if so, move it to linux-previous.cfg,
currentCfg := filepath.Join(baseName, bootDir, "linux-current.cfg")
currentCfg := filepath.Join(baseName, install.BootDir, "linux-current.cfg")
if _, err := os.Stat(currentCfg); !os.IsNotExist(err) {
previousCfg := filepath.Join(baseName, bootDir, "linux-previous.cfg")
previousCfg := filepath.Join(baseName, install.BootDir, "linux-previous.cfg")
if _, err := os.Stat(previousCfg); !os.IsNotExist(err) {
if err := os.Remove(previousCfg); err != nil {
return currentCfg, err
@@ -1059,19 +946,19 @@ func installRancher(baseName, bootDir, VERSION, DIST, kappend string) (string, e
if file.IsDir() {
continue
}
if err := dfs.CopyFile(filepath.Join(DIST, file.Name()), filepath.Join(baseName, bootDir), file.Name()); err != nil {
if err := dfs.CopyFile(filepath.Join(DIST, file.Name()), filepath.Join(baseName, install.BootDir), file.Name()); err != nil {
log.Errorf("copy %s: %s", file.Name(), err)
//return err
}
}
// the general INCLUDE syslinuxcfg
if err := dfs.CopyFile(filepath.Join(DIST, "isolinux", "isolinux.cfg"), filepath.Join(baseName, bootDir, "syslinux"), "syslinux.cfg"); err != nil {
if err := dfs.CopyFile(filepath.Join(DIST, "isolinux", "isolinux.cfg"), filepath.Join(baseName, install.BootDir, "syslinux"), "syslinux.cfg"); err != nil {
log.Errorf("copy global syslinux.cfgS%s: %s", "syslinux.cfg", err)
//return err
}
// The global.cfg INCLUDE - useful for over-riding the APPEND line
globalFile := filepath.Join(filepath.Join(baseName, bootDir), "global.cfg")
globalFile := filepath.Join(filepath.Join(baseName, install.BootDir), "global.cfg")
if _, err := os.Stat(globalFile); !os.IsNotExist(err) {
err := ioutil.WriteFile(globalFile, []byte("APPEND "+kappend), 0644)
if err != nil {