Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue 2247: draft implementation of 'mountonly' workflow. #2269

Merged
merged 6 commits into from Nov 26, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
104 changes: 104 additions & 0 deletions doc/user-guide/04-scenarios.adoc
Expand Up @@ -1331,3 +1331,107 @@ Finished recovering your system. You can explore it under '/mnt/local'.

Finished in 361 seconds.
----

== Using ReaR to mount and repair your system
Instead of using your ReaR image to completely recover your system from bare
metal (as illustrated in most of the above scenarios), you can also use it
as a live media to boot a broken but hopefully repairable system.

Once booted on your recovery image, the `mountonly` workflow will:

* activate all Volume Groups

* offer to decrypt any LUKS-encrypted filesystem that may be present

* mount all the target filesystems (including the most important virtual
ones) below `/mnt/local`

thereby making it possible for you to explore your system at will,
correcting any configuration mistake that may have prevented its startup,
or allowing you to simply `chroot` into it and further repair it using its
own administrative tools.

One important point to remember is that the `mountonly` workflow on its own
won't modify the target system in any way. Of course, once the target
petroniusniger marked this conversation as resolved.
Show resolved Hide resolved
filesystems are mounted you, as the administrator, may decide to do so
manually.

**Beware:** The `mountonly` workflow can only be used on the system where
the rescue image was generated, as it bases its logic on the filesystem
layout description file generated during the run of the `mkrescue` or
`mkbackup` workflows.

Here are the steps you would typically follow:

=== Create your recovery image
Using any of the techniques described in the other scenarios, create a
ReaR recovery image for your system (through `rear mkrescue` or `rear
mkbackup`). If you only take the `mountonly` workflow into consideration, it
doesn't matter whether you also make a backup of your system or not
(obviously, you'd better cover all your bases and make sure you'd be able to
perform a full `recover` as well should the need occur).

