#!/bin/bash # Description: This simple Scripts creates an Virtualmachine on Proxmox, with the Qemu-Cli. # Usage: Just Execute the script, it's a guided Script (chmod +x CreateCloudInitVM.sh && ./ CreateCloudInitVM.sh) # # Creator: Janic Joël Voser, Mettmenstetten - CH # Date of Creation: 03.12.2021 # # Active Maintainer: Janic Joël Voser # Date of Last Maintenance: 03.12.2021 # # Current State: Development # Version: 1.0.0 # Version History: # v0.0.1 - Basic Script Structure # v0.1.0 - Get the User input # v0.2.0 - Gather Virtual Machine ID # v0.3.0 - Get & Select the Image of the Virtualmachine # v0.4.0 - Create the VM & Gather additional Information # v0.5.0 - Add proper Comments # v1.0.0 - First Properly Working Version # Planned Features: # - [X] Guided VM Creation # - [X] Image Download URL # - [X] Image Selection # - [X] VM-ID check # - [X] Choose Memorysize # - [X] Choose CPU cores # - [X] Choose Network # - [X] IMG & ISO & qcow2 support # Global Constants IMAGE_STORAGE_LOCATION="/var/lib/vz/template/iso/" # Enter here the location of your iso-Templates - This is not adjustable while running the script DEFAULT_VM_STORAGE="tank-vms" # Enter here the default Storage Location, so you can Skip it by pressing enter DEFAULT_DOWNLOAD_IMG_yn="n" # Set the default value for the "Download new Image"-Questing DEFAULT_VM_NAME="cloudinit-vm" # Set the default value for the Virtual Machine Name DEFAULT_VM_RAM="2048" # Set the default value of Memory for the Virtual Machine DEFAULT_VM_CORES="2" # Set the default amount of cpu-cores for the Virtual Machine DEFAULT_VM_NET="vmbr0" # Set the default network interface for the Virtual Machine # Functions ## Gather the ID of the Virtual machine function gather_vmid { echo "Already used IDs" qm list | tr -s ' ' | cut -d ' ' -f 2,3 # Get the already used VMIDs & VM-Name echo "Enter the new ID of your Virtual Machine (It must be unused)" read VM_ID # Get the User Input(This VMID will be used for the new created VM) readarray -t VMID_ARRAY < <(qm list | tail -n +2 | tr -s ' ' | cut -d ' ' -f 2) if [[ "${VMID_ARRAY[*]}" =~ "$VM_ID" ]]; then # Check if Virtual Machine ID is alredy in use echo "Your selected Virtual Machine ID is already in use, choose an other ID" gather_vmid fi } ## Download a new Image in to the Image Storage function get_img { echo "Do you wish to download an Image? (yes/no)" read DOWNLOAD_IMG_yn case "${DOWNLOAD_IMG_yn:=DEFAULT_DOWNLOAD_IMG_yn}" in # Case Statement to switch based on the User Input yes|YES|Yes|y|Y) # The Yes case enables the possibility to download an Image echo "Please enter the URL of your Image" read DOWNLOAD_IMG_URL wget "$DOWNLOAD_IMG_URL" --directory-prefix="$IMAGE_STORAGE_LOCATION" # Download the Image in to the default Image-Storage if [ $? -eq 0 ]; then # Check if last command (Download) was successful echo "Download was Successful" else echo "Download failed" echo "Retry or Downloadfile manually" get_img fi ;; no|NO|No|n|N) # The No Case skips the Image Download step echo "Carrying on without a new Image" ;; *) echo "Invalid Argument: Please type \"yes\" or \"no\"" get_img # Question again if the Answer was not an possible Option ;; esac } ## Select an Image function sel_img { echo "The following list represents all Images which exist on the Hoststorage" ls $IMAGE_STORAGE_LOCATION -l | tr -s ' ' | cut -d' ' -f 6-9 # List all files in the Image Location and their Age of Creation readarray -t OS_IMG_ARRAY < <(ls $IMAGE_STORAGE_LOCATION -l | tr -s ' ' | cut -d' ' -f 9) # Create an Array of all Images echo "Please enter the correct Image Name(shown above)" read OS_IMG_NAME if ! [[ "${OS_IMG_ARRAY[*]}" =~ "$OS_IMG_NAME" ]]; then # Check if Selected Image is in the Array, else go back to the selection echo "Your selected Image does not exist" echo "Maybe it was a Typo, Please check:" echo " - Upper/Lowercase writing" echo " - Fileextension(needs to be appended)" echo "ProTip: Copy & Paste" sleep 3 sel_img fi } ## Get the prepared Cloud-Init Image function gather_img { get_img sel_img } ## Gather Virtualmachine Network function gather_vm_net { ip -o link show | awk -F': ' '{print $2}' | grep vmbr # Get all the Virtual Bridge Interfaces of the Hostsystem echo "Enter one of the above shown Network-Interfaces to add to your VM" read VM_NET readarray -t VM_NET_ARRAY < <(ip -o link show | awk -F': ' '{print $2}' | grep vmbr) # Create an array of all Virtual Bridge Interfaces of the Hostsystem if ! [[ "${VM_NET_ARRAY[*]}" =~ "$VM_NET" ]]; then # Check if Selected Network is an existing network else go back to the Selection echo "Your selected Network does not exist" echo "Maybe it was a Typo, Please check:" echo " - Upper/Lowercase writing" echo "ProTip: Copy & Paste" sleep 3 gather_vm_net fi } ## Gather hardware function gather_hardware { echo "Enter the amount of memory in MegaBytes" echo "Example for 2GB = \"2048\"" read VM_RAM echo "Enter the amount of Cpu-Cores you want to give to the Virtual machine" read VM_CORES gather_vm_net } ## Gather all aditional Data function gather_additional { gather_vmid echo "Enter the name of the new Virtualmachine" read VM_NAME } ## Gather VM_Storage function gather_vm_storage { echo "Please enter the Virtual Machine Storage Pool:[$DEFAULT_VM_STORAGE]" read VM_STORAGE VM_STORAGE=${VM_STORAGE:=$DEFAULT_VM_STORAGE} # Get the Storage of the VM, if nothing is set just use the Default } ## Get all the Variables from the User function get_user_input { gather_img gather_hardware gather_vm_storage gather_additional } # Import the Cloudinit image and append it to the Virtual Machine function vm_import_cloudinit_img { IMG_TYPE=$(echo "$OS_IMG_NAME" | rev | cut -d "." -f 1 | rev) # Get the Image Fileending for further operations if [ $IMG_TYPE == "iso" ] || [ $IMG_TYPE == "img" ];then # If the Image Fileending is "iso" or img" do the following qm importdisk "$VM_ID" "$IMAGE_STORAGE_LOCATION$OS_IMG_NAME" "$VM_STORAGE" -format qcow2 # Convert the Image to qcow2 format and write it to the VM-Storage if ! [ $? -eq 0 ];then echo "It was not possible to convert a new Image with your values" echo "Read the error message above" exit fi elif [ $IMG_TYPE == "qcow2" ];then # If the Image Fileending is "qcow2" do the following qm importdisk "$VM_ID" "$IMAGE_STORAGE_LOCATION$OS_IMG_NAME" "$VM_STORAGE" #import a copy of the Image to the VM, safe the copy in the set Storagepath if ! [ $? -eq 0 ];then echo "It was not possible to convert a new Image with your values" echo "Read the error message above" exit fi else echo "Your OS-Image does not have a fileending which is supported by this scirpt" echo "only iso & img are Supported" exit fi } # Create the Virtual Machine with Set-Values function create_qm_vm { qm create "$VM_ID" --name "${VM_NAME:=$DEFAULT_VM_NAME}" --memory "${VM_RAM:=$DEFAULT_VM_RAM}" --cores "${VM_CORES:=$DEFAULT_VM_CORES}" --net0 virtio,bridge="${VM_NET:=$DEFAULT_VM_NET}" # Create the Virtualmachine with the set hardware specification if ! [ $? -eq 0 ];then echo "It was not possible to create a Virtual machine with your values" echo "Read the error message above" exit fi vm_import_cloudinit_img # Import the Image to the Virtual Machine qm set $VM_ID --scsihw virtio-scsi-pci --scsi0 $VM_STORAGE:vm-$VM_ID-disk-0 #Add the Image to the Virtual Machine if ! [ $? -eq 0 ];then echo "It was not possible to add the custom Image to your Virtual machine" echo "Read the error message above" exit fi qm set $VM_ID --ide2 $VM_STORAGE:cloudinit --boot c --bootdisk scsi0 --serial0 socket --vga serial0 #Add the Cloud-Initdrive & set the Bootdrive & Add a serial console(is needed for cloud-init) if ! [ $? -eq 0 ];then echo "It was not possible to add an cloudinit drive to your Virtual machine" echo "Read the error message above" exit fi } # Main Script get_user_input create_qm_vm echo "Script was Successful" echo "Have fun with your newly deployed Virtual Machine"