Skip to content

Instantly share code, notes, and snippets.

@cloudnull
Last active November 11, 2023 13:43
Show Gist options
  • Save cloudnull/67a31d50fbd60f8150d0175326059ae9 to your computer and use it in GitHub Desktop.
Save cloudnull/67a31d50fbd60f8150d0175326059ae9 to your computer and use it in GitHub Desktop.
Create KVM VMs similar to OpenStack with cloud init, networking, and such.
#!/bin/bash
set -ev
set -o pipefail
if [[ -f "/etc/default/vm-defaults" ]]; then
source /etc/default/vm-defaults
fi
export NAME=${NAME:-TargetVM}
export CORE=${CORE:-1}
export SIZE=${SIZE:-8}
export RAM=${RAM:-1024}
export IMAGE=${IMAGE:-CentOS-8-x86_64-GenericCloud.qcow2}
export IMAGE_PATH=${IMAGE_PATH:-/mnt/rhv/images}
export UEFI_BOOT=${UEFI_BOOT:-true}
export PUBKEY=${PUBKEY:-$(cat ~/.ssh/id_rsa.pub)}
export DEFAULT_SECRET=${DEFAULT_SECRET:-secrete}
export USER_DATA_FILE=${USER_DATA_FILE:-}
export VM_STORAGE_ROOT=${VM_STORAGE_ROOT:-/var/lib/libvirt/images}
export VM_ROOT="${VM_STORAGE_ROOT}/${NAME}"
[ -f ~/.ssh/id_rsa.pub ] || ssh-keygen -t rsa -f ~/.ssh/id_rsa -q -P ""
mkdir -p "${VM_ROOT}"
cat <<EOF > ${VM_ROOT}/user-data
#cloud-config
password: ${DEFAULT_SECRET}
chpasswd: { expire: False }
# Hostname management
preserve_hostname: False
hostname: ${NAME}
fqdn: ${NAME}
# Setup Users with ssh keys so that I can log in into new machine
users:
- default
- name: vm-user
groups: []
shell: /bin/bash
sudo:
- ALL=(ALL) NOPASSWD:ALL
ssh_pwauth: True
ssh-authorized-keys:
- ${PUBKEY}
# Configure where output will go
output:
all: ">> /var/log/cloud-init.log"
# configure interaction with ssh server
ssh_svcname: ssh
ssh_deletekeys: True
ssh_genkeytypes:
- rsa
- ecdsa
ssh_pwauth: True
ssh_authorized_keys:
- ${PUBKEY}
# set timezone for VM
timezone: UTC
packages:
- qemu-guest-agent
runcmd:
- sudo bash -c 'dnf -y upgrade || apt -y upgrade || zypper -y dup'
- sudo hostnamectl --pretty set-hostname ${NAME}
- sudo hostnamectl --static set-hostname ${NAME}
- sudo hostnamectl --transient set-hostname ${NAME}
- sudo systemctl enable qemu-guest-agent
- sudo bash -c 'systemctl enable sshd || systemctl enable ssh'
- sudo systemctl disable cloud-init-local
- sudo systemctl mask cloud-init-local
- sudo systemctl disable cloud-init
- sudo systemctl mask cloud-init
- sudo bash -c "nmcli con modify \$(nmcli --fields UUID,type con show --active | awk '/ethernet/ {print \$1}' | head -n 1) ipv4.method manual ipv4.addresses \$(ip -o a show \$(ip -o r g 1 | awk '{print \$5}') | awk '/inet\s/ {print \$4}') ipv4.gateway \$(ip -o r g 1 | awk '{print \$3}') ipv4.dns \$(ip -o r g 1 | awk '{print \$3}') ipv4.dns-search no"
- sudo bash -c 'curl https://raw.githubusercontent.com/cloudnull/directord/main/tools/dev-setup.sh | bash'
- sudo reboot
EOF
cat <<EOF > ${VM_ROOT}/meta-data
instance-id: ${NAME}
local-hostname: ${NAME}
EOF
export LIBGUESTFS_BACKEND=direct
if [[ ! -f "${VM_ROOT}/root-disk.raw" ]]; then
qemu-img create -f raw -o preallocation=falloc ${VM_ROOT}/root-disk.raw ${SIZE}G
export ROOT_DEVICE=$(virt-filesystems --long -h --all -a ${VM_ROOT}/root-disk.raw | grep root | awk '{print $1}' | head -n 1 || echo /dev/sda1)
virt-resize --quiet --expand ${ROOT_DEVICE} --align-first=auto ${IMAGE_PATH}/${IMAGE} ${VM_ROOT}/root-disk.raw
fi
if [ ! -z ${USER_DATA_FILE} ]; then
envsubst < ${USER_DATA_FILE} > ${VM_ROOT}/user-data
fi
pushd ${VM_ROOT}
genisoimage -output ${VM_ROOT}/cidata.iso -volid cidata -joliet -r user-data meta-data
popd
function uefi-image {
virt-install --boot uefi \
--ram ${RAM} \
--import \
--vcpus=${CORE},sockets=1,cores=${CORE} \
--os-variant rhl8.0 \
--disk ${VM_ROOT}/cidata.iso,device=cdrom \
--disk path=${VM_ROOT}/root-disk.raw,device=disk,bus=virtio,format=raw,discard=unmap,size=${SIZE},cache=none,io=native \
--network network:uplink,model=virtio,driver_name=vhost,driver_queues=${CORE},trustGuestRxFilters=yes \
--name ${NAME} \
--graphics vnc,listen=0.0.0.0 \
--controller scsi,model=virtio-scsi \
--controller usb,model=none \
--serial pty \
--parallel pty \
--virt-type kvm \
--memballoon virtio \
--memorybacking locked=on \
--hvm \
--cpu host-passthrough,topology.cores=${CORE},topology.sockets=1,topology.threads=1 \
--rng /dev/urandom \
--watchdog default,action=poweroff \
--check all=off \
--noautoconsole \
--features pmu=off \
--channel unix,target_type=virtio,name=org.qemu.guest_agent.0 \
--machine q35
}
function legacy-image {
virt-install --boot hd \
--ram ${RAM} \
--import \
--vcpus=${CORE},sockets=1,cores=${CORE} \
--os-variant rhl8.0 \
--disk ${VM_ROOT}/cidata.iso,device=cdrom \
--disk path=${VM_ROOT}/root-disk.raw,device=disk,bus=virtio,format=raw,discard=unmap,size=${SIZE},cache=none,io=native \
--network network:uplink,model=virtio,driver_name=vhost,driver_queues=${CORE},trustGuestRxFilters=yes \
--name ${NAME} \
--graphics vnc,listen=0.0.0.0 \
--controller scsi,model=virtio-scsi \
--controller usb,model=none \
--serial pty \
--parallel pty \
--virt-type kvm \
--memballoon virtio \
--memorybacking locked=on \
--hvm \
--cpu host-passthrough,topology.cores=${CORE},topology.sockets=1,topology.threads=1 \
--rng /dev/urandom \
--watchdog default,action=poweroff \
--check all=off \
--noautoconsole \
--features pmu=off \
--channel unix,target_type=virtio,name=org.qemu.guest_agent.0
}
if [ ${UEFI_BOOT} = true ]; then
uefi-image
else
legacy-image
fi
virsh autostart --domain ${NAME}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment