John Chittum 05bba4cbbd
ubuntu-cpc:Vagrant Serial to Null (LP: #1874453)
Original fix proposed by Stanislav German-Evtushenko (giner)

CPC Ubuntu cloud images default to enabling a serial console connection
via the kernel commandline option `console=ttyS0`. Many clouds support
the serial connection, and utilize it for debugging purposes. Virtualbox
supports the serial connection as well. In Bionic and earlier images,
Vagrant boxes created a serial log file in the directory of the
Vagrantfile by default. However this is not standard behaviour for
Vagrant images, and so it was removed in Eoan onwards.

Starting in Eoan, there were reports of image booting slowdown (1874453
is a single example). After testing, it was determined that the serial
connection starting, without a device attached, was the cause of the
slow down. However, we did not want to revert to the old functionality
of creating a file. Much thanks to <giner> for providing the Ruby syntax
for sending to File::NULL.

This option will not create a local file, however, the default
Vagrantfile configuration is overwritable via a users Vagrantfile. The
original syntax for creating a file local to the users Vagrantfile has
been included as an example.
2020-09-22 15:57:52 -05:00

246 lines
8.2 KiB
Bash
Executable File

#!/bin/bash -ex
# vi: ts=4 noexpandtab
#
# Generate a generic Vagrant Box.
#
# Vagrant images are essentially nothing more than OVA's with extra-metadata
# and some preinstalled packages.
#
# We can't use the OVA's for Vagrant since Vagrant uses SSH to modify the
# instance. This build step creates a cloud-config ISO so that Cloud-Init
# will configure the initial user, creates meta-data that tells Vagrant how
# to interact with the cloud-init created users, and finally create the OVA.
#
# For this step, we make a deriviative of binary/boot/disk.ext4 and install
# some packages in it, convert it to a vmdk, and then assemble the vagrant
# box.
case ${SUBPROJECT:-} in
minimized)
echo "Skipping minimized $0 build as images won't boot with linux-kvm"
exit 0
;;
*)
;;
esac
cur_d=${PWD}
my_d=$(dirname $(readlink -f ${0}))
# Switch on $ARCH to determine which ID and description to use in the produced
# OVF. We have fancy Ubuntu-specific IDs in the OVF specification, we might as
# well use them.
case $ARCH in
amd64)
ovf_id=94
ovf_os_type="ubuntu64Guest"
ovf_desc_bits=64 ;;
*)
echo "Vagrant images are not supported for $ARCH yet."
exit 0;;
esac
. config/functions
# Lets be safe about this
box_d=$(mktemp -d)
seed_d=$(mktemp -d)
mount_d=$(mktemp -d)
create_derivative "disk" "vagrant" #sets ${derivative_img}
mount_disk_image ${derivative_img} ${mount_d}
cleanup_vagrant() {
if [ -d "$mount_d" ]; then
umount_disk_image "$mount_d"
fi
rm -rf ${box_d} ${seed_d} ${mount_d} ${derivative_img}
}
trap cleanup_vagrant EXIT
chroot ${mount_d} apt-get update
# virtualbox-guest-utils Recommends: virtualbox-guest-x11, which we want to
# avoid pulling into a cloud image.
chroot ${mount_d} apt-get install --no-install-recommends -y virtualbox-guest-utils
chroot ${mount_d} apt-get clean
# Create and setup users inside the image.
# Vagrant users expect a "vagrant" user with a "vagrant" username.
# See https://www.vagrantup.com/docs/boxes/base.html
# Note: We decided NOT to allow root login with a default password.
chroot ${mount_d} adduser vagrant --disabled-password --gecos ""
echo "vagrant:vagrant" | chroot ${mount_d} chpasswd
# The vagrant user should have passwordless sudo.
cat << EOF > ${mount_d}/etc/sudoers.d/vagrant
vagrant ALL=(ALL) NOPASSWD:ALL
EOF
# Add the insecure vagrant pubkey to the vagrant user, as is expected by the
# vagrant ecosystem (https://www.vagrantup.com/docs/boxes/base.html)
chroot ${mount_d} chmod 0440 /etc/sudoers.d/vagrant
chroot ${mount_d} mkdir -p /home/vagrant/.ssh
cat << EOF > ${mount_d}/home/vagrant/.ssh/authorized_keys
ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA6NF8iallvQVp22WDkTkyrtvp9eWW6A8YVr+kz4TjGYe7gHzIw+niNltGEFHzD8+v1I2YJ6oXevct1YeS0o9HZyN1Q9qgCgzUFtdOKLv6IedplqoPkcmF0aYet2PkEDo3MlTBckFXPITAMzF8dJSIFo9D8HfdOV0IAdx4O7PtixWKn5y2hMNG0zQPyUecp4pzC6kivAIhyfHilFR61RGL+GPXQ2MWZWFYbAGjyiYJnAmCP3NOTd0jMZEnDkbUvxhMmBYSdETk1rRgm+R4LOzFUGaHqHDLKLX+FIPKcF96hrucXzcWyLbIbEgE98OHlnVYCzRdK8jlqm8tehUc9c9WhQ== vagrant insecure public key
EOF
chroot ${mount_d} chown -R vagrant:vagrant /home/vagrant/.ssh
chroot ${mount_d} chmod 700 /home/vagrant/.ssh
umount_disk_image "$mount_d"
rmdir "$mount_d"
# Used to identify bits
suite=$(chroot chroot lsb_release -c -s)
version=$(chroot chroot lsb_release --release --short)
distro=$(chroot chroot lsb_release --id --short | tr [:upper:] [:lower:])
# Get the VMDK in place
prefix="${distro}-${suite}-${version}-cloudimg"
vmdk_f="${box_d}/${prefix}.vmdk"
create_vmdk ${derivative_img} ${vmdk_f} 40960
####################################
# Create the ConfigDrive
# This is a cloud-init piece that instructs cloud-init to configure
# a default user at first boot.
cdrom_vmdk_f="${box_d}/${prefix}-configdrive.vmdk"
# Create the user-data. This is totally insecure, but so is Vagrant. To
# mitigate this insecurity, the vagrant instance is not accessible
# except via local host.
cat > ${seed_d}/user-data <<END
#cloud-config
manage_etc_hosts: localhost
END
# Create the fake meta-data
cat > ${seed_d}/meta-data <<END
instance-id: iid-$(openssl rand -hex 8)
local-hostname: ubuntu-${suite}
END
# Pad the cdrom, otherwise the VMDK will be invalid
dd if=/dev/zero of=${seed_d}/bloat_file bs=1M count=10
# Create the ISO
genisoimage \
-output ${seed_d}/seed.iso \
-volid cidata \
-joliet -rock \
-input-charset utf-8 \
${seed_d}/user-data \
${seed_d}/meta-data
# Make a VMDK out of the seed file.
create_vmdk ${seed_d}/seed.iso ${cdrom_vmdk_f} 10
### END Create ConfigDrive
##########################
##########################
# VAGRANT meta-data
# Create the Vagrant file. This file is used by Vagrant to define how
# Vagrant uses Virtualbox and how Vagrant interacts with the host.
macaddr="02$(openssl rand -hex 5 | tr [:lower:] [:upper:])"
cat > ${box_d}/Vagrantfile <<EOF
# Front load the includes
include_vagrantfile = File.expand_path("../include/_Vagrantfile", __FILE__)
load include_vagrantfile if File.exist?(include_vagrantfile)
Vagrant.configure("2") do |config|
config.vm.base_mac = "${macaddr}"
config.vm.provider "virtualbox" do |vb|
vb.customize [ "modifyvm", :id, "--uart1", "0x3F8", "4" ]
# Create a NULL serial port to skip console logging by default
vb.customize [ "modifyvm", :id, "--uartmode1", "file", File::NULL ]
# If console logging is desired, uncomment this line and remove prior
# vb.customize [ "modifyvm", :id, "--uartmode1", "file", File.join(Dir.pwd, "${prefix}-console.log") ]
# Ubuntu cloud images, by default, enable console=ttyS0. This enables serial consoles to
# connect to the images. With the change related to LP #1777827, removing a serial
# file logger, Vagrant image boot times increased and now run greater than 5 minutes
# Creating a console log file is not an expected default behavior for vagrant boxes.
# As a workaround, we create a console connection to File:NULL. LP #1874453
# This is overrideable in user files to write to a local file
end
end
EOF
# Tag it as a Virtualbox Vagrant
cat > ${box_d}/metadata.json <<EOF
{
"provider": "virtualbox"
}
EOF
# END
##########################
##########################
# Create the actual box
# Get information about the disks for the OVF
vmdk_size=$(du -b "${vmdk_f}" | cut -f1)
vmdk_capacity=$(qemu-img info "${vmdk_f}" | awk '-F[\( ]' '$1 ~ /virtual/ && $NF ~ /bytes.*/ {print$(NF-1)}')
vmdk_sha256=$(sha256sum ${vmdk_f} | cut -d' ' -f1)
cdrom_size=$(du -b "${cdrom_vmdk_f}" | cut -f1)
cdrom_capacity=$(qemu-img info "${cdrom_vmdk_f}" | awk '-F[\( ]' '$1 ~ /virtual/ && $NF ~ /bytes.*/ {print$(NF-1)}')
cdrom_sha256=$(sha256sum ${cdrom_vmdk_f} | cut -d' ' -f1)
# Populate the OVF template
ovf="${box_d}/box.ovf"
cp ${my_d}/ovf/ubuntu-ova-v1-cloudcfg-vmdk.tmpl ${ovf}
serial_stamp=$(date +%Y%m%d)
sed -i "${ovf}" \
-e "s/@@NAME@@/${prefix}-${serial_stamp}/g" \
-e "s/@@FILENAME1@@/${vmdk_f##*/}/g" \
-e "s/@@VMDK_FILE_SIZE@@/${vmdk_size}/g" \
-e "s/@@VMDK_CAPACITY@@/${vmdk_capacity}/g" \
-e "s/@@FILENAME2@@/${cdrom_vmdk_f##*/}/g" \
-e "s/@@VMDK_FILE_SIZE2@@/${cdrom_size}/g" \
-e "s/@@VMDK_CAPACITY2@@/${cdrom_capacity}/g" \
-e "s/@@NUM_CPUS@@/2/g" \
-e "s/@@VERSION@@/${version}/g" \
-e "s/@@DATE@@/${serial_stamp}/g" \
-e "s/@@MEM_SIZE@@/1024/g" \
-e "s/@@OVF_ID@@/${ovf_id}/g" \
-e "s/@@OVF_OS_TYPE@@/${ovf_os_type}/g" \
-e "s/@@OVF_DESC_BITS@@/${ovf_desc_bits}/g"
ovf_sha256=$(sha256sum ${ovf} | cut -d' ' -f1)
# Generate the manifest
manifest="${box_d}/${prefix}.mf"
cat > "${manifest}" <<EOF
SHA256(${vmdk_f##*/})= ${vmdk_sha256}
SHA256(${cdrom_vmdk_f##*/})= ${cdrom_sha256}
SHA256(${ovf##*/})= ${ovf_sha256}
EOF
# Now create the box
echo "Creating OVA with the following attributes:"
cat <<EOM
OVA information:
Name: ${prefix}
Size: ${vmdk_size}
VMDK Name: ${vmdk_f##*/}
VMDK Capacity: ${vmdk_capacity}
VMDK SHA256: ${vmdk_sha256}
CDROM Name: ${cdrom_vmdk_f##*/}
CDROM Capacity: ${cdrom_capacity}
CDROM SHA256: ${cdrom_sha256}
EOM
tar -C ${box_d} \
--sort=name \
-cf ${cur_d}/livecd.ubuntu-cpc.vagrant.box \
box.ovf \
Vagrantfile \
metadata.json \
${prefix}.mf \
${vmdk_f##*/} \
${cdrom_vmdk_f##*/}