Hello,
i worked today on the Case "How to deploy a KVM Template and auto Resizing the Partition on it?" and this is my Result (But keep in Mind, im not a Pro in Bash Scripting! :-) ):
1.) Prepare your VM to run as a Template. A very good Solution to run a few Commands if the Template is booted the First time is the following:
Move the rc.local File:
mv /etc/rc.local /etc/rc.local.orig
And then put your Stuff in it (e.g. you can recreate the SSH Keys with this too):
#!/bin/sh resize2fs /dev/sda1 mv -f /etc/rc.local.orig /etc/rc.local
If the VM is now booting the First Time, it runs the rc.local File and perform an resize of the File System, after this the File moved the orig rc.local back and deletes him self - so the Customer will have no idea how you do this :-)
2.) Put the Script on the Proxmox Node and make it executable (chmod +x resize_template.sh):
#!/bin/bash # This is Script is for use with the Modules Factory Proxmox Module for WHMCS # # This Script performs a resizing of the Partition from a Cloned VM (e.g. Template VM with 2GB Hard Disk) # # The Script was written by StorageBase UG (haftungsbeschränkt). If you wish to get in Contact with us, please use the contact form on https://storage-base.de/?language=english # Feel free to Modify the Script for you own use, but please respect my Work for this Script and dont set your own Copyright or Name on it :-) # # ATTENTION: RUN THIS SCRIPT ON YOUR OWN RISK - WE GURANTEE FOR ABSOLUTLY NOTHING! # I have written the script with best knowledge and certain to avoid many mistakes, yet I do not guarantee that it always functions as thought! # If you have Problems by running this Script, feel free to fix it by yourself or get in Contact with us. IN=$@ IFS=',' read varvmid varhostname varusername varpassword varmac varip varnode <<< "$IN";IFS='=' read var1 vmid <<< "$varvmid";IFS='=' read var2 hostname <<< "$varhostname";IFS='=' read var3 password <<< "$varpassword";IFS='=' read var4 username <<< "$varusername";IFS='=' read var5 macs <<< "$varmac";IFS='=' read var6 ips <<< "$varip";IFS='=' read var7 node <<< "$varnode" # Define Global Variables VMID_CUSTOM=$vmid NODE_CUSTOM=$node # Settings for Logging LOG_ALL_ACTION=1 LOGROTATE_FILE="/etc/logrotate.d/modules_factory-resize_template" ROTATE="7" LOG_DIR="/var/log/modulesfactory/resize_template" CURRENT_TIME=$(date +"%d.%m.%Y %H:%M:%S") # Define allowed File Systems FS_ARRAY=['ext2','ext3','ext4'] # Check if loggin is enabled if [ "$LOG_ALL_ACTION" = "1" ] ; then # Check if the Logrotate File already exists if [ ! -f "$LOGROTATE_FILE" ] ; then echo -e "$LOG_DIR/*.log {\n\tdaily\n\trotate $ROTATE\n\tdelaycompress\n\tcompress\n\tnotifempty\n\tmissingok\n}" > /etc/logrotate.d/modules_factory-resize_template fi # Check if the Log Directory already exists if [ ! -d "$LOG_DIR" ]; then mkdir -p $LOG_DIR fi fi # Function to redirect the Output to the Log and return it function LOG { if [ "$LOG_ALL_ACTION" = "1" ] ; then if [ -z "$2" ] ; then echo "* $CURRENT_TIME * $1" >> $LOG_DIR/other.log else echo "* $CURRENT_TIME * $1" >> $LOG_DIR/$2.log fi fi echo "$1" } # Check if parted is installed PARTED="$((dpkg-query -W -f='${Status}' parted) 2>&1)" if [ "$PARTED" != "install ok installed" ] ; then LOG "Parted is not installed, run: \"apt-get install parted\" to fix" exit; fi # Check if kpartx is installed KPARTX="$((dpkg-query -W -f='${Status}' kpartx) 2>&1)" if [ "$KPARTX" != "install ok installed" ] ; then LOG "Kpartx is not installed, run: \"apt-get install kpartx\" to fix" exit; fi # Needed: lsblk UTILLINUX="$((dpkg-query -W -f='${Status}' util-linux) 2>&1)" if [ "$UTILLINUX" != "install ok installed" ] ; then LOG "Util-linux is not installed, run: \"apt-get install util-linux\" to fix" exit; fi # Get the Current VM Status VM_STATUS="$((qm status $VMID_CUSTOM | awk '{print $2}') 2>&1)" if [ "$VM_STATUS" = "running" ] ; then LOG "ERROR: Re-configuration can not be executed when the VM is running" $VMID_CUSTOM exit; # If VM is stopped, then lets go! elif [ "$VM_STATUS" = "stopped" ] ; then # Get Bootdisk of VM (in most cases the OS is installed here) BOOTDISK=`grep -E 'bootdisk' /etc/pve/nodes/$NODE_CUSTOM/qemu-server/$VMID_CUSTOM.conf | awk '{print $2}' | cut -f1 -d":"` # Get the Storage from the VM Config (e.g. /etc/pve/nodes/pve01/qemu-server/105.conf) STORAGE=`grep -E $BOOTDISK':' /etc/pve/nodes/$NODE_CUSTOM/qemu-server/$VMID_CUSTOM.conf | awk '{print $2}' | cut -f1 -d":"` # Get the VM Image Name from the VM Config VM_IMAGE_NAME=`grep -E $BOOTDISK':' /etc/pve/nodes/$NODE_CUSTOM/qemu-server/$VMID_CUSTOM.conf | awk '{print $2}' | cut -f1 -d"," |cut -f2 -d":"` # Read the Storage Type from /etc/pve/storage.cfg (e.g. dir or zfspool) STORAGE_TYPE=`awk '/'$STORAGE'/ {print $1; exit(0);}' /etc/pve/storage.cfg | cut -f1 -d":"` # Read the Path to the Storage from /etc/pve/storage.cfg (e.g. rpool/data for ZFS) # !!! For NFS / LVM Thin there is a new Variable $NFS_STORAGE_PATH / $LVM_THIN_STORAGE_PATH because of multiple "getline" STORAGE_PATH=`awk '/'$STORAGE'/ { getline; print $2; exit(0);}' /etc/pve/storage.cfg` # Create the VM Storage Path # ZFS if [ "$STORAGE_TYPE" = "zfspool" ] ; then VM_STORAGE_PATH="/dev/zvol/$STORAGE_PATH/$VM_IMAGE_NAME" # Local Directory elif [ "$STORAGE_TYPE" = "dir" ] ; then VM_STORAGE_PATH="$STORAGE_PATH/images/$VMID_CUSTOM/$VM_IMAGE_NAME" # LVM Thin elif [ "$STORAGE_TYPE" = "lvmthin" ] ; then LVM_THIN_STORAGE_PATH=`awk '/'$STORAGE'/ { getline; getline; print $2; exit(0);}' /etc/pve/storage.cfg` VM_STORAGE_PATH="/dev/$LVM_THIN_STORAGE_PATH/$VM_IMAGE_NAME" # NFS elif [ "$STORAGE_TYPE" = "nfs" ] ; then NFS_STORAGE_PATH=`awk '/'$STORAGE'/ { getline; getline; getline; print $2; exit(0);}' /etc/pve/storage.cfg` VM_STORAGE_PATH="$NFS_STORAGE_PATH/images/$VMID_CUSTOM/$VM_IMAGE_NAME" # RBD or CEPH - currently no idea how to implement this elif [ "$STORAGE_TYPE" = "rbd" ] ; then LOG "RBD / CEPH Currently not supported!" $VMID_CUSTOM exit; fi # Check if the VM Storage Path exist if [ -e "$VM_STORAGE_PATH" ] ; then # Get the File System from the Image FILE_SYSTEM_LSBLK=`lsblk -f $VM_STORAGE_PATH | awk '{getline; getline; print $2; exit(0);}'` FILE_SYSTEM_PARTED=`parted $VM_STORAGE_PATH print | awk '/File system/{getline; print $6}'` # Check if the File System are in Variable if [ -z "$FILE_SYSTEM_LSBLK" ] ; then FILE_SYSTEM=$FILE_SYSTEM_LSBLK elif [ -z "$FILE_SYSTEM_PARTED" ] ; then FILE_SYSTEM=$FILE_SYSTEM_PARTED elif [ -z "$FILE_SYSTEM_LSBLK" AND -z "$FILE_SYSTEM_PARTED" ] ; then FILE_SYSTEM="" LOG "File System could not be determined" $VMID_CUSTOM exit; fi # Check if the File System is in Array (For prevent some faults) if [[ ${FS_ARRAY[*]} =~ "$FILE_SYSTEM" ]] ; then # Check again if the VM is running or not RECHECK_VM_STATUS="$((qm status $VMID_CUSTOM | awk '{print $2}') 2>&1)" if [ "$RECHECK_VM_STATUS" = "stopped" ] ; then LOG "kpartx: Add partition devmappings..." $VMID_CUSTOM kpartx -a $VM_STORAGE_PATH LOG "parted: Remove Partition number 1..." $VMID_CUSTOM parted $VM_STORAGE_PATH rm 1 LOG "parted: Create new Partition with full size" $VMID_CUSTOM parted $VM_STORAGE_PATH mkpart -a optimal p $FILE_SYSTEM 0% 100% LOG "kpartx: Delete partition devmappings" $VMID_CUSTOM kpartx -d $VM_STORAGE_PATH LOG "All Actions performed - Please start the VM and run \"resize2fs /dev/sda1\" in it." $VMID_CUSTOM # If the VM is running elif [ "$RECHECK_VM_STATUS" = "running" ] ; then LOG "ERROR: Re-configuration can not be executed when the VM is running" $VMID_CUSTOM exit; fi # If the File System is not in the Array else LOG "File System not in Array" $VMID_CUSTOM exit; fi # If the VM Image could not be found on the Path else LOG "VM Image not found" $VMID_CUSTOM exit; fi # If the Status is not running or stopped else LOG "Unexpected Status, see Error Message below:" $VMID_CUSTOM LOG "$VM_STATUS" $VMID_CUSTOM exit; fi
This Script have a heavy automation for Resize the Disk.
First we check if all Packages which we need are installed on the Host (we need: kpartx, parted and lsblk alias util-linux). The next step is to check if the VM is running or not, if they stopped, we go forward and grep the Bootdisk, now we look on which Storage the Bootdisk are created, then we get the correct path to the Storage itself (currently supported: dir, zfs and nfs). After we have most of our needed Parameter, we get the File System from the Disk Image (there is an Array, which currently contain ext2, ext3 and ext4 - you can add your own File Systems like xfs or something (but only ext4 is tested)) and start with the Resizing itself.
Edited by StorageBase, 25 January 2017 - 08:08 PM.