-
-
Save mkol5222/7868dce923b41b490e3f6aab472f82ef to your computer and use it in GitHub Desktop.
create cloud init template proxmox
This file contains hidden or 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 | |
| # Exit immediately if a command exits with a non-zero status. | |
| set -e | |
| # Function to create or update a template | |
| # Args: | |
| # $1: VM ID | |
| # $2: VM Name | |
| # $3: Image file name | |
| function create_template() { | |
| local vm_id="$1" | |
| local vm_name="$2" | |
| local image_file="$3" | |
| echo "Processing template ${vm_name} (${vm_id})" | |
| # Compute the checksum of the image file | |
| local image_checksum | |
| image_checksum=$(sha256sum "${image_file}" | awk '{print $1}') | |
| local checksum_file="checksums/${vm_id}.sha256" | |
| # Check if the template already exists | |
| if qm status "${vm_id}" &>/dev/null; then | |
| echo "Template with VM ID ${vm_id} already exists." | |
| # Check if a checksum file exists | |
| if [[ -f "${checksum_file}" ]]; then | |
| local stored_checksum | |
| stored_checksum=$(cat "${checksum_file}") | |
| if [[ "${image_checksum}" == "${stored_checksum}" ]]; then | |
| echo "Template is up to date. Skipping creation." | |
| # Remove the image file if it was downloaded | |
| rm -f "${image_file}" | |
| return | |
| else | |
| echo "Image has changed. Updating template..." | |
| # Destroy the existing template and its disks | |
| qm destroy "${vm_id}" --destroy-unreferenced-disks yes | |
| fi | |
| else | |
| echo "No checksum file found for VM ID ${vm_id}. Recreating template." | |
| # Destroy the existing template and its disks | |
| qm destroy "${vm_id}" --destroy-unreferenced-disks yes | |
| fi | |
| fi | |
| echo "Creating template ${vm_name} (${vm_id})" | |
| # Create new VM | |
| qm create "${vm_id}" --name "${vm_name}" --ostype l26 | |
| # Set networking to default bridge | |
| qm set "${vm_id}" --net0 virtio,bridge=vmbr0 | |
| # Set display to serial | |
| qm set "${vm_id}" --serial0 socket --vga serial0 | |
| # Set memory, CPU, and type defaults | |
| qm set "${vm_id}" --memory 1024 --cores 4 --cpu host | |
| # Import the disk | |
| qm set "${vm_id}" --scsi0 "${storage}:0,import-from=${PWD}/${image_file},discard=on" | |
| # Set SCSI hardware as default boot disk using virtio SCSI single | |
| qm set "${vm_id}" --boot order=scsi0 --scsihw virtio-scsi-single | |
| # Enable QEMU guest agent | |
| qm set "${vm_id}" --agent enabled=1,fstrim_cloned_disks=1 | |
| # Add cloud-init device | |
| qm set "${vm_id}" --ide2 "${storage}:cloudinit" | |
| # Set cloud-init network configuration | |
| qm set "${vm_id}" --ipconfig0 "ip=dhcp,ip6=auto" | |
| # Import the SSH keyfile | |
| if [[ -f "${ssh_keyfile}" ]]; then | |
| qm set "${vm_id}" --sshkeys "${ssh_keyfile}" | |
| else | |
| echo "SSH key file not found at ${ssh_keyfile}" | |
| exit 1 | |
| fi | |
| # Add the user | |
| qm set "${vm_id}" --ciuser "${username}" | |
| # Resize the disk to 8G | |
| qm disk resize "${vm_id}" scsi0 8G || true | |
| # Convert the VM into a template | |
| qm template "${vm_id}" | |
| # Save the checksum | |
| mkdir -p checksums | |
| echo "${image_checksum}" > "${checksum_file}" | |
| # Remove the image file when done | |
| rm -f "${image_file}" | |
| } | |
| # Check for required utilities | |
| command -v qm >/dev/null 2>&1 || { echo "qm command not found. Please ensure you are running this on a Proxmox VE host."; exit 1; } | |
| command -v wget >/dev/null 2>&1 || { echo "wget not found. Please install wget."; exit 1; } | |
| command -v xz >/dev/null 2>&1 || { echo "xz not found. Please install xz-utils."; exit 1; } | |
| command -v sha256sum >/dev/null 2>&1 || { echo "sha256sum not found. Please install coreutils."; exit 1; } | |
| # User-configurable variables | |
| export ssh_keyfile="Path_to_your_id_rsa.pub_here" # Update this path if necessary | |
| export username="your_username_here" # Replace with your desired username | |
| export storage="ceph_local" # Replace with your Proxmox storage name | |
| # Validate variables | |
| if [[ -z "${username}" || "${username}" == "your_username_here" ]]; then | |
| echo "Please set a valid username in the script." | |
| exit 1 | |
| fi | |
| if ! pvesm status | grep -q "^${storage}\s"; then | |
| echo "Storage '${storage}' not found. Please check your Proxmox storage configuration." | |
| exit 1 | |
| fi | |
| # Array of images to download and create templates from | |
| declare -a images=( | |
| # Format: "VM_ID|VM_NAME|IMAGE_URL" | |
| # Debian 11 (Bullseye) | |
| "901|debian-11-template|https://cloud.debian.org/images/cloud/bullseye/latest/debian-11-genericcloud-amd64.qcow2" | |
| # Debian 12 (Bookworm) | |
| "902|debian-12-template|https://cloud.debian.org/images/cloud/bookworm/latest/debian-12-genericcloud-amd64.qcow2" | |
| # Debian 13 (Trixie, daily) | |
| "903|debian-13-template|https://cloud.debian.org/images/cloud/trixie/daily/latest/debian-13-genericcloud-amd64-daily.qcow2" | |
| # Debian Sid (unstable) | |
| "909|debian-sid-template|https://cloud.debian.org/images/cloud/sid/daily/latest/debian-sid-genericcloud-amd64-daily.qcow2" | |
| # Ubuntu 20.04 LTS (Focal Fossa) | |
| "910|ubuntu-20.04-template|https://cloud-images.ubuntu.com/releases/focal/release/ubuntu-20.04-server-cloudimg-amd64.img" | |
| # Ubuntu 22.04 LTS (Jammy Jellyfish) | |
| "911|ubuntu-22.04-template|https://cloud-images.ubuntu.com/releases/22.04/release/ubuntu-22.04-server-cloudimg-amd64.img" | |
| # Ubuntu 24.04 (Lunar Lobster) | |
| "912|ubuntu-24.04-template|https://cloud-images.ubuntu.com/releases/24.04/release/ubuntu-24.04-server-cloudimg-amd64.img" | |
| # Fedora 39 | |
| "920|fedora-39-template|https://fedora.mirror.constant.com/fedora/linux/releases/39/Cloud/x86_64/images/Fedora-Cloud-Base-39-1.5.x86_64.qcow2" | |
| # Fedora 40 | |
| "921|fedora-40-template|https://fedora.mirror.constant.com/fedora/linux/releases/40/Cloud/x86_64/images/Fedora-Cloud-Base-Generic.x86_64-40-1.14.qcow2" | |
| # Rocky Linux 8 | |
| "930|rocky-8-template|https://dl.rockylinux.org/pub/rocky/8/images/x86_64/Rocky-8-GenericCloud.latest.x86_64.qcow2" | |
| # Rocky Linux 9 | |
| "931|rocky-9-template|https://dl.rockylinux.org/pub/rocky/9/images/x86_64/Rocky-9-GenericCloud.latest.x86_64.qcow2" | |
| # Alpine Linux 3.19.1 | |
| "940|alpine-3.19-template|https://dl-cdn.alpinelinux.org/alpine/v3.19/releases/cloud/nocloud_alpine-3.19.1-x86_64-bios-cloudinit-r0.qcow2" | |
| ) | |
| # Loop through the images array | |
| for entry in "${images[@]}"; do | |
| IFS='|' read -r vm_id vm_name image_url <<< "${entry}" | |
| # Extract the filename from the URL | |
| image_file="${image_url##*/}" | |
| # Download the image with timestamping | |
| echo "Downloading ${image_file}..." | |
| wget -N "${image_url}" | |
| # If the image is compressed, decompress it | |
| if [[ "${image_file}" == *.xz ]]; then | |
| decompressed_file="${image_file%.xz}" | |
| if [[ ! -f "${decompressed_file}" || "${image_file}" -nt "${decompressed_file}" ]]; then | |
| echo "Decompressing ${image_file}..." | |
| xz -d -v -f "${image_file}" | |
| image_file="${decompressed_file}" | |
| else | |
| echo "Decompressed file ${decompressed_file} is up to date." | |
| image_file="${decompressed_file}" | |
| fi | |
| fi | |
| # Create or update the template | |
| create_template "${vm_id}" "${vm_name}" "${image_file}" | |
| done |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment