Skip to content

Commit c84d6e0

Browse files
Mic92Qubasa
andcommitted
Refactor kexec execution to handle sudo passwords
- Create a temporary script file that can be executed with sudo - Add proper error handling and log retrieval on failure - Support uploading kexec tarball to user's home directory when not root - Use tee to capture output to log file while showing it to user Co-authored-by: Qubasa <consulting@qube.email>
1 parent a8f4153 commit c84d6e0

File tree

1 file changed

+87
-12
lines changed

1 file changed

+87
-12
lines changed

src/nixos-anywhere.sh

Lines changed: 87 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -722,14 +722,60 @@ runKexec() {
722722
kexecUrl=${kexecUrl/"github.com"/"gh-v6.com"}
723723
fi
724724
725+
if [[ -z $remoteLogFile ]]; then
726+
abort "Could not create a temporary log file for $sshUser"
727+
fi
728+
729+
# Unified kexec error handling function
730+
handleKexecResult() {
731+
local exitCode=$1
732+
local operation=$2
733+
734+
if [[ $exitCode -eq 0 ]]; then
735+
echo "$operation completed successfully" >&2
736+
else
737+
# If operation failed, try to fetch the log file
738+
local logContent=""
739+
if logContent=$(
740+
set +x
741+
runSsh "cat \"$remoteLogFile\" 2>/dev/null" 2>/dev/null
742+
); then
743+
echo "Remote output log:" >&2
744+
echo "$logContent" >&2
745+
fi
746+
echo "$operation failed" >&2
747+
exit 1
748+
fi
749+
}
750+
725751
# Define common remote commands template
726752
local remoteCommandTemplate
727753
remoteCommandTemplate="
754+
${enableDebug:+set -x}
755+
# Create a script that we can run with sudo
756+
kexec_script_tmp=\$(mktemp /tmp/kexec-script.XXXXXX.sh)
757+
trap 'rm -f \"\$kexec_script_tmp\"' EXIT
758+
cat > \"\$kexec_script_tmp\" << 'KEXEC_SCRIPT'
759+
#!/usr/bin/env bash
728760
set -eu ${enableDebug}
729-
${maybeSudo} rm -rf /root/kexec
730-
${maybeSudo} mkdir -p /root/kexec
731-
%TAR_COMMAND%
732-
TMPDIR=/root/kexec setsid --wait ${maybeSudo} /root/kexec/kexec/run --kexec-extra-flags $(printf '%q ' "$kexecExtraFlags")
761+
rm -rf /root/kexec
762+
mkdir -p /root/kexec
763+
cd /root/kexec
764+
echo 'Downloading kexec tarball (this may take a moment)...'
765+
# Execute tar command
766+
%TAR_COMMAND% && TMPDIR=/root/kexec setsid --wait /root/kexec/kexec/run --kexec-extra-flags $(printf '%q ' "$kexecExtraFlags")
767+
KEXEC_SCRIPT
768+
769+
# Run the script and let output flow naturally
770+
${maybeSudo} bash \"\$kexec_script_tmp\" 2>&1 | tee \"$remoteLogFile\" || true
771+
# The script will likely disconnect us, so we consider it successful if we see the kexec message
772+
if grep -q 'machine will boot into nixos' \"$remoteLogFile\"; then
773+
echo 'Kexec initiated successfully'
774+
exit 0
775+
else
776+
echo 'Kexec may have failed - check output above'
777+
exit 1
778+
fi
733779
"
734780
735781
# Define upload commands
@@ -759,21 +805,50 @@ TMPDIR=/root/kexec setsid --wait ${maybeSudo} /root/kexec/kexec/run --kexec-extr
759805
localUploadCommand=(curl --fail -Ss -L "${kexecUrl}")
760806
fi
761807
762-
local tarCommand
763-
local remoteCommands
808+
# If no local upload command is defined, we use the remote command to download and execute
764809
if [[ ${#localUploadCommand[@]} -eq 0 ]]; then
765810
# Use remote command for download and execution
766-
tarCommand="$(printf '%q ' "${remoteUploadCommand[@]}") | ${maybeSudo} tar -C /root/kexec -xv ${tarDecomp}"
767-
811+
local tarCommand
812+
tarCommand="$(printf '%q ' "${remoteUploadCommand[@]}") | tar -xv ${tarDecomp}"
813+
local remoteCommands
768814
remoteCommands=${remoteCommandTemplate//'%TAR_COMMAND%'/$tarCommand}
769815
770-
runSsh sh -c "$(printf '%q' "$remoteCommands")"
816+
# Run the SSH command - for kexec with sudo, we expect it might disconnect
817+
local sshExitCode
818+
(
819+
set +x
820+
runSsh sh -c "$(printf '%q' "$remoteCommands")"
821+
)
822+
sshExitCode=$?
823+
824+
handleKexecResult $sshExitCode "Kexec"
771825
else
826+
# Why do we need $remoteHomeDir?
827+
# In the case where the ssh user is not root, we need to upload the kexec tarball
828+
# to a location where the user has write permissions. We then use sudo to run
829+
# kexec from that location.
830+
if [[ -z $remoteHomeDir ]]; then
831+
abort "Could not determine home directory for user $sshUser"
832+
fi
833+
834+
(
835+
set +x
836+
"${localUploadCommand[@]}" | runSsh "cat > \"$remoteHomeDir\"/kexec-tarball.tar.gz"
837+
)
838+
772839
# Use local command with pipe to remote
773-
tarCommand="${maybeSudo} tar -C /root/kexec -xv ${tarDecomp}"
774-
remoteCommands=${remoteCommandTemplate//'%TAR_COMMAND%'/$tarCommand}
840+
local tarCommand="cat \"$remoteHomeDir\"/kexec-tarball.tar.gz | tar -xv ${tarDecomp}"
841+
local remoteCommands=${remoteCommandTemplate//'%TAR_COMMAND%'/$tarCommand}
842+
843+
# Execute the local upload command and check for success
844+
local uploadExitCode
845+
(
846+
set +x
847+
runSsh sh -c "$(printf '%q' "$remoteCommands")"
848+
)
849+
uploadExitCode=$?
775850
776-
"${localUploadCommand[@]}" | runSsh sh -c "$(printf '%q' "$remoteCommands")"
851+
handleKexecResult $uploadExitCode "Upload"
777852
fi
778853
779854
# use the default SSH port to connect at this point

0 commit comments

Comments
 (0)