Skip to content

Instantly share code, notes, and snippets.

@creatldd1
Last active July 4, 2021 09:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save creatldd1/99db8d68e2a97e2737c5bb488be67328 to your computer and use it in GitHub Desktop.
Save creatldd1/99db8d68e2a97e2737c5bb488be67328 to your computer and use it in GitHub Desktop.
Ifenslave issue when preinstalling it on Ubuntu 20.04 Offline Custom iso
#!/bin/bash
PARAM_DEBUGON=${PARAM_DEBUGON:-true}
set -o errexit
set -o nounset
if [[ "${PARAM_DEBUGON}" == "true" ]]; then
set -x xtrace
set -o errtrace
set -o functrace
export PS4='+ $(basename ${BASH_SOURCE[0]}) Line ${LINENO}: ' # available in -x mode
fi
trap 'echo "+ $(basename ${BASH_SOURCE[0]:-""}) Line ${LINENO}" ERROR' ERR
# ----------------------------------------------------------------------------------
# INTERNAL PARAMETERS
# ----------------------------------------------------------------------------------
export _APTCACHER_DEFAULT_CONFIG='
Acquire::http::Proxy "http://192.168.250.27:3142";}
//Bypass HTTPS repos
Acquire::http::Proxy { apt.releases.hashicorp.com DIRECT; };
Acquire::http::Proxy { download.docker.com DIRECT; };
Acquire::http::Proxy { deb.nodesource.com DIRECT; };
Acquire::http::Proxy { packages.microsoft.com DIRECT; };
Acquire::http::Proxy { packages.cloud.google.com DIRECT; };
Acquire::http::Proxy { packagecloud.io DIRECT; };
Acquire::http::Proxy { deb.opera.com DIRECT; };
//Bypass some problematic repo
# Acquire::http::Proxy { security.ubuntu.com DIRECT; };
'
export _APTCACHER_DEFAULT_CONFIG=
export _SOURCE_INSTALLER="old_iso/casper/installer.squashfs"
export _SOURCE_FILESYSTEM="old_iso/casper/filesystem.squashfs"
_TMP_ROOTDIR=$( readlink -f "./tmp")
export MDD_CHROOT="" # chroot cmd like "chroot <rootfs dir>"
export MDD_TARGET_DIR="" # rootfs dir
# ----------------------------------------------------------------------------------
# PARAMETERS
# ----------------------------------------------------------------------------------
export PARAM_PREINSTALL_PACKAGES=${PARAM_PREINSTALL_PACKAGES:-"true"} # live install ?
export PARAM_APT_PROXYCONFIG=${PARAM_APT_PROXYCONFIG:-"$_APTCACHER_DEFAULT_CONFIG"}
export PARAM_PACKAGES=${PARAM_PACKAGES:-ifenslave} # packages to install on target
export PARAM_OLD_ISO=${PARAM_OLD_ISO:-"$(readlink -f ./ubuntu-20.04.2-live-server-amd64.iso)"}
export PARAM_NEW_ISO=${PARAM_NEW_ISO:-"./customIsoTest_ubuntu-20.04.2-live-server-amd64.iso"}
# ----------------------------------------------------------------------------------
# FUNCTIONS
# ----------------------------------------------------------------------------------
_MOUNTS=()
do_createTmpDir()
{
local argDirNamePrefix="$1"
# local tmpdir="$(mktemp --directory --tmpdir="${_TMP_ROOTDIR}" "${argDirNamePrefix}_XXXXX")" # FIXME : doesn't work
local tmpdir="${_TMP_ROOTDIR}/${argDirNamePrefix}_$(date +%s%3N)"
mkdir -p ${tmpdir}
if [[ ! -d "${tmpdir}" ]]; then
return 1
fi
echo "${tmpdir}"
return 0
}
do_mount_existing()
{
local mountpoint="${!#}"
mount "$@"
_MOUNTS=( "${mountpoint}" "${_MOUNTS[@]:+"${_MOUNTS[@]}"}" )
}
do_mount()
{
local mountpoint="${!#}"
mkdir -p "${mountpoint}"
do_mount_existing "$@"
}
undo_mount() {
echo "FS to unmount ${_MOUNTS[@]}"
for i in ${!_MOUNTS[@]}; # number of retries
do
local retry="false"
local failed=()
for m in "${_MOUNTS[@]:+"${_MOUNTS[@]}"}"; do
echo "Trying to unmount ${m}"
if grep --quiet --no-messages $(readlink -f ${m}) /proc/mounts; then
umount "${m}" || ( echo "Unmount failed for ${m}. Will retry later"; retry="true")
sleep 1
else
echo "Skipping ${m}. Not mounted."
fi
done
[[ "$retry" == "false" ]] && break
done
_MOUNTS=()
return 0
}
add_overlay()
{
local lower="$1"
local mountpoint="$2"
local work=$(do_createTmpDir "overlaywork_${lower//[ ;:,\\]_}")
if [ -n "${3-}" ]; then
local upper="${3}"
else
local upper="$(do_createTmpDir "overlayup_${lower//[ ;:,\\]_}")"
fi
if ! [[ -d "${work}" && -d "${upper}" ]]; then
return 1
fi
chmod go+rx "${work}" "${upper}"
do_mount -t overlay overlay -o lowerdir="${lower}",upperdir="${upper}",workdir="${work}" "${mountpoint}"
}
prepare_rootfs()
{
if [[ ! ( -n "$MDD_TARGET_DIR" && -d "$MDD_TARGET_DIR" ) || -z $MDD_CHROOT ]]; then # check
return 1
fi
# configure the rootfs
# Change policy to not start daemons
echo "#!/bin/sh
exit 101" > ${MDD_TARGET_DIR}/usr/sbin/policy-rc.d
chmod a+x ${MDD_TARGET_DIR}/usr/sbin/policy-rc.d
if [[ "${#PARAM_APT_PROXYCONFIG}" != "0" ]]; then
echo "$PARAM_APT_PROXYCONFIG" > ${MDD_TARGET_DIR}/etc/apt/apt.conf.d/01proxy
cat ${MDD_TARGET_DIR}/etc/apt/apt.conf.d/01proxy # check
fi
# prepare for chroot
do_mount_existing dev-live-fs -t devtmpfs "new_filesystem/dev"
do_mount devpts-live-fs -t devpts "new_filesystem/dev/pts"
do_mount_existing proc-live-fs -t proc "new_filesystem/proc"
do_mount_existing sysfs-live-fs -t sysfs "new_filesystem/sys"
do_mount_existing securityfs-live-fs -t securityfs "new_filesystem/sys/kernel/security"
# Network
# sudo cp /etc/resolv.conf new_filesystem/etc/resolv.conf
mv "${MDD_TARGET_DIR}/etc/resolv.conf" "${MDD_TARGET_DIR}/etc/resolv.conf.backup"
cp -f /etc/resolv.conf "${MDD_TARGET_DIR}/etc/resolv.conf"
[ -f "${MDD_TARGET_DIR}/etc/hosts" ] && mv "${MDD_TARGET_DIR}/etc/hosts" "${MDD_TARGET_DIR}/etc/hosts.backup"
cp -f /etc/hosts "${MDD_TARGET_DIR}/etc/hosts"
return 0
}
clean_rootfs()
{
if [[ -z "${MDD_CHROOT}" ]]; then
return 1
fi
# Change policy to allow daemons to start
rm -f ${MDD_TARGET_DIR}/usr/sbin/policy-rc.d
# disable Apt Proxy
# if packages are not preinstalled (meaning online install) we keep the proxy config for debug purpose
if [[ "${PARAM_PREINSTALL_PACKAGES}" == "true" ]]; then
rm -f ${MDD_TARGET_DIR}/etc/apt/apt.conf.d/01proxy
fi
# Network
rm -f "${MDD_TARGET_DIR}/etc/resolv.conf"
mv "${MDD_TARGET_DIR}/etc/resolv.conf.backup" "${MDD_TARGET_DIR}/etc/resolv.conf"
rm -f "${MDD_TARGET_DIR}/etc/hosts"
mv "${MDD_TARGET_DIR}/etc/hosts.backup" "${MDD_TARGET_DIR}/etc/hosts"
# do_mounts are automatically undone upon shell exit
}
function main()
{
_MOUNTS=()
trap undo_mount EXIT
# raz
sudo rm -rf "${_TMP_ROOTDIR}"
mkdir -p "${_TMP_ROOTDIR}"
chmod ugo+rwx "${_TMP_ROOTDIR}"
cd "${_TMP_ROOTDIR}"
# ---------------------
# Mount the iso
# ---------------------
do_mount -t iso9660 -o loop,ro "${PARAM_OLD_ISO}" old_iso
# do_mount -t squashfs ${_SOURCE_FILESYSTEM} old_filesystem
argLower="old_iso"
argMountpoint="new_iso"
argUpper=
add_overlay "$argLower" "$argMountpoint" "$argUpper"
# ---------------------
# AUTOINSTALL / CLOUD INIT
# ---------------------
mkdir --parents new_iso/nocloud/
touch new_iso/nocloud/meta-data
cat > new_iso/nocloud/user-data << 'EOF'
#cloud-config
autoinstall:
version: 1
interactive-sections:
- network
- locale
keyboard: {layout: fr, toggle: toggle, variant: ""}
identity:
hostname: customhostname
username: user1
password: "__USER1_PASSWORD__"
ssh:
allow-pw: true
install-server: yes
late-commands:
- curtin in-target --target=/target -- timedatectl set-timezone UTC
- curtin in-target --target=/target -- timedatectl set-ntp true
- curtin in-target --target=/target -- apt-get --purge -y --quiet=2 autoremove
- curtin in-target --target=/target -- apt-get clean
EOF
sed --in-place "s@__USER1_PASSWORD__@$(echo "password1"|mkpasswd -m sha-512 --stdin)@g" new_iso/nocloud/user-data
# Update boot flags with cloud-init autoinstall:
## Should look similar to this: initrd=/casper/initrd quiet autoinstall ds=nocloud;s=/cdrom/nocloud/ ---
sed -i 's|---|autoinstall ds=nocloud\\\;s=/cdrom/nocloud/ ---|g' new_iso/boot/grub/grub.cfg
sed -i 's|---|autoinstall ds=nocloud;s=/cdrom/nocloud/ ---|g' new_iso/isolinux/txt.cfg
# ---------------------
# INSTALL PACKAGES
# ---------------------
if true; then
# mount iso/filesystem.squashfs
do_mount -t squashfs ${_SOURCE_FILESYSTEM} old_filesystem
# create an overlay over it to register the changes
argLower="old_filesystem"
argMountpoint="new_filesystem"
argUpper="upper_filesystem"
mkdir -p "$argUpper"
add_overlay "$argLower" "$argMountpoint" "$argUpper"
export MDD_CHROOT="chroot new_filesystem"
export MDD_TARGET_DIR="$argMountpoint"
# Pre-install some packages ?
(
_MOUNTS=()
trap undo_mount EXIT # clean any mounted fs in this block upon exiting this block
prepare_rootfs
if [ "${PARAM_PREINSTALL_PACKAGES}" == "true" ]; then
set +o nounset # nounset is problematic with the use of <<EOF
${MDD_CHROOT} bash -x <<'EOF'
set -o errexit # exit on sight of the first error
env
export DEBIAN_FRONTEND=noninteractive
export DEBCONF_NONINTERACTIVE_SEEN=true
export LC_ALL=C
export HOME=/root
apt-get update
apt-get dist-upgrade -y
apt install -y -f ${PARAM_PACKAGES}
apt-get dist-upgrade -y
# Clean apt
apt-get -y clean
apt-get -y autoremove --purge -y
apt-get -y autoclean
apt-get check
EOF
set -o nounset
fi
clean_rootfs
# Compute filesystem manifest.
${MDD_CHROOT} dpkg-query -W --showformat='${Package} ${Version}\n' > new_iso/casper/filesystem.manifest
)
rm new_iso/casper/filesystem.squashfs
mksquashfs new_filesystem new_iso/casper/filesystem.squashfs
fi
# update md5
(
# Disable mandatory md5 checksum on boot:
md5sum new_iso/.disk/info > new_iso/md5sum.txt
sed -i 's|new_iso/|./|g' new_iso/md5sum.txt
# FIXME : restore computation of md5
)
# rebuild iso
(
opts="$(xorriso -indev ${PARAM_OLD_ISO} -report_el_torito as_mkisofs)"
echo "xorriso options : $opts"
eval set -- ${opts}
xorriso -as mkisofs "$@" -o ${PARAM_NEW_ISO} -V LDE_Ubuntu new_iso
)
}
# ----------------------------------------------------------------------------------
# M A I N
# ----------------------------------------------------------------------------------
main
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment