Skip to content

Instantly share code, notes, and snippets.

@anjannath
Created July 1, 2025 12:21
Show Gist options
  • Select an option

  • Save anjannath/4cadd9376c1ac4777bf159852d78e356 to your computer and use it in GitHub Desktop.

Select an option

Save anjannath/4cadd9376c1ac4777bf159852d78e356 to your computer and use it in GitHub Desktop.
script to start crc self sufficient bundle using libvirt
#!/bin/bash
set -euo pipefail
PASS_DEVELOPER="${PASS_DEVELOPER:-P@ssd3v3loper}"
PASS_KUBEADMIN="${PASS_DEVELOPER:-P@sskub3admin}"
CRC_BUNDLE_PATH="${CRC_BUNDLE_PATH:-$HOME/.crc/cache/crc_libvirt_4.19.0_amd64.crcbundle}"
SSH="ssh -oUserKnownHostsFile=/dev/null -oStrictHostKeyChecking=no -i ${PUB_KEY_PATH%.*}"
SCP="scp -oUserKnownHostsFile=/dev/null -oStrictHostKeyChecking=no -i ${PUB_KEY_PATH%.*}"
if [[ "${PULL_SECRET_PATH}" == "" ]]; then
echo -n "Path to Pull secret file needs to be set using PULL_SECRET_PATH env variable"
exit 1
fi
if [[ "${PUB_KEY_PATH}" == "" ]]; then
echo -n "Path to the SSH Public key needs to be set using PUB_KEY_PATH env variable"
exit 1
fi
if [[ "${CRC_BUNDLE_PATH}" == "" ]]; then
echo -n "Path to a CRC bundle needs to be set using CRC_BUNDLE_PATH env variable"
exit 1
fi
PULL_SECRET=$(cat ${PULL_SECRET_PATH})
PUB_KEY=$(cat ${PUB_KEY_PATH})
function gen_cloud_init() {
echo -n "Generating cloud-init user-data..."
rm -rf seed.iso
cat <<EOF > user-data
#cloud-config
runcmd:
- systemctl enable --now kubelet
write_files:
- path: /home/core/.ssh/authorized_keys
content: '$PUB_KEY'
owner: core
permissions: '0600'
- path: /opt/crc/id_rsa.pub
content: '$PUB_KEY'
owner: root:root
permissions: '0644'
- path: /etc/sysconfig/crc-env
content: |
CRC_CLOUD=1
CRC_NETWORK_MODE_USER=0
owner: root:root
permissions: '0644'
- path: /usr/local/bin/crc-check-cloud-env.sh
content: |
#!/bin/bash
exit 0
owner: root:root
permissions: '0777'
- path: /opt/crc/pull-secret
content: |
$PULL_SECRET
permissions: '0644'
- path: /opt/crc/pass_kubeadmin
content: '$PASS_KUBEADMIN'
permissions: '0644'
- path: /opt/crc/pass_developer
content: '$PASS_DEVELOPER'
permissions: '0644'
- path: /opt/crc/ocp-custom-domain.service.done
permissions: '0644'
EOF
# create cloud-init ISO
touch meta-data
mkisofs -output seed.iso -volid cidata -joliet -rock user-data meta-data
# macos: hdiutil makehybrid -o seed.iso -hfs -joliet -iso -default-volume-name cidata seedconfig/
}
function extract_disk_img() {
echo -n "Extracting VM image from CRC bundle ..."
zstd -d --format=zstd -o bundle.tar "${CRC_BUNDLE_PATH}"
bundle_name=$(basename "${CRC_BUNDLE_PATH}")
tar -O -xvf bundle.tar "${bundle_name%.*}"/crc.qcow2 > crc.qcow2
rm -rf bundle.tar
}
function create_libvirt_vm() {
crc_disk_path="$(pwd)/crc.qcow2"
cloud_init_iso="$(pwd)/seed.iso"
uuid=$(uuidgen)
vm_name=${1}
echo -n "Creating VM..."
cat <<EOF > crc-ssf.xml
<domain type='kvm'>
<name>${vm_name}</name>
<uuid>${uuid}</uuid>
<memory unit='KiB'>11010048</memory>
<currentMemory unit='KiB'>11010048</currentMemory>
<memoryBacking>
<source type='memfd'/>
<access mode='shared'/>
</memoryBacking>
<vcpu placement='static'>4</vcpu>
<os firmware='efi'>
<type arch='x86_64' machine='pc-q35-9.1'>hvm</type>
<firmware>
<feature enabled='no' name='enrolled-keys'/>
<feature enabled='no' name='secure-boot'/>
</firmware>
<loader readonly='yes' type='pflash' format='qcow2'>/usr/share/edk2/ovmf/OVMF_CODE_4M.qcow2</loader>
<nvram template='/usr/share/edk2/ovmf/OVMF_VARS_4M.qcow2' format='qcow2'>/var/lib/libvirt/qemu/nvram/crc-2_VARS.qcow2</nvram>
<boot dev='hd'/>
<bootmenu enable='no'/>
</os>
<features>
<acpi/>
<apic/>
<pae/>
</features>
<cpu mode='host-passthrough' check='none' migratable='on'/>
<clock offset='utc'/>
<on_poweroff>destroy</on_poweroff>
<on_reboot>restart</on_reboot>
<on_crash>destroy</on_crash>
<devices>
<emulator>/usr/bin/qemu-system-x86_64</emulator>
<disk type='file' device='disk'>
<driver name='qemu' type='qcow2'/>
<source file='${crc_disk_path}'/>
<target dev='vda' bus='virtio'/>
<address type='pci' domain='0x0000' bus='0x04' slot='0x00' function='0x0'/>
</disk>
<disk type='file' device='cdrom'>
<driver name='qemu' type='raw' cache='none'/>
<source file='${cloud_init_iso}'/>
<target dev='sda' bus='sata'/>
<readonly/>
<address type='drive' controller='0' bus='0' target='0' unit='0'/>
</disk>
<controller type='usb' index='0' model='qemu-xhci'>
<address type='pci' domain='0x0000' bus='0x03' slot='0x00' function='0x0'/>
</controller>
<controller type='sata' index='0'>
<address type='pci' domain='0x0000' bus='0x00' slot='0x1f' function='0x2'/>
</controller>
<controller type='pci' index='0' model='pcie-root'/>
<controller type='pci' index='1' model='pcie-root-port'>
<model name='pcie-root-port'/>
<target chassis='1' port='0x10'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0' multifunction='on'/>
</controller>
<controller type='pci' index='2' model='pcie-root-port'>
<model name='pcie-root-port'/>
<target chassis='2' port='0x11'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x1'/>
</controller>
<controller type='pci' index='3' model='pcie-root-port'>
<model name='pcie-root-port'/>
<target chassis='3' port='0x12'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x2'/>
</controller>
<controller type='pci' index='4' model='pcie-root-port'>
<model name='pcie-root-port'/>
<target chassis='4' port='0x13'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x3'/>
</controller>
<controller type='pci' index='5' model='pcie-root-port'>
<model name='pcie-root-port'/>
<target chassis='5' port='0x14'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x4'/>
</controller>
<controller type='pci' index='6' model='pcie-root-port'>
<model name='pcie-root-port'/>
<target chassis='6' port='0x15'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x5'/>
</controller>
<interface type='network'>
<mac address='52:fd:fc:07:21:82'/>
<source network='crc'/>
<model type='virtio'/>
<address type='pci' domain='0x0000' bus='0x02' slot='0x00' function='0x0'/>
</interface>
<serial type='stdio'>
<target type='isa-serial' port='0'>
<model name='isa-serial'/>
</target>
</serial>
<console type='stdio'>
<target type='serial' port='0'/>
</console>
<input type='mouse' bus='ps2'/>
<input type='keyboard' bus='ps2'/>
<graphics type='vnc' port='-1' autoport='yes'>
<listen type='address'/>
</graphics>
<audio id='1' type='none'/>
<video>
<model type='cirrus' vram='16384' heads='1' primary='yes'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0'/>
</video>
<watchdog model='itco' action='reset'/>
<memballoon model='none'/>
<rng model='virtio'>
<backend model='random'>/dev/urandom</backend>
<address type='pci' domain='0x0000' bus='0x05' slot='0x00' function='0x0'/>
</rng>
</devices>
</domain>
EOF
sudo virsh define --file crc-ssf.xml --validate
sudo virsh start ${vm_name}
}
function get_kubeconfig() {
echo -n "Waiting 5mins for VM to start ..."
VM_IP=$(sudo virsh domifaddr ${vm_name} | tail -2 | head -1 | awk '{print $4}' | cut -d/ -f1)
while ! ${SSH} core@${VM_IP} -- exit 0; do
sleep 5
echo -n "Waiting for SSH to be available ..."
done
echo -n "VM is running ..."
while ! ${SSH} core@${VM_IP} -- 'sudo oc get node --kubeconfig /opt/crc/kubeconfig --context system:admin'; do
sleep 30
echo -n "Waiting for CA to be rotated ..."
done
${SCP} core@${VM_IP}:/opt/kubeconfig .
}
gen_cloud_init
extract_disk_img
create_libvirt_vm crc-test
get_kubeconfig
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment