Last active
November 11, 2023 13:43
-
-
Save cloudnull/67a31d50fbd60f8150d0175326059ae9 to your computer and use it in GitHub Desktop.
Create KVM VMs similar to OpenStack with cloud init, networking, and such.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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