tripleo-common/scripts/tripleo-mount-image
Harald Jensås 0366b14d0b Fix condition for CHROOT, missing quotes
The condition controlling if start_chroot should run was
always evaluating to true, so the start_chroot function was
called even when --chroot option was not used.

Adding quotes, and curly braces, on the $CHROOT variable should
fix the issue.

Closes-Bug: #1988808
Change-Id: I318809454924a342750c6044f56ec05893a8da25
2022-09-06 18:00:30 +02:00

343 lines
10 KiB
Bash
Executable File

#!/bin/bash
# Copyright 2021 Red Hat, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
# Script to upload files to a Artifact container for deployment via
# TripleO Heat Templates.
#
set -eu
set -o pipefail
SCRIPT_NAME=$(basename $0)
NBD_DEVICE=""
IMAGE_FILE=""
MOUNT_DIR=""
CHROOT=""
if [ ! -a "/dev/nbd0" ]; then
modprobe nbd
fi
# GPT GUIDs of interest.
# See https://en.wikipedia.org/wiki/GUID_Partition_Table#Partition_type_GUIDs
# also https://systemd.io/BOOT_LOADER_SPECIFICATION/
GUID_EFI="c12a7328-f81f-11d2-ba4b-00a0c93ec93b"
GUID_LINUX_BOOT="bc13c2ff-59e6-4262-a352-b275fd6f7172"
# supported LVM devices and mount points for whole-disk overcloud images
MOUNTS="/dev/mapper/vg-lv_var:/var \
/dev/mapper/vg-lv_log:/var/log \
/dev/mapper/vg-lv_audit:/var/log/audit \
/dev/mapper/vg-lv_home:/home \
/dev/mapper/vg-lv_tmp:/tmp \
/dev/mapper/vg-lv_srv:/srv"
REVERSE_MOUNTS=""
for m in $MOUNTS; do
REVERSE_MOUNTS="$m $REVERSE_MOUNTS"
done
mount_show_options() {
echo "Usage: $SCRIPT_NAME"
echo
echo "Options:"
echo " -h, --help -- print this help."
echo " -a <file> -- Image file to mount."
echo " -m <directory> -- Directory to mount image to."
echo " -n <nbd device> -- NBD device to use (example, /dev/nbd0)."
echo " Defaults to first available"
echo " --chroot -- Start a working chroot which is active until exit."
echo " Directory will be unmounted on chroot exit"
echo
echo "Mount an overcloud image to a directory"
echo
exit $1
}
unmount_show_options() {
echo "Usage: $SCRIPT_NAME"
echo
echo "Options:"
echo " -h, --help -- print this help."
echo " -m <directory> -- Directory to unmount."
echo " -n <nbd device> -- NBD device to disconnect (example, /dev/nbd0)."
echo " Defaults to detected device from mounted directory"
echo
echo "Unmount a mounted overcloud image"
echo
exit $1
}
mount_volume () {
if [ -b "$1" ]; then
if [ ! -d $2 ]; then
mkdir $2
fi
mount $1 $2
fi
}
unmount_volume () {
if mountpoint "$1"; then
umount $1
fi
}
remove_device () {
if [ -b "$1" ]; then
dmsetup remove $1
fi
}
start_chroot () {
EACTION="echo Exited chroot, unmounting $MOUNT_DIR ; unmount_image"
trap "$EACTION" EXIT
mount -o bind /dev $MOUNT_DIR/dev/
EACTION="umount $MOUNT_DIR/dev/; $EACTION"
trap "$EACTION" EXIT
if [ -a $MOUNT_DIR/etc/resolv.conf ]; then
mv $MOUNT_DIR/etc/resolv.conf $MOUNT_DIR/etc/resolv.conf.tmi
EACTION="mv $MOUNT_DIR/etc/resolv.conf.tmi $MOUNT_DIR/etc/resolv.conf; $EACTION"
trap "$EACTION" EXIT
fi
cp /etc/resolv.conf $MOUNT_DIR/etc/resolv.conf
EACTION="rm $MOUNT_DIR/etc/resolv.conf; $EACTION"
trap "$EACTION" EXIT
echo "Starting chroot in $MOUNT_DIR, exit will also unmount"
PS1="[\u@chroot \W]\$ " chroot $MOUNT_DIR /bin/bash -l
}
mount_image() {
set -x
if qemu-img info --output json $IMAGE_FILE |grep '"format": "raw"' ; then
image_format='--format raw'
elif qemu-img info --output json $IMAGE_FILE |grep '"format": "qcow2"' ; then
image_format='--format qcow2'
else
image_format=''
fi
qemu-nbd $image_format --connect $NBD_DEVICE $IMAGE_FILE
# search for the vg volume group, this is automatic in some environments
vgscan
# refresh for when this script is called with different values of $NBD_DEVICE
vgchange --refresh
# activate new logical volumes, this is automatic in some environments
vgchange -ay
root_device=""
boot_device=""
efi_device=""
# wait for any sub-devices to appear
timeout 5 sh -c "while ! ls ${NBD_DEVICE}p* ; do sleep 1; done" || true
set +e
devices=$(ls ${NBD_DEVICE}p*)
set -e
device_count=$(echo $devices | wc -w)
if [ $device_count == "0" ]; then
# if there are no partition devices, assume one root device
root_device=${NBD_DEVICE}
elif [ $device_count == "1" ]; then
# if there is one partition device, assume it is the root device
root_device=${devices}
devices=""
fi
for device in ${devices}; do
lsblk --nodeps -P --output-all $device
fstype=$(lsblk --all --nodeps --noheadings --output FSTYPE $device)
label=$(lsblk --all --nodeps --noheadings --output LABEL $device)
part_type_name=$(lsblk --all --nodeps --noheadings --output PARTTYPENAME $device || echo "")
part_type=$(lsblk --all --nodeps --noheadings --output PARTTYPE $device)
if [ -z "${fstype}" ]; then
# Ignore block device with no filesystem type
continue
fi
# look for EFI partition to mount at /boot/efi
if [ -z "$efi_device" ]; then
if [[ ${part_type} == ${GUID_EFI} || ${part_type_name} == "EFI System" ]]; then
efi_device=$device
continue
fi
fi
# look for partition to mount as /boot, only the RHEL guest image is known
# to have this
if [ -z "$boot_device" ]; then
if [[ ${part_type} == ${GUID_LINUX_BOOT} || ${label} == "boot" ]]; then
boot_device=$device
continue
fi
fi
if [ -z "$root_device" ]; then
root_device=$device
continue
fi
done
if [ -z "$root_device" ]; then
echo "ERROR: No root device found to mount"
exit 1
else
if [ -b "/dev/mapper/vg-lv_root" ]; then
# a whole-disk overcloud with lvm volumes
# for example, overcloud-hardened-uefi-full.qcow2
mount /dev/mapper/vg-lv_root $MOUNT_DIR
for m in $MOUNTS; do
device=${m%:*}
path=${m#*:}
mount_volume $device $MOUNT_DIR$path
done
else
# a simple root partition
mount $root_device $MOUNT_DIR
fi
fi
if [ ! -z "$boot_device" ]; then
# mount to /boot
mount $boot_device $MOUNT_DIR/boot
fi
if [ ! -z "$efi_device" ]; then
# mount to /boot/efi
mount $efi_device $MOUNT_DIR/boot/efi
fi
}
unmount_image() {
set -x
if mountpoint "$MOUNT_DIR"; then
for m in $REVERSE_MOUNTS; do
path=${m#*:}
unmount_volume $MOUNT_DIR$path
done
unmount_volume $MOUNT_DIR/boot/efi
unmount_volume $MOUNT_DIR/boot
unmount_volume $MOUNT_DIR
fi
# `--activate n` makes LVs inactive, they must be set
# inactive so that the nbd device can be disconnected.
# Ref bug: https://bugs.launchpad.net/tripleo/+bug/1950137
vgchange --activate n vg || true
qemu-nbd --disconnect $NBD_DEVICE
vgchange --refresh vg || true
for m in $REVERSE_MOUNTS; do
device=${m%:*}
remove_device $device
done
remove_device vg-lv_root
}
if [ $SCRIPT_NAME == "tripleo-unmount-image" ]; then
TEMP=`getopt -o hm:n: -l help -n $SCRIPT_NAME -- "$@"`
if [ $? != 0 ]; then
echo "Terminating..." >&2
exit 1
fi
eval set -- "$TEMP"
while true ; do
case "$1" in
-h|--help) unmount_show_options 0 >&2;;
-m) MOUNT_DIR=$2 ; shift 2;;
-n) NBD_DEVICE=$2 ; shift 2;;
--) shift ; break;;
*) echo "Error: unsupported option $1." ; exit 1;;
esac
done
if [ -z "${MOUNT_DIR}" ]; then
unmount_show_options 1
fi
MOUNT_DIR=$(realpath ${MOUNT_DIR})
if [ -z "${NBD_DEVICE}" ]; then
for i in {0..15} ; do
device="/dev/nbd${i}"
mountpoints=$(lsblk --noheadings --output MOUNTPOINT $device)
if [[ $mountpoints =~ "$MOUNT_DIR" ]]; then
NBD_DEVICE="$device"
break
fi
done
fi
if [ -z "${NBD_DEVICE}" ]; then
echo "NBD device could not be detected from existing mounts."
echo "Specify a device with -n if an unmount is really required"
exit 1
fi
unmount_image
else
TEMP=`getopt -o ha:m:n: -l help,chroot -n $SCRIPT_NAME -- "$@"`
if [ $? != 0 ]; then
echo "Terminating..." >&2
exit 1
fi
eval set -- "$TEMP"
while true ; do
case "$1" in
-h|--help) mount_show_options 0 >&2;;
-a) IMAGE_FILE=$2 ; shift 2;;
-m) MOUNT_DIR=$2 ; shift 2;;
-n) NBD_DEVICE=$2 ; shift 2;;
--chroot) CHROOT=yes ; shift;;
--) shift ; break;;
*) echo "Error: unsupported option $1." ; exit 1;;
esac
done
if [ -z "${MOUNT_DIR}" ]; then
MOUNT_DIR=$(mktemp -d)
fi
if [ -z "${IMAGE_FILE}" ]; then
mount_show_options 1
fi
MOUNT_DIR=$(realpath ${MOUNT_DIR})
if mountpoint "${MOUNT_DIR}"; then
echo "${MOUNT_DIR} is already a mountpoint, unmount it or specify a different path"
mount_show_options 1
fi
if [ -z "${NBD_DEVICE}" ]; then
for i in {0..15} ; do
device="/dev/nbd${i}"
part_type=$(lsblk --nodeps --noheadings --output PTTYPE $device)
if [ -z "${part_type}" ]; then
NBD_DEVICE="$device"
break
fi
done
if [ -z "${NBD_DEVICE}" ]; then
echo "No NBD device is available"
exit 1
fi
fi
mount_image
if [ -n "${CHROOT}" ]; then
start_chroot
fi
fi