Skip to content

Commit

Permalink
Fix deployments deletion + more testing
Browse files Browse the repository at this point in the history
Added a test that creates an archlinux deployment and installs it
Adding a test for the deletion algorithm I discovered that did not work
in installer mode: fixed
Fix installing images from file
  • Loading branch information
NeroReflex committed Jun 24, 2024
1 parent 5d6f560 commit 9f49e96
Show file tree
Hide file tree
Showing 14 changed files with 416 additions and 101 deletions.
27 changes: 26 additions & 1 deletion .github/workflows/tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,35 @@ jobs:
test:

runs-on: ubuntu-latest

permissions:
contents: write
steps:
- name: Maximize build space
run: |
df -h
sudo rm -rf /usr/share/dotnet
sudo rm -rf /usr/share/swift
sudo rm -rf /usr/share/java
sudo rm -rf /usr/local/lib/android
sudo rm -rf /opt/ghc
sudo rm -rf /opt/hostedtoolcache
sudo rm -rf /opt/az
df -h
- uses: actions/checkout@v3
- name: Fix files permission
run: |
chmod +x frzr* __frzr*
- name: Run tests
run: |
cd test
./run.sh
- name: Test Deployment creation & installation
run: |
docker run --name test_deploy -u root --rm --entrypoint=/workdir/test/test-deploy.sh -v $(pwd):/workdir -v /dev:/dev --privileged archlinux:latest
- name: Test Install
run: |
docker run --name test_install -u root --rm --entrypoint=/workdir/test/test-install.sh -v $(pwd):/workdir -v /dev:/dev --privileged archlinux:latest
- name: Test Removal
run: |
docker run --name test_removal -u root --rm --entrypoint=/workdir/test/test-removal.sh -v $(pwd):/workdir -v /dev:/dev --privileged archlinux:latest
30 changes: 21 additions & 9 deletions __frzr
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ write_tracker_file() {
local running_user=$(whoami)
if [ ! -f "${TRACKER_FILE_PATH}" ]; then
touch "${TRACKER_FILE_PATH}"
chown :frzr "${TRACKER_FILE_PATH}"
chown $UID:379 "${TRACKER_FILE_PATH}"
chmod g+w "${TRACKER_FILE_PATH}"
fi

Expand Down Expand Up @@ -308,18 +308,30 @@ install_image() {

if [ -d "${deploy_path}" ]; then
if [[ "${IMG_FILE##*.}" == "img" ]]; then
btrfs receive --quiet ${DEPLOY_PATH} <${IMG_FILE}
echo "OK"
if btrfs receive --quiet "${DEPLOY_PATH}" < "${IMG_FILE}"; then
echo "OK"
else
echo "ERROR: Could not install raw image '${IMG_FILE}' to '${DEPLOY_PATH}'"
fi
elif [[ "${IMG_FILE##*.}" == "zst" ]]; then
zstd -d -c ${IMG_FILE} | btrfs receive --quiet ${DEPLOY_PATH}
echo "OK"
if zstd -d -c "${IMG_FILE}" | btrfs receive --quiet "${DEPLOY_PATH}"; then
echo "OK"
else
echo "ERROR: Could not install zstd image '${IMG_FILE}' to '${DEPLOY_PATH}'"
fi
elif [[ "${IMG_FILE##*.}" == "xz" ]]; then
if [[ "${IMG_FILE}" == *".tar.xz" ]]; then
tar xfO ${IMG_FILE} | btrfs receive --quiet ${DEPLOY_PATH}
echo "OK"
if tar xfO ${IMG_FILE} | btrfs receive --quiet "${DEPLOY_PATH}"; then
echo "OK"
else
echo "ERROR: Could not install tar.xz image '${IMG_FILE}' to '${DEPLOY_PATH}'"
fi
else
xz -dc ${IMG_FILE} | btrfs receive --quiet ${DEPLOY_PATH}
echo "OK"
if xz -dc "${IMG_FILE}" | btrfs receive --quiet "${DEPLOY_PATH}"; then
echo "OK"
else
echo "ERROR: Could not install xz image '${IMG_FILE}' to '${DEPLOY_PATH}'"
fi
fi
else
echo "ERROR: Unsupported file format for file '${IMG_FILE}'"
Expand Down
9 changes: 4 additions & 5 deletions __frzr-bootloader
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,11 @@ frzr_bootloader() {
continue
fi

MOUNT_PATH="/frzr_root"
# Make sure the frzr_root is mounted during the deployment procedure
# this code is based on the fact that when a btrfs filesystem is created
# the default subvolid that is created contextually has the ID set to 256
# also as a matter of fact in btrfs is impossible to change subvolumes IDs
if mount | grep -Fq "${MOUNT_PATH}"; then
if mount | grep -Fq "on ${MOUNT_PATH}"; then
local MOUNTED_MOUNT_PATH="no"
else
MOUNT_PATH="/tmp/frzr_root"
Expand All @@ -58,9 +57,9 @@ frzr_bootloader() {
fi

# Make sure the EFI partition is mounted during the deployment procedure
EFI_MOUNT_PATH="${MOUNT_PATH}/efi"

if mount | grep -Fq "${EFI_MOUNT_PATH}"; then
TASK_MSG="Checking for EFI partition"
send_data
if mount | grep -Fq "on ${EFI_MOUNT_PATH}"; then
local MOUNTED_EFI_MOUNT_PATH="no"
else
mkdir -p "${EFI_MOUNT_PATH}"
Expand Down
43 changes: 27 additions & 16 deletions __frzr-bootstrap
Original file line number Diff line number Diff line change
Expand Up @@ -168,8 +168,8 @@ fresh_install() {
local root_part=$(fdisk -o Device --list ${disk} | grep "^${disk}.*${ROOT_PART_NUMBER}$")
mkfs.btrfs -L frzr_root -f ${root_part}
local root_uuid=$(blkid -s UUID -o value "${root_part}")
mount ${root_part} ${frzr_root} # mount rootfs
mkdir -p ${frzr_root}/efi # prepare to mount vfat
mount -t btrfs -o compress-force=zstd:15 "${root_part}" "${frzr_root}" # mount rootfs
mkdir -p "${frzr_root}/efi" # prepare to mount vfat
#echo "${root_uuid}" > "${frzr_root}/root_uuid"
btrfs subvolume create ${frzr_root}/var
mkdir -p "${frzr_root}/etc"
Expand Down Expand Up @@ -264,29 +264,40 @@ frzr_bootstrap() {

echo "Checking for drives connected to the system"
MOUNT_PATH=/tmp/frzr_root
device_list=()
device_output=$(lsblk --list -n -o name,model,size,type | grep disk | tr -s ' ' '\t')
while read -r line; do
name=/dev/$(echo "$line" | cut -f 1)
model=$(echo "$line" | cut -f 2)
size=$(echo "$line" | cut -f 3)
device_list+=($name)
device_list+=("$model ($size)")
done <<<"$device_output"
DISK=$(whiptail --nocancel --menu "Choose a disk to install to:" 20 50 5 "${device_list[@]}" 3>&1 1>&2 2>&3)
if [ -z "${DISK}" ]; then
device_list=()
device_output=$(lsblk --list -n -o name,model,size,type | grep disk | tr -s ' ' '\t')
while read -r line; do
name=/dev/$(echo "$line" | cut -f 1)
model=$(echo "$line" | cut -f 2)
size=$(echo "$line" | cut -f 3)
device_list+=($name)
device_list+=("$model ($size)")
done <<<"$device_output"
DISK=$(whiptail --nocancel --menu "Choose a disk to install to:" 20 50 5 "${device_list[@]}" 3>&1 1>&2 2>&3)
else
echo "specified disk is '$DISK'"
fi
echo "Checking for existing FRZR deployments"
# Checking for existing installation

if (lsblk -o label ${DISK} | grep -q frzr_efi); then
echo "Existing installation found"

if (whiptail --yesno --yes-button "Repair" --no-button "Clean" "WARNING: $DISK appears to already have a system installed. Would you like to repair it or do a clean install?\n\nNOTE: A clean install will delete everything on the disk, but a repair install will preserve your user data." 13 70); then
echo "User chose to do a repair install"
if [ "$REPAIR_INSTALL" = "1"]; then
REPAIR_INSTALL=1
STATE="REPAIR"
else
echo "User chose to do a clean install"
elif [ "$REPAIR_INSTALL" = "0"]; then
STATE="FORMAT"
else
if (whiptail --yesno --yes-button "Repair" --no-button "Clean" "WARNING: $DISK appears to already have a system installed. Would you like to repair it or do a clean install?\n\nNOTE: A clean install will delete everything on the disk, but a repair install will preserve your user data." 13 70); then
echo "User chose to do a repair install"
REPAIR_INSTALL=1
STATE="REPAIR"
else
echo "User chose to do a clean install"
STATE="FORMAT"
fi
fi
else
echo "Existing installation not found"
Expand Down
100 changes: 58 additions & 42 deletions __frzr-deploy
Original file line number Diff line number Diff line change
Expand Up @@ -38,16 +38,19 @@ frzr_deploy() {
continue
fi

TASK_MSG="Checking if the system has booted via UEFI"
send_data
check_uefi_result=$(check_uefi)
if echo "${check_uefi_result}" | grep -Fq 'ERROR'; then
TASK_ERROR=1
TASK_ERROR_MSG="UEFI boot check failed: ${check_uefi_result}"
STATE="FAIL"
send_data
continue
fi
# Since this code is tested in GitHub CI it is important to to disable the UEFI test in that scenario
if [ -z "${SKIP_UEFI_CHECK}" ]; then
TASK_MSG="Checking if the system has booted via UEFI"
send_data
check_uefi_result=$(check_uefi)
if echo "${check_uefi_result}" | grep -Fq 'ERROR'; then
TASK_ERROR=1
TASK_ERROR_MSG="UEFI boot check failed: ${check_uefi_result}"
STATE="FAIL"
send_data
continue
fi
fi

# Check if any updates are available and preserve FRZR parameters
while (("$#")); do
Expand Down Expand Up @@ -75,8 +78,8 @@ frzr_deploy() {

# keep only the first param as source
FRZR_SOURCE="${FRZR_PARAMS%% *}"
if frzr-release > /dev/null; then
CURRENT=`frzr-release`
if "${BASH_SOURCE%/*}/frzr-release" > /dev/null; then
CURRENT=$("${BASH_SOURCE%/*}/frzr-release")
fi

STATE="BEGIN"
Expand All @@ -85,7 +88,7 @@ frzr_deploy() {
TASK_STATE="BEGIN"
send_data

local version=$(frzr-version)
local version=$("${BASH_SOURCE%/*}/frzr-version")
if echo "${version}" | grep -Fq "ERROR"; then
TASK_ERROR=1
TASK_ERROR_MSG="Could not fetch frzr version: ${version}"
Expand All @@ -98,8 +101,7 @@ frzr_deploy() {
# this code is based on the fact that when a btrfs filesystem is created
# the default subvolid that is created contextually has the ID set to 256
# also as a matter of fact in btrfs is impossible to change subvolumes IDs
MOUNT_PATH="/frzr_root"
if mount | grep -Fq "${MOUNT_PATH}"; then
if mount | grep -Fq "on ${MOUNT_PATH}"; then
local MOUNTED_MOUNT_PATH="no"
else
MOUNT_PATH="/tmp/frzr_root"
Expand Down Expand Up @@ -135,12 +137,9 @@ frzr_deploy() {
fi

# Make sure the EFI partition is mounted during the deployment procedure
EFI_MOUNT_PATH="${MOUNT_PATH}/efi"

TASK_MSG="Preparing '${EFI_MOUNT_PATH}' to be used as the EFI System path"
send_data

if mount | grep -Fq "${EFI_MOUNT_PATH}"; then
if mount | grep -Fq "on ${EFI_MOUNT_PATH}"; then
local MOUNTED_EFI_MOUNT_PATH="no"
else
mkdir -p "${EFI_MOUNT_PATH}"
Expand Down Expand Up @@ -170,7 +169,6 @@ frzr_deploy() {
TASK_WARNING=1
TASK_WARNING_MSG="Could not retrieve deployment to keep: ${CURRENT}"
send_data
continue
fi

local default_btrfs_subvolid_cmd_res=$(btrfs subvolume get-default "${MOUNT_PATH}")
Expand All @@ -182,7 +180,7 @@ frzr_deploy() {
local removal_deployment=$(basename "${deployment_to_be_removed}")
local removal_deployment_subvolid=$(btrfs_subvol_get_id "${deployment_to_be_removed}")

if echo "${removal_deployment}" | grep -Fq "${CURRENT}"; then
if echo "${removal_deployment}" | grep -Fq "${CURRENT}" && ! echo "${CURRENT}" | grep -Fq "ERROR"; then
TASK_MSG="Deployment '${removal_deployment}' will be kept: is the current deployment"
send_data
elif echo "${removal_deployment_subvolid}" | grep -Fq "ERROR"; then
Expand Down Expand Up @@ -212,16 +210,18 @@ frzr_deploy() {
done

# Execute deployment removal scripts
TASK_MSG="Executing removal hooks"
send_data
local deployment_removal_hooks=$(execute_removal "${removal_deployment}" "${deployment_to_be_removed}" "${MOUNT_PATH}" "${version}")
if echo "${deployment_removal_hooks}" | grep -Fq "ERROR"; then
TASK_ERROR=1
TASK_ERROR_MSG="Removal hook on subvolume '${deployment_to_be_removed}' failed: ${deployment_removal_hooks}"
STATE="FAIL"
send_data
continue
fi
if [ -d "${deployment_to_be_removed}/usr/lib/frzr.d" ]; then
TASK_MSG="Executing removal hooks"
send_data
local deployment_removal_hooks=$(execute_removal "${removal_deployment}" "${deployment_to_be_removed}" "${MOUNT_PATH}" "${version}")
if echo "${deployment_removal_hooks}" | grep -Fq "ERROR"; then
TASK_ERROR=1
TASK_ERROR_MSG="Removal hook on subvolume '${deployment_to_be_removed}' failed: ${deployment_removal_hooks}"
STATE="FAIL"
send_data
continue
fi
fi

# Delete the deployment btrfs subvolume
local deployment_removal_result=$(btrfs_subvolume_simple_delete "${DEPLOY_PATH}/${removal_deployment}")
Expand Down Expand Up @@ -270,6 +270,11 @@ frzr_deploy() {
NAME=$(echo "${FILE_NAME}" | cut -f 1 -d '.')
SUBVOL="${DEPLOY_PATH}/${NAME}"
IMG_FILE="${FRZR_SOURCE}"
elif [[ "$FRZR_SOURCE" == *".img.xz" ]]; then
FILE_NAME=$(basename ${FRZR_SOURCE})
NAME=$(echo "${FILE_NAME}" | cut -f 1 -d '.')
SUBVOL="${DEPLOY_PATH}/${NAME}"
IMG_FILE="${FRZR_SOURCE}"
elif [[ "$FRZR_SOURCE" == *".img" ]]; then
FILE_NAME=$(basename ${FRZR_SOURCE})
NAME=$(echo "${FILE_NAME}" | cut -f 1 -d '.')
Expand Down Expand Up @@ -361,21 +366,32 @@ frzr_deploy() {
STATE="CHECKSUM"
;;
"CHECKSUM")
# If the image is a local one try to fetch its sha256sum
if [ -z "$EXPECTED_CHECKSUM" ] && [ -f "${IMG_FILE}.sha256" ]; then
EXPECTED_CHECKSUM=$(cat "${IMG_FILE}.sha256")
fi

TASK_STATE="CHECKSUM"
TASK_MSG="Verifying if checksums match"
send_data
ACTUAL_CHECKSUM=$(sha256sum "${IMG_FILE}" | cut -d' ' -f 1)
if [ "$EXPECTED_CHECKSUM" != "$ACTUAL_CHECKSUM" ]; then
rm -f "${IMG_FILE}"

# We can attempt to redownload the image again here instead of aborting like the original behavior
TASK_ERROR=1
TASK_ERROR_MSG="Checksum does not match"
STATE="FAIL"
if [ ! -z "$EXPECTED_CHECKSUM" ]; then
if [ "$EXPECTED_CHECKSUM" != "$ACTUAL_CHECKSUM" ]; then
rm -f "${IMG_FILE}"

# We can attempt to redownload the image again here instead of aborting like the original behavior
TASK_ERROR=1
TASK_ERROR_MSG="Checksum does not match"
STATE="FAIL"
send_data
continue
fi
else
TASK_WARNING=1
TASK_WARNING_MSG="Could not fetch the deployment checksum"
send_data
continue
fi
TASK_TRACKER=1 # Tell any listeners this task was completed, I'm not sure this variable will be needed in the end
fi
TASK_TRACKER=1 # Tell any listeners this task was completed, I'm not sure this variable will be needed in the end
send_data

STATE="EXTRACT"
Expand Down Expand Up @@ -489,7 +505,7 @@ frzr_deploy() {
send_data

# This is used to update the EFI partition: setting up systemd-boot (or whatever else bootlader might be supported) to boot the new deployment
local efi_update_result=$(frzr-bootloader "${NAME}")
local efi_update_result=$("${BASH_SOURCE%/*}/frzr-bootloader" "${NAME}")
if echo "${efi_update_result}" | grep -Fq 'ERROR'; then
# bootloader configuration could not be updated
TASK_ERROR=1
Expand Down
19 changes: 15 additions & 4 deletions __frzr-envars
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,26 @@ if [ -z $TARGET ]; then
TARGET="" # Set to the target deployment channel. This should only be set by the installer script
fi

if [ -z $LOCAL_INSTALL ]; then
if [ -z "$LOCAL_INSTALL" ]; then
LOCAL_INSTALL=0 # Set to 1 to perform a local media install. This should be set by the installer script
fi

UPGRADE=0
REPAIR_INSTALL=0 # Set to 1 if you want to do a repair install. This should be set by frzr-bootstrap later if an existing install is found.

if [ -z "$REPAIR_INSTALL" ]; then
REPAIR_INSTALL=0 # Set to 1 if you want to do a repair install. This should be set by frzr-bootstrap later if an existing install is found.
fi

NAME="" # Name of the OS to be deployed
EFI_MOUNT_PATH="" # EFI mount path
MOUNT_PATH="" # This is set as /tmp/frzr_root/ in the installer and /frzr_root during upgrades

if [ -z "$MOUNT_PATH" ]; then
MOUNT_PATH="/frzr_root" # This is set as /tmp/frzr_root/ in the installer and /frzr_root during upgrades
fi

if [ -z "$EFI_MOUNT_PATH" ]; then
EFI_MOUNT_PATH="${MOUNT_PATH}/efi" # EFI mount path
fi

SUBVOL=""
DEPLOY_PATH="" # ${MOUNT_PATH}/deployments
FRZR_CHECK_UPDATE=0
Expand Down
Loading

0 comments on commit 9f49e96

Please sign in to comment.