Skip to content

Instantly share code, notes, and snippets.

@billchurch
Last active August 9, 2023 14:14
Show Gist options
  • Save billchurch/0f5388e8025d55b5830519937f628aaf to your computer and use it in GitHub Desktop.
Save billchurch/0f5388e8025d55b5830519937f628aaf to your computer and use it in GitHub Desktop.
A simple script that builds a template on Proxmox VE v7.x from a qcow2 image and provides some customization
newbigip.sh
#!/bin/bash
# This script will:
# - Create a 2 core 4096MB BIG-IP virtual machine
# - Install the image specified
# - Customize the image by loading bootstrap files to /config and
# expects:
# startup*
# .startup-env
# to be in the current directoy
# - Promote virtual machine to a template for later use.
#
# This script is only useful/safe on Proxmox VE v7.x+ AND
# those that use ZFS as storage and NO LVM usage. This is due
# to the fact that there's not a lot of error checking on LVM
# operations to mount and umount the BIG-IP image and it will
# most likley blow away any existing LVM config
#
# See: https://github.com/billchurch/bigip-bootstrap for details on
# how I use /startup* and .startup-env files
#
# usage:
# newbigip.sh <big-ip qcow image file (without path)> <vmid>
#
# requires:
# kpartx (apt-get install kpartx)
# proxmox ve v7.x+
# a bigip image?
#
# Bill Church - bill@f5.com
#
# Changelog:
#
# 20220615 - First Release
script_version=20220615
prerequisites="kpartx pvesh qemu-img vgchange lvchange dmsetup"
logfile="/var/log/$(mktemp -u newbigip-XXXX.log)"
scriptname=$(basename "$0")
script_path="${BASH_SOURCE[0]}";
script_full="${script_path}/${scriptname}"
pve_node=pve
file=$1
node_id=$2
cols=$(tput cols)
node_name=${file%.qcow2*}
# cpu cores
cores=2
# ram in megabytes
memory=4096
vm_config="--net0 model=virtio,bridge=vmbr0,tag=30 --net1 model=virtio,bridge=vmbr0,tag=10 --net2 model=virtio,bridge=vmbr0,tag=20 --net3 model=virtio,bridge=vmbr0,link_down=1 --ostype l26 --serial0 socket --cores ${cores} -sockets 1 --memory ${memory} --name ${node_name}"
#colors
_fgLtRed=$(tput bold;tput setaf 1)
_fgLtGrn=$(tput bold;tput setaf 2)
_fgLtYel=$(tput bold;tput setaf 3)
_fgLtBlu=$(tput bold;tput setaf 4)
_fgLtMag=$(tput bold;tput setaf 5)
_fgLtCya=$(tput bold;tput setaf 6)
_fgLtWhi=$(tput bold;tput setaf 7)
_fgLtGry=$(tput bold;tput setaf 8)
echo "${_fgLtWhi}"
clear
echoNotice () { echo -e -n "\n$*... "; }
logit() {
date=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
echo "$date - $script_full}: f$*" >> "$logfile"
}
touch "${logfile}"
logit "${script_full} - $script_version"
# checks the output of a command to get the status and report/handle failure
checkOutput() {
if [ "$result" -eq 0 ]; then
# success
echo "${_fgLtGrn}[OK]${_fgLtWhi}"
logit "[SUCCESS]: ${command}"
return
else
# failure
logit " [FAILED]: ${command}"
logit " ${output}"
tput bel;tput bel;tput bel;tput bel
echo "${_fgLtRed}[FAILED]${_fgLtWhi}"
echo -e "\nPrevious command failed in ${script_full} with error level: ${result}"
echo -e "\nCommand:\n"
echo " ${command}"
echo -e "\nSTDOUT/STDERR:\n"
echo "${output}"
rm -rf "$workingdir"
exit 255
fi
}
# run a comand and check call checkOutput
runCommand() {
# $1 command
# $2 show output (0 yes, 1 no)
command=$1
if [[ -n "$2" ]]; then
eval "$command"
output="Sent to console..."
result="$?" 2>&1
else
output=$( (eval "$command") 2>&1)
result="$?" 2>&1
fi
checkOutput
}
function run_help() {
fold -s -w "$cols" <<HELPFILE | less --RAW-CONTROL-CHARS -X -F -K -E
${_fgLtGrn}${scriptname} v${script_version}${_fgLtWhi}
---------------------
Create a BIG-IP virtual machine on Proxmox v7.x+ and install a new image
usage:
${_fgLtCya}${scriptname} ${_fgLtYel}<big-ip qcow image file (without path)> ${_fgLtMag}<new_vmid>${_fgLtWhi}
Details
This script will:
- Create a 2 core 4096MB BIG-IP virtual machine
- Install the image specified
- Customize the image by loading bootstrap files to ${_fgLtCya}/config${_fgLtWhi} and
expects:
${_fgLtCya}startup*${_fgLtWhi}
${_fgLtCya}.startup-env${_fgLtWhi}
to be in the current directoy
- Promote virtual machine to a template for later use.
This script is only useful/safe on Proxmox VE v7.x+ AND those that use ZFS as storage and ${_fgLtRed}NO LVM usage${_fgLtWhi}. This is due to the fact that there's not a lot of error checking on LVM operations to mount and umount the BIG-IP image and it will most likley blow away any existing LVM config.
HELPFILE
echo
}
if [[ $# -lt 2 ]] ; then
run_help
exit 255
fi
# get cli params...
POSITIONAL=()
while [[ $# -gt 0 ]]
do
key="$1"
case $key in
-h|--help)
run_help
exit 255
shift
;;
*)
shift
;;
esac
done
set -- "${POSITIONAL[@]}" # restore positional parameters
for prereq in $prerequisites
do
echoNotice "Checking prerequisite \"$prereq\" installed"
runCommand "which $prereq"
done
echoNotice "Source image exists"
runCommand "test -f $file"
echoNotice "Checking that target node does not exist"
output=$( (pvesh get /nodes/$pve_node/qemu/$node_id/status/current) 2>&1)
result="$?" 2>&1
if [ "$result" -ne 0 ]; then
# success
echo "${_fgLtGrn}[OK]${_fgLtWhi}"
else
echo "${_fgLtRed}[FAILED]${_fgLtWhi}"
echo -e "\nThe target node already exists, aborting!\n"
exit 255
fi
echoNotice "Geting disk size of source image $file"
disk_size=$(qemu-img info $file | grep "virtual size"|awk '{ print $3 }')
echo ${_fgLtGrn}[${disk_size}G]${_fgLtWhi}
echoNotice "Creating guest VM $node_id"
runCommand "pvesh create /nodes/$pve_node/qemu --vmid $node_id $vm_config --scsi0 local-zfs:${disk_size},discard=on,ssd=on --scsihw virtio-scsi-pci --balloon 0 --boot order=scsi0"
echoNotice "Getting disk location"
disk_loc=$(pvesh get /nodes/pve/qemu/$node_id/config --output-format json-pretty | jq .scsi0 | grep -Po "vm[^,]*+")
echo "${_fgLtGrn}[$disk_loc]${_fgLtWhi}"
echo -e "\nConverting source image of $file to $node_id"
runCommand "/usr/bin/qemu-img convert -p -n -f qcow2 -O raw $file zeroinit:/dev/zvol/rpool/data/$disk_loc" 1
echoNotice "Reading LVM data from disk image"
runCommand "kpartx -a /dev/zvol/rpool/data/$disk_loc"
echoNotice "Waiting for config volume"
until [ -b /dev/vg-db-vda/set.1._config ]
do
echo -n "."
sleep 1
done
echo "${_fgLtGrn}[OK]${_fgLtWhi}"
temp_mount=$(mktemp -d -t newbigip.XXXXXXXXXX)
echoNotice "Mounting config volume"
runCommand "mount /dev/vg-db-vda/set.1._config $temp_mount"
echoNotice "Copying startup to config"
runCommand "cp startup* .startup-env $temp_mount;chmod 755 ${temp_mount}/startup* ${temp_mount}/.startup-env"
echoNotice "Un mounting config volume"
runCommand "umount $temp_mount"
echoNotice "Removing temp mountpoint"
runCommand "rmdir ${temp_mount}"
echo "\n${_fgLtRed}This next part is potentially destructive${_fgLtWhi}, especially if you're using LVM... In fact, if you're using LVM you shouldn't even be using this script!"
echo "\nPress any key to deactivate LVM..."
read -n1 _NUL
echoNotice "Deactivating LVM volumes"
runCommand "lvchange -an /dev/vg-db-vda/*"
echoNotice "Deactivating volume groups"
runCommand "vgchange -an vg-db-vda"
echo "Removing disks from lvm config"
for disk in $(dmsetup ls | awk '{print $1}'); do dmsetup remove $disk; done
echoNotice "Promoting $node_id to template"
runCommand "pvesh create /nodes/$pve_node/qemu/$node_id/template"
echo "${_fgLtGrn}Complete!${_fgLtWhi}"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment