Skip to content

Commit

Permalink
Armbian internal: deploy Armbian qemu KVM instances (#365)
Browse files Browse the repository at this point in the history
* Armbian internal: port runners deployment script

Refference: https://github.com/armbian/scripts/blob/main/generate-runners/deploy.sh

* comment out the test commands

* Enable Docker install, enable parameters para1=a para2=b ...

* Armbian internals: deploy KVM instances

* Dependencies

* Test image

* Fixes

* Cleanup

---------

Co-authored-by: Joey Turner <[email protected]>
  • Loading branch information
igorpecovnik and Tearran authored Jan 17, 2025
1 parent 4e1ed48 commit 302c1e1
Showing 1 changed file with 221 additions and 0 deletions.
221 changes: 221 additions & 0 deletions tools/modules/system/module_armbian_kvmtest.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,221 @@
module_options+=(
["module_armbian_kvmtest,author"]="@igorpecovnik"
["module_armbian_kvmtest,feature"]="module_armbian_kvmtest"
["module_armbian_kvmtest,desc"]="Deploy Armbian KVM instances"
["module_armbian_kvmtest,example"]="install remove save restore list help"
["module_armbian_kvmtest,port"]=""
["module_armbian_kvmtest,status"]="Active"
["module_armbian_kvmtest,arch"]="x86-64"
)
#
# Module deploy Armbian QEMU KVM instances
#
function module_armbian_kvmtest () {

local title="kvmtest"
local condition=$(which "$title" 2>/dev/null)

# read additional parameters from command line
local parameter
IFS=' ' read -r -a parameter <<< "${1}"
for feature in instances provisioning firstconfig startingip gateway keyword arch kvmprefix network bridge memory vcpus; do
for selected in ${parameter[@]}; do
IFS='=' read -r -a split <<< "${selected}"
[[ ${split[0]} == $feature ]] && eval "$feature=${split[1]}"
done
done

# if we provide startingip and gateway, set network
if [[ -n "${startingip}" && -n "${gateway}" ]]; then
PRESET_NET_CHANGE_DEFAULTS="1"
fi

local arch="${arch:-x86}" # VM architecture
local network="${network:-default}"
if [[ -n "${bridge}" ]]; then network="bridge=${bridge}"; fi
local instances="${instances:-01}" # number of instances
local destination="${destination:-/var/lib/libvirt/images}"
local kvmprefix="${kvmprefix:-kvmtest}"
local memory="${memory:-3072}"
local vcpus="${vcpus:-2}"
local startingip="${startingip:-10.0.60.60}"
local gateway="${gateway:-10.0.60.1}"
local keyword=$(echo $keyword | sed "s/_/|/g") # convert

qcowimages=(
"https://dl.armbian.com/nightly/uefi-${arch}/Bullseye_current_minimal-qcow2"
"https://dl.armbian.com/nightly/uefi-${arch}/Bookworm_current_minimal-qcow2"
"https://dl.armbian.com/nightly/uefi-${arch}/Trixie_current_minimal-qcow2"
"https://dl.armbian.com/nightly/uefi-${arch}/Focal_current_minimal-qcow2"
"https://dl.armbian.com/nightly/uefi-${arch}/Jammy_current_minimal-qcow2"
"https://dl.armbian.com/nightly/uefi-${arch}/Noble_current_minimal-qcow2"
"https://dl.armbian.com/nightly/uefi-${arch}/Oracular_current_minimal-qcow2"
)

local commands
IFS=' ' read -r -a commands <<< "${module_options["module_armbian_kvmtest,example"]}"

case "${parameter[0]}" in

"${commands[0]}")

# Install portainer with KVM support and / KVM support only
# TBD - need to be added to armbian-config
pkg_install virtinst libvirt-daemon-system libvirt-clients qemu-kvm qemu-utils dnsmasq

# start network
virsh net-start default 2>/dev/null
virsh net-autostart default

if ! pkg_installed xz-utils; then
pkg_install xz-utils
fi

# download images
tempfolder=$(mktemp -d)
trap '{ rm -rf -- "$tempfolder"; }' EXIT
for qcowimage in ${qcowimages[@]}; do
[[ ! $qcowimage =~ ${keyword/,/|} ]] && continue # skip not needed ones
curl --progress-bar -L $qcowimage | xz -d > ${tempfolder}/$(basename $qcowimage | sed "s/-qcow2/.qcow2/g")
done

# we will mount qcow image
modprobe nbd max_part=8

mounttempfolder=$(mktemp -d)
trap '{ umount "$mounttempfolder" 2>/dev/null; rm -rf -- "$tempfolder"; }' EXIT
# Deploy several instances
for i in $(seq -w 01 $instances); do
for qcowimage in ${qcowimages[@]}; do
[[ ! $qcowimage =~ ${keyword/,/|} ]] && continue # skip not needed ones
local filename=$(basename $qcowimage | sed "s/-qcow2/.qcow2/g") # identify filename
local domain=$i-${kvmprefix}-$(basename $qcowimage | sed "s/-qcow2//g") # without qcow2
local image="$i"-"${kvmprefix}"-"${filename}" # get image name
cp ${tempfolder}/${filename} ${destination}/${image} # make a copy under different number
sync
qemu-img resize ${destination}/${image} +10G # expand
qemu-nbd --connect=/dev/nbd0 ${destination}/${image} # connect to qemu image
printf "fix\n" | sudo parted ---pretend-input-tty /dev/nbd0 print >/dev/null # fix resize
mount /dev/nbd0p3 ${mounttempfolder} # 3rd partition on uefi images is rootfs
# Check if it reads
cat ${mounttempfolder}/etc/os-release | grep ARMBIAN_PRETTY_NAME | cut -d"=" -f2 | sed 's/"//g'
# commands for changing follows here
j=$(( j + 1 ))
local ip_address=$(awk -F\. '{ print $1"."$2"."$3"."$4+'$j' }' <<< $startingip )

# script that is executed at firstrun
if [[ -f ${provisioning} ]]; then
echo "INSTANCE=$i" > ${mounttempfolder}/root/provisioning.sh
cat "${provisioning}" >> ${mounttempfolder}/root/provisioning.sh
chmod +x ${mounttempfolder}/root/provisioning.sh
fi

# first config
if [[ ${firstconfig} ]]; then
if [[ -f ${firstconfig} ]]; then
cat "${firstconfig}" >> ${mounttempfolder}/root/.not_logged_in_yet
fi
else
echo "first config"
cat <<- EOF >> ${mounttempfolder}/root/.not_logged_in_yet
PRESET_NET_CHANGE_DEFAULTS="${PRESET_NET_CHANGE_DEFAULTS}"
PRESET_NET_ETHERNET_ENABLED="1"
PRESET_NET_USE_STATIC="1"
PRESET_NET_STATIC_IP="${ip_address}"
PRESET_NET_STATIC_MASK="255.255.255.0"
PRESET_NET_STATIC_GATEWAY="${gateway}"
PRESET_NET_STATIC_DNS="9.9.9.9 8.8.4.4"
SET_LANG_BASED_ON_LOCATION="y"
PRESET_LOCALE="sl_SI.UTF-8"
PRESET_TIMEZONE="Europe/Ljubljana"
PRESET_ROOT_PASSWORD="armbian"
PRESET_USER_NAME="armbian"
PRESET_USER_PASSWORD="armbian"
PRESET_USER_KEY=""
PRESET_DEFAULT_REALNAME="Armbian user"
PRESET_USER_SHELL="bash"
EOF
fi

umount /dev/nbd0p3 # unmount
qemu-nbd --disconnect /dev/nbd0 >/dev/null # disconnect from qemu image
# install and start VM
sleep 3
virt-install \
--name ${domain} \
--memory ${memory} \
--vcpus 2 \
--autostart \
--disk ${destination}/${image},bus=sata \
--import \
--os-variant ubuntu24.04 \
--network default \
--noautoconsole
done
done
;;
"${commands[1]}")
for i in {1..10}; do
for j in $(virsh list --all --name | grep ${kvmprefix}); do
virsh shutdown $j 2>/dev/null
for snapshot in $(virsh snapshot-list $j \
| tail -n +3 | head -n -1 | cut -d' ' -f2); do virsh snapshot-delete $j $snapshot; done
done
sleep 2
if [[ -z "$(virsh list --name | grep ${kvmprefix})" ]]; then break; fi
done
if [[ $i -lt 10 ]]; then
for j in $(virsh list --all --name | grep ${kvmprefix}); do virsh undefine $j --remove-all-storage; done
fi
;;
"${commands[2]}")
for j in $(virsh list --all --name | grep ${kvmprefix}); do
# create snapshot
virsh snapshot-create-as --domain ${j} --name "initial-state"
done
;;
"${commands[3]}")
for j in $(virsh list --all --name | grep ${kvmprefix}); do
virsh shutdown $j 2>/dev/null
virsh snapshot-revert --domain $j --snapshotname "initial-state" --running
virsh shutdown $j 2>/dev/null
for i in {1..20}; do
sleep 2
if [[ "$(virsh domstate $j | grep "shut off")" == "shut off" ]]; then break; fi
done
virsh start $j 2>/dev/null
done
;;
"${commands[4]}")
for qcowimage in ${qcowimages[@]}; do
[[ ! $qcowimage =~ ${keyword/,/|} ]] && continue # skip not needed ones
echo $qcowimage
done
;;
"${commands[5]}")
echo -e "\nUsage: ${module_options["module_armbian_kvmtest,feature"]} <command> [switches]"
echo -e "Commands: ${module_options["module_armbian_kvmtest,example"]}"
echo -e "Available commands:\n"
echo -e "\tinstall\t- Install $title."
echo -e "\tremove\t- Remove all virtual machines $title."
echo -e "\tsave\t- Save state of all VM $title."
echo -e "\trestore\t- Restore all saved state of VM $title."
echo -e "\tlist\t- Show available VM machines $title."
echo -e "\nAvailable switches:\n"
echo -e "\tkvmprefix\t- Name prefix (default = kvmtest)"
echo -e "\tmemory\t\t- KVM memory (default = 2048)"
echo -e "\tvcpus\t\t- Virtual CPUs (default = 2)"
echo -e "\tbridge\t\t- Use network bridge br0,br1,... instead of default inteface"
echo -e "\tinstances\t- Repetitions if more then 1"
echo -e "\tprovisioning\t- File of command that is executed at first run."
echo -e "\tfirstconfig\t- Armbian first config."
echo -e "\tkeyword\t\t- Select only certain image, example: Focal_Jammy VM image."
echo -e "\tarch\t\t- architecture of VM image."
echo
;;
*)
${module_options["module_armbian_kvmtest,feature"]} ${commands[5]}
;;
esac
}

0 comments on commit 302c1e1

Please sign in to comment.