From 470c686bbc08859e33fb5a801faa155a26043acf Mon Sep 17 00:00:00 2001 From: niusmallnan Date: Tue, 14 May 2019 10:06:10 +0800 Subject: [PATCH] Update os install logic 1. Fix a bug where install to a nvme disk 2. Remove unused code 3. Move cache services logic to os installer --- cmd/control/install.go | 77 +---- cmd/control/install/install.go | 7 + cmd/control/install/service.go | 9 +- images/01-base/Dockerfile | 1 - .../01-base/usr/lib/rancher/cache-services.sh | 33 -- scripts/installer/BaseDockerfile.amd64 | 2 + scripts/installer/BaseDockerfile.arm64 | 2 + scripts/installer/Dockerfile.amd64 | 0 scripts/installer/README.md | 52 --- scripts/installer/cache-services.sh | 28 ++ scripts/installer/lay-down-os | 299 ------------------ scripts/installer/seed-data | 25 -- scripts/installer/set-disk-partitions | 49 --- 13 files changed, 58 insertions(+), 526 deletions(-) delete mode 100755 images/01-base/usr/lib/rancher/cache-services.sh mode change 100755 => 100644 scripts/installer/Dockerfile.amd64 create mode 100755 scripts/installer/cache-services.sh delete mode 100755 scripts/installer/lay-down-os delete mode 100755 scripts/installer/seed-data delete mode 100755 scripts/installer/set-disk-partitions diff --git a/cmd/control/install.go b/cmd/control/install.go index 5dcbddc8..036205ea 100644 --- a/cmd/control/install.go +++ b/cmd/control/install.go @@ -11,10 +11,8 @@ import ( "os/exec" "path/filepath" "runtime" - "strconv" "strings" - "github.com/rancher/catalog-service/utils/version" "github.com/rancher/os/cmd/control/install" "github.com/rancher/os/cmd/power" "github.com/rancher/os/config" @@ -181,7 +179,11 @@ func installAction(c *cli.Context) error { cloudConfig = uc } - stageImages := install.GetCacheImageList(c.Bool("stage"), cloudConfig, installType, cfg) + stageImages := []string{} + if c.Bool("stage") && cloudConfig != "" && installType != "upgrade" { + stageImages = install.GetCacheImageList(cloudConfig, cfg) + log.Debugf("Will cache these images: %s", stageImages) + } if err := runInstall(image, installType, cloudConfig, device, partition, statedir, kappend, force, kexec, isoinstallerloaded, debug, stageImages); err != nil { log.WithFields(log.Fields{"err": err}).Fatal("Failed to run install") @@ -205,49 +207,8 @@ func runInstall(image, installType, cloudConfig, device, partition, statedir, ka os.Exit(1) } } - diskType := "msdos" - - if installType == "gptsyslinux" { - diskType = "gpt" - } - - // Versions before 0.8.0-rc3 use the old calling convention (from the lay-down-os shell script) - imageVersion := strings.Split(image, ":")[1] - if version.GreaterThan("v0.8.0-rc3", imageVersion) { - log.Infof("user specified to install pre v0.8.0: %s", image) - imageVersion = strings.Replace(imageVersion, "-", ".", -1) - vArray := strings.Split(imageVersion, ".") - 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) - cmd.Stdout, cmd.Stderr = os.Stdout, os.Stderr - return cmd.Run() - } - } - } - - //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) - //} - //} useIso := false - usePartition := false // --isoinstallerloaded is used if the ros has created the installer container from and image that was on the booted iso if !isoinstallerloaded { log.Infof("start !isoinstallerloaded") @@ -318,11 +279,13 @@ func runInstall(image, installType, cloudConfig, device, partition, statedir, ka } if partition != "" { installerCmd = append(installerCmd, "--partition", partition) - usePartition = true } if statedir != "" { installerCmd = append(installerCmd, "--statedir", statedir) } + if len(stageImages) > 0 { + installerCmd = append(installerCmd, "--stage") + } // TODO: mount at /mnt for shared mount? if useIso { @@ -332,16 +295,7 @@ func runInstall(image, installType, cloudConfig, device, partition, statedir, ka log.Debugf("Run(%v)", cmd) cmd.Stdout, cmd.Stderr = os.Stdout, os.Stderr - if err = cmd.Run(); err != nil { - return err - } - if len(stageImages) > 0 && cloudConfig != "" && installType != "upgrade" { - if usePartition { - return runCacheScript(partition, stageImages) - } - return runCacheScript(device+"1", stageImages) - } - return nil + return cmd.Run() } } @@ -365,7 +319,7 @@ func runInstall(image, installType, cloudConfig, device, partition, statedir, ka 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} + partition = install.GetDefaultPartition(device) } } @@ -394,6 +348,10 @@ func runInstall(image, installType, cloudConfig, device, partition, statedir, ka return err } + if len(stageImages) > 0 { + return install.RunCacheScript(partition, stageImages) + } + return nil } @@ -1092,10 +1050,3 @@ func installRancher(baseName, VERSION, DIST, kappend string) (string, error) { } return currentCfg, nil } - -func runCacheScript(partition string, images []string) error { - args := make([]string, 0) - args = append(args, partition) - args = append(args, strings.Join(images, " ")) - return util.RunScript("/usr/lib/rancher/cache-services.sh", args...) -} diff --git a/cmd/control/install/install.go b/cmd/control/install/install.go index db9422a5..efa8d9ed 100644 --- a/cmd/control/install/install.go +++ b/cmd/control/install/install.go @@ -82,3 +82,10 @@ func GetStatePartition() string { } return d } + +func GetDefaultPartition(device string) string { + if strings.Contains(device, "nvme") { + return device + "p1" + } + return device + "1" +} diff --git a/cmd/control/install/service.go b/cmd/control/install/service.go index e4bbb3e8..81a2748a 100644 --- a/cmd/control/install/service.go +++ b/cmd/control/install/service.go @@ -17,11 +17,8 @@ type ImageConfig struct { Image string `yaml:"image,omitempty"` } -func GetCacheImageList(stage bool, cloudconfig, installType string, cfg *config.CloudConfig) []string { +func GetCacheImageList(cloudconfig string, cfg *config.CloudConfig) []string { stageImages := make([]string, 0) - if !stage || cloudconfig == "" || installType == "upgrade" { - return stageImages - } bytes, err := readConfigFile(cloudconfig) if err != nil { log.WithFields(log.Fields{"err": err}).Fatal("Failed to read cloud-config") @@ -60,6 +57,10 @@ func GetCacheImageList(stage bool, cloudconfig, installType string, cfg *config. return stageImages } +func RunCacheScript(partition string, images []string) error { + return util.RunScript("/scripts/cache-services.sh", partition, strings.Join(images, " ")) +} + func readConfigFile(file string) ([]byte, error) { content, err := ioutil.ReadFile(file) if err != nil { diff --git a/images/01-base/Dockerfile b/images/01-base/Dockerfile index b397ed3d..f2bb5414 100644 --- a/images/01-base/Dockerfile +++ b/images/01-base/Dockerfile @@ -39,7 +39,6 @@ RUN rm /sbin/poweroff /sbin/reboot /sbin/halt && \ ln -s /usr/share/dhcpcd/hooks/10-wpa_supplicant /lib/dhcpcd/dhcpcd-hooks/ && \ rm -f /usr/share/bash-completion/completions/* && \ chmod 555 /lib/dhcpcd/dhcpcd-run-hooks && \ - chmod +x /usr/lib/rancher/cache-services.sh && \ sed -i 1,10d /etc/rsyslog.conf && \ echo "*.* /var/log/syslog" >> /etc/rsyslog.conf # dump kernel log to console (but after we've finished booting) diff --git a/images/01-base/usr/lib/rancher/cache-services.sh b/images/01-base/usr/lib/rancher/cache-services.sh deleted file mode 100755 index 3ca2b684..00000000 --- a/images/01-base/usr/lib/rancher/cache-services.sh +++ /dev/null @@ -1,33 +0,0 @@ -#!/bin/bash -set -e -x - -root="/mnt/install" -cache="/var/lib/rancher/cache" -preload="/var/lib/rancher/preload/system-docker" - -partition=$1 -images=${@:2} -images_arr=(${images// / }) - -mount_directory() { - sudo mkdir -p ${root} - mount ${partition} ${root} -} - -cache_services() { - mkdir -p ${root}${cache} - cp ${cache}/* ${root}${cache} -} - -cache_images() { - mkdir -p ${root}${preload} - for i in "${images_arr[@]}" - do - system-docker pull $i - done - system-docker save ${images} | xz > ${root}${preload}/os-include.xz -} - -mount_directory -cache_services -cache_images \ No newline at end of file diff --git a/scripts/installer/BaseDockerfile.amd64 b/scripts/installer/BaseDockerfile.amd64 index be892c18..31e57f45 100644 --- a/scripts/installer/BaseDockerfile.amd64 +++ b/scripts/installer/BaseDockerfile.amd64 @@ -21,6 +21,8 @@ COPY kexec/dist/sbin/kexec /sbin/ RUN ln -s /bootiso/boot/ /dist +COPY cache-services.sh /scripts/ + # need to make a /scripts/set-disk-partitions so that older releases can call the installer RUN echo "#!/bin/sh" > /scripts/set-disk-partitions \ && echo "echo 'set-disk-partitions deprecated'" >> /scripts/set-disk-partitions \ diff --git a/scripts/installer/BaseDockerfile.arm64 b/scripts/installer/BaseDockerfile.arm64 index a56458a2..094658f4 100644 --- a/scripts/installer/BaseDockerfile.arm64 +++ b/scripts/installer/BaseDockerfile.arm64 @@ -21,6 +21,8 @@ COPY kexec/dist/sbin/kexec /sbin/ RUN ln -s /bootiso/boot/ /dist +COPY cache-services.sh /scripts/ + # need to make a /scripts/set-disk-partitions so that older releases can call the installer RUN echo "#!/bin/sh" > /scripts/set-disk-partitions \ && echo "echo 'set-disk-partitions deprecated'" >> /scripts/set-disk-partitions \ diff --git a/scripts/installer/Dockerfile.amd64 b/scripts/installer/Dockerfile.amd64 old mode 100755 new mode 100644 diff --git a/scripts/installer/README.md b/scripts/installer/README.md index 928dc44c..c2704f3e 100644 --- a/scripts/installer/README.md +++ b/scripts/installer/README.md @@ -3,55 +3,3 @@ The container can be used directly, but there is a wrapper in RancherOS CLI, `ros install`, that handles calling things in the right order. -##Basics - -When booting from the ISO file RancherOS runs completely from memory. In order to run more containers, and save state between reboots, you need to persist and run from disk. - -When booting, RancherOS looks for a device labeled "RANCHER_STATE". If it finds a volume with that labeled the OS will mount the device and use it to store state. - -The scripts in this container will create a device labeled RANCHER_STATE and make it bootable. The two supported methods, are generic and amazon-ebs. The approach can be translated to suit different needs. - -The generic install type follows these steps: - -1. ) partition device with a single partition the size of the disk. -2. ) format ext4 and label partition as RANCHER_STATE -3. ) Install grub2 on device -4. ) Place kernel/initrd and grub.cfg inside /boot on the device. -5. ) Seeds the cloud-init data so that a ssh key or other RancherOS configuration can be set. - -The amazon-ebs approach follows these steps: - -1. ) format the device (Ext4) and label RANCHER_STATE -2. ) Add PV-GRUB configuration (menu.lst) -3. ) Add Kernel and Initrd -4. ) Sets Rancher to look for EC2 cloud-init data. - - - -## Usage - -**Warning:** Using this container directly can be like running with scissors... - -``` - # Partition disk without prompting of any sort: - docker run --privileged -it --entrypoint=/scripts/set-disk-partitions rancher/os: - - - # install - docker run --privileged -it -v /home:/home -v /opt:/opt \ - rancher/os: -d -t -c \ - -i /custom/dist/dir \ - -f -``` - -The installation process requires a cloud config file. It needs to be placed in either /home/rancher/ or /opt/. The installer make use of the user-volumes to facilitate files being available between system containers. `-i` and `-f` options are, well, optional. - -By providing `-i` (or `DIST` env var) you specify the path to your custom `vmlinuz` and `initrd`. - -`-f` allows you to copy arbitrary files to the target root filesystem. - -## Contact -For bugs, questions, comments, corrections, suggestions, etc., open an issue in - [rancher/os](//github.com/rancher/os/issues) with a title starting with `[os-installer] `. - -Or just [click here](//github.com/rancher/os/issues/new?title=%5Bos-installer%5D%20) to create a new issue. diff --git a/scripts/installer/cache-services.sh b/scripts/installer/cache-services.sh new file mode 100755 index 00000000..ef54c536 --- /dev/null +++ b/scripts/installer/cache-services.sh @@ -0,0 +1,28 @@ +#!/bin/sh +set -e -x + +root="/mnt/install" +cache="/var/lib/rancher/cache" +preload="/var/lib/rancher/preload/system-docker" + +partition=$1 +images=$2 + +cache_services() { + mkdir -p ${root}${cache} + cp ${cache}/* ${root}${cache} +} + +cache_images() { + mkdir -p ${root}${preload} + for i in ${images}; do + system-docker pull $i + done + system-docker save -o ${root}${preload}/os-include.tar ${images} +} + +mkdir -p ${root} +mount ${partition} ${root} +cache_services +cache_images +umount ${root} diff --git a/scripts/installer/lay-down-os b/scripts/installer/lay-down-os deleted file mode 100755 index c1e9166b..00000000 --- a/scripts/installer/lay-down-os +++ /dev/null @@ -1,299 +0,0 @@ -#!/bin/bash -set -e -x - -SCRIPTS_DIR=$(dirname ${0}) - -VERSION=${VERSION:?"VERSION not set"} - -MBR_FILE=mbr.bin - -while getopts "i:f:c:d:t:r:o:p:ka:g" OPTION -do - case ${OPTION} in - # used by `ros install` - d) DEVICE="$OPTARG" ;; - t) ENV="$OPTARG" ;; # install type - c) CLOUD_CONFIG="$OPTARG" ;; - a) APPEND="$OPTARG" ;; - g) MBR_FILE=gptmbr.bin ;; - # upgrade! - r) ROLLBACK_VERSION="$OPTARG" ;; - k) KEXEC=y ;; - # used for testing? - p) PARTITION="$OPTARG" ;; - # notused? - i) DIST="$OPTARG" ;; - f) FILES="$OPTARG" ;; - o) OEM="$OPTARG" ;; - *) exit 1 ;; - esac -done -[[ "$ARCH" == "arm" && "$ENV" != "rancher-upgrade" ]] && ENV=arm - -if [[ "$ENV" == "gptsyslinux" ]]; then - MBR_FILE="gptmbr.bin" -fi - -DIST=${DIST:-/dist} -CLOUD_CONFIG=${CLOUD_CONFIG:-"${SCRIPTS_DIR}/conf/empty.yml"} -CONSOLE=tty0 -BASE_DIR="/mnt/new_img" -BOOT=boot/ -# 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=${PARTITION:=${DEVICE}1} -KERNEL_ARGS="rancher.state.dev=LABEL=RANCHER_STATE rancher.state.wait console=${CONSOLE}" - -device_defined() -{ - if [[ -z "$1" ]]; then - echo "Need to Pass a device name -d ." 1>&2 - exit 1 - fi -} - -format_device() -{ - device_defined ${DEVICE} - mkfs.ext4 -F -i 4096 -L RANCHER_STATE ${PARTITION} -} - -get_dev() -{ - if [ -z "$(which ros)" ]; then - lsblk -n -o label $1 - else - ros dev LABEL=${1} - fi -} - -mount_device() -{ - LABEL=RANCHER_STATE - local raw="${1:-false}" - - mkdir -p ${BASE_DIR} - - if [ -n "$(get_dev RANCHER_BOOT)" ]; then - LABEL=RANCHER_BOOT - BOOT= - fi - - local mount_opts="-L ${LABEL}" - if [ "${raw}" == "true" ]; then - device_defined ${DEVICE} - mount_opts=${PARTITION} - fi - - mount ${mount_opts} ${BASE_DIR} - trap "umount ${BASE_DIR}" EXIT -} - -create_boot_dirs() -{ - mkdir -p ${BASE_DIR}/${BOOT}grub - mkdir -p ${BASE_DIR}/${BOOT}syslinux -} - -install_syslinux() { - dd bs=440 count=1 if=/usr/lib/syslinux/mbr/${MBR_FILE} of=${DEVICE} - cp /usr/lib/syslinux/modules/bios/* ${BASE_DIR}/${BOOT}syslinux/ - extlinux --install ${BASE_DIR}/${BOOT}syslinux -} - -install_syslinux_raid() { - dd bs=440 count=1 if=/usr/lib/syslinux/mbr/${MBR_FILE} of=/dev/sda - dd bs=440 count=1 if=/usr/lib/syslinux/mbr/${MBR_FILE} of=/dev/sdb - cp /usr/lib/syslinux/modules/bios/* ${BASE_DIR}/${BOOT}syslinux/ - extlinux --install --raid ${BASE_DIR}/${BOOT}syslinux -} - -install_grub() { - grub-install --boot-directory=${BASE_DIR}/boot ${DEVICE} -} - -grub2_config(){ - local grub_cfg=${BASE_DIR}/${BOOT}grub/grub.cfg - local append_line="${1}" -cat >${grub_cfg} <>${grub_cfg} <${syslinux_cfg} <>${syslinux_cfg} < ${grub_file}<> ${grub_file}<&2 - exit 1 - ;; - esac -fi - -if [ -e ${BASE_DIR}/${BOOT}append ]; then - PRESERVED_APPEND=$(cat ${BASE_DIR}/${BOOT}append) -fi -if [ "${APPEND}" = "" ]; then - APPEND="${PRESERVED_APPEND}" -fi -echo "${APPEND}" > ${BASE_DIR}/${BOOT}append - -grub2_config "${APPEND}" -syslinux_config "${APPEND}" -pvgrub_config "${APPEND}" -install_rancher - -seusers=${BASE_DIR}/etc/selinux/ros/seusers -failsafe_context=${BASE_DIR}/etc/selinux/ros/contexts/failsafe_context -if [ -f "${seusers}" ]; then - echo "__default__:unconfined_u:s0-s0:c0.c1023" > ${seusers} -fi -if [ -f "${failsafe_context}" ]; then - echo "unconfined_r:unconfined_t:s0" > ${failsafe_context} -fi - -if [ "$KEXEC" = "y" ]; then - kexec -l ${DIST}/vmlinuz --initrd=${DIST}/initrd --append="${KERNEL_ARGS} ${APPEND}" -f -fi - diff --git a/scripts/installer/seed-data b/scripts/installer/seed-data deleted file mode 100755 index 306f47f2..00000000 --- a/scripts/installer/seed-data +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/bash - -set -e -x - -SCRIPTS_DIR=$(dirname ${0}) - -BASE_DIR=${1} -CLOUD_DATA=${2} -IFS=',' read -ra FILES <<< "${3}" - -if [ -z ${BASE_DIR} ]; then - echo "Need base directory to place files" 1>&2 - exit 1 -fi - -mkdir -p ${BASE_DIR}/var/lib/rancher/conf/cloud-config.d -if [ "${CLOUD_DATA}" != "${SCRIPTS_DIR}/conf/empty.yml" ]; then - cp ${CLOUD_DATA} ${BASE_DIR}/var/lib/rancher/conf/cloud-config.d/ -fi - -for f in ${FILES[@]}; do - IFS=":" read s d <<< "${f}" - mkdir -p $(dirname ${BASE_DIR}/${d}) - cp -a -T ${s} ${BASE_DIR}/${d} -done diff --git a/scripts/installer/set-disk-partitions b/scripts/installer/set-disk-partitions deleted file mode 100755 index 0ad2cd8c..00000000 --- a/scripts/installer/set-disk-partitions +++ /dev/null @@ -1,49 +0,0 @@ -#!/bin/bash - -set -e -set -x - -DEVICE=${1} -DISKTYPE=${2} -if [[ -z $DISKTYPE ]]; then - DISKTYPE="msdos" -fi - -if [[ -z $DEVICE ]]; then - echo "Need to Pass a device name as arg1." 1>&2 - exit 1 -fi - -PARTITION_COUNT=$(grep $(echo $DEVICE | cut -d '/' -f3) /proc/partitions | wc -l) -if [ "$PARTITION_COUNT" -gt "1" ]; then - echo "Device ${DEVICE} already partitioned!" - echo "Checking to see if it is mounted" - - # Check this container first... - if grep -q "${DEVICE}" /proc/mounts; then - echo "Device is mounted, we can not repartition" 1>&2 - exit 1 - fi - - # Check other system containers... - for container in $(system-docker ps -q); do - if system-docker exec $container grep -q "${DEVICE}" /proc/mounts; then - echo "Device is mounted in system container ${container}, we can not repartition" 1>&2 - exit 1 - fi - done -fi - -dd if=/dev/zero of=${DEVICE} bs=512 count=2048 -partprobe ${DEVICE} - -# https://www.gnu.org/software/parted/manual/html_node/set.html -# https://wiki.archlinux.org/index.php/syslinux -BOOTFLAG="boot" -if [ "${DISKTYPE}" == "gpt" ]; then - BOOTFLAG="legacy_boot" -fi -parted -s -a optimal ${DEVICE} mklabel ${DISKTYPE} -- \ - mkpart primary ext4 1 -1 \ - set 1 ${BOOTFLAG} on -