#!/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} #################################### # 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" ] # Creating a console log file is not an expected behavior for vagrant boxes. LP #1777827 # vb.customize [ "modifyvm", :id, "--uartmode1", "file", File.join(Dir.pwd, "${prefix}-console.log") ] 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} \ -cf ${cur_d}/livecd.ubuntu-cpc.vagrant.box \ box.ovf \ Vagrantfile \ metadata.json \ ${prefix}.mf \ ${vmdk_f##*/} \ ${cdrom_vmdk_f##*/}