TemplateBuilder

Building templates with a script. How to use bash, whiptail, pve qm commands and wget. At the same time VM's can be applied for large Kubernetes clusters (K8s, K3s, K3s HA, K0s). LArge lettering done with figlet.

TemplateBuilder
Photo by Danny Lau / Unsplash

The things utilized in building the GUI and the logic. Proxmox qemu-img resize <size> and qm set, --firstboot <file>, --add <file>. Bash functions and commands. Downloading stuff with wget.
Features implemented is sudo detection and setting, logging, initialization of variables and screens, spinner wit many patterns to indicate background working. Graphical user interface with Yes/No, radiobox, msgbox, checklist screens. Large text with figlet.

Cluster Install

In version 4.2 Kubernetes K8s cluster install was added. K0s and K3s will be added.

  • 5.1adds K0s cluster install
  • 5.2 adds K3s cluster install
  • 5.3 adds K3s HA-cluster install

Figlet

Install figlet on a PC and do find your font. Then to print CasaUrsus do figlet -f standard CasaUrsus.

function header() { # print CasaUrsus. figlet -f standard CasaUrsus
  clear
  cat <<"EOF"

              ____                _   _
             / ___|__ _ ___  __ _| | | |_ __ ___ _   _ ___
            | |   / _` / __|/ _` | | | | '__/ __| | | / __|
            | |__| (_| \__ \ (_| | |_| | |  \__ \ |_| \__ \
             \____\__,_|___/\__,_|\___/|_|  |___/\__,_|___/
EOF
}

Whiptail

This is like working on MS Dos. You have seen these blue screens with shaded grey boxes all over the place.
It's really a walk down memory lane to use whiptail. I did plenty programming in Dos (starting from version 0.1). XP needed alot of Dos programming and setting to be productive. The best (IMHO) manual/guid I had was around 1.000 pages of commands, explanations and examples.

Later in this blog post you will see examples.

Design

The size of the script is not small but I kept it easy to read and didn't optimize. To keep it readable I use function calls (functions are like sub-rutines) for digestive things lice creating a VM and an other for creating a Template, variables and comments. All output to standard output or the log is in color. Passing parameters to functions makes code more flexible.

Separation of options selection and implementation for extra flexibility.

############################################################################
 #                                                                        #
  #    đŸĻē 🧰 đŸĻē   G L O B A L  Variables and Functions   🤓   đŸšĢ   🤓     #
 #                                                                        #
############################################################################

One type of comments

Spinner

function spinner() { # display a animated spinner
    # The different Spinner Arrays to choose from
    local array1=("◐" "◓" "◑" "◒")
    local array2=("░" "▒" "▓" "█")
    local array3=("╔" "╗" "╝" "╚")
    local array4=("┌" "┐" "┘" "└")
    local array5=("▄" "█" "▀" "█")
    local array6=('-' '\' '|' '/') # L to R
    local array7=('-' '/' '|' '\') # R to L
    local array9=("⠋" "⠙" "â š" "â ¸" "â ŧ" "â ´" "â Ļ" "â §" "⠇" "⠏")
    local array10=("▏" "▎" "▍" "▌" "▋" "▊" "▉" "█")
    local array11=("▁" "▂" "▃" "▄" "▅" "▆" "▇" "█")

    local delays=0.1 # Delay between each characte

    tput civis # Hide cursor and spinn
    #echo -e "${yelb} "
    while :; do
        for character in "${array9[@]}"; do # Use this Array
            printf "%s" "$character"
            sleep "$delays"
            printf "\b"  # Move cursor back
        done
    done
}

Using init-variables

In this example, in the function setLAN the variables vmbr and vlan are initialized by $initVMBR and by $initVLAN using whiptail.

function setLAN(){
    # Set the Virtual Bridge
    vmbr=$(whiptail --backtitle "$backTEXT" --title "VLAN Dialog" --inputbox \
    "\nVirtual Bridge to be useed" \
    10 48 $initVMBR 3>&1 1>&2 2>&3)
    echo "${cyn}     -  Bridge: $vmbr" >> $logFILE
    # Use a Virtual LAN
    if whiptail --backtitle "$backTEXT"  --title "VLAN Dialog" --yesno \
       "\nDo you need to use a VLAN?" 10 48; then
       vlan=$(whiptail --backtitle "$backTEXT" --title "VLAN Dialog" --inputbox\
       "\nVLAN to use for the VM/Template" 10 48 $initVLAN  3>&1 1>&2 2>&3)
       echo "${cyn}     -  VLAN: $vlan" >> $logFILE
    else
        vlan=0
        echo "${cyn}     -  User selected NOT to use a VLAN" >> $logFILE
    fi
}

Setting up the LAN and VLAN

Set root or stop if not root

function setRoot() { # Function I am root
if [[ "$EUID" = 0 ]]; then
    echo -e "\n${okcm} Initialaizing: $pgrm version $ver"          # I am root
else
    sudo -k                             # ask for sudo password
    if sudo true; then                  # Correct password
        clear
        echo -e "\n${yelb}Start $pgrm version $ver${end}"
        echo -e "\n${okcm}Initialaizing...${end}"
    else
        echo "${redb}wrong password!${end}"
        exit                            #exit if 3 times wrong
    fi
fi
}

Check for root and if not ask to be sudo

function stopNotRoot(){ # Function Check for root privilidges and exit if not
if [[ "$EUID" != 0 ]]; then
    echo -e "\e[0;31mYou need to be root! Pleas run as sudo.\033[0m" # Message in read
    exit
fi
}

Stop and warn if not root

Read environment from Proxmox

For things like the pools for VM disks and ISO's I read the storage locations into a radiolist depending on a passed variable.

function getPool() { # Show basic pool info and Select a Pool
    local ST=$1
    local LABEL
    local TYPE
    case $ST in
    VM)
      LABEL='VM/CT storage'
      TYPE=$zfs_st
      ;;
    ISO)
      LABEL='IMG/ISO storage'
      TYPE=$img_st
      ;;
    *) exit ;;
    esac
    local -a LIST
    while read -r line; do
      local TAG=$(echo $line | awk '{print $1}')
      local TYPE=$(echo $line | awk '{printf "%-10s", $2}')
      local FREE=$(echo $line | numfmt --field 4-6 --from-unit=K --to=iec --format %.2f | awk '{printf( "%9sB", $6)}')
      local ITEM="  Type: $TYPE Free: $FREE "
      local OFFSET=2
      if [[ $((${#ITEM} + $OFFSET)) -gt ${LONGA:-} ]]; then
        local LONGA=$((${#ITEM} + $OFFSET))
      fi
      LIST+=("$TAG" "$ITEM" "OFF")
    done < <(echo "$TYPE" | awk 'NR>1')
    # Select storage location
    if [ $((${#LIST[@]} / 3)) -eq 0 ]; then
      echo "${nocm}${red}Unable to detect valid storage location for ISO storage.${end}" >> $logFILE
    elif [ $((${#LIST[@]} / 3)) -eq 1 ]; then
      printf ${LIST[0]}
    else
      local POOL
      while [ -z "${POOL:+x}" ]; do
        POOL=$(whiptail --backtitle "$backTEXT" --title "Select Storage Pool" --radiolist \
          "\nStorage pool to use for the ${LABEL,,}?\nSelect [ Space ] and Accept [ Enter ]\n" \
          18 $(($LONGA + 23)) 6 \
          "${LIST[@]}" 3>&1 1>&2 2>&3) || echo "getPool RadioList aborted."  >> $logFILE
      done
      printf $POOL
    fi
}

References

TemplateBuilder [1] Whiptail [2] Pve qm [3] figlet [4] wget [5]


  1. TemplateBuilder homepage, getting started GitHub ↩ī¸Ž

  2. Whiptail man page, getting started GitHub ↩ī¸Ž

  3. Pve qm commands homepage ↩ī¸Ž

  4. Figlet homepage ↩ī¸Ž

  5. Wget man page ↩ī¸Ž