initial commit
This commit is contained in:
commit
5b3e79c671
|
@ -0,0 +1,220 @@
|
|||
#!/usr/bin/sh -eu
|
||||
|
||||
usage() {
|
||||
echo "usage: mkimg-archlinux --name NAME --disk SIZE --ipv4 IPV4 --ipv6 IPV6"
|
||||
exit 1
|
||||
}
|
||||
|
||||
|
||||
# TODO make a real cli
|
||||
NAME="cosmos"
|
||||
DISK_SIZE="10G"
|
||||
IPV4="10.238.2.3"
|
||||
IPV6="2a00:5881:4008:46ff::203"
|
||||
IPV4_GATEWAY="10.238.2.254"
|
||||
IPV6_GATEWAY="2a00:5881:4008:46ff::2ff"
|
||||
|
||||
fsroot="/tmp/$NAME"
|
||||
|
||||
unmount() {
|
||||
echo "=> INFO: unmounting root partition"
|
||||
|
||||
while mountpoint "$fsroot" > /dev/null 2>&1; do
|
||||
if ! umount -R "$fsroot" > /dev/null 2>&1; then
|
||||
echo -n "."
|
||||
sleep 5
|
||||
fi
|
||||
done
|
||||
|
||||
rm -df "$fsroot"
|
||||
}
|
||||
|
||||
disconnect() {
|
||||
echo "=> INFO: disconnecting disk image"
|
||||
qemu-nbd --disconnect /dev/nbd0
|
||||
sleep 2
|
||||
rmmod nbd
|
||||
}
|
||||
|
||||
cleanup() {
|
||||
echo "=> ERROR: cleaning up"
|
||||
unmount
|
||||
disconnect
|
||||
}
|
||||
|
||||
# run command as root inside the chroot
|
||||
run_cmd() {
|
||||
local cmd="$@"
|
||||
echo "=> CHROOT: $cmd"
|
||||
chroot "$fsroot" /bin/bash -c "$cmd"
|
||||
}
|
||||
|
||||
## DISK SETUP ##
|
||||
|
||||
echo "=> INFO: creating disk image"
|
||||
mkdir -p "/srv/vm/$NAME"
|
||||
qemu-img create -f qcow2 "/srv/vm/$NAME/disk.qcow2" $DISK_SIZE
|
||||
chown qemu:qemu "/srv/vm/$NAME/disk.qcow2"
|
||||
|
||||
echo "=> INFO: connecting disk image"
|
||||
modprobe nbd
|
||||
qemu-nbd --connect=/dev/nbd0 "/srv/vm/$NAME/disk.qcow2"
|
||||
trap cleanup EXIT
|
||||
|
||||
echo "=> INFO: creating root partition"
|
||||
sfdisk /dev/nbd0 << EOF
|
||||
label: dos
|
||||
,,linux,*
|
||||
EOF
|
||||
mkfs.ext4 /dev/nbd0p1
|
||||
|
||||
echo "=> INFO: mounting root partition"
|
||||
mkdir "$fsroot"
|
||||
mount /dev/nbd0p1 "$fsroot"
|
||||
|
||||
## INSTALLATION ##
|
||||
|
||||
echo "=> INFO: installing base packages"
|
||||
pacstrap -K "$fsroot" base linux mkinitcpio syslinux neovim zsh openntpd
|
||||
|
||||
echo "=> INFO: writing mirrorlist"
|
||||
reflector --country fr,de --latest 20 --protocol https --sort rate > "$fsroot/etc/pacman.d/mirrorlist"
|
||||
|
||||
echo "=> INFO: writing fstab"
|
||||
cat > "$fsroot/etc/fstab" << EOF
|
||||
/dev/vda1 / ext4 rw,relatime 0 1
|
||||
EOF
|
||||
|
||||
echo "=> INFO: writing hostname"
|
||||
echo $NAME > "$fsroot/etc/hostname"
|
||||
|
||||
echo "=> INFO: configuring locales"
|
||||
sed -i "s/#en_US.UTF-8/en_US.UTF-8/" -i "$fsroot/etc/locale.gen"
|
||||
run_cmd locale-gen
|
||||
|
||||
echo "=> INFO: configuring network"
|
||||
cat > "$fsroot/etc/resolv.conf" << EOF
|
||||
nameserver $IPV4_GATEWAY
|
||||
EOF
|
||||
|
||||
cat > "$fsroot/etc/systemd/network/radon.network" << EOF
|
||||
[Match]
|
||||
Type=ether
|
||||
|
||||
[Network]
|
||||
Address=$IPV4
|
||||
Address=$IPV6
|
||||
|
||||
[Route]
|
||||
Gateway=$IPV4_GATEWAY
|
||||
GatewayOnLink=true
|
||||
Destination=0.0.0.0/0
|
||||
|
||||
[Route]
|
||||
Gateway=$IPV6_GATEWAY
|
||||
GatewayOnLink=true
|
||||
Destination=::/0
|
||||
EOF
|
||||
|
||||
mount -t proc /proc "$fsroot/proc"
|
||||
mount -t sysfs /sys "$fsroot/sys"
|
||||
mount --rbind /dev "$fsroot/dev"
|
||||
mount --make-rslave "$fsroot"
|
||||
|
||||
run_cmd systemctl enable systemd-networkd
|
||||
run_cmd systemctl enable openntpd
|
||||
|
||||
echo "=> INFO: configuring bootloader"
|
||||
mkdir -p "$fsroot/boot/syslinux"
|
||||
cat > "$fsroot/boot/syslinux/syslinux.cfg" << EOF
|
||||
DEFAULT arch
|
||||
PROMPT 0
|
||||
TIMEOUT 0
|
||||
|
||||
LABEL arch
|
||||
LINUX ../vmlinuz-linux
|
||||
APPEND root=/dev/vda1 rw earlyprintk=ttyS0 console=ttyS0
|
||||
INITRD ../initramfs-linux.img
|
||||
EOF
|
||||
|
||||
cp "$fsroot/usr/lib/syslinux/bios/ldlinux.c32" "$fsroot/boot/syslinux/"
|
||||
run_cmd extlinux --install /boot/syslinux
|
||||
|
||||
cp "$fsroot/usr/lib/syslinux/bios/mbr.bin" /tmp/mbr.bin
|
||||
|
||||
echo "=> INFO: configuring initramfs"
|
||||
cat > "$fsroot/etc/mkinitcpio.conf" << EOF
|
||||
MODULES=(virtio virtio_pci virtio_blk ext4)
|
||||
BINARIES=()
|
||||
FILES=()
|
||||
HOOKS=(base)
|
||||
EOF
|
||||
sed -i "s/PRESETS=('default' 'fallback')/PRESETS=('default')/" "$fsroot/etc/mkinitcpio.d/linux.preset"
|
||||
rm "$fsroot/boot/initramfs-linux-fallback.img"
|
||||
run_cmd mkinitcpio -P
|
||||
|
||||
#echo "=> INFO: configuring zsh"
|
||||
#
|
||||
#cat > "$fsroot/root/.zshrc" << EOF
|
||||
#HISTFILE=~/.histfile
|
||||
#HISTSIZE=10000
|
||||
#SAVEHIST=10000
|
||||
#setopt appendhistory nomatch
|
||||
#
|
||||
#bindkey -e
|
||||
#
|
||||
#zstyle :compinstall filename '/root/.zshrc'
|
||||
#autoload -Uz compinit
|
||||
#compinit
|
||||
#
|
||||
#PS1='[%n@%m %~]$ '
|
||||
#export EDITOR=nvim
|
||||
#
|
||||
#term-resize() {
|
||||
# if [[ -t 0 && $# -eq 0 ]]; then
|
||||
# local IFS='[;' escape geometry x y
|
||||
# echo -ne '\e7\e[r\e[999;999H\e[6n\e8'
|
||||
# read -t 5 -sd R escape geometry || {
|
||||
# echo unsupported terminal emulator. >&2
|
||||
# return 1
|
||||
# }
|
||||
# x="${geometry##*;}" y="${geometry%%;*}"
|
||||
# if [[ ${COLUMNS} -eq "${x}" && ${LINES} -eq "${y}" ]]; then
|
||||
# echo "${TERM} ${x}x${y}"
|
||||
# elif [[ "$x" -gt 0 && "$y" -gt 0 ]]; then
|
||||
# echo "${COLUMNS}x${LINES} -> ${x}x${y}"
|
||||
# stty cols ${x} rows ${y}
|
||||
# else
|
||||
# echo unsupported terminal emulator. >&2
|
||||
# return 1
|
||||
# fi
|
||||
# else
|
||||
# echo 'Usage: term-resize'
|
||||
# fi
|
||||
#}
|
||||
#EOF
|
||||
|
||||
echo "=> INFO: setting root password"
|
||||
passwd=$(openssl rand -base64 12)
|
||||
echo "root:$passwd" | run_cmd chpasswd
|
||||
|
||||
echo "=> INFO: setting qemu config file"
|
||||
cat > "/srv/vm/$NAME/config" << EOF
|
||||
NCPU=2
|
||||
MEMORY=2048M
|
||||
EOF
|
||||
|
||||
## WRAPPING UP
|
||||
|
||||
trap - EXIT
|
||||
|
||||
unmount
|
||||
|
||||
echo "=> INFO: writing the MBR"
|
||||
dd bs=440 count=1 conv=notrunc if=/tmp/mbr.bin of=/dev/nbd0
|
||||
rm /tmp/mbr.bin
|
||||
|
||||
disconnect
|
||||
|
||||
echo "=> INFO: root password: $passwd"
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
#!/usr/bin/sh
|
||||
|
||||
### CONFIG
|
||||
|
||||
VG_NAME=nvme # volume group of the target
|
||||
ORIG_NAME=system # logical volume name to backup
|
||||
SNAP_NAME=tmp-snap # name of temporary snapshot
|
||||
BORG_REPO=/data/backup/radon-host # path to borg repository
|
||||
|
||||
### SETUP
|
||||
|
||||
TMPDIR=$(mktemp -d)
|
||||
|
||||
info() { printf "%s\n" "$*" >&2; }
|
||||
|
||||
cleanup() {
|
||||
cd /
|
||||
umount --force --quiet "/dev/$VG_NAME/$SNAP_NAME"
|
||||
rm --recursive --force "$TMPDIR"
|
||||
lvremove --force "$VG_NAME/$SNAP_NAME"
|
||||
}
|
||||
|
||||
trap 'info "Backup interrupted"; cleanup; exit 2' INT TERM
|
||||
|
||||
### THE ACTUAL THING
|
||||
|
||||
info "Checking for old snapshot"
|
||||
if lvs --options lv_name "$VG_NAME" | grep --quiet "$SNAP_NAME"; then
|
||||
cleanup
|
||||
fi
|
||||
|
||||
info "Creating temporary snapshot"
|
||||
lvcreate --size 1G --snapshot --name "$SNAP_NAME" "$VG_NAME/$ORIG_NAME"
|
||||
mount "/dev/$VG_NAME/$SNAP_NAME" "$TMPDIR"
|
||||
|
||||
info "Starting backup"
|
||||
|
||||
cd "$TMPDIR"
|
||||
borg create \
|
||||
--verbose \
|
||||
--stats \
|
||||
--show-rc \
|
||||
--compression zstd,1 \
|
||||
--exclude-caches \
|
||||
--exclude 'archive' \
|
||||
--exclude 'backup' \
|
||||
--exclude 'content' \
|
||||
--exclude 'dev' \
|
||||
--exclude 'mnt' \
|
||||
--exclude 'proc' \
|
||||
--exclude 'run' \
|
||||
--exclude 'sys' \
|
||||
--exclude 'tmp' \
|
||||
--exclude 'var/tmp/*' \
|
||||
--exclude 'var/cache/*' \
|
||||
"$BORG_REPO"::'system-{now:%Y-%m-%d}' \
|
||||
.
|
||||
|
||||
info "Pruning repository"
|
||||
borg prune \
|
||||
--list \
|
||||
--glob-archives 'system-*' \
|
||||
--show-rc \
|
||||
--keep-daily 7 \
|
||||
--keep-weekly 2 \
|
||||
--keep-monthly 10 \
|
||||
"$BORG_REPO"
|
||||
|
||||
info "Compacting repository"
|
||||
borg compact "$BORG_REPO"
|
||||
|
||||
info "Removing snapshot"
|
||||
cleanup
|
|
@ -0,0 +1,143 @@
|
|||
#!/bin/bash -eu
|
||||
|
||||
QEMU=/usr/bin/qemu-system-x86_64
|
||||
VIRTIOFSD=/usr/lib/qemu/virtiofsd
|
||||
SOCAT=/usr/bin/socat
|
||||
IP=/usr/bin/ip
|
||||
|
||||
CFG_BASE=/srv/vm
|
||||
RUN_BASE=/run/vm
|
||||
|
||||
check_vm() {
|
||||
if [[ ! -e $MONITOR_PATH ]]; then
|
||||
echo "error: monitor socket not found, is VM '$VM_NAME' running?"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
monitor_cmd() {
|
||||
check_vm
|
||||
echo $1 | $SOCAT - unix-connect:$MONITOR_PATH
|
||||
}
|
||||
|
||||
do_start() {
|
||||
mkdir -p /dev/hugepages/qemu $RUN_DIR
|
||||
chown qemu:qemu /dev/hugepages/qemu $RUN_DIR
|
||||
|
||||
# read config variables
|
||||
QEMU_EXTRA_ARGS=""
|
||||
FS_SHARE=""
|
||||
MEM_OPTS=""
|
||||
. $CFG_DIR/config
|
||||
ID_HEX="$(printf %02x $VM_ID)"
|
||||
ID_DEC="$(printf %03d $VM_ID)"
|
||||
MAC_ADDR="52:54:00:00:00:$ID_HEX"
|
||||
IPV4_ADDR="10.238.2.$ID_DEC"
|
||||
IPV6_ADDR="2a00:5881:4008:46ff::2$ID_HEX"
|
||||
|
||||
# setup network
|
||||
$IP tuntap add dev $IFNAME mode tap group qemu
|
||||
$IP link set dev $IFNAME up
|
||||
$IP address add 10.238.1.1 dev $IFNAME
|
||||
$IP address add 2a00:5881:4008:46ff::101 dev $IFNAME
|
||||
$IP route add $IPV4_ADDR dev $IFNAME
|
||||
$IP route add $IPV6_ADDR dev $IFNAME
|
||||
|
||||
# setup virtiofs daemon and opts
|
||||
if [ ! -z $FS_SHARE ]; then
|
||||
VHOST_PATH=$RUN_DIR/vhost-fs.sock
|
||||
QEMU_EXTRA_ARGS="$QEMU_EXTRA_ARGS -chardev socket,id=vhost0,path=$VHOST_PATH"
|
||||
QEMU_EXTRA_ARGS="$QEMU_EXTRA_ARGS -device vhost-user-fs-pci,queue-size=1024,chardev=vhost0,tag=fs0"
|
||||
MEM_OPTS=",share=on"
|
||||
$VIRTIOFSD --socket-path=$VHOST_PATH --socket-group=qemu -o source=$FS_SHARE -o cache=always &
|
||||
fi
|
||||
|
||||
exec setpriv --reuid=qemu --regid=qemu --init-groups --inh-caps=-all --reset-env \
|
||||
$QEMU -nodefaults -no-user-config -nographic -sandbox on -enable-kvm \
|
||||
-machine pc -cpu host -smp $NCPU -m $MEMORY \
|
||||
-object memory-backend-file,id=mem,size=$MEMORY,mem-path=/dev/hugepages/qemu$MEM_OPTS -numa node,memdev=mem \
|
||||
-monitor unix:$MONITOR_PATH,server=on,wait=off \
|
||||
-serial unix:$CONSOLE_PATH,server=on,wait=off \
|
||||
-drive file=$DISK_IMG,format=qcow2,id=disk0,if=none \
|
||||
-device virtio-blk-pci,drive=disk0 \
|
||||
-netdev tap,id=net0,ifname=$IFNAME,script=no,downscript=no,vhost=on \
|
||||
-device virtio-net-pci,mac=$MAC_ADDR,netdev=net0 \
|
||||
$QEMU_EXTRA_ARGS
|
||||
}
|
||||
|
||||
do_console() {
|
||||
check_vm
|
||||
echo "info: connecting to console: '$VM_NAME'"
|
||||
echo "info: press ctrl-o to exit"
|
||||
exec $SOCAT -,escape=0x0f,raw,echo=0 unix-connect:$CONSOLE_PATH
|
||||
}
|
||||
|
||||
do_monitor() {
|
||||
check_vm
|
||||
echo "info: connecting to monitor: '$VM_NAME'"
|
||||
echo "info: press ctrl-c to exit"
|
||||
exec $SOCAT readline unix-connect:$MONITOR_PATH
|
||||
}
|
||||
|
||||
do_stop() {
|
||||
monitor_cmd system_powerdown
|
||||
$IP link del $IFNAME
|
||||
}
|
||||
|
||||
do_mount() {
|
||||
fsroot="/tmp/$VM_NAME"
|
||||
|
||||
modprobe nbd
|
||||
qemu-nbd --connect=/dev/nbd0 "$DISK_IMG"
|
||||
|
||||
mkdir "$fsroot"
|
||||
mount /dev/nbd0p1 "$fsroot"
|
||||
mount -t proc /proc "$fsroot/proc"
|
||||
mount -t sysfs /sys "$fsroot/sys"
|
||||
mount --rbind /dev "$fsroot/dev"
|
||||
mount --make-rslave "$fsroot"
|
||||
|
||||
echo "info: mounted VM '$VM_NAME' rootfs at '/tmp/$VM_NAME'"
|
||||
}
|
||||
|
||||
do_umount() {
|
||||
if ! mountpoint "/tmp/$VM_NAME" > /dev/null 2>&1; then
|
||||
echo "error: mountpoint not found, is VM '$VM_NAME' mounted?"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
umount -R "/tmp/$VM_NAME"
|
||||
rm -df "/tmp/$VM_NAME"
|
||||
|
||||
qemu-nbd --disconnect /dev/nbd0 > /dev/null
|
||||
rmmod nbd
|
||||
|
||||
echo "info: unmounted VM '$VM_NAME' successfully"
|
||||
}
|
||||
|
||||
usage() {
|
||||
echo "usage: vm-mgmt ( start | stop | reboot | console | monitor | mount | umount ) NAME"
|
||||
exit 1
|
||||
}
|
||||
|
||||
test $# -lt 2 && usage
|
||||
VM_NAME=$2
|
||||
|
||||
RUN_DIR=$RUN_BASE/$VM_NAME
|
||||
CFG_DIR=$CFG_BASE/$VM_NAME
|
||||
|
||||
CONSOLE_PATH=$RUN_DIR/console.sock
|
||||
MONITOR_PATH=$RUN_DIR/monitor.sock
|
||||
DISK_IMG=$CFG_DIR/disk.qcow2
|
||||
IFNAME=vm-$VM_NAME
|
||||
|
||||
case $1 in
|
||||
start) do_start;;
|
||||
stop) do_stop;;
|
||||
reboot) monitor_cmd system_reset;;
|
||||
console) do_console;;
|
||||
monitor) do_monitor;;
|
||||
mount) do_mount;;
|
||||
umount) do_umount;;
|
||||
*) usage;;
|
||||
esac
|
Loading…
Reference in New Issue