Please note, that by default ReaR only includes in the recovery image the
tools it will need to recover the system. If you anticipate the need for
some extra tools in the context of a repair operation (e.g. tools that you
might need in the event `chroot`ing into the target system doesn't work), you
should make sure to include them in your recovery image by adding to the
`PROGS` or `REQUIRED_PROGS` configuration variables (please refer to the
comments in `default.conf` for the exact meaning of each).

=== Booting on the recovery image
Arrange for the target system to boot on your recovery image as you would in
any of the other scenarios.

=== Launching the "mount only" workflow
Issue the `rear mountonly` command to launch the workflow (that one is always
verbose):

----
RESCUE pc-pan:~ # rear mountonly
Relax-and-Recover 2.5 / Git
Running rear mountonly (PID 625)
Using log file: /var/log/rear/rear-pc-pan.log
Running workflow mountonly within the ReaR rescue/recovery system
Comparing disks
Device sda has expected (same) size 34359738368 (will be used for 'mountonly')
Disk configuration looks identical
Proceed with 'mountonly' (yes) otherwise manual disk layout configuration is enforced
(default 'yes' timeout 30 seconds)
yes
User confirmed to proceed with 'mountonly'
Start target system mount.
Mounting filesystem /
Mounting filesystem /home
Mounting filesystem /boot/efi
Please enter the password for LUKS device cr_vg00-lvol4 (/dev/mapper/vg00-lvol4):
Enter passphrase for /dev/mapper/vg00-lvol4:
Mounting filesystem /products
Disk layout processed.
Finished 'mountonly'. The target system is mounted at '/mnt/local'.
Exiting rear mountonly (PID 625) and its descendant processes ...
Running exit tasks
----

As you can see in the output above, you will first be asked to confirm
running the workflow (`Proceed with 'mountonly'`) -- simply press return.
All the target filesystems should now be mounted below `/mnt/local` (including
LUKS-encrypted ones if present and all needed virtual ones). In case any of
them fails to mount, you will be offered to review the mount script and to
re-execute it if needed.

Once the system is in the desired state, you can start exploring it, correcting
any configuration mistake or filesystem corruption that prevented it from
booting properly. In this state, the only tools at your disposal are those
included by default in ReaR recovery image, or those you saw fit to add
yourself (see above).

If this is not enough and you need to run the native administrative tools
hosted inside your target system (such as YaST in the case of SUSE
distributions), you are now in a position where you can `chroot` inside
your system to reach them (`chroot /mnt/local`).

=== Closing the session
Once done, don't forget to leave the `chroot` environment if applicable
(Ctrl-D), then issue the `shutdown` command. This will ensure that all the
target filesystems will be cleanly unmounted before the system is restarted.
2 changes: 1 addition & 1 deletion usr/sbin/rear
Expand Up @@ -236,7 +236,7 @@ ARGS=( "$@" )

# The following workflows are always verbose:
case "$WORKFLOW" in
(validate|shell|recover)
(validate|shell|recover|mountonly)
petroniusniger marked this conversation as resolved.
Show resolved Hide resolved
VERBOSE=1
;;
esac
Expand Down
1 change: 1 addition & 0 deletions usr/share/rear/check/GNU
1 change: 1 addition & 0 deletions usr/share/rear/check/default
1 change: 1 addition & 0 deletions usr/share/rear/final-mount/default/900_remount_sync.sh
4 changes: 2 additions & 2 deletions usr/share/rear/finalize/default/900_remount_sync.sh
Expand Up @@ -14,8 +14,8 @@
# scripts that do umount plus sync to safely shut down the recovery system,
# cf. https://github.com/rear/rear/pull/1011

# Skip if not recover WORKFLOW:
test "recover" = "$WORKFLOW" || return 0
# Skip if not 'recover' or 'mountonly' WORKFLOW:
test "recover" = "$WORKFLOW" -o "mountonly" = "$WORKFLOW" || return 0

# Skip if systemd is used
# systemctl gets copied into the recovery system as /bin/systemctl:
Expand Down
3 changes: 2 additions & 1 deletion usr/share/rear/init/default/050_check_rear_recover_mode.sh
@@ -1,5 +1,6 @@
# In the ReaR rescue/recovery system the only possible workflows are
# - 'recover' and its partial workflows 'layoutonly' 'restoreonly' 'finalizeonly'
# - 'mountonly'
# - 'opaladmin'
# - 'help'
# cf. https://github.com/rear/rear/issues/987
Expand All @@ -8,7 +9,7 @@
# In the ReaR rescue/recovery system /etc/rear-release is unique (it does not exist otherwise):
test -f /etc/rear-release || return 0
case "$WORKFLOW" in
(recover|layoutonly|restoreonly|finalizeonly|opaladmin|help)
(recover|layoutonly|restoreonly|finalizeonly|mountonly|opaladmin|help)
LogPrint "Running workflow $WORKFLOW within the ReaR rescue/recovery system"
;;
(*)
Expand Down
1 change: 1 addition & 0 deletions usr/share/rear/layout/do-mount/default/250_verify_mount.sh
@@ -0,0 +1,69 @@
# Use the dependencies to order device processing and generate code for them.

# LAYOUT_CODE is the script to mount the target system based on its disk
# layout (diskrestore.sh).

save_original_file "$LAYOUT_CODE"

# Initialize diskrestore.sh:
cat <<EOF >"$LAYOUT_CODE"
#!/bin/bash

# Create "breadcrumb" file (used as interlock by other workflows),
# defined and checked by ./setup/default/002_clean_start.sh
echo "$WORKFLOW" > $BREADCRUMB

LogPrint "Start target system mount."

mkdir -p $TARGET_FS_ROOT
if create_component "vgchange" "rear" ; then
lvm vgchange -a y >/dev/null
component_created "vgchange" "rear"
fi

set -e
set -x

EOF

# Populate diskrestore.sh with further code to (re)-mount all disk layout components:
all_done=
while [ -z "$all_done" ] ; do
# Cycle through all components and find one that can be mounted.
willdodev=
willdotype=

cp "$LAYOUT_TODO" "${LAYOUT_TODO}.tmp"
while read status thisdev type; do
# Test if all dependencies are already created.
Debug "Testing $thisdev for dependencies..."
deps=($(grep "^$thisdev\ " "$LAYOUT_DEPS" | cut -d " " -f "2"))
Debug "deps (${#deps[@]}): ${deps[*]}"

donedeps=0
for dep in "${deps[@]}" ; do
if grep -q "done $dep " "$LAYOUT_TODO.tmp"; then
let donedeps++
fi
done

if [ ${#deps[@]} -eq $donedeps ] ; then
Debug "All dependencies for $thisdev are present, processing..."
willdodev="$thisdev"
willdotype="$type"
break
fi
done < <(grep "^todo" "$LAYOUT_TODO")
rm "$LAYOUT_TODO.tmp"

# Write the code to mount a device.
if [ -n "$willdodev" ] ; then
do_mount_device "$willdodev" "$willdotype"

mark_as_done "$willdodev"
else
# No device to be mounted, no additional dependencies can be satisfied.
all_done="y"
fi

done
@@ -0,0 +1,10 @@
# Add final information to the script.

cat >> $LAYOUT_CODE <<EOF

set +x
set +e

LogPrint "Disk layout processed."

EOF
@@ -0,0 +1,58 @@

# Warn about missing components and for each missing component
# offer the user a way to manually add code that mounts it.

rear_workflow="rear $WORKFLOW"
rear_shell_history="$( echo -e "vi $LAYOUT_CODE\nless $LAYOUT_CODE" )"

unset choices
choices[0]="View $LAYOUT_CODE"
choices[1]="Edit $LAYOUT_CODE"
choices[2]="Go to Relax-and-Recover shell"
choices[3]="Continue '$rear_workflow'"
choices[4]="Abort '$rear_workflow'"

while read status name type junk ; do
missing_component="$name ($type)"
LogUserOutput "No code has been generated to mount $missing_component."
LogUserOutput "To mount $missing_component manually add code to $LAYOUT_CODE or abort."
while true ; do
# The default user input is "Continue" to make it possible to run ReaR unattended
# so that 'rear mountonly' proceeds after the timeout regardless that it probably fails
# when the component is not recreated but perhaps it could succeed in migration mode
# on different replacement hardware where it might be even right to simply "Continue".
# Generate a runtime-specific user_input_ID so that for each missing component
# a different user_input_ID is used for the UserInput call so that the user can specify
# for each missing component a different predefined user input.
# Only uppercase letters and digits are used to ensure the user_input_ID is a valid bash variable name
# (otherwise the UserInput call could become invalid which aborts 'rear mountonly' with a BugError) and
# hopefully only uppercase letters and digits are sufficient to distinguish different missing components:
current_missing_component_alnum_uppercase="$( echo "$missing_component" | tr -d -c '[:alnum:]' | tr '[:lower:]' '[:upper:]' )"
test "$current_missing_component_alnum_uppercase" || current_missing_component_alnum_uppercase="COMPONENT"
user_input_ID="ADD_CODE_TO_RECREATE_MISSING_$current_missing_component_alnum_uppercase"
case "$( UserInput -I $user_input_ID -p "Manually add code that mounts $missing_component" -D "${choices[3]}" "${choices[@]}" )" in
(${choices[0]})
# Run 'less' with the original STDIN STDOUT and STDERR when 'rear' was launched by the user:
less $LAYOUT_CODE 0<&6 1>&7 2>&8
;;
(${choices[1]})
# Run 'vi' with the original STDIN STDOUT and STDERR when 'rear' was launched by the user:
vi $LAYOUT_CODE 0<&6 1>&7 2>&8
;;
(${choices[2]})
# rear_shell runs 'bash' with the original STDIN STDOUT and STDERR when 'rear' was launched by the user:
rear_shell "" "$rear_shell_history"
;;
(${choices[3]})
# Continue with the next missing component:
break
;;
(${choices[4]})
abort_recreate
Error "User chose to abort '$rear_workflow' in ${BASH_SOURCE[0]}"
;;
# No default case is needed here because the 'while true' loop repeats for invalid user input.
esac
done
done < <(grep "^todo" "$LAYOUT_TODO")