From ac27f767d638836386c6188d1e37ccc46ab37a3d Mon Sep 17 00:00:00 2001 From: Ian Kelling Date: Wed, 19 Mar 2025 10:15:34 -0400 Subject: [PATCH] move more scripts into public repo --- .../files/simple/usr/local/bin/mount-vm | 217 ++++++++++++++++++ .../files/simple/usr/local/bin/umount-vm | 72 ++++++ 2 files changed, 289 insertions(+) create mode 100755 roles/kvmhost/files/simple/usr/local/bin/mount-vm create mode 100755 roles/kvmhost/files/simple/usr/local/bin/umount-vm diff --git a/roles/kvmhost/files/simple/usr/local/bin/mount-vm b/roles/kvmhost/files/simple/usr/local/bin/mount-vm new file mode 100755 index 0000000..f4f5bf0 --- /dev/null +++ b/roles/kvmhost/files/simple/usr/local/bin/mount-vm @@ -0,0 +1,217 @@ +#!/bin/bash +# Script managed by Ansible, do not edit +# +# Copyright (C) 2017 Free Software Foundation +# Copyright (C) 2022 Ian Kelling +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +# + + +if [[ ! -s /usr/local/lib/err ]]; then + echo "$0: error, missing /usr/local/lib/err" >&2 + exit 1 +fi +source /usr/local/lib/err + +usage() { + cat <&2; exit 1; } + +force=false +first_disk=false # default +temp=$(getopt -l help,first-disk,force,key-file: h1fk: "$@") || usage 1 +eval set -- "$temp" +while true; do + case $1 in + -f|--force) force=true ;; + -1|--first-disk) first_disk=true ;; + -k|--key-file) key_arg="--key-file $2"; shift ;; + -m|--mapper) mapper="$2"; shift ;; + -h|--help) usage ;; + --) shift; break ;; + *) echo "$0: unexpected args: $*" >&2 ; usage 1 ;; + esac + shift +done +read -r host <<<"$@" + +if (( $# != 1 )); then + echo "$0: error, expected 1 argument, got $#. usage:" + usage 1 +fi + +### end command line parsing #### + + +if virsh list --name | grep -qFx $host >/dev/null; then + if $force; then + echo "WARNING: you are forcing me to mount a vm that is running!!! sleeping for 10 seconds" + sleep 10 + else + echo "I'm sorry, Dave. I'm afraid I can't do that." + echo "Guest $host seems to be running!" + echo "note --force exists if you know better" + exit 1 + fi +fi + + +did_something=false +pre="${0##*/}: running " +m() { + did_something=true + printf "$pre %s\n" "$*"; "$@" +} + + +xmltmp=$(mktemp) +rbdnames=() +devpaths=() +if virsh dumpxml $host >$xmltmp; then + xpathtmp=$(mktemp) + # 10 exit code is when result is empty + xmllint --xpath "/domain/devices/disk[@type='block']/source/@dev" $xmltmp >$xpathtmp 2>/dev/null || [[ $? == 10 ]] + # https://mywiki.wooledge.org/BashFAQ/001#My_text_files_are_broken.21__They_lack_their_final_newlines.21 + breakout=false + while read -r line || [[ $line ]]; do + for word in $line; do + path=$(echo "" | xmllint --xpath "string(//a/@dev)" -) + devpaths+=($path) + if (( ${#devpaths[@]} >= 1 )) && $first_disk; then + breakout=true + break + fi + done + if $breakout; then break; fi + done <$xpathtmp + rm -f $xpathtmp + xmllint --xpath "/domain/devices/disk/source[@protocol='rbd']/@name" $xmltmp >$xpathtmp 2>/dev/null || [[ $? == 10 ]] + breakout=false + while read -r line || [[ $line ]]; do + # newer xmllint outputs lines, older one outputs words + for word in $line; do + name=$(echo "" | xmllint --xpath "string(//a/@name)" -) + name="${name#rbd/}" + rbdnames+=( "$name" ) + if (( ${#rbdnames[@]} >= 1 )) && $first_disk; then + breakout=true + break + fi + done + if $breakout; then break; fi + done <$xpathtmp +else + echo "$0: error: the domain is not defined" + exit 1 +fi + +mountsuf= +mount_i=0 + +domount() { + local dir + dir=/mnt/$host$mountsuf + mkdir -p $dir + if mountpoint -q $dir; then + echo "$0: error: $dir is a mountpoint already" + exit 1 + fi + m mount "$@" $dir + mount_i=$(( mount_i + 1 )) + mountsuf=-$mount_i +} + +declare -A btrfs_extra_devs +for devpath in ${devpaths[@]}; do + if [[ ${btrfs_extra_devs[$devpath]} ]]; then + continue + fi + # we assume paths dont have spaces + if btrfs_devs=$(btrfs filesystem show "$devpath" 2>/dev/null | awk '$1 == "devid" { print $NF }') && [[ $btrfs_devs ]]; then + for btrfs_dev in $btrfs_devs; do + if [[ $btrfs_dev == "$devpath" ]]; then + continue + fi + btrfs_extra_devs[$btrfs_dev]=t + done + if (( mount_i >= 2 )); then + domount $devpath + else + domount -o subvol=root $devpath + fi + else + domount $devpath + fi +done + +first=true +for rbdname in ${rbdnames[@]}; do + echo "$pre rbd-nbd map $rbdname" + dev=$(rbd-nbd map $rbdname) + echo "warning: cleanup required if if script fails: rbd-nbd unmap $dev" + did_something=true + if $first && [[ $mapper ]]; then + cryptname=$mapper + else + cryptname=$host-crypt$mount_i + fi + echo "mount-vm: WARNING: prompt for key will be hidden if this runs on ssh without -t" + m cryptsetup luksOpen $key_arg $dev $cryptname + echo "warning: cleanup required if if script fails: cryptsetup luksClose $cryptname" + domount /dev/mapper/$cryptname + first=false +done + +if ! $did_something; then + echo "$0: warning. I found nothing to do" +fi diff --git a/roles/kvmhost/files/simple/usr/local/bin/umount-vm b/roles/kvmhost/files/simple/usr/local/bin/umount-vm new file mode 100755 index 0000000..40c5054 --- /dev/null +++ b/roles/kvmhost/files/simple/usr/local/bin/umount-vm @@ -0,0 +1,72 @@ +#!/bin/bash +# Script managed by Ansible, do not edit +# +# Copyright (C) 2022 Ian Kelling +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +# This script undoes mounts made by mount-vm + +if [[ ! -s /usr/local/lib/err ]]; then + echo "$0: error, missing /usr/local/lib/err" >&2 + exit 1 +fi +source /usr/local/lib/err + +### begin command line parsing #### +if (( $# != 1 )); then + echo Usage $0 fully.qualified.host + exit 1 +fi + +host=$1 +### end command line parsing #### + +did_something=false +pre="${0##*/}:" +m() { + did_something=true + printf "$pre %s\n" "$*"; "$@" +} + + +# looking for up to 100 mountpoints should be way more than we ever use + +not_mounted_i=0 +for (( i=1; i < 100; i++ )); do + mp=/mnt/$host$mountsuf + mountsuf=-$i + if ! mountpoint -q $mp; then + not_mounted_i=$(( not_mounted_i + 1 )) + if (( not_mounted_i > 10 )); then + break + else + continue + fi + fi + dev=$(awk '$2 == "'$mp'" {print $1}' /etc/mtab) + if type -p rbd-nbd &>/dev/null && nbd=$(cryptsetup status "$dev" | awk '$1 == "device:" {print $2}') && [[ $nbd == /dev/nbd* ]]; then + m umount $mp + m cryptsetup luksClose $dev + m rbd-nbd unmap $nbd + else + echo "$0: note: not a ceph backed mount" + m umount $mp + fi +done + +if ! $did_something; then + echo "$0: warning. I found nothing to do" +fi -- 2.25.1