Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
182 changes: 123 additions & 59 deletions proxmox/chr_install.sh
Original file line number Diff line number Diff line change
@@ -1,84 +1,148 @@
#!/bin/bash
#
# chr_install.sh — deploy a MikroTik CHR (Cloud Hosted Router) as a Proxmox VE VM.
#
# Downloads the requested RouterOS CHR image, converts it to qcow2, optionally
# resizes the disk and creates the VM. Can look up and suggest the current
# Long-term and Stable RouterOS releases from MikroTik.

#vars
version="nil"
vmID="nil"
set -euo pipefail

echo "############## Start of Script ##############
#### vars
TEMP_DIR="/root/temp"
NODE="$(hostname)"
MIKROTIK_DL="https://download.mikrotik.com/routeros"
MIKROTIK_UPG="https://upgrade.mikrotik.com/routeros"

## Checking if temp dir is available..."
if [ -d /root/temp ]
then
# Defaults for the created VM (override here if needed)
VM_MEMORY=256
VM_SOCKETS=1
VM_CORES=1
VM_BRIDGE="vmbr0"
VM_STORAGE="local"

#### helpers

# die MESSAGE — print an error and exit with a failure code.
die() {
echo "-- ERROR: $*" >&2
exit 1
}

# cleanup — remove a half-created image dir if we fail after creating it.
IMG_DIR=""
cleanup() {
local rc=$?
if [ "$rc" -ne 0 ] && [ -n "$IMG_DIR" ] && [ -d "$IMG_DIR" ]; then
echo "-- Cleaning up incomplete image dir $IMG_DIR" >&2
rm -rf "$IMG_DIR"
fi
}
trap cleanup EXIT

# valid_version VERSION — accept e.g. 6.40.1, 7.16, 7.16.2
valid_version() {
[[ "$1" =~ ^[0-9]+\.[0-9]+(\.[0-9]+)?$ ]]
}

# fetch_channel CHANNEL — print the newest version for a RouterOS channel.
# CHANNEL is one of: stable, long-term, testing. Prints empty on failure.
fetch_channel() {
local channel="$1" line
# The NEWESTv7.<channel> file contains: "<version> <unix-timestamp>"
line="$(wget -qO- "${MIKROTIK_UPG}/NEWESTv7.${channel}" 2>/dev/null || true)"
echo "${line%% *}"
}

echo "############## Start of Script ##############"

#### 1. temp dir
echo "## Checking if temp dir is available..."
if [ -d "$TEMP_DIR" ]; then
echo "-- Directory exists!"
else
echo "-- Creating temp dir!"
mkdir /root/temp
mkdir -p "$TEMP_DIR" || die "Could not create $TEMP_DIR"
fi
# Ask user for version

#### 2. determine version to deploy
echo "## Preparing for image download and VM creation!"
read -p "Please input CHR version to deploy (6.38.2, 6.40.1, etc):" version
# Check if image is available and download if needed
if [ -f /root/temp/chr-$version.img ]
then
echo "-- Looking up current RouterOS releases from MikroTik..."
stable_ver="$(fetch_channel stable)"
lt_ver="$(fetch_channel long-term)"

[ -n "$lt_ver" ] && echo " Long-term (recommended): $lt_ver"
[ -n "$stable_ver" ] && echo " Stable: $stable_ver"
[ -z "$lt_ver$stable_ver" ] && \
echo " (could not reach MikroTik — enter a version manually)"

# Default to long-term, fall back to stable.
default_ver="${lt_ver:-$stable_ver}"
prompt="Please input CHR version to deploy (6.38.2, 6.40.1, etc)"
[ -n "$default_ver" ] && prompt="$prompt [$default_ver]"
read -r -p "$prompt: " version
version="${version:-$default_ver}"

valid_version "$version" || die "Invalid version format: '$version'"

