From 66e1a3f76296c3e9e5a543b4946cbfc79092efb0 Mon Sep 17 00:00:00 2001 From: linuxer Date: Tue, 8 Sep 2020 16:45:54 +0300 Subject: [PATCH] Corrections for Beowulf --- build-openstack-devuan-image.sh | 465 ++++++++++++++++++++++++++++++++ 1 file changed, 465 insertions(+) create mode 100644 build-openstack-devuan-image.sh diff --git a/build-openstack-devuan-image.sh b/build-openstack-devuan-image.sh new file mode 100644 index 0000000..6bd4a3e --- /dev/null +++ b/build-openstack-devuan-image.sh @@ -0,0 +1,465 @@ +#!/bin/sh + +set -e + +# Parse input parameters +usage() { + echo "Usage: $0 --release|-r [options] +Options are: + --minimal|-m + --debootstrap-url|-u (default: http://deb.devuan.org/merged) + --sources.list-mirror|-s (default: http://deb.devuan.org/merged) + --extra-packages|-e ,,... + --hook-script|-hs + --image-size|-is (default: 2G) + --automatic-resize|-ar + --automatic-resize-space|-ars (default: 50M) + --login|-l (default: devuan) + --password|-p (dangerous option: avoid it if possible) +For more info: man $0" + exit 1 +} + +EXTRA=yes +for i in $@ ; do + case "${1}" in + "--extra-packages"|"-e") + if [ -z "${2}" ] ; then + echo "No parameter defining the extra packages" + usage + fi + EXTRA_PACKAGES=${2} + shift + shift + ;; + "--debootstrap-url"|"-u") + if [ -z "${2}" ] ; then + echo "No parameter defining the debootstrap URL" + usage + fi + DEB_MIRROR=${2} + shift + shift + ;; + "--minimal"|"-m") + EXTRA=no + shift + ;; + "--automatic-resize"|"-ar") + AUTOMATIC_RESIZE=yes + shift + ;; + "--automatic-resize-space"|"-ars") + if [ -z "${2}" ] ; then + echo "No parameter defining the suplementary space" + usage + fi + AUTOMATIC_RESIZE_SPACE=${2} + shift + shift + ;; + "--image-size"|"-is") + if [ -z "${2}" ] ; then + echo "No parameter defining the image size" + usage + fi + IMAGE_SIZE=${2} + shift + shift + ;; + "--hook-script"|"-hs") + if [ -z "${2}" ] ; then + echo "No parameter defining the hook script" + usage + fi + if ! [ -x "${2}" ] ; then + echo "Hook script not executable" + fi + HOOK_SCRIPT=${2} + shift + shift + ;; + "--sources.list-mirror"|"-s") + if [ -z "${2}" ] ; then + echo "No parameter defining the hook script" + usage + fi + SOURCE_LIST_MIRROR=${2} + shift + shift + ;; + "--release"|"-r") + if [ "${2}" = "beowulf" ] || [ "${2}" = "ascii" ] || [ "${2}" = "stretch" ] || [ "${2}" = "buster" ] ; then + RELEASE=${2} + shift + shift + else + echo "Release not recognized." + usage + fi + ;; + "--login"|"-l") + if [ -z "${2}" ] ; then + echo "No parameter defining the user login" + usage + fi + USER_LOGIN=${2} + shift + shift + ;; + "--password"|"-p") + if [ -z "${2}" ] ; then + echo "No parameter defining the root password" + fi + ROOT_PASSWORD=${2} + shift + shift + ;; + *) + ;; + esac +done + +if [ -z "${RELEASE}" ] ; then + echo "Release not recognized: please specify the -r parameter." + usage +fi +case "${RELEASE}" in + "beowulf") + RELEASE_NUM=3 + ;; + "ascii") + RELEASE_NUM=2 + ;; + "jessie") + RELEASE_NUM=1 + ;; +esac + +if [ -z "${DEB_MIRROR}" ] ; then + # DEB_MIRROR=http://httpredir.devuan.org/devuan + DEB_MIRROR=http://deb.devuan.org/merged +fi +if [ -z "${EXTRA_PACKAGES}" ] ; then + EXTRA_PACKAGES=bash-completion,joe,most,screen,less,vim,bzip2,nano +fi +if [ -z "${SOURCE_LIST_MIRROR}" ] ; then + SOURCE_LIST_MIRROR=http://deb.devuan.org/merged +fi +if [ -z "${IMAGE_SIZE}" ] ; then + IMAGE_SIZE=2 +fi +if [ -z "${AUTOMATIC_RESIZE_SPACE}" ] ; then + AUTOMATIC_RESIZE_SPACE=50 +fi +if [ -z "${USER_LOGIN}" ] ; then + USER_LOGIN=devuan +fi + +NEEDED_PACKAGES=sudo,adduser,locales,extlinux,openssh-server,linux-image-amd64,euca2ools,file,kbd,aptitude,python3-cffi-backend +if [ "${RELEASE}" = "beowulf" ] ; then + # These are needed by cloud-init and friends, and since we don't want backports of them, + # but just normal packages from Wheezy, we resolve dependencies by hand, prior to using + # apt-get -t beowulf-backports install cloud-init cloud-utils cloud-initramfs-growroot + ###NEEDED_PACKAGES=${NEEDED_PACKAGES},python,python-paramiko,python-argparse,python-cheetah,python-configobj,python-oauth,python-software-properties,python-yaml,python-boto,python-prettytable,initramfs-tools,python-requests,acpid,acpi-support-base + NEEDED_PACKAGES=${NEEDED_PACKAGES},runit,runit-init,python,python-paramiko,python-cheetah,python-configobj,python-oauth,python-yaml,python-boto,python-prettytable,initramfs-tools,python-requests,acpid,acpi-support-base +else + NEEDED_PACKAGES=${NEEDED_PACKAGES},cloud-init,cloud-utils,cloud-initramfs-growroot,dbus +fi + +if [ ${EXTRA} = "no" ] ; then + PKG_LIST=${NEEDED_PACKAGES} +else + PKG_LIST=${NEEDED_PACKAGES},${EXTRA_PACKAGES} +fi +if ! [ `whoami` = "root" ] ; then + echo "You have to be root to run this script" + exit 1 +fi +FILE_NAME=devuan-${RELEASE}-${RELEASE_NUM}.0.0-1-amd64 +AMI_NAME=${FILE_NAME}.raw +QCOW2_NAME=${FILE_NAME}.qcow2 +rm -f ${AMI_NAME} + +set -x + +###################################### +### Prepare the HDD (format, ext.) ### +###################################### +PARTED=/sbin/parted +rm -f $AMI_NAME +qemu-img create ${AMI_NAME} ${IMAGE_SIZE}G +#dd if=/dev/null bs=1M seek=1024 of=${AMI_NAME} + +${PARTED} -s ${AMI_NAME} mktable msdos +${PARTED} -s -a optimal ${AMI_NAME} mkpart primary ext4 1Mi 100% +${PARTED} -s ${AMI_NAME} set 1 boot on +/sbin/install-mbr ${AMI_NAME} --force +RESULT_KPARTX=`/sbin/kpartx -asv ${AMI_NAME} 2>&1` + +if echo "${RESULT_KPARTX}" | grep "^add map" ; then + LOOP_DEVICE=`echo ${RESULT_KPARTX} | cut -d" " -f3` + echo "kpartx mounted using: ${LOOP_DEVICE}" +else + echo "It seems kpartx didn't mount the image correctly: exiting." + exit 1 +fi + +cleanup(){ + error=$? + [ ! -d "${MOUNT_DIR}" ] && return + echo + echo "error $error, umounting $MOUNT_DIR" + /usr/sbin/chroot ${MOUNT_DIR} umount /proc || true + /usr/sbin/chroot ${MOUNT_DIR} umount /sys || true + umount ${MOUNT_DIR} +## rmdir ${MOUNT_DIR} + /sbin/kpartx -d ${AMI_NAME} + exit $error +} +trap "cleanup" EXIT TERM INT + +# We first use ext2, THEN convert to ext4, because that's so much faster this way. +##mkfs.ext2 /dev/mapper/${LOOP_DEVICE} + +# No way, create ext4 filesystem at once +#/sbin/mkfs.ext4 /dev/mapper/${LOOP_DEVICE} + +# Create XFS filesystem at once +/sbin/mkfs.xfs -f /dev/mapper/${LOOP_DEVICE} + +# No fsck because of X days without checks +#tune2fs -i 0 /dev/mapper/${LOOP_DEVICE} + +MOUNT_DIR=`mktemp -d -t build-debimg.XXXXXX` +mount -o loop /dev/mapper/${LOOP_DEVICE} ${MOUNT_DIR} +/usr/sbin/debootstrap --arch=amd64 --verbose \ + --include=${PKG_LIST} \ + ${RELEASE} ${MOUNT_DIR} ${DEB_MIRROR} + +############################ +### Customize the distro ### +############################ +### Customize: access to the VM ### +# # # # # # # # # # # # # # # # # # +# Setup default root password to what has been set on the command line +if [ -n "${ROOT_PASSWORD}" ] ; then + /usr/sbin/chroot ${MOUNT_DIR} sh -c "echo root:${ROOT_PASSWORD} | chpasswd" +fi + +# Otherwise, we have a huge backdoor, since the root password +# is always the same. +sed -i "s/PermitRootLogin yes/PermitRootLogin without-password/" ${MOUNT_DIR}/etc/ssh/sshd_config + +# Add a default user which is used by cloud-init by default +/usr/sbin/chroot ${MOUNT_DIR} adduser --gecos Cloud-init-user --disabled-password --quiet ${USER_LOGIN} + +# Adds the "devuan" user to sudoers, since that is the way +# cloud-init grant access +mkdir -p ${MOUNT_DIR}/etc/sudoers.d +echo "${USER_LOGIN} ALL = NOPASSWD: ALL" >${MOUNT_DIR}/etc/sudoers.d/devuan-cloud-init +chmod 0440 ${MOUNT_DIR}/etc/sudoers.d/devuan-cloud-init + +### Customize: misc stuff ### +# # # # # # # # # # # # # # # +# Setup fstab +echo "# /etc/fstab: static file system information. +proc /proc proc nodev,noexec,nosuid 0 0 +/dev/vda1 / ext4 errors=remount-ro 0 1 +" > ${MOUNT_DIR}/etc/fstab +/usr/sbin/chroot ${MOUNT_DIR} mount /proc || true + +echo "# disable pc speaker +blacklist pcspkr" >${MOUNT_DIR}/etc/modprobe.d/blacklist.conf + +#echo "# Required for cinder hotplug +#acpiphp +#pci_hotplug +#" >>${MOUNT_DIR}/etc/modules + +# Enable bash-completion by default +if [ ${EXTRA} = "yes" ] ; then + echo "# enable bash completion in interactive shells +if ! shopt -oq posix; then + if [ -f /usr/share/bash-completion/bash_completion ]; then + . /usr/share/bash-completion/bash_completion + elif [ -f /etc/bash_completion ]; then + . /etc/bash_completion + fi +fi" >>${MOUNT_DIR}/etc/bash.bashrc + + # No clear for the tty1 console + if [ "${RELEASE}" = "beowulf" ] ; then + sed -i "s#1:2345:respawn:/sbin/getty 38400 tty1#1:2345:respawn:/sbin/getty --noclear 38400 tty1#" ${MOUNT_DIR}/etc/inittab + else + echo ForwardToConsole=yes >> ${MOUNT_DIR}/etc/systemd/journald.conf + fi + + + /usr/sbin/chroot ${MOUNT_DIR} apt-get install -y locales-all +fi + +# Turn off console blanking which is *very* annoying +# and increase KEYBOARD_DELAY because it can be annoying +# over network. + +## sed -i s/^BLANK_TIME=.*/BLANK_TIME=0/ ${MOUNT_DIR}/etc/kbd/config +## sed -i s/^POWERDOWN_TIME=.*/POWERDOWN_TIME=0/ ${MOUNT_DIR}/etc/kbd/config +## sed -i 's/^[ \t#]KEYBOARD_DELAY=.*/KEYBOARD_DELAY=1000/' ${MOUNT_DIR}/etc/kbd/config + +# ^ This kbd config does not exist in Devuan Ascii + + +rm -f ${MOUNT_DIR}/etc/ssh/ssh_host_* +rm -f ${MOUNT_DIR}/etc/udev/rules.d/70-persistent-net.rules +rm -f ${MOUNT_DIR}/lib/udev/write_net_rules + +# Setup networking (eg: DHCP by default) +echo "# This file describes the network interfaces available on your system +# and how to activate them. For more information, see interfaces(5). + +# The loopback network interface +auto lo +iface lo inet loopback + +# The normal eth0 +auto eth0 +iface eth0 inet dhcp + +# Maybe the VM has 2 NICs? +allow-hotplug eth1 +iface eth1 inet dhcp + +# Maybe the VM has 3 NICs? +allow-hotplug eth2 +iface eth2 inet dhcp +" > ${MOUNT_DIR}/etc/network/interfaces + +# Setup the default hostname (will be set by cloud-init +# at boot time anyway) +echo "devuan.example.com" >${MOUNT_DIR}/etc/hostname + +# This should be a correct default everywhere +echo "deb ${SOURCE_LIST_MIRROR} ${RELEASE} main +deb-src ${SOURCE_LIST_MIRROR} ${RELEASE} main" >${MOUNT_DIR}/etc/apt/sources.list + +if [ "${RELEASE}" = "beowulf" ] || [ "${RELEASE}" = "ascii" ] ; then + echo "deb ${SOURCE_LIST_MIRROR} ${RELEASE}-updates main +deb-src ${SOURCE_LIST_MIRROR} ${RELEASE}-updates main +deb http://security.devuan.org/ ${RELEASE}/updates main +deb-src http://security.devuan.org/ ${RELEASE}/updates main +" >>${MOUNT_DIR}/etc/apt/sources.list +fi + +if [ "${RELEASE}" = "beowulf" ] ; then + echo "deb ${SOURCE_LIST_MIRROR} beowulf-backports main +deb-src ${SOURCE_LIST_MIRROR} beowulf-backports main +" >>${MOUNT_DIR}/etc/apt/sources.list +fi + +/usr/sbin/chroot ${MOUNT_DIR} apt-get update +/usr/sbin/chroot ${MOUNT_DIR} apt-get upgrade -y + +# Setup cloud-init, cloud-utils and cloud-initramfs-growroot +# These are only available from backports in Wheezy +if [ "${RELEASE}" = "beowulf" ] ; then + /usr/sbin/chroot ${MOUNT_DIR} apt-get -t beowulf-backports install cloud-init cloud-utils cloud-initramfs-growroot -y +fi + +# For OpenStack, we would like to use Ec2 and no other API +echo "# to update this file, run dpkg-reconfigure cloud-init +datasource_list: [ConfigDrive, Openstack, Ec2]" >${MOUNT_DIR}/etc/cloud/cloud.cfg.d/90_dpkg.cfg + +# Needed to have automatic mounts of /dev/vdb +echo "mount_default_fields: [~, ~, 'auto', 'defaults,nofail', '0', '2']" >>${MOUNT_DIR}/etc/cloud/cloud.cfg +echo "manage_etc_hosts: true" >>${MOUNT_DIR}/etc/cloud/cloud.cfg + +# Set the cloud init default user (required for the keypair to be put in the right home directory) +sed -i "s/name: devuan/name: ${USER_LOGIN}/" ${MOUNT_DIR}/etc/cloud/cloud.cfg + +# Setting-up initramfs +/usr/sbin/chroot ${MOUNT_DIR} update-initramfs -u + +rm ${MOUNT_DIR}/var/cache/apt/archives/*.deb + +# Set console for emergency and rescue shells +SYSTEMD_DIR="${MOUNT_DIR}/etc/systemd/system/" +for service in emergency.service rescue.service ; do + mkdir "${SYSTEMD_DIR}/${service}.d" + echo '[Service] +ExecStart= +ExecStart=-/bin/sh -c "/sbin/sulogin /dev/tty0; /bin/systemctl --fail --no-block default"' > "${SYSTEMD_DIR}/${service}.d/console.conf" +done + +########################### +### Setting-up extlinux ### +########################### +UUID=`blkid -o value -s UUID /dev/mapper/${LOOP_DEVICE}` +mkdir -p ${MOUNT_DIR}/boot/extlinux +echo "default linux +timeout 1 +label linux +kernel /vmlinuz +append initrd=/initrd.img root=/dev/vda1 console=tty0 console=ttyS0,115200 ro" > ${MOUNT_DIR}/boot/extlinux/extlinux.conf +extlinux --install ${MOUNT_DIR}/boot/extlinux + +################### +### HOOK SCRIPT ### +################### +if [ -x ${HOOK_SCRIPT} ] ; then + export BODI_CHROOT_PATH=${MOUNT_DIR} + export BODI_RELEASE=${RELEASE} + ${HOOK_SCRIPT} +fi + +########################## +### Unmount everything ### +########################## + +cleanup(){ + # refine cleanup everything was ok + echo "Finished." +} + +sync +/usr/sbin/chroot ${MOUNT_DIR} umount /proc || true +umount ${MOUNT_DIR} +# Run FSCK so that resize can work +tune2fs -j /dev/mapper/${LOOP_DEVICE} +fsck.ext4 -f /dev/mapper/${LOOP_DEVICE} || true + +if [ "${AUTOMATIC_RESIZE}" = "yes" ] ; then + resize2fs -M /dev/mapper/${LOOP_DEVICE} + FS_BLOCKS=`tune2fs -l /dev/mapper/${LOOP_DEVICE} | awk '/Block count/{print $3}'` + WANTED_SIZE=`expr $FS_BLOCKS '*' 4 '/' 1024 + ${AUTOMATIC_RESIZE_SPACE}` # Add ${AUTOMATIC_RESIZE_SPACE}M + resize2fs /dev/mapper/${LOOP_DEVICE} ${WANTED_SIZE}M + + FINAL_FS_BLOCKS=`tune2fs -l /dev/mapper/${LOOP_DEVICE} | awk '/Block count/{print $3}'` + FINAL_IMG_SIZE=`expr '(' $FINAL_FS_BLOCKS + 258 ')' '*' 4 '/' 1024` # some blocks for mbr and multiple block size (4k) +fi + +sync +kpartx -d ${AMI_NAME} + +## Do not remove build directory yet: we'll use it for debug +## rmdir ${MOUNT_DIR} + +if [ "${AUTOMATIC_RESIZE}" = "yes" ] ; then + # Rebuild a smaller partition table + parted -s ${AMI_NAME} rm 1 + parted -s ${AMI_NAME} mkpart primary ext4 1Mi ${FINAL_IMG_SIZE}Mi + parted -s ${AMI_NAME} set 1 boot on + + # Add 2M for the 1M at the beginning of the partition and some additionnal space + truncate -s `expr 3 + ${FINAL_IMG_SIZE}`M ${AMI_NAME} + install-mbr ${AMI_NAME} --force +fi + +QEMU_VERSION=`qemu-img --help | head -n 1 | cut -d" " -f3 | cut -d"," -f1` +if dpkg --compare-versions ${QEMU_VERSION} gt 1.0 ; then + OTHER_QEMU_IMG_OPTIONS=" -o compat=0.10" +else + OTHER_QEMU_IMG_OPTIONS="" +fi + +qemu-img convert -c -f raw ${AMI_NAME}${OTHER_QEMU_IMG_OPTIONS} -O qcow2 ${QCOW2_NAME}