From a0f6a6633f8df8165de6c8b68d26e1a314bed10d Mon Sep 17 00:00:00 2001 From: Lars Eggert Date: Wed, 17 Apr 2024 12:14:24 +0300 Subject: [PATCH] Try and prevent running out of disk space --- .../actions/maximize-build-space/action.yml | 206 ++++++++++++++++++ .github/workflows/firefox.yml | 3 + 2 files changed, 209 insertions(+) create mode 100644 .github/actions/maximize-build-space/action.yml diff --git a/.github/actions/maximize-build-space/action.yml b/.github/actions/maximize-build-space/action.yml new file mode 100644 index 0000000000..c9ada92815 --- /dev/null +++ b/.github/actions/maximize-build-space/action.yml @@ -0,0 +1,206 @@ +# https://github.com/easimon/maximize-build-space/blob/fadc013e293a3453768b4ddb9db8c85104752807/action.yml + +name: 'Maximize build disk space' +description: 'Maximize the available disk space for your build job' +branding: + icon: 'crop' + color: 'orange' +inputs: + root-reserve-mb: + description: 'Space to be left free on the root filesystem, in Megabytes.' + required: false + default: '1024' + temp-reserve-mb: + description: 'Space to be left free on the temp filesystem (/mnt), in Megabytes.' + required: false + default: '100' + swap-size-mb: + description: 'Swap space to create, in Megabytes.' + required: false + default: '4096' + overprovision-lvm: + description: | + Create the LVM disk images as sparse files, making the space required for the LVM image files *appear* unused on the + hosting volumes until actually allocated. Use with care, this can lead to surprising out-of-disk-space situations. + You should prefer adjusting root-reserve-mb/temp-reserve-mb over using this option. + required: false + default: 'false' + build-mount-path: + description: 'Absolute path to the mount point where the build space will be available, defaults to $GITHUB_WORKSPACE if unset.' + required: false + build-mount-path-ownership: + description: 'Ownership of the mount point path, defaults to standard "runner" user and group.' + required: false + default: 'runner:runner' + pv-loop-path: + description: 'Absolute file path for the LVM image created on the root filesystem, the default is usually fine.' + required: false + default: '/pv.img' + tmp-pv-loop-path: + description: 'Absolute file path for the LVM image created on the temp filesystem, the default is usually fine. Must reside on /mnt' + required: false + default: '/mnt/tmp-pv.img' + remove-dotnet: + description: 'Removes .NET runtime and libraries. (frees ~17 GB)' + required: false + default: 'false' + remove-android: + description: 'Removes Android SDKs and Tools. (frees ~11 GB)' + required: false + default: 'false' + remove-haskell: + description: 'Removes GHC (Haskell) artifacts. (frees ~2.7 GB)' + required: false + default: 'false' + remove-codeql: + description: 'Removes CodeQL Action Bundles. (frees ~5.4 GB)' + required: false + default: 'false' + remove-docker-images: + description: 'Removes cached Docker images. (frees ~3 GB)' + required: false + default: 'false' +runs: + using: "composite" + steps: + - name: Disk space report before modification + shell: bash + run: | + echo "Memory and swap:" + sudo free + echo + sudo swapon --show + echo + + echo "Available storage:" + sudo df -h + echo + + - name: Maximize build disk space + shell: bash + run: | + set -euo pipefail + + BUILD_MOUNT_PATH="${{ inputs.build-mount-path }}" + if [[ -z "${BUILD_MOUNT_PATH}" ]]; then + BUILD_MOUNT_PATH="${GITHUB_WORKSPACE}" + fi + + echo "Arguments:" + echo + echo " Root reserve: ${{ inputs.root-reserve-mb }} MiB" + echo " Temp reserve: ${{ inputs.temp-reserve-mb }} MiB" + echo " Swap space: ${{ inputs.swap-size-mb }} MiB" + echo " Overprovision LVM: ${{ inputs.overprovision-lvm }}" + echo " Mount path: ${BUILD_MOUNT_PATH}" + echo " Root PV loop path: ${{ inputs.pv-loop-path }}" + echo " Temp PV loop path: ${{ inputs.tmp-pv-loop-path }}" + echo -n " Removing: " + if [[ ${{ inputs.remove-dotnet }} == 'true' ]]; then + echo -n "dotnet " + fi + if [[ ${{ inputs.remove-android }} == 'true' ]]; then + echo -n "android " + fi + if [[ ${{ inputs.remove-haskell }} == 'true' ]]; then + echo -n "haskell " + fi + if [[ ${{ inputs.remove-codeql }} == 'true' ]]; then + echo -n "codeql " + fi + if [[ ${{ inputs.remove-docker-images }} == 'true' ]]; then + echo -n "docker " + fi + echo + + # store owner of $GITHUB_WORKSPACE in case the action deletes it + WORKSPACE_OWNER="$(stat -c '%U:%G' "${GITHUB_WORKSPACE}")" + + # ensure mount path exists before the action + sudo mkdir -p "${BUILD_MOUNT_PATH}" + sudo find "${BUILD_MOUNT_PATH}" -maxdepth 0 ! -empty -exec echo 'WARNING: directory [{}] is not empty, data loss might occur. Content:' \; -exec ls -al "{}" \; + + echo "Removing unwanted software... " + if [[ ${{ inputs.remove-dotnet }} == 'true' ]]; then + sudo rm -rf /usr/share/dotnet + fi + if [[ ${{ inputs.remove-android }} == 'true' ]]; then + sudo rm -rf /usr/local/lib/android + fi + if [[ ${{ inputs.remove-haskell }} == 'true' ]]; then + sudo rm -rf /opt/ghc + fi + if [[ ${{ inputs.remove-codeql }} == 'true' ]]; then + sudo rm -rf /opt/hostedtoolcache/CodeQL + fi + if [[ ${{ inputs.remove-docker-images }} == 'true' ]]; then + sudo docker image prune --all --force + fi + echo "... done" + + VG_NAME=buildvg + + # github runners have an active swap file in /mnt/swapfile + # we want to reuse the temp disk, so first unmount swap and clean the temp disk + echo "Unmounting and removing swap file." + sudo swapoff -a + sudo rm -f /mnt/swapfile + + echo "Creating LVM Volume." + echo " Creating LVM PV on root fs." + # create loop pv image on root fs + ROOT_RESERVE_KB=$(expr ${{ inputs.root-reserve-mb }} \* 1024) + ROOT_FREE_KB=$(df --block-size=1024 --output=avail / | tail -1) + ROOT_LVM_SIZE_KB=$(expr $ROOT_FREE_KB - $ROOT_RESERVE_KB) + ROOT_LVM_SIZE_BYTES=$(expr $ROOT_LVM_SIZE_KB \* 1024) + sudo touch "${{ inputs.pv-loop-path }}" && sudo fallocate -z -l "${ROOT_LVM_SIZE_BYTES}" "${{ inputs.pv-loop-path }}" + export ROOT_LOOP_DEV=$(sudo losetup --find --show "${{ inputs.pv-loop-path }}") + sudo pvcreate -f "${ROOT_LOOP_DEV}" + + # create pv on temp disk + echo " Creating LVM PV on temp fs." + TMP_RESERVE_KB=$(expr ${{ inputs.temp-reserve-mb }} \* 1024) + TMP_FREE_KB=$(df --block-size=1024 --output=avail /mnt | tail -1) + TMP_LVM_SIZE_KB=$(expr $TMP_FREE_KB - $TMP_RESERVE_KB) + TMP_LVM_SIZE_BYTES=$(expr $TMP_LVM_SIZE_KB \* 1024) + sudo touch "${{ inputs.tmp-pv-loop-path }}" && sudo fallocate -z -l "${TMP_LVM_SIZE_BYTES}" "${{ inputs.tmp-pv-loop-path }}" + export TMP_LOOP_DEV=$(sudo losetup --find --show "${{ inputs.tmp-pv-loop-path }}") + sudo pvcreate -f "${TMP_LOOP_DEV}" + + # create volume group from these pvs + sudo vgcreate "${VG_NAME}" "${TMP_LOOP_DEV}" "${ROOT_LOOP_DEV}" + + echo "Recreating swap" + # create and activate swap + sudo lvcreate -L "${{ inputs.swap-size-mb }}M" -n swap "${VG_NAME}" + sudo mkswap "/dev/mapper/${VG_NAME}-swap" + sudo swapon "/dev/mapper/${VG_NAME}-swap" + + echo "Creating build volume" + # create and mount build volume + sudo lvcreate -l 100%FREE -n buildlv "${VG_NAME}" + if [[ ${{ inputs.overprovision-lvm }} == 'true' ]]; then + sudo mkfs.ext4 -m0 "/dev/mapper/${VG_NAME}-buildlv" + else + sudo mkfs.ext4 -Enodiscard -m0 "/dev/mapper/${VG_NAME}-buildlv" + fi + sudo mount "/dev/mapper/${VG_NAME}-buildlv" "${BUILD_MOUNT_PATH}" + sudo chown -R "${{ inputs.build-mount-path-ownership }}" "${BUILD_MOUNT_PATH}" + + # if build mount path is a parent of $GITHUB_WORKSPACE, and has been deleted, recreate it + if [[ ! -d "${GITHUB_WORKSPACE}" ]]; then + sudo mkdir -p "${GITHUB_WORKSPACE}" + sudo chown -R "${WORKSPACE_OWNER}" "${GITHUB_WORKSPACE}" + fi + + - name: Disk space report after modification + shell: bash + run: | + echo "Memory and swap:" + sudo free + echo + sudo swapon --show + echo + + echo "Available storage:" + sudo df -h diff --git a/.github/workflows/firefox.yml b/.github/workflows/firefox.yml index b3eda4dd08..c6833de5d0 100644 --- a/.github/workflows/firefox.yml +++ b/.github/workflows/firefox.yml @@ -19,6 +19,9 @@ jobs: MOZBUILD_STATE_PATH: ${{ github.workspace }}/mozbuild steps: + - name: Maximize buld space + uses: ./.github/actions/maximize-build-space + - name: Checkout Neqo uses: actions/checkout@v4