#### 3. download image if needed
img="$TEMP_DIR/chr-$version.img"
if [ -f "$img" ]; then
echo "-- CHR image is available."
else
echo "-- Downloading CHR $version image file."
cd /root/temp || exit 1
echo "---------------------------------------------------------------------------"
wget https://download.mikrotik.com/routeros/$version/chr-$version.img.zip
unzip chr-$version.img.zip
wget -O "$TEMP_DIR/chr-$version.img.zip" \
"${MIKROTIK_DL}/$version/chr-$version.img.zip" \
|| die "Download failed for version $version"
unzip -o "$TEMP_DIR/chr-$version.img.zip" -d "$TEMP_DIR" \
|| die "Failed to unzip chr-$version.img.zip"
echo "---------------------------------------------------------------------------"
fi
if [ ! -f /root/temp/chr-$version.img ]
then
echo "-- Error downloading CHR $version image file!"
exit 0
fi
# List already existing VM's and ask for vmID
[ -f "$img" ] || die "CHR $version image file is missing after download!"

#### 4. choose a free VM ID
echo "== Printing list of VM's on this hypervisor!"
qm list
echo "== Printing list of CT's on this hypervisor!"
pct list
echo ""
read -p "Please Enter free vm ID to use:" vmID
read -r -p "Please enter free VM ID to use: " vmID
echo ""
# Create storage dir for VM if needed.
if [ -f /etc/pve/nodes/pve/qemu-server/$vmID.conf ]
then
echo "-- VM exists! Try another vm ID!"
exit 0
fi
if [ -f /etc/pve/nodes/pve/lxc/$vmID.conf ]
then
echo "-- CT exists! Try another vm ID!"
exit 0
fi

[[ "$vmID" =~ ^[0-9]+$ ]] || die "VM ID must be a number: '$vmID'"
[ -f "/etc/pve/nodes/$NODE/qemu-server/$vmID.conf" ] && die "VM $vmID exists! Try another ID."
[ -f "/etc/pve/nodes/$NODE/lxc/$vmID.conf" ] && die "CT $vmID exists! Try another ID."

#### 5. create image dir + qcow2
IMG_DIR="/var/lib/vz/images/$vmID"
echo "-- Creating VM image dir!"
mkdir /var/lib/vz/images/$vmID
# Creating qcow2 image for CHR.
read -p "Please input image size, GB:" imgsize
echo "-- Converting image to qcow2 format "
qemu-img convert \
-f raw \
-O qcow2 \
/root/temp/chr-$version.img \
/var/lib/vz/images/$vmID/vm-$vmID-disk-1.qcow2
if [ $imgsize -ne 0 ]
then
echo "-- Resize image to $imgsize GB"
qemu-img resize \
/var/lib/vz/images/$vmID/vm-$vmID-disk-1.qcow2 +${imgsize}G
mkdir -p "$IMG_DIR" || die "Could not create $IMG_DIR"

read -r -p "Please input extra image size in GB (0 for none): " imgsize
[[ "$imgsize" =~ ^[0-9]+$ ]] || die "Image size must be a non-negative number: '$imgsize'"

disk="$IMG_DIR/vm-$vmID-disk-0.qcow2"
echo "-- Converting image to qcow2 format"
qemu-img convert -f raw -O qcow2 "$img" "$disk" || die "qemu-img convert failed"

if [ "$imgsize" -ne 0 ]; then
echo "-- Resizing image by +${imgsize}G"
qemu-img resize "$disk" "+${imgsize}G" || die "qemu-img resize failed"
fi
# Creating VM

#### 6. create the VM
echo "-- Creating new CHR VM"
qm create $vmID \
--name chr-$version \
--net0 virtio,bridge=vmbr0 \
--bootdisk virtio0 \
--ostype l26 \
--memory 256 \
--onboot no \
--sockets 1 \
--cores 1 \
--virtio0 local:$vmID/vm-$vmID-disk-1.qcow2
qm create "$vmID" \
--name "chr-$version" \
--net0 "virtio,bridge=$VM_BRIDGE" \
--bootdisk virtio0 \
--ostype l26 \
--memory "$VM_MEMORY" \
--onboot no \
--sockets "$VM_SOCKETS" \
--cores "$VM_CORES" \
--virtio0 "$VM_STORAGE:$vmID/vm-$vmID-disk-0.qcow2" \
|| die "qm create failed"

echo "############## End of Script ##############"
Loading