Jump to content

- - - - -


  • Please log in to reply
2 replies to this topic

#1 StorageBase



  • Members
  • Pip
  • 3 posts

Posted 16 December 2016 - 07:34 PM



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):


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):


# 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 :-)
# 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.


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

# Settings for Logging
CURRENT_TIME=$(date +"%d.%m.%Y %H:%M:%S")

# Define allowed File Systems

# 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

    # Check if the Log Directory already exists
    if [ ! -d "$LOG_DIR" ]; then
        mkdir -p $LOG_DIR


# 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
            echo "* $CURRENT_TIME * $1" >> $LOG_DIR/$2.log

    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"

# 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"

# 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"

# 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

# 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

    # Local Directory
    elif [ "$STORAGE_TYPE" = "dir" ] ; then

    # LVM Thin
    elif [ "$STORAGE_TYPE" = "lvmthin" ] ; then
        LVM_THIN_STORAGE_PATH=`awk '/'$STORAGE'/ { getline; getline; print $2; exit(0);}' /etc/pve/storage.cfg`

    # NFS
    elif [ "$STORAGE_TYPE" = "nfs" ] ; then
        NFS_STORAGE_PATH=`awk '/'$STORAGE'/ { getline; getline; getline; print $2; exit(0);}' /etc/pve/storage.cfg`

    # RBD or CEPH - currently no idea how to implement this
    elif [ "$STORAGE_TYPE" = "rbd" ] ; then
        LOG "RBD / CEPH Currently not supported!" $VMID_CUSTOM

    # 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

        elif [ -z "$FILE_SYSTEM_PARTED" ] ; then
        elif [ -z "$FILE_SYSTEM_LSBLK" AND -z "$FILE_SYSTEM_PARTED" ] ; then

            LOG "File System could not be determined" $VMID_CUSTOM

        # 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


        # If the File System is not in the Array

            LOG "File System not in Array" $VMID_CUSTOM


    # If the VM Image could not be found on the Path

        LOG "VM Image not found" $VMID_CUSTOM


# If the Status is not running or stopped

    LOG "Unexpected Status, see Error Message below:" $VMID_CUSTOM


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.

#2 StorageBase



  • Members
  • Pip
  • 3 posts

Posted 17 December 2016 - 09:59 AM

*** UPDATE #1 ***


+ I have add the option to Log all Outputs for a better Tracking if you dont know if the Action was performed or not.

* I moved all Settings which you can change on top of the File, so you dont have to check the complete File for these Settings

- I have removed one Line, which are not more needed



Default the Logging is enabled, it would create an Logrotate File, which run daily and for 7 rotations (you can change the 7 Rotations for your needings). If an VMID is present, then the Script will logging into the File which named as the VMID (e.g. VMID = 105 the Log File will named 105.log), if the VMID isnt present, the Script Logging all actions to other.log. In the "other.log" you will find any Messages which are not related to the VM (e.g. missing Package).

#3 StorageBase



  • Members
  • Pip
  • 3 posts

Posted 25 January 2017 - 08:10 PM

*** UPDATE #2 ***


+ Now LVM-Thin in default PVE Installation is supported (Currently i checking, if lsblk has the needed Information, if not then parted would be use)

0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users

Check your Pings