2015-08-18 14:07:00 +00:00
package control
import (
2016-12-01 03:55:19 +00:00
"bufio"
"bytes"
2017-06-28 13:58:14 +00:00
"crypto/md5"
2015-08-18 14:07:00 +00:00
"fmt"
2016-12-01 03:55:19 +00:00
"io"
"io/ioutil"
2015-08-18 14:07:00 +00:00
"os"
"os/exec"
2016-12-01 03:55:19 +00:00
"path/filepath"
2017-03-13 06:49:28 +00:00
"runtime"
2016-12-07 11:56:32 +00:00
"strconv"
2016-09-27 00:27:53 +00:00
"strings"
2015-08-18 14:07:00 +00:00
2018-09-16 04:55:26 +00:00
"github.com/rancher/os/pkg/log"
2015-08-18 14:07:00 +00:00
"github.com/codegangsta/cli"
2018-01-17 09:06:07 +00:00
"github.com/pkg/errors"
2017-02-10 00:37:08 +00:00
"github.com/rancher/catalog-service/utils/version"
2016-12-20 12:49:34 +00:00
"github.com/rancher/os/cmd/control/install"
2015-10-12 11:50:17 +00:00
"github.com/rancher/os/cmd/power"
"github.com/rancher/os/config"
2018-09-16 04:55:26 +00:00
"github.com/rancher/os/pkg/dfs" // TODO: move CopyFile into util or something.
"github.com/rancher/os/pkg/util"
2015-08-18 14:07:00 +00:00
)
var installCommand = cli . Command {
Name : "install" ,
Usage : "install RancherOS to disk" ,
HideHelp : true ,
Action : installAction ,
Flags : [ ] cli . Flag {
cli . StringFlag {
2016-10-12 12:41:52 +00:00
// TODO: need to validate ? -i rancher/os:v0.3.1 just sat there.
Name : "image, i" ,
Usage : ` install from a certain image ( e . g . , ' rancher / os : v0 .7 .0 ' )
use ' ros os list ' to see what versions are available . ` ,
2015-08-18 14:07:00 +00:00
} ,
cli . StringFlag {
Name : "install-type, t" ,
2016-12-15 01:54:43 +00:00
Usage : ` generic : ( Default ) Creates 1 ext4 partition and installs RancherOS ( syslinux )
2016-12-14 11:01:58 +00:00
amazon - ebs : Installs RancherOS and sets up PV - GRUB
2017-01-05 11:29:09 +00:00
gptsyslinux : partition and format disk ( gpt ) , then install RancherOS and setup Syslinux
2016-12-14 11:01:58 +00:00
` ,
2015-08-18 14:07:00 +00:00
} ,
cli . StringFlag {
Name : "cloud-config, c" ,
Usage : "cloud-config yml file - needed for SSH authorized keys" ,
} ,
cli . StringFlag {
Name : "device, d" ,
Usage : "storage device" ,
} ,
2017-03-24 12:39:40 +00:00
cli . StringFlag {
Name : "partition, p" ,
Usage : "partition to install to" ,
} ,
2017-04-11 10:19:11 +00:00
cli . StringFlag {
Name : "statedir" ,
Usage : "install to rancher.state.directory" ,
} ,
2015-08-18 14:07:00 +00:00
cli . BoolFlag {
Name : "force, f" ,
Usage : "[ DANGEROUS! Data loss can happen ] partition/format without prompting" ,
} ,
cli . BoolFlag {
Name : "no-reboot" ,
Usage : "do not reboot after install" ,
} ,
2016-09-27 00:27:53 +00:00
cli . StringFlag {
Name : "append, a" ,
Usage : "append additional kernel parameters" ,
} ,
2017-02-09 05:12:17 +00:00
cli . StringFlag {
Name : "rollback, r" ,
Usage : "rollback version" ,
Hidden : true ,
2016-12-20 12:49:34 +00:00
} ,
2017-02-09 05:12:17 +00:00
cli . BoolFlag {
2016-12-20 12:49:34 +00:00
Name : "isoinstallerloaded" ,
Usage : "INTERNAL use only: mount the iso to get kernel and initrd" ,
Hidden : true ,
} ,
2016-12-07 03:33:43 +00:00
cli . BoolFlag {
2017-03-30 03:01:50 +00:00
Name : "kexec, k" ,
2016-12-20 12:49:34 +00:00
Usage : "reboot using kexec" ,
2016-12-07 03:33:43 +00:00
} ,
2017-01-18 00:50:37 +00:00
cli . BoolFlag {
Name : "debug" ,
Usage : "Run installer with debug output" ,
} ,
2015-08-18 14:07:00 +00:00
} ,
}
2016-05-17 03:36:08 +00:00
func installAction ( c * cli . Context ) error {
2018-01-17 09:06:07 +00:00
log . InitLogger ( )
debug := c . Bool ( "debug" )
if debug {
log . Info ( "Log level is debug" )
originalLevel := log . GetLevel ( )
defer log . SetLevel ( originalLevel )
log . SetLevel ( log . DebugLevel )
}
2017-03-13 06:49:28 +00:00
if runtime . GOARCH != "amd64" {
log . Fatalf ( "ros install / upgrade only supported on 'amd64', not '%s'" , runtime . GOARCH )
}
2015-08-18 14:07:00 +00:00
if c . Args ( ) . Present ( ) {
log . Fatalf ( "invalid arguments %v" , c . Args ( ) )
}
2017-01-18 00:50:37 +00:00
2016-12-20 12:49:34 +00:00
kappend := strings . TrimSpace ( c . String ( "append" ) )
force := c . Bool ( "force" )
kexec := c . Bool ( "kexec" )
reboot := ! c . Bool ( "no-reboot" )
isoinstallerloaded := c . Bool ( "isoinstallerloaded" )
2015-08-18 14:07:00 +00:00
image := c . String ( "image" )
2016-06-02 01:41:55 +00:00
cfg := config . LoadConfig ( )
2015-08-18 14:07:00 +00:00
if image == "" {
2018-03-06 10:07:21 +00:00
image = fmt . Sprintf ( "%s:%s%s" ,
cfg . Rancher . Upgrade . Image ,
config . Version ,
config . Suffix )
image = formatImage ( image , cfg )
2015-08-18 14:07:00 +00:00
}
installType := c . String ( "install-type" )
if installType == "" {
log . Info ( "No install type specified...defaulting to generic" )
installType = "generic"
}
2016-12-20 12:49:34 +00:00
if installType == "rancher-upgrade" ||
installType == "upgrade" {
2017-02-21 19:27:03 +00:00
installType = "upgrade" // rancher-upgrade is redundant!
force = true // the os.go upgrade code already asks
2016-12-20 12:49:34 +00:00
reboot = false
isoinstallerloaded = true // OMG this flag is aweful - kill it with fire
}
device := c . String ( "device" )
2017-03-24 12:39:40 +00:00
partition := c . String ( "partition" )
2017-04-11 10:19:11 +00:00
statedir := c . String ( "statedir" )
2017-04-13 11:21:28 +00:00
if statedir != "" && installType != "noformat" {
2017-04-11 10:19:11 +00:00
log . Fatal ( "--statedir %s requires --type noformat" , statedir )
}
2016-12-20 12:49:34 +00:00
if installType != "noformat" &&
installType != "raid" &&
installType != "bootstrap" &&
2017-02-21 19:27:03 +00:00
installType != "upgrade" {
2016-12-20 12:49:34 +00:00
// These can use RANCHER_BOOT or RANCHER_STATE labels..
if device == "" {
log . Fatal ( "Can not proceed without -d <dev> specified" )
}
}
2015-08-18 14:07:00 +00:00
cloudConfig := c . String ( "cloud-config" )
if cloudConfig == "" {
2017-02-21 19:27:03 +00:00
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
2017-07-05 04:14:22 +00:00
log . Warn ( "Cloud-config not provided: you might need to provide cloud-config on boot with ssh_authorized_keys" )
2017-02-21 19:27:03 +00:00
}
2015-08-18 14:07:00 +00:00
} else {
2017-03-24 12:39:40 +00:00
os . MkdirAll ( "/opt" , 0755 )
2015-08-18 14:07:00 +00:00
uc := "/opt/user_config.yml"
2018-01-02 09:17:43 +00:00
if strings . HasPrefix ( cloudConfig , "http://" ) || strings . HasPrefix ( cloudConfig , "https://" ) {
if err := util . HTTPDownloadToFile ( cloudConfig , uc ) ; err != nil {
log . WithFields ( log . Fields { "cloudConfig" : cloudConfig , "error" : err } ) . Fatal ( "Failed to http get cloud-config" )
}
} else {
if err := util . FileCopy ( cloudConfig , uc ) ; err != nil {
log . WithFields ( log . Fields { "cloudConfig" : cloudConfig , "error" : err } ) . Fatal ( "Failed to copy cloud-config" )
}
2015-08-18 14:07:00 +00:00
}
cloudConfig = uc
}
2017-04-11 10:19:11 +00:00
if err := runInstall ( image , installType , cloudConfig , device , partition , statedir , kappend , force , kexec , isoinstallerloaded , debug ) ; err != nil {
2015-08-18 14:07:00 +00:00
log . WithFields ( log . Fields { "err" : err } ) . Fatal ( "Failed to run install" )
2017-03-13 06:36:50 +00:00
return err
2015-08-18 14:07:00 +00:00
}
2016-05-17 03:36:08 +00:00
2017-03-14 02:11:24 +00:00
if ! kexec && reboot && ( force || yes ( "Continue with reboot" ) ) {
2017-01-17 12:13:35 +00:00
log . Info ( "Rebooting" )
power . Reboot ( )
}
2016-05-17 03:36:08 +00:00
return nil
2015-08-18 14:07:00 +00:00
}
2017-04-11 10:19:11 +00:00
func runInstall ( image , installType , cloudConfig , device , partition , statedir , kappend string , force , kexec , isoinstallerloaded , debug bool ) error {
2015-08-18 14:07:00 +00:00
fmt . Printf ( "Installing from %s\n" , image )
if ! force {
2017-03-14 02:11:24 +00:00
if util . IsRunningInTty ( ) && ! yes ( "Continue" ) {
2016-12-01 03:55:19 +00:00
log . Infof ( "Not continuing with installation due to user not saying 'yes'" )
2015-08-18 14:07:00 +00:00
os . Exit ( 1 )
}
}
2016-12-14 11:01:58 +00:00
diskType := "msdos"
2016-12-20 12:49:34 +00:00
2016-12-14 11:01:58 +00:00
if installType == "gptsyslinux" {
diskType = "gpt"
}
2017-01-30 03:07:05 +00:00
// Versions before 0.8.0-rc3 use the old calling convention (from the lay-down-os shell script)
2018-03-06 10:07:21 +00:00
imageVersion := strings . Split ( image , ":" ) [ 1 ]
2017-02-10 00:37:08 +00:00
if version . GreaterThan ( "v0.8.0-rc3" , imageVersion ) {
2017-01-30 03:07:05 +00:00
log . Infof ( "user specified to install pre v0.8.0: %s" , image )
2016-12-07 11:56:32 +00:00
imageVersion = strings . Replace ( imageVersion , "-" , "." , - 1 )
vArray := strings . Split ( imageVersion , "." )
2017-05-17 06:02:39 +00:00
if len ( vArray ) >= 2 {
v , _ := strconv . ParseFloat ( vArray [ 0 ] + "." + vArray [ 1 ] , 32 )
if v < 0.8 || imageVersion == "0.8.0-rc1" {
log . Infof ( "starting installer container for %s" , image )
if installType == "generic" ||
installType == "syslinux" ||
installType == "gptsyslinux" {
cmd := exec . Command ( "system-docker" , "run" , "--net=host" , "--privileged" , "--volumes-from=all-volumes" ,
"--entrypoint=/scripts/set-disk-partitions" , image , device , diskType )
cmd . Stdout , cmd . Stderr = os . Stdout , os . Stderr
if err := cmd . Run ( ) ; err != nil {
return err
}
}
cmd := exec . Command ( "system-docker" , "run" , "--net=host" , "--privileged" , "--volumes-from=user-volumes" ,
"--volumes-from=command-volumes" , image , "-d" , device , "-t" , installType , "-c" , cloudConfig ,
"-a" , kappend )
2016-12-07 11:56:32 +00:00
cmd . Stdout , cmd . Stderr = os . Stdout , os . Stderr
2017-12-06 05:45:49 +00:00
return cmd . Run ( )
2016-12-07 11:56:32 +00:00
}
2016-12-01 03:55:19 +00:00
}
2015-08-18 14:07:00 +00:00
}
2016-12-01 03:55:19 +00:00
2018-02-27 09:52:24 +00:00
//if _, err := os.Stat("/usr/bin/system-docker"); os.IsNotExist(err) {
//if err := os.Symlink("/usr/bin/ros", "/usr/bin/system-docker"); err != nil {
//log.Errorf("ln error %s", err)
//}
//}
2016-12-20 12:49:34 +00:00
2016-12-06 03:16:18 +00:00
useIso := false
2016-12-20 12:49:34 +00:00
// --isoinstallerloaded is used if the ros has created the installer container from and image that was on the booted iso
if ! isoinstallerloaded {
2017-01-17 01:16:49 +00:00
log . Infof ( "start !isoinstallerloaded" )
2017-01-30 06:11:46 +00:00
if _ , err := os . Stat ( "/dist/initrd-" + config . Version ) ; os . IsNotExist ( err ) {
2018-01-17 09:06:07 +00:00
deviceName , deviceType , err := getBootIso ( )
if err != nil {
log . Errorf ( "Failed to get boot iso: %v" , err )
fmt . Println ( "There is no boot iso drive, terminate the task" )
return err
}
if err = mountBootIso ( deviceName , deviceType ) ; err != nil {
log . Debugf ( "Failed to mountBootIso: %v" , err )
2016-12-20 12:49:34 +00:00
} else {
2017-01-17 01:16:49 +00:00
log . Infof ( "trying to load /bootiso/rancheros/installer.tar.gz" )
2016-12-07 03:33:43 +00:00
if _ , err := os . Stat ( "/bootiso/rancheros/" ) ; err == nil {
cmd := exec . Command ( "system-docker" , "load" , "-i" , "/bootiso/rancheros/installer.tar.gz" )
cmd . Stdout , cmd . Stderr = os . Stdout , os . Stderr
if err := cmd . Run ( ) ; err != nil {
2018-01-25 01:47:17 +00:00
log . Infof ( "failed to load images from /bootiso/rancheros: %v" , err )
2016-12-07 03:33:43 +00:00
} else {
log . Infof ( "Loaded images from /bootiso/rancheros/installer.tar.gz" )
//TODO: add if os-installer:latest exists - we might have loaded a full installer?
useIso = true
// now use the installer image
cfg := config . LoadConfig ( )
2017-01-30 06:11:46 +00:00
if image == cfg . Rancher . Upgrade . Image + ":" + config . Version + config . Suffix {
// TODO: fix the fullinstaller Dockerfile to use the ${VERSION}${SUFFIX}
image = cfg . Rancher . Upgrade . Image + "-installer" + ":latest"
}
2016-12-07 03:33:43 +00:00
}
2016-12-01 03:55:19 +00:00
}
2016-12-07 03:33:43 +00:00
// TODO: also poke around looking for the /boot/vmlinuz and initrd...
2016-12-01 03:55:19 +00:00
}
2016-12-07 03:33:43 +00:00
log . Infof ( "starting installer container for %s (new)" , image )
installerCmd := [ ] string {
"run" , "--rm" , "--net=host" , "--privileged" ,
// bind mount host fs to access its ros, vmlinuz, initrd and /dev (udev isn't running in container)
"-v" , "/:/host" ,
2016-12-15 01:54:43 +00:00
"--volumes-from=all-volumes" ,
2016-12-07 03:33:43 +00:00
image ,
2016-12-20 12:49:34 +00:00
// "install",
2016-12-07 03:33:43 +00:00
"-t" , installType ,
"-d" , device ,
2017-01-17 01:16:49 +00:00
"-i" , image , // TODO: this isn't used - I'm just using it to over-ride the defaulting
2016-12-07 03:33:43 +00:00
}
2017-01-17 12:13:35 +00:00
// Need to call the inner container with force - the outer one does the "are you sure"
installerCmd = append ( installerCmd , "-f" )
// The outer container does the reboot (if needed)
installerCmd = append ( installerCmd , "--no-reboot" )
2016-12-07 03:33:43 +00:00
if cloudConfig != "" {
installerCmd = append ( installerCmd , "-c" , cloudConfig )
}
if kappend != "" {
installerCmd = append ( installerCmd , "-a" , kappend )
}
if useIso {
2016-12-20 12:49:34 +00:00
installerCmd = append ( installerCmd , "--isoinstallerloaded=1" )
}
if kexec {
installerCmd = append ( installerCmd , "--kexec" )
2016-12-07 03:33:43 +00:00
}
2017-03-27 00:59:11 +00:00
if debug {
installerCmd = append ( installerCmd , "--debug" )
}
2017-04-13 07:36:35 +00:00
if partition != "" {
installerCmd = append ( installerCmd , "--partition" , partition )
}
if statedir != "" {
installerCmd = append ( installerCmd , "--statedir" , statedir )
}
2016-12-01 03:55:19 +00:00
2017-01-17 01:16:49 +00:00
// TODO: mount at /mnt for shared mount?
if useIso {
util . Unmount ( "/bootiso" )
}
2016-12-07 03:33:43 +00:00
cmd := exec . Command ( "system-docker" , installerCmd ... )
log . Debugf ( "Run(%v)" , cmd )
cmd . Stdout , cmd . Stderr = os . Stdout , os . Stderr
2017-12-06 05:45:49 +00:00
return cmd . Run ( )
2016-12-06 03:16:18 +00:00
}
2016-12-01 03:55:19 +00:00
}
2016-12-15 13:15:49 +00:00
log . Debugf ( "running installation" )
2016-12-01 03:55:19 +00:00
2017-03-27 00:59:11 +00:00
if partition == "" {
2017-03-24 12:39:40 +00:00
if installType == "generic" ||
installType == "syslinux" ||
installType == "gptsyslinux" {
diskType := "msdos"
if installType == "gptsyslinux" {
diskType = "gpt"
}
log . Debugf ( "running setDiskpartitions" )
err := setDiskpartitions ( device , diskType )
if err != nil {
log . Errorf ( "error setDiskpartitions %s" , err )
return err
}
// use the bind mounted host filesystem to get access to the /dev/vda1 device that udev on the host sets up (TODO: can we run a udevd inside the container? `mknod b 253 1 /dev/vda1` doesn't work)
device = "/host" + device
//# TODO: Change this to a number so that users can specify.
//# Will need to make it so that our builds and packer APIs remain consistent.
partition = device + "1" //${partition:=${device}1}
}
2016-12-07 03:33:43 +00:00
}
2017-02-21 19:27:03 +00:00
if installType == "upgrade" {
2016-12-20 12:49:34 +00:00
isoinstallerloaded = false
}
if isoinstallerloaded {
log . Debugf ( "running isoinstallerloaded..." )
2017-01-17 01:16:49 +00:00
// TODO: detect if its not mounted and then optionally mount?
2018-01-17 09:06:07 +00:00
deviceName , deviceType , err := getBootIso ( )
if err != nil {
log . Errorf ( "Failed to get boot iso: %v" , err )
fmt . Println ( "There is no boot iso drive, terminate the task" )
return err
}
if err := mountBootIso ( deviceName , deviceType ) ; err != nil {
2016-12-15 13:15:49 +00:00
log . Errorf ( "error mountBootIso %s" , err )
2017-03-24 12:39:40 +00:00
//return err
2016-12-07 03:33:43 +00:00
}
2016-12-01 03:55:19 +00:00
}
2017-04-11 10:19:11 +00:00
err := layDownOS ( image , installType , cloudConfig , device , partition , statedir , kappend , kexec )
2016-12-01 03:55:19 +00:00
if err != nil {
2016-12-15 13:15:49 +00:00
log . Errorf ( "error layDownOS %s" , err )
2015-08-18 14:07:00 +00:00
return err
}
return nil
}
2016-12-01 03:55:19 +00:00
2018-03-14 10:35:30 +00:00
func getDeviceByLabel ( label string ) ( string , string ) {
d , t , err := util . Blkid ( label )
if err != nil {
log . Warnf ( "Failed to run blkid for %s" , label )
return "" , ""
}
return d , t
}
2018-01-17 09:06:07 +00:00
func getBootIso ( ) ( string , string , error ) {
2016-12-07 11:56:32 +00:00
deviceName := "/dev/sr0"
deviceType := "iso9660"
2018-03-14 10:35:30 +00:00
// Our ISO LABEL is RancherOS
// But some tools(like rufus) will change LABEL to RANCHEROS
for _ , label := range [ ] string { "RancherOS" , "RANCHEROS" } {
d , t := getDeviceByLabel ( label )
if d != "" {
deviceName = d
deviceType = t
continue
}
2016-12-15 01:54:43 +00:00
}
2018-01-17 09:06:07 +00:00
// Check the sr deive if exist
2018-03-14 10:35:30 +00:00
if _ , err := os . Stat ( deviceName ) ; os . IsNotExist ( err ) {
2018-01-17 09:06:07 +00:00
return "" , "" , err
}
return deviceName , deviceType , nil
}
func mountBootIso ( deviceName , deviceType string ) error {
2017-03-23 01:31:35 +00:00
mountsFile , err := os . Open ( "/proc/mounts" )
2016-12-07 11:56:32 +00:00
if err != nil {
2018-01-17 09:06:07 +00:00
return errors . Wrap ( err , "Failed to read /proc/mounts" )
2016-12-07 11:56:32 +00:00
}
2017-03-23 01:31:35 +00:00
defer mountsFile . Close ( )
2016-12-07 11:56:32 +00:00
2017-03-23 01:31:35 +00:00
if partitionMounted ( deviceName , mountsFile ) {
return nil
2016-12-07 11:56:32 +00:00
}
2017-03-23 01:31:35 +00:00
os . MkdirAll ( "/bootiso" , 0755 )
cmd := exec . Command ( "mount" , "-t" , deviceType , deviceName , "/bootiso" )
2017-03-21 10:26:52 +00:00
log . Debugf ( "mount (%#v)" , cmd )
2016-12-07 11:56:32 +00:00
2018-01-17 09:06:07 +00:00
var outBuf , errBuf bytes . Buffer
cmd . Stdout = & outBuf
cmd . Stderr = & errBuf
2016-12-07 11:56:32 +00:00
err = cmd . Run ( )
2016-12-07 03:33:43 +00:00
if err != nil {
2018-01-17 09:06:07 +00:00
return errors . Wrapf ( err , "Tried and failed to mount %s: stderr output: %s" , deviceName , errBuf . String ( ) )
2016-12-07 03:33:43 +00:00
}
2018-01-17 09:06:07 +00:00
log . Debugf ( "Mounted %s, output: %s" , deviceName , outBuf . String ( ) )
return nil
2016-12-07 03:33:43 +00:00
}
2017-04-11 10:19:11 +00:00
func layDownOS ( image , installType , cloudConfig , device , partition , statedir , kappend string , kexec bool ) error {
2016-12-01 03:55:19 +00:00
// ENV == installType
2017-02-21 19:27:03 +00:00
//[[ "$ARCH" == "arm" && "$ENV" != "upgrade" ]] && ENV=arm
2016-12-01 03:55:19 +00:00
// image == rancher/os:v0.7.0_arm
// TODO: remove the _arm suffix (but watch out, its not always there..)
VERSION := image [ strings . Index ( image , ":" ) + 1 : ]
var FILES [ ] string
DIST := "/dist" //${DIST:-/dist}
//cloudConfig := SCRIPTS_DIR + "/conf/empty.yml" //${cloudConfig:-"${SCRIPTS_DIR}/conf/empty.yml"}
CONSOLE := "tty0"
baseName := "/mnt/new_img"
2018-03-26 02:22:22 +00:00
kernelArgs := "printk.devkmsg=on rancher.state.dev=LABEL=RANCHER_STATE rancher.state.wait panic=10" // console="+CONSOLE
2017-04-11 10:19:11 +00:00
if statedir != "" {
2017-04-13 11:21:28 +00:00
kernelArgs = kernelArgs + " rancher.state.directory=" + statedir
2017-04-11 10:19:11 +00:00
}
2016-12-01 03:55:19 +00:00
// unmount on trap
defer util . Unmount ( baseName )
2016-12-15 01:54:43 +00:00
diskType := "msdos"
if installType == "gptsyslinux" {
diskType = "gpt"
}
2016-12-01 03:55:19 +00:00
switch installType {
2016-12-15 01:54:43 +00:00
case "syslinux" :
fallthrough
case "gptsyslinux" :
fallthrough
2016-12-01 03:55:19 +00:00
case "generic" :
2016-12-07 11:56:32 +00:00
log . Debugf ( "formatAndMount" )
2016-12-01 03:55:19 +00:00
var err error
2017-07-05 04:14:22 +00:00
device , partition , err = formatAndMount ( baseName , device , partition )
2016-12-01 03:55:19 +00:00
if err != nil {
2016-12-15 13:15:49 +00:00
log . Errorf ( "formatAndMount %s" , err )
2016-12-01 03:55:19 +00:00
return err
}
2017-07-05 04:14:22 +00:00
err = installSyslinux ( device , baseName , diskType )
2016-12-01 03:55:19 +00:00
if err != nil {
2016-12-15 13:15:49 +00:00
log . Errorf ( "installSyslinux %s" , err )
2016-12-01 03:55:19 +00:00
return err
}
err = seedData ( baseName , cloudConfig , FILES )
if err != nil {
2016-12-15 13:15:49 +00:00
log . Errorf ( "seedData %s" , err )
2016-12-01 03:55:19 +00:00
return err
}
case "arm" :
var err error
2017-07-05 04:14:22 +00:00
device , partition , err = formatAndMount ( baseName , device , partition )
2016-12-01 03:55:19 +00:00
if err != nil {
return err
}
seedData ( baseName , cloudConfig , FILES )
case "amazon-ebs-pv" :
fallthrough
case "amazon-ebs-hvm" :
CONSOLE = "ttyS0"
var err error
2017-07-05 04:14:22 +00:00
device , partition , err = formatAndMount ( baseName , device , partition )
2016-12-01 03:55:19 +00:00
if err != nil {
return err
}
if installType == "amazon-ebs-hvm" {
2017-07-05 04:14:22 +00:00
installSyslinux ( device , baseName , diskType )
2016-12-01 03:55:19 +00:00
}
//# AWS Networking recommends disabling.
seedData ( baseName , cloudConfig , FILES )
case "googlecompute" :
CONSOLE = "ttyS0"
var err error
2017-07-05 04:14:22 +00:00
device , partition , err = formatAndMount ( baseName , device , partition )
2016-12-01 03:55:19 +00:00
if err != nil {
return err
}
2017-07-05 04:14:22 +00:00
installSyslinux ( device , baseName , diskType )
2016-12-01 03:55:19 +00:00
seedData ( baseName , cloudConfig , FILES )
case "noformat" :
var err error
2017-07-05 04:14:22 +00:00
device , partition , err = install . MountDevice ( baseName , device , partition , false )
2016-12-01 03:55:19 +00:00
if err != nil {
return err
}
2017-07-05 04:14:22 +00:00
installSyslinux ( device , baseName , diskType )
2017-04-11 10:19:11 +00:00
if err := os . MkdirAll ( filepath . Join ( baseName , statedir ) , 0755 ) ; err != nil {
return err
}
2018-10-08 06:58:03 +00:00
err = seedData ( baseName , cloudConfig , FILES )
if err != nil {
log . Errorf ( "seedData %s" , err )
return err
}
2016-12-01 03:55:19 +00:00
case "raid" :
var err error
2017-07-05 04:14:22 +00:00
device , partition , err = install . MountDevice ( baseName , device , partition , false )
2016-12-01 03:55:19 +00:00
if err != nil {
return err
}
2017-07-05 04:14:22 +00:00
installSyslinux ( device , baseName , diskType )
2016-12-01 03:55:19 +00:00
case "bootstrap" :
CONSOLE = "ttyS0"
var err error
2017-07-05 04:14:22 +00:00
device , partition , err = install . MountDevice ( baseName , device , partition , true )
2016-12-01 03:55:19 +00:00
if err != nil {
return err
}
kernelArgs = kernelArgs + " rancher.cloud_init.datasources=[ec2,gce]"
case "rancher-upgrade" :
2017-02-21 19:27:03 +00:00
installType = "upgrade" // rancher-upgrade is redundant
fallthrough
case "upgrade" :
2016-12-01 03:55:19 +00:00
var err error
2017-07-05 04:14:22 +00:00
device , partition , err = install . MountDevice ( baseName , device , partition , false )
2016-12-01 03:55:19 +00:00
if err != nil {
return err
}
2017-07-05 04:14:22 +00:00
log . Debugf ( "upgrading - %s, %s, %s, %s" , device , baseName , diskType )
2016-12-20 12:49:34 +00:00
// TODO: detect pv-grub, and don't kill it with syslinux
2017-07-05 04:14:22 +00:00
upgradeBootloader ( device , baseName , diskType )
2016-12-01 03:55:19 +00:00
default :
return fmt . Errorf ( "unexpected install type %s" , installType )
}
kernelArgs = kernelArgs + " console=" + CONSOLE
if kappend == "" {
2018-09-30 06:30:25 +00:00
preservedAppend , _ := ioutil . ReadFile ( filepath . Join ( baseName , config . BootDir , "append" ) )
2016-12-01 03:55:19 +00:00
kappend = string ( preservedAppend )
} else {
2018-09-30 06:30:25 +00:00
ioutil . WriteFile ( filepath . Join ( baseName , config . BootDir , "append" ) , [ ] byte ( kappend ) , 0644 )
2016-12-01 03:55:19 +00:00
}
2016-12-20 12:49:34 +00:00
if installType == "amazon-ebs-pv" {
menu := install . BootVars {
BaseName : baseName ,
2018-09-30 06:30:25 +00:00
BootDir : config . BootDir ,
2016-12-20 12:49:34 +00:00
Timeout : 0 ,
Fallback : 0 , // need to be conditional on there being a 'rollback'?
Entries : [ ] install . MenuEntry {
2018-09-30 06:30:25 +00:00
install . MenuEntry { "RancherOS-current" , config . BootDir , VERSION , kernelArgs , kappend } ,
2016-12-20 12:49:34 +00:00
} ,
}
install . PvGrubConfig ( menu )
}
2016-12-01 03:55:19 +00:00
log . Debugf ( "installRancher" )
2017-07-06 01:37:18 +00:00
_ , err := installRancher ( baseName , VERSION , DIST , kernelArgs + " " + kappend )
2016-12-01 03:55:19 +00:00
if err != nil {
log . Errorf ( "%s" , err )
return err
}
log . Debugf ( "installRancher done" )
2016-12-20 12:49:34 +00:00
if kexec {
2018-09-30 06:30:25 +00:00
power . Kexec ( false , filepath . Join ( baseName , config . BootDir ) , kernelArgs + " " + kappend )
2016-12-20 12:49:34 +00:00
}
2016-12-01 03:55:19 +00:00
return nil
}
// 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" )
_ , err := os . Stat ( baseName )
if err != nil {
return err
}
2017-03-13 07:17:15 +00:00
if err = os . MkdirAll ( filepath . Join ( baseName , "/var/lib/rancher/conf/cloud-config.d" ) , 0700 ) ; err != nil {
2016-12-01 03:55:19 +00:00
return err
}
2016-12-20 12:49:34 +00:00
if ! strings . HasSuffix ( cloudData , "empty.yml" ) {
2016-12-01 03:55:19 +00:00
if err = dfs . CopyFile ( cloudData , baseName + "/var/lib/rancher/conf/cloud-config.d/" , filepath . Base ( cloudData ) ) ; err != nil {
return err
}
}
for _ , f := range files {
e := strings . Split ( f , ":" )
if err = dfs . CopyFile ( e [ 0 ] , baseName , e [ 1 ] ) ; err != nil {
return err
}
}
return nil
}
// set-disk-partitions is called with device == **/dev/sda**
2016-12-15 01:54:43 +00:00
func setDiskpartitions ( device , diskType string ) error {
2016-12-01 03:55:19 +00:00
log . Debugf ( "setDiskpartitions" )
d := strings . Split ( device , "/" )
if len ( d ) != 3 {
return fmt . Errorf ( "bad device name (%s)" , device )
}
deviceName := d [ 2 ]
file , err := os . Open ( "/proc/partitions" )
if err != nil {
2016-12-07 03:33:43 +00:00
log . Debugf ( "failed to read /proc/partitions %s" , err )
2016-12-01 03:55:19 +00:00
return err
}
defer file . Close ( )
exists := false
haspartitions := false
scanner := bufio . NewScanner ( file )
for scanner . Scan ( ) {
str := scanner . Text ( )
last := strings . LastIndex ( str , " " )
if last > - 1 {
dev := str [ last + 1 : ]
if strings . HasPrefix ( dev , deviceName ) {
if dev == deviceName {
exists = true
} else {
haspartitions = true
}
}
}
}
if ! exists {
2016-12-07 11:56:32 +00:00
return fmt . Errorf ( "disk %s not found: %s" , device , err )
2016-12-01 03:55:19 +00:00
}
if haspartitions {
2016-12-07 03:33:43 +00:00
log . Debugf ( "device %s already partitioned - checking if any are mounted" , device )
2016-12-01 03:55:19 +00:00
file , err := os . Open ( "/proc/mounts" )
if err != nil {
2016-12-07 11:56:32 +00:00
log . Errorf ( "failed to read /proc/mounts %s" , err )
2016-12-01 03:55:19 +00:00
return err
}
defer file . Close ( )
if partitionMounted ( device , file ) {
err = fmt . Errorf ( "partition %s mounted, cannot repartition" , device )
2016-12-07 11:56:32 +00:00
log . Errorf ( "%s" , err )
2016-12-01 03:55:19 +00:00
return err
}
2016-12-15 13:15:49 +00:00
2016-12-01 03:55:19 +00:00
cmd := exec . Command ( "system-docker" , "ps" , "-q" )
var outb bytes . Buffer
cmd . Stdout = & outb
if err := cmd . Run ( ) ; err != nil {
2016-12-15 13:15:49 +00:00
log . Printf ( "ps error: %s" , err )
2016-12-01 03:55:19 +00:00
return err
}
for _ , image := range strings . Split ( outb . String ( ) , "\n" ) {
if image == "" {
continue
}
r , w := io . Pipe ( )
go func ( ) {
// TODO: consider a timeout
2016-12-15 13:15:49 +00:00
// TODO:some of these containers don't have cat / shell
2016-12-01 03:55:19 +00:00
cmd := exec . Command ( "system-docker" , "exec" , image , "cat /proc/mount" )
cmd . Stdout = w
if err := cmd . Run ( ) ; err != nil {
2016-12-15 13:15:49 +00:00
log . Debugf ( "%s cat %s" , image , err )
2016-12-01 03:55:19 +00:00
}
2016-12-15 13:15:49 +00:00
w . Close ( )
2016-12-01 03:55:19 +00:00
} ( )
if partitionMounted ( device , r ) {
err = fmt . Errorf ( "partition %s mounted in %s, cannot repartition" , device , image )
2016-12-15 13:15:49 +00:00
log . Errorf ( "k? %s" , err )
2016-12-01 03:55:19 +00:00
return err
}
}
}
//do it!
2018-01-17 09:06:07 +00:00
log . Debugf ( "running dd device: %s" , device )
2016-12-01 03:55:19 +00:00
cmd := exec . Command ( "dd" , "if=/dev/zero" , "of=" + device , "bs=512" , "count=2048" )
2016-12-07 11:56:32 +00:00
//cmd.Stdout, cmd.Stderr = os.Stdout, os.Stderr
2016-12-01 03:55:19 +00:00
if err := cmd . Run ( ) ; err != nil {
2016-12-15 13:15:49 +00:00
log . Errorf ( "dd error %s" , err )
2016-12-01 03:55:19 +00:00
return err
}
2018-01-17 09:06:07 +00:00
log . Debugf ( "running partprobe: %s" , device )
2016-12-01 03:55:19 +00:00
cmd = exec . Command ( "partprobe" , device )
2016-12-07 11:56:32 +00:00
//cmd.Stdout, cmd.Stderr = os.Stdout, os.Stderr
2016-12-01 03:55:19 +00:00
if err := cmd . Run ( ) ; err != nil {
2018-01-17 09:06:07 +00:00
log . Errorf ( "Failed to partprobe device %s: %v" , device , err )
2016-12-01 03:55:19 +00:00
return err
}
2018-01-17 09:06:07 +00:00
log . Debugf ( "making single RANCHER_STATE partition, device: %s" , device )
2016-12-15 01:54:43 +00:00
cmd = exec . Command ( "parted" , "-s" , "-a" , "optimal" , device ,
"mklabel " + diskType , "--" ,
2016-12-20 12:49:34 +00:00
"mkpart primary ext4 1 -1" )
2016-12-15 01:54:43 +00:00
cmd . Stdout , cmd . Stderr = os . Stdout , os . Stderr
2016-12-01 03:55:19 +00:00
if err := cmd . Run ( ) ; err != nil {
2018-01-17 09:06:07 +00:00
log . Errorf ( "Failed to parted device %s: %v" , device , err )
2016-12-01 03:55:19 +00:00
return err
}
2017-12-06 05:45:49 +00:00
return setBootable ( device , diskType )
2016-12-01 03:55:19 +00:00
}
func partitionMounted ( device string , file io . Reader ) bool {
scanner := bufio . NewScanner ( file )
for scanner . Scan ( ) {
str := scanner . Text ( )
// /dev/sdb1 /data ext4 rw,relatime,errors=remount-ro,data=ordered 0 0
ele := strings . Split ( str , " " )
if len ( ele ) > 5 {
if strings . HasPrefix ( ele [ 0 ] , device ) {
return true
}
}
if err := scanner . Err ( ) ; err != nil {
2016-12-15 13:15:49 +00:00
log . Errorf ( "scanner %s" , err )
2016-12-01 03:55:19 +00:00
return false
}
}
return false
}
func formatdevice ( device , partition string ) error {
log . Debugf ( "formatdevice %s" , partition )
//mkfs.ext4 -F -i 4096 -L RANCHER_STATE ${partition}
2016-12-04 11:27:06 +00:00
// -O ^64bit: for syslinux: http://www.syslinux.org/wiki/index.php?title=Filesystem#ext
cmd := exec . Command ( "mkfs.ext4" , "-F" , "-i" , "4096" , "-O" , "^64bit" , "-L" , "RANCHER_STATE" , partition )
2016-12-01 03:55:19 +00:00
log . Debugf ( "Run(%v)" , cmd )
2017-05-11 23:44:45 +00:00
cmd . Stdout , cmd . Stderr = os . Stdout , os . Stderr
2016-12-01 03:55:19 +00:00
if err := cmd . Run ( ) ; err != nil {
2016-12-07 11:56:32 +00:00
log . Errorf ( "mkfs.ext4: %s" , err )
2016-12-01 03:55:19 +00:00
return err
}
return nil
}
2017-07-05 04:14:22 +00:00
func formatAndMount ( baseName , device , partition string ) ( string , string , error ) {
2016-12-01 03:55:19 +00:00
log . Debugf ( "formatAndMount" )
err := formatdevice ( device , partition )
if err != nil {
2016-12-15 13:15:49 +00:00
log . Errorf ( "formatdevice %s" , err )
2016-12-20 12:49:34 +00:00
return device , partition , err
2016-12-01 03:55:19 +00:00
}
2017-07-05 04:14:22 +00:00
device , partition , err = install . MountDevice ( baseName , device , partition , false )
2016-12-01 03:55:19 +00:00
if err != nil {
2016-12-15 13:15:49 +00:00
log . Errorf ( "mountdevice %s" , err )
2016-12-20 12:49:34 +00:00
return device , partition , err
2016-12-01 03:55:19 +00:00
}
2016-12-20 12:49:34 +00:00
return device , partition , nil
2016-12-01 03:55:19 +00:00
}
2016-12-20 12:49:34 +00:00
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
bootflag := "boot"
if diskType == "gpt" {
bootflag = "legacy_boot"
}
log . Debugf ( "making device 1 on %s bootable as %s" , device , diskType )
cmd := exec . Command ( "parted" , "-s" , "-a" , "optimal" , device , "set 1 " + bootflag + " on" )
cmd . Stdout , cmd . Stderr = os . Stdout , os . Stderr
if err := cmd . Run ( ) ; err != nil {
log . Errorf ( "parted: %s" , err )
return err
}
return nil
}
2017-07-05 04:14:22 +00:00
func upgradeBootloader ( device , baseName , diskType string ) error {
2016-12-20 12:49:34 +00:00
log . Debugf ( "start upgradeBootloader" )
2018-09-30 06:30:25 +00:00
grubDir := filepath . Join ( baseName , config . BootDir , "grub" )
2016-12-20 12:49:34 +00:00
if _ , err := os . Stat ( grubDir ) ; os . IsNotExist ( err ) {
log . Debugf ( "%s does not exist - no need to upgrade bootloader" , grubDir )
// we've already upgraded
// TODO: in v0.9.0, need to detect what version syslinux we have
return nil
}
2017-02-09 05:12:17 +00:00
// deal with systems which were previously upgraded, then rolled back, and are now being re-upgraded
2018-09-30 06:30:25 +00:00
grubBackup := filepath . Join ( baseName , config . BootDir , "grub_backup" )
2017-02-09 05:12:17 +00:00
if err := os . RemoveAll ( grubBackup ) ; err != nil {
log . Errorf ( "RemoveAll (%s): %s" , grubBackup , err )
return err
}
2018-09-30 06:30:25 +00:00
backupSyslinuxDir := filepath . Join ( baseName , config . BootDir , "syslinux_backup" )
2017-03-31 12:15:15 +00:00
if _ , err := os . Stat ( backupSyslinuxDir ) ; ! os . IsNotExist ( err ) {
backupSyslinuxLdlinuxSys := filepath . Join ( backupSyslinuxDir , "ldlinux.sys" )
if _ , err := os . Stat ( backupSyslinuxLdlinuxSys ) ; ! os . IsNotExist ( err ) {
//need a privileged container that can chattr -i ldlinux.sys
cmd := exec . Command ( "chattr" , "-i" , backupSyslinuxLdlinuxSys )
if err := cmd . Run ( ) ; err != nil {
log . Errorf ( "%s" , err )
return err
}
}
if err := os . RemoveAll ( backupSyslinuxDir ) ; err != nil {
log . Errorf ( "RemoveAll (%s): %s" , backupSyslinuxDir , err )
return err
}
2017-02-09 05:12:17 +00:00
}
if err := os . Rename ( grubDir , grubBackup ) ; err != nil {
2017-01-27 14:27:48 +00:00
log . Errorf ( "Rename(%s): %s" , grubDir , err )
2016-12-20 12:49:34 +00:00
return err
}
2018-09-30 06:30:25 +00:00
syslinuxDir := filepath . Join ( baseName , config . BootDir , "syslinux" )
2017-01-30 03:07:05 +00:00
// 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 {
log . Infof ( "error Rename(%s, %s): %s" , syslinuxDir , backupSyslinuxDir , err )
} else {
//mv the old syslinux into linux-previous.cfg
oldSyslinux , err := ioutil . ReadFile ( filepath . Join ( backupSyslinuxDir , "syslinux.cfg" ) )
if err != nil {
log . Infof ( "error read(%s / syslinux.cfg): %s" , backupSyslinuxDir , err )
} else {
cfg := string ( oldSyslinux )
//DEFAULT RancherOS-current
//
//LABEL RancherOS-current
// LINUX ../vmlinuz-v0.7.1-rancheros
// APPEND rancher.state.dev=LABEL=RANCHER_STATE rancher.state.wait console=tty0 rancher.password=rancher
// INITRD ../initrd-v0.7.1-rancheros
cfg = strings . Replace ( cfg , "current" , "previous" , - 1 )
// TODO consider removing the APPEND line - as the global.cfg should have the same result
2018-09-30 06:30:25 +00:00
ioutil . WriteFile ( filepath . Join ( baseName , config . BootDir , "linux-current.cfg" ) , [ ] byte ( cfg ) , 0644 )
2017-01-30 03:07:05 +00:00
lines := strings . Split ( cfg , "\n" )
for _ , line := range lines {
line = strings . TrimSpace ( line )
if strings . HasPrefix ( line , "APPEND" ) {
2018-09-30 06:30:25 +00:00
log . Errorf ( "write new (%s) %s" , filepath . Join ( baseName , config . BootDir , "global.cfg" ) , err )
2017-01-30 03:07:05 +00:00
// TODO: need to append any extra's the user specified
2018-09-30 06:30:25 +00:00
ioutil . WriteFile ( filepath . Join ( baseName , config . BootDir , "global.cfg" ) , [ ] byte ( cfg ) , 0644 )
2017-01-30 03:07:05 +00:00
break
}
}
}
2017-01-27 14:27:48 +00:00
}
}
2017-07-05 04:14:22 +00:00
return installSyslinux ( device , baseName , diskType )
2016-12-20 12:49:34 +00:00
}
2017-07-05 04:14:22 +00:00
func installSyslinux ( device , baseName , diskType string ) error {
2017-03-24 12:39:40 +00:00
log . Debugf ( "installSyslinux(%s)" , device )
2016-12-01 03:55:19 +00:00
2016-12-15 01:54:43 +00:00
mbrFile := "mbr.bin"
if diskType == "gpt" {
mbrFile = "gptmbr.bin"
}
2016-12-01 03:55:19 +00:00
//dd bs=440 count=1 if=/usr/lib/syslinux/mbr/mbr.bin of=${device}
2016-12-04 11:27:06 +00:00
// ubuntu: /usr/lib/syslinux/mbr/mbr.bin
// alpine: /usr/share/syslinux/mbr.bin
2017-01-27 14:27:48 +00:00
if device == "/dev/" {
2017-02-09 05:12:17 +00:00
log . Debugf ( "installSyslinuxRaid(%s)" , device )
2017-01-27 14:27:48 +00:00
//RAID - assume sda&sdb
//TODO: fix this - not sure how to detect what disks should have mbr - perhaps we need a param
// perhaps just assume and use the devices that make up the raid - mdadm
device = "/dev/sda"
if err := setBootable ( device , diskType ) ; err != nil {
log . Errorf ( "setBootable(%s, %s): %s" , device , diskType , err )
//return err
}
cmd := exec . Command ( "dd" , "bs=440" , "count=1" , "if=/usr/share/syslinux/" + mbrFile , "of=" + device )
if err := cmd . Run ( ) ; err != nil {
log . Errorf ( "%s" , err )
return err
}
device = "/dev/sdb"
if err := setBootable ( device , diskType ) ; err != nil {
log . Errorf ( "setBootable(%s, %s): %s" , device , diskType , err )
//return err
}
cmd = exec . Command ( "dd" , "bs=440" , "count=1" , "if=/usr/share/syslinux/" + mbrFile , "of=" + device )
if err := cmd . Run ( ) ; err != nil {
log . Errorf ( "%s" , err )
return err
}
} else {
if err := setBootable ( device , diskType ) ; err != nil {
log . Errorf ( "setBootable(%s, %s): %s" , device , diskType , err )
//return err
}
2017-02-09 05:12:17 +00:00
log . Debugf ( "installSyslinux(%s)" , device )
2017-01-27 14:27:48 +00:00
cmd := exec . Command ( "dd" , "bs=440" , "count=1" , "if=/usr/share/syslinux/" + mbrFile , "of=" + device )
log . Debugf ( "Run(%v)" , cmd )
if err := cmd . Run ( ) ; err != nil {
log . Errorf ( "dd: %s" , err )
return err
}
2016-12-01 03:55:19 +00:00
}
2017-01-30 03:07:05 +00:00
2018-09-30 06:30:25 +00:00
sysLinuxDir := filepath . Join ( baseName , config . BootDir , "syslinux" )
2017-01-30 03:07:05 +00:00
if err := os . MkdirAll ( sysLinuxDir , 0755 ) ; err != nil {
log . Errorf ( "MkdirAll(%s)): %s" , sysLinuxDir , err )
//return err
2016-12-20 12:49:34 +00:00
}
2016-12-01 03:55:19 +00:00
//cp /usr/lib/syslinux/modules/bios/* ${baseName}/${bootDir}syslinux
2016-12-04 11:27:06 +00:00
files , _ := ioutil . ReadDir ( "/usr/share/syslinux/" )
for _ , file := range files {
if file . IsDir ( ) {
continue
}
2017-01-30 03:07:05 +00:00
if err := dfs . CopyFile ( filepath . Join ( "/usr/share/syslinux/" , file . Name ( ) ) , sysLinuxDir , file . Name ( ) ) ; err != nil {
2016-12-04 11:27:06 +00:00
log . Errorf ( "copy syslinux: %s" , err )
return err
}
2016-12-01 03:55:19 +00:00
}
2016-12-04 11:27:06 +00:00
2016-12-01 03:55:19 +00:00
//extlinux --install ${baseName}/${bootDir}syslinux
2017-01-30 03:07:05 +00:00
cmd := exec . Command ( "extlinux" , "--install" , sysLinuxDir )
2017-01-27 14:27:48 +00:00
if device == "/dev/" {
//extlinux --install --raid ${baseName}/${bootDir}syslinux
2017-01-30 03:07:05 +00:00
cmd = exec . Command ( "extlinux" , "--install" , "--raid" , sysLinuxDir )
2017-01-27 14:27:48 +00:00
}
2016-12-07 11:56:32 +00:00
//cmd.Stdout, cmd.Stderr = os.Stdout, os.Stderr
2016-12-04 11:27:06 +00:00
log . Debugf ( "Run(%v)" , cmd )
2016-12-01 03:55:19 +00:00
if err := cmd . Run ( ) ; err != nil {
2017-01-27 14:27:48 +00:00
log . Errorf ( "extlinux: %s" , err )
2016-12-01 03:55:19 +00:00
return err
}
return nil
}
2017-06-28 13:58:14 +00:00
func different ( existing , new string ) bool {
// assume existing file exists
if _ , err := os . Stat ( new ) ; os . IsNotExist ( err ) {
return true
}
data , err := ioutil . ReadFile ( existing )
if err != nil {
return true
}
newData , err := ioutil . ReadFile ( new )
if err != nil {
return true
}
md5sum := md5 . Sum ( data )
newmd5sum := md5 . Sum ( newData )
if md5sum != newmd5sum {
return true
}
return false
}
2017-07-05 04:14:22 +00:00
func installRancher ( baseName , VERSION , DIST , kappend string ) ( string , error ) {
2016-12-01 03:55:19 +00:00
log . Debugf ( "installRancher" )
2016-12-20 12:49:34 +00:00
// detect if there already is a linux-current.cfg, if so, move it to linux-previous.cfg,
2018-09-30 06:30:25 +00:00
currentCfg := filepath . Join ( baseName , config . BootDir , "linux-current.cfg" )
2016-12-20 12:49:34 +00:00
if _ , err := os . Stat ( currentCfg ) ; ! os . IsNotExist ( err ) {
2017-06-28 13:58:14 +00:00
existingCfg := filepath . Join ( DIST , "linux-current.cfg" )
// only remove previous if there is a change to the current
if different ( currentCfg , existingCfg ) {
2018-09-30 06:30:25 +00:00
previousCfg := filepath . Join ( baseName , config . BootDir , "linux-previous.cfg" )
2017-06-28 13:58:14 +00:00
if _ , err := os . Stat ( previousCfg ) ; ! os . IsNotExist ( err ) {
if err := os . Remove ( previousCfg ) ; err != nil {
return currentCfg , err
}
2016-12-20 12:49:34 +00:00
}
2017-06-28 13:58:14 +00:00
os . Rename ( currentCfg , previousCfg )
// TODO: now that we're parsing syslinux.cfg files, maybe we can delete old kernels and initrds
2016-12-20 12:49:34 +00:00
}
}
2016-12-07 03:33:43 +00:00
2016-12-07 10:55:38 +00:00
// The image/ISO have all the files in it - the syslinux cfg's and the kernel&initrd, so we can copy them all from there
2016-12-07 03:33:43 +00:00
files , _ := ioutil . ReadDir ( DIST )
for _ , file := range files {
if file . IsDir ( ) {
continue
}
2017-06-28 13:58:14 +00:00
// TODO: should overwrite anything other than the global.cfg
overwrite := true
if file . Name ( ) == "global.cfg" {
overwrite = false
}
2018-09-30 06:30:25 +00:00
if err := dfs . CopyFileOverwrite ( filepath . Join ( DIST , file . Name ( ) ) , filepath . Join ( baseName , config . BootDir ) , file . Name ( ) , overwrite ) ; err != nil {
2016-12-07 03:33:43 +00:00
log . Errorf ( "copy %s: %s" , file . Name ( ) , err )
2017-01-30 03:07:05 +00:00
//return err
2016-12-07 03:33:43 +00:00
}
}
2017-06-28 13:58:14 +00:00
2016-12-20 12:49:34 +00:00
// the general INCLUDE syslinuxcfg
2017-06-28 13:58:14 +00:00
isolinuxFile := filepath . Join ( DIST , "isolinux" , "isolinux.cfg" )
2018-09-30 06:30:25 +00:00
syslinuxDir := filepath . Join ( baseName , config . BootDir , "syslinux" )
2017-06-28 13:58:14 +00:00
if err := dfs . CopyFileOverwrite ( isolinuxFile , syslinuxDir , "syslinux.cfg" , true ) ; err != nil {
2017-01-30 03:07:05 +00:00
log . Errorf ( "copy global syslinux.cfgS%s: %s" , "syslinux.cfg" , err )
//return err
2017-06-28 13:58:14 +00:00
} else {
log . Debugf ( "installRancher copy global syslinux.cfgS OK" )
2016-12-01 03:55:19 +00:00
}
2016-12-20 12:49:34 +00:00
2016-12-07 10:55:38 +00:00
// The global.cfg INCLUDE - useful for over-riding the APPEND line
2018-09-30 06:30:25 +00:00
globalFile := filepath . Join ( baseName , config . BootDir , "global.cfg" )
2017-01-30 03:07:05 +00:00
if _ , err := os . Stat ( globalFile ) ; ! os . IsNotExist ( err ) {
err := ioutil . WriteFile ( globalFile , [ ] byte ( "APPEND " + kappend ) , 0644 )
if err != nil {
log . Errorf ( "write (%s) %s" , "global.cfg" , err )
2017-03-30 03:01:50 +00:00
return currentCfg , err
2017-01-30 03:07:05 +00:00
}
2016-12-07 10:55:38 +00:00
}
2017-03-30 03:01:50 +00:00
return currentCfg , nil
2016-12-01 03:55:19 +00:00
}