0366b14d0b
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
343 lines
10 KiB
Bash
Executable File
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
|