300 lines
14 KiB
Bash
Executable File
300 lines
14 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
# Taken from https://github.com/covertsh/ubuntu-autoinstall-generator
|
|
# modified Aug 23, 2024
|
|
#
|
|
# MIT License
|
|
#
|
|
# Copyright (c) 2020 covertsh
|
|
#
|
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
# of this software and associated documentation files (the "Software"), to deal
|
|
# in the Software without restriction, including without limitation the rights
|
|
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
# copies of the Software, and to permit persons to whom the Software is
|
|
# furnished to do so, subject to the following conditions:
|
|
#
|
|
# The above copyright notice and this permission notice shall be included in all
|
|
# copies or substantial portions of the Software.
|
|
#
|
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
# SOFTWARE.
|
|
|
|
|
|
|
|
|
|
set -Eeuo pipefail
|
|
|
|
function cleanup() {
|
|
trap - SIGINT SIGTERM ERR EXIT
|
|
if [ -n "${tmpdir+x}" ]; then
|
|
rm -rf "$tmpdir"
|
|
log "🚽 Deleted temporary working directory $tmpdir"
|
|
fi
|
|
}
|
|
|
|
trap cleanup SIGINT SIGTERM ERR EXIT
|
|
script_dir=$(cd "$(dirname "${BASH_SOURCE[0]}")" &>/dev/null && pwd -P)
|
|
[[ ! -x "$(command -v date)" ]] && echo "💥 date command not found." && exit 1
|
|
today=$(date +"%Y-%m-%d")
|
|
|
|
function log() {
|
|
echo >&2 -e "[$(date +"%Y-%m-%d %H:%M:%S")] ${1-}"
|
|
}
|
|
|
|
function die() {
|
|
local msg=$1
|
|
local code=${2-1} # Bash parameter expansion - default exit status 1. See https://wiki.bash-hackers.org/syntax/pe#use_a_default_value
|
|
log "$msg"
|
|
exit "$code"
|
|
}
|
|
|
|
usage() {
|
|
cat <<EOF
|
|
Usage: $(basename "${BASH_SOURCE[0]}") [-h] [-v] [-a] [-e] [-u user-data-file] [-m meta-data-file] [-k] [-c] [-r] [-s source-iso-file] [-d destination-iso-file]
|
|
|
|
💁 This script will create fully-automated Ubuntu 24.04 Noble Numbat installation media.
|
|
|
|
Available options:
|
|
|
|
-h, --help Print this help and exit
|
|
-v, --verbose Print script debug info
|
|
-a, --all-in-one Bake user-data and meta-data into the generated ISO. By default you will
|
|
need to boot systems with a CIDATA volume attached containing your
|
|
autoinstall user-data and meta-data files.
|
|
For more information see: https://ubuntu.com/server/docs/install/autoinstall-quickstart
|
|
-e, --use-hwe-kernel Force the generated ISO to boot using the hardware enablement (HWE) kernel. Not supported
|
|
by early Ubuntu 24.04 release ISOs.
|
|
-u, --user-data Path to user-data file. Required if using -a
|
|
-m, --meta-data Path to meta-data file. Will be an empty file if not specified and using -a
|
|
-k, --no-verify Disable GPG verification of the source ISO file. By default SHA256SUMS-$today and
|
|
SHA256SUMS-$today.gpg in ${script_dir} will be used to verify the authenticity and integrity
|
|
of the source ISO file. If they are not present the latest daily SHA256SUMS will be
|
|
downloaded and saved in ${script_dir}. The Ubuntu signing key will be downloaded and
|
|
saved in a new keyring in ${script_dir}
|
|
-c, --no-md5 Disable MD5 checksum on boot
|
|
-r, --use-release-iso Use the current release ISO instead of the daily ISO. The file will be used if it already
|
|
exists.
|
|
-s, --source Source ISO file. By default the latest daily ISO for Ubuntu 24.04 will be downloaded
|
|
and saved as ${script_dir}/ubuntu-original-$today.iso
|
|
That file will be used by default if it already exists.
|
|
-d, --destination Destination ISO file. By default ${script_dir}/ubuntu-autoinstall-$today.iso will be
|
|
created, overwriting any existing file.
|
|
EOF
|
|
exit
|
|
}
|
|
|
|
function parse_params() {
|
|
# default values of variables set from params
|
|
user_data_file=''
|
|
meta_data_file=''
|
|
download_url="https://cdimage.ubuntu.com/ubuntu-server/noble/daily-live/current"
|
|
download_iso="noble-live-server-amd64.iso"
|
|
original_iso="ubuntu-original-$today.iso"
|
|
source_iso="${script_dir}/${original_iso}"
|
|
destination_iso="${script_dir}/ubuntu-autoinstall-$today.iso"
|
|
sha_suffix="${today}"
|
|
gpg_verify=1
|
|
all_in_one=0
|
|
use_hwe_kernel=0
|
|
md5_checksum=1
|
|
use_release_iso=0
|
|
|
|
while :; do
|
|
case "${1-}" in
|
|
-h | --help) usage ;;
|
|
-v | --verbose) set -x ;;
|
|
-a | --all-in-one) all_in_one=1 ;;
|
|
-e | --use-hwe-kernel) use_hwe_kernel=1 ;;
|
|
-c | --no-md5) md5_checksum=0 ;;
|
|
-k | --no-verify) gpg_verify=0 ;;
|
|
-r | --use-release-iso) use_release_iso=1 ;;
|
|
-u | --user-data)
|
|
user_data_file="${2-}"
|
|
shift
|
|
;;
|
|
-s | --source)
|
|
source_iso="${2-}"
|
|
shift
|
|
;;
|
|
-d | --destination)
|
|
destination_iso="${2-}"
|
|
shift
|
|
;;
|
|
-m | --meta-data)
|
|
meta_data_file="${2-}"
|
|
shift
|
|
;;
|
|
-?*) die "Unknown option: $1" ;;
|
|
*) break ;;
|
|
esac
|
|
shift
|
|
done
|
|
|
|
log "👶 Starting up..."
|
|
|
|
# check required params and arguments
|
|
if [ ${all_in_one} -ne 0 ]; then
|
|
[[ -z "${user_data_file}" ]] && die "💥 user-data file was not specified."
|
|
[[ ! -f "$user_data_file" ]] && die "💥 user-data file could not be found."
|
|
[[ -n "${meta_data_file}" ]] && [[ ! -f "$meta_data_file" ]] && die "💥 meta-data file could not be found."
|
|
fi
|
|
|
|
if [ "${source_iso}" != "${script_dir}/${original_iso}" ]; then
|
|
[[ ! -f "${source_iso}" ]] && die "💥 Source ISO file could not be found."
|
|
fi
|
|
|
|
if [ "${use_release_iso}" -eq 1 ]; then
|
|
download_url="https://releases.ubuntu.com/noble"
|
|
log "🔎 Checking for current release..."
|
|
download_iso=$(curl -sSL "${download_url}" | grep -oP 'ubuntu-24\.04\.\d*-live-server-amd64\.iso' | head -n 1)
|
|
original_iso="${download_iso}"
|
|
source_iso="${script_dir}/${download_iso}"
|
|
current_release=$(echo "${download_iso}" | cut -f2 -d-)
|
|
sha_suffix="${current_release}"
|
|
log "💿 Current release is ${current_release}"
|
|
fi
|
|
|
|
destination_iso=$(realpath "${destination_iso}")
|
|
source_iso=$(realpath "${source_iso}")
|
|
|
|
return 0
|
|
}
|
|
|
|
ubuntu_gpg_key_id="843938DF228D22F7B3742BC0D94AA3F0EFE21092"
|
|
|
|
parse_params "$@"
|
|
|
|
tmpdir=$(mktemp -d)
|
|
|
|
if [[ ! "$tmpdir" || ! -d "$tmpdir" ]]; then
|
|
die "💥 Could not create temporary working directory."
|
|
else
|
|
log "📁 Created temporary working directory $tmpdir"
|
|
fi
|
|
|
|
log "🔎 Checking for required utilities..."
|
|
[[ ! -x "$(command -v xorriso)" ]] && die "💥 xorriso is not installed. On Ubuntu, install the 'xorriso' package."
|
|
[[ ! -x "$(command -v sed)" ]] && die "💥 sed is not installed. On Ubuntu, install the 'sed' package."
|
|
[[ ! -x "$(command -v curl)" ]] && die "💥 curl is not installed. On Ubuntu, install the 'curl' package."
|
|
[[ ! -x "$(command -v gpg)" ]] && die "💥 gpg is not installed. On Ubuntu, install the 'gpg' package."
|
|
log "👍 All required utilities are installed."
|
|
|
|
if [ ! -f "${source_iso}" ]; then
|
|
log "🌎 Downloading ISO image for Ubuntu 24.04 Noble Numbat..."
|
|
curl -NsSL "${download_url}/${download_iso}" -o "${source_iso}"
|
|
log "👍 Downloaded and saved to ${source_iso}"
|
|
else
|
|
log "☑️ Using existing ${source_iso} file."
|
|
if [ ${gpg_verify} -eq 1 ]; then
|
|
if [ "${source_iso}" != "${script_dir}/${original_iso}" ]; then
|
|
log "⚠️ Automatic GPG verification is enabled. If the source ISO file is not the latest daily or release image, verification will fail!"
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
if [ ${gpg_verify} -eq 1 ]; then
|
|
if [ ! -f "${script_dir}/SHA256SUMS-${sha_suffix}" ]; then
|
|
log "🌎 Downloading SHA256SUMS & SHA256SUMS.gpg files..."
|
|
curl -NsSL "${download_url}/SHA256SUMS" -o "${script_dir}/SHA256SUMS-${sha_suffix}"
|
|
curl -NsSL "${download_url}/SHA256SUMS.gpg" -o "${script_dir}/SHA256SUMS-${sha_suffix}.gpg"
|
|
else
|
|
log "☑️ Using existing SHA256SUMS-${sha_suffix} & SHA256SUMS-${sha_suffix}.gpg files."
|
|
fi
|
|
|
|
if [ ! -f "${script_dir}/${ubuntu_gpg_key_id}.keyring" ]; then
|
|
log "🌎 Downloading and saving Ubuntu signing key..."
|
|
gpg -q --no-default-keyring --keyring "${script_dir}/${ubuntu_gpg_key_id}.keyring" --keyserver "hkp://keyserver.ubuntu.com" --recv-keys "${ubuntu_gpg_key_id}"
|
|
log "👍 Downloaded and saved to ${script_dir}/${ubuntu_gpg_key_id}.keyring"
|
|
else
|
|
log "☑️ Using existing Ubuntu signing key saved in ${script_dir}/${ubuntu_gpg_key_id}.keyring"
|
|
fi
|
|
|
|
log "🔐 Verifying ${source_iso} integrity and authenticity..."
|
|
gpg -q --keyring "${script_dir}/${ubuntu_gpg_key_id}.keyring" --verify "${script_dir}/SHA256SUMS-${sha_suffix}.gpg" "${script_dir}/SHA256SUMS-${sha_suffix}" 2>/dev/null
|
|
if [ $? -ne 0 ]; then
|
|
rm -f "${script_dir}/${ubuntu_gpg_key_id}.keyring~"
|
|
die "👿 Verification of SHA256SUMS signature failed."
|
|
fi
|
|
|
|
rm -f "${script_dir}/${ubuntu_gpg_key_id}.keyring~"
|
|
digest=$(sha256sum "${source_iso}" | cut -f1 -d ' ')
|
|
set +e
|
|
grep -Fq "$digest" "${script_dir}/SHA256SUMS-${sha_suffix}"
|
|
if [ $? -eq 0 ]; then
|
|
log "👍 Verification succeeded."
|
|
set -e
|
|
else
|
|
die "👿 Verification of ISO digest failed."
|
|
fi
|
|
else
|
|
log "🤞 Skipping verification of source ISO."
|
|
fi
|
|
log "🔧 Extracting ISO image..."
|
|
./xc.sh ${source_iso}
|
|
xorriso -osirrox on -indev "${source_iso}" -extract / "$tmpdir" &>/dev/null
|
|
chmod -R u+w "$tmpdir"
|
|
rm -rf "$tmpdir/"'[BOOT]'
|
|
log "👍 Extracted to $tmpdir"
|
|
|
|
if [ ${use_hwe_kernel} -eq 1 ]; then
|
|
if grep -q "hwe-vmlinuz" "$tmpdir/boot/grub/grub.cfg"; then
|
|
log "☑️ Destination ISO will use HWE kernel."
|
|
sed -i -e 's|/casper/vmlinuz|/casper/hwe-vmlinuz|g' "$tmpdir/boot/grub/grub.cfg"
|
|
sed -i -e 's|/casper/initrd|/casper/hwe-initrd|g' "$tmpdir/boot/grub/grub.cfg"
|
|
sed -i -e 's|/casper/vmlinuz|/casper/hwe-vmlinuz|g' "$tmpdir/boot/grub/loopback.cfg"
|
|
sed -i -e 's|/casper/initrd|/casper/hwe-initrd|g' "$tmpdir/boot/grub/loopback.cfg"
|
|
else
|
|
log "⚠️ This source ISO does not support the HWE kernel. Proceeding with the regular kernel."
|
|
fi
|
|
fi
|
|
|
|
log "🧩 Adding autoinstall parameter to kernel command line..."
|
|
sed -i -e 's/---/ autoinstall ---/g' "$tmpdir/boot/grub/grub.cfg"
|
|
sed -i -e 's/---/ autoinstall ---/g' "$tmpdir/boot/grub/loopback.cfg"
|
|
log "👍 Added parameter to UEFI and BIOS kernel command lines."
|
|
|
|
if [ ${all_in_one} -eq 1 ]; then
|
|
log "🧩 Adding user-data and meta-data files..."
|
|
mkdir "$tmpdir/nocloud"
|
|
cp "$user_data_file" "$tmpdir/nocloud/user-data"
|
|
if [ -n "${meta_data_file}" ]; then
|
|
cp "$meta_data_file" "$tmpdir/nocloud/meta-data"
|
|
else
|
|
touch "$tmpdir/nocloud/meta-data"
|
|
fi
|
|
sed -i -e 's,timeout=30,timeout=1,g' "$tmpdir/boot/grub/grub.cfg"
|
|
sed -i -e 's,---, ds=nocloud\\\;s=/cdrom/nocloud/ ---,g' "$tmpdir/boot/grub/grub.cfg"
|
|
sed -i -e 's,---, ds=nocloud\\\;s=/cdrom/nocloud/ ---,g' "$tmpdir/boot/grub/loopback.cfg"
|
|
log "👍 Added data and configured kernel command line."
|
|
fi
|
|
|
|
if [ ${md5_checksum} -eq 1 ]; then
|
|
log "👷 Updating $tmpdir/md5sum.txt with hashes of modified files..."
|
|
md5=$(md5sum "$tmpdir/boot/grub/grub.cfg" | cut -f1 -d ' ')
|
|
sed -i -e 's,^.*[[:space:]] ./boot/grub/grub.cfg,'"$md5"' ./boot/grub/grub.cfg,' "$tmpdir/md5sum.txt"
|
|
md5=$(md5sum "$tmpdir/boot/grub/loopback.cfg" | cut -f1 -d ' ')
|
|
sed -i -e 's,^.*[[:space:]] ./boot/grub/loopback.cfg,'"$md5"' ./boot/grub/loopback.cfg,' "$tmpdir/md5sum.txt"
|
|
log "👍 Updated hashes."
|
|
else
|
|
log "🗑️ Clearing MD5 hashes..."
|
|
echo > "$tmpdir/md5sum.txt"
|
|
log "👍 Cleared hashes."
|
|
fi
|
|
|
|
log "📦 Repackaging extracted files into an ISO image..."
|
|
cd "$tmpdir"
|
|
xorriso -as mkisofs -r -V 'Ubuntu-Server 24.04.1 LTS amd64' --modification-date='2024091107542800' --grub2-mbr --interval:local_fs:0s-15s:zero_mbrpt,zero_gpt:'/home/dtookey/infra/build/ubuntu-original-2024-09-12.iso' --protective-msdos-label -partition_cyl_align off -partition_offset 16 --mbr-force-bootable -append_partition 2 28732ac11ff8d211ba4b00a0c93ec93b --interval:local_fs:5526876d-5537019d::'/home/dtookey/infra/build/ubuntu-original-2024-09-12.iso' -appended_part_as_gpt -iso_mbr_part_type a2a0d0ebe5b9334487c068b6b72699c7 -c '/boot.catalog' -b '/boot/grub/i386-pc/eltorito.img' -no-emul-boot -boot-load-size 4 -boot-info-table --grub2-boot-info -eltorito-alt-boot -e '--interval:appended_partition_2_start_1381719s_size_10144d:all::' -no-emul-boot -boot-load-size 10144 -o "${destination_iso}" . #&>/dev/null
|
|
|
|
|
|
cd "$OLDPWD"
|
|
log "👍 Repackaged into ${destination_iso}"
|
|
|
|
die "✅ Completed." 0
|
|
|