diff --git a/.github/workflows/cache.yml b/.github/workflows/cache.yml new file mode 100644 index 0000000..e03de2c --- /dev/null +++ b/.github/workflows/cache.yml @@ -0,0 +1,321 @@ +name: with actions_cache +on: + push: + pull_request: + schedule: + - cron: '21 6 * * *' + +env: + CVMFS_CACHE_BASE: ~/.cvmfs-cache + +jobs: + populate-cache: + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v6 + - uses: ./ + with: + actions_cache: 'true' + cvmfs_cache_base: ${{ env.CVMFS_CACHE_BASE }} + cvmfs_repositories: 'sft.cern.ch' + - name: Diagnose workspace and cache base access before first access + run: | + cache_parent=$(dirname "${{ env.CVMFS_CACHE_BASE }}") + echo "### Compare workspace and cache path ancestry ###" + namei -l "${{ github.workspace }}" || true + namei -l "${cache_parent}" || true + namei -l "${{ env.CVMFS_CACHE_BASE }}" || true + echo "### Check action-prepared cache base permissions ###" + id + getent passwd cvmfs + ls -ld "${{ github.workspace }}" "${cache_parent}" "${{ env.CVMFS_CACHE_BASE }}" + test -r "${{ env.CVMFS_CACHE_BASE }}" + test -w "${{ env.CVMFS_CACHE_BASE }}" + sudo -u cvmfs test -w "${{ env.CVMFS_CACHE_BASE }}" + - name: Populate CernVM-FS cache + run: | + echo "### Dump default.local ###" + cat /etc/cvmfs/default.local + echo "### Check configured cache base ###" + grep "CVMFS_CACHE_BASE='${{ env.CVMFS_CACHE_BASE }}'" /etc/cvmfs/default.local + echo "### Service and mount state before first repository access ###" + sudo cvmfs_config chksetup || true + sudo systemctl status autofs --no-pager || true + mount | grep -E "autofs|cvmfs" || true + findmnt /cvmfs || true + findmnt /cvmfs/sft.cern.ch || true + echo "### Probe before first repository access ###" + set +e + sudo cvmfs_config probe + pre_probe_rc=$? + set -e + printf 'Pre-access probe exit code: %s\n' "${pre_probe_rc}" + if [ "${pre_probe_rc}" -ne 0 ]; then + echo "::warning::cvmfs_config probe failed before first repository access" + fi + echo "### Exercise /cvmfs/sft.cern.ch ###" + ls /cvmfs/sft.cern.ch + echo "### Check lcg/lastUpdate before the deeper cache exercise ###" + show_exact_target_io_diagnostics() { + echo "### journalctl: autofs unit ###" + sudo journalctl -u autofs --no-pager -n 100 || true + echo "### journalctl: filtered cvmfs/autofs/I-O lines ###" + sudo journalctl --no-pager -n 400 | grep -Ei 'cvmfs|autofs|Input/output|I/O error|sft\.cern\.ch' | tail -n 120 || true + if [ -f /var/log/syslog ]; then + echo "### /var/log/syslog: filtered cvmfs/autofs/I-O lines ###" + sudo tail -n 400 /var/log/syslog | grep -Ei 'cvmfs|autofs|Input/output|I/O error|sft\.cern\.ch' | tail -n 120 || true + fi + } + exact_update_marker=/cvmfs/sft.cern.ch/lcg/lastUpdate + if ! ls "${exact_update_marker}"; then + echo "::warning::Exact lcg/lastUpdate access failed; dumping CVMFS/autofs diagnostics before fallback" + show_exact_target_io_diagnostics + fi + echo "### Resolve a Bazel target to exercise broader cache content ###" + exact_bazel_bin=/cvmfs/sft.cern.ch/lcg/contrib/bazel/Linux-x86_64//lib/bazel/bin/bazel + if ! ls "${exact_bazel_bin}"; then + echo "::warning::Exact bazel access failed; dumping CVMFS/autofs diagnostics before fallback" + show_exact_target_io_diagnostics + fi + bazel_bin="${exact_bazel_bin}" + if [ ! -e "${bazel_bin}" ]; then + bazel_bin=$({ + find /cvmfs/sft.cern.ch/lcg/contrib/bazel -path '*/Linux-x86_64*/lib/bazel/bin/bazel' -print 2>/dev/null + find /cvmfs/sft.cern.ch/lcg/contrib/bazel -path '*/lib/bazel/bin/bazel' -print 2>/dev/null + } | sort -u | tail -n 1) + fi + if [ -z "${bazel_bin}" ]; then + echo "::error::Could not find any fallback bazel binary under /cvmfs/sft.cern.ch/lcg/contrib/bazel" + exit 1 + fi + bazel_bin_dir=${bazel_bin%/bazel} + bazel_root_dir=${bazel_bin_dir%/bin} + printf 'Selected bazel binary: %s\n' "${bazel_bin}" + echo "### Try the exact problematic ROOT libTree.so path without making it mandatory ###" + exact_root_lib=/cvmfs/sft.cern.ch/lcg/releases/ROOT/6.36.02-1f134/x86_64-ubuntu2404-gcc13-opt/lib/libTree.so + root_lib_for_read= + if ls "${exact_root_lib}"; then + root_lib_for_read="${exact_root_lib}" + else + echo "::warning::Exact ROOT libTree.so access failed; dumping CVMFS/autofs diagnostics and continuing without making it required" + show_exact_target_io_diagnostics + fi + echo "### Read the checked paths and nearby bazel files to populate more cached objects ###" + { + if [ -n "${root_lib_for_read}" ]; then + printf '%s\n' "${root_lib_for_read}" + fi + if [ -e "${exact_update_marker}" ]; then + printf '%s\n' "${exact_update_marker}" + fi + printf '%s\n' "${bazel_bin}" + find "${bazel_bin_dir}" -maxdepth 1 \( -type f -o -type l \) | sort + find "${bazel_root_dir}" -maxdepth 1 \( -type f -o -type l \) | sort + } | awk '!seen[$0]++' > "${RUNNER_TEMP}/bazel-files.txt" + test -s "${RUNNER_TEMP}/bazel-files.txt" + grep -F '/bin/bazel' "${RUNNER_TEMP}/bazel-files.txt" + while IFS= read -r path; do + cat "${path}" > /dev/null + done < "${RUNNER_TEMP}/bazel-files.txt" + printf 'Read %s bazel-related entries from %s\n' "$(wc -l < "${RUNNER_TEMP}/bazel-files.txt")" "${bazel_root_dir}" + echo "### Probe after first repository access ###" + set +e + sudo cvmfs_config probe + post_probe_rc=$? + set -e + printf 'Post-access probe exit code: %s\n' "${post_probe_rc}" + if [ "${pre_probe_rc}" -ne 0 ] && [ "${post_probe_rc}" -eq 0 ]; then + echo "Probe succeeded after first repository access" + fi + echo "### Service and mount state after first repository access ###" + mount | grep -E "autofs|cvmfs" || true + findmnt /cvmfs || true + findmnt /cvmfs/sft.cern.ch || true + sudo cvmfs_config status || true + echo "### Assert cache was populated ###" + sudo test -e "${{ env.CVMFS_CACHE_BASE }}/shared/cachedb" + populated_object=$(sudo find "${{ env.CVMFS_CACHE_BASE }}/shared" -mindepth 2 -maxdepth 2 -type f -path "${{ env.CVMFS_CACHE_BASE }}/shared/[0-9a-f][0-9a-f]/*" | head -n 1) + test -n "${populated_object}" + printf 'Populated cache object: %s\n' "${populated_object}" + echo "### Show selected cache entries ###" + sudo find "${{ env.CVMFS_CACHE_BASE }}/shared" -maxdepth 2 \( -name cachedb -o -name '[0-9a-f][0-9a-f]' \) | sort | head -n 40 + if [ "${post_probe_rc}" -ne 0 ]; then + echo "::error::cvmfs_config probe still failed after first repository access" + exit "${post_probe_rc}" + fi + - name: Make CernVM-FS cache readable for actions/cache post-job save + if: ${{ always() }} + run: | + if [ -d "${{ env.CVMFS_CACHE_BASE }}" ]; then + sudo chmod -R a+rwX "${{ env.CVMFS_CACHE_BASE }}" + sudo find "${{ env.CVMFS_CACHE_BASE }}" -type d -exec chmod a+rwx {} + + fi + + reuse-cache: + needs: populate-cache + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v6 + - uses: ./ + with: + actions_cache: 'true' + cvmfs_cache_base: ${{ env.CVMFS_CACHE_BASE }} + cvmfs_repositories: 'sft.cern.ch' + - name: Diagnose workspace and cache base access before reuse + run: | + cache_parent=$(dirname "${{ env.CVMFS_CACHE_BASE }}") + echo "### Compare workspace and cache path ancestry ###" + namei -l "${{ github.workspace }}" || true + namei -l "${cache_parent}" || true + namei -l "${{ env.CVMFS_CACHE_BASE }}" || true + echo "### Check action-prepared cache base permissions ###" + id + getent passwd cvmfs + ls -ld "${{ github.workspace }}" "${cache_parent}" "${{ env.CVMFS_CACHE_BASE }}" + test -r "${{ env.CVMFS_CACHE_BASE }}" + test -w "${{ env.CVMFS_CACHE_BASE }}" + sudo -u cvmfs test -w "${{ env.CVMFS_CACHE_BASE }}" + echo "### Check autofs / cvmfs setup ###" + sudo cvmfs_config chksetup || true + sudo systemctl is-active autofs || true + sudo systemctl status autofs --no-pager || true + findmnt /cvmfs || true + findmnt /cvmfs/sft.cern.ch || true + - name: Assert restored CernVM-FS cache contents + run: | + echo "### Check restored cache before first repository access ###" + sudo test -e "${{ env.CVMFS_CACHE_BASE }}/shared/cachedb" + restored_object=$(sudo find "${{ env.CVMFS_CACHE_BASE }}/shared" -mindepth 2 -maxdepth 2 -type f -path "${{ env.CVMFS_CACHE_BASE }}/shared/[0-9a-f][0-9a-f]/*" | head -n 1) + if [ -z "${restored_object}" ]; then + echo "Expected restored cache content under the persistent hash directories before first CVMFS access" + sudo find "${{ env.CVMFS_CACHE_BASE }}/shared" -maxdepth 2 \( -name cachedb -o -name '[0-9a-f][0-9a-f]' \) | sort | head -n 80 + exit 1 + fi + printf 'Restored cache object: %s\n' "${restored_object}" + - name: Reuse populated CernVM-FS cache + run: | + echo "### Dump default.local ###" + cat /etc/cvmfs/default.local + echo "### Try cvmfs_config probe ###" + if ! sudo cvmfs_config probe; then + echo "::warning::Initial cvmfs_config probe failed; dumping diagnostics, restarting autofs, and retrying once" + sudo systemctl status autofs --no-pager || true + findmnt /cvmfs || true + findmnt /cvmfs/sft.cern.ch || true + sudo systemctl restart autofs + sleep 2 + sudo systemctl is-active autofs + sudo cvmfs_config probe + fi + show_cvmfs_talk_metrics() { + label="$1" + metrics_file="${RUNNER_TEMP}/cvmfs-${label}.prom" + echo "### cvmfs_talk metrics (${label}) ###" + sudo cvmfs_talk -i sft.cern.ch metrics prometheus > "${metrics_file}" || return 0 + grep -Ei 'cvmfs_.*(cache|download|hit|rx)' "${metrics_file}" | head -n 40 || true + } + echo "### Reuse /cvmfs/sft.cern.ch ###" + ls /cvmfs/sft.cern.ch + echo "### Resolve the lcg/lastUpdate and bazel targets used for targeted reuse ###" + show_exact_target_io_diagnostics() { + echo "### journalctl: autofs unit ###" + sudo journalctl -u autofs --no-pager -n 100 || true + echo "### journalctl: filtered cvmfs/autofs/I-O lines ###" + sudo journalctl --no-pager -n 400 | grep -Ei 'cvmfs|autofs|Input/output|I/O error|sft\.cern\.ch' | tail -n 120 || true + if [ -f /var/log/syslog ]; then + echo "### /var/log/syslog: filtered cvmfs/autofs/I-O lines ###" + sudo tail -n 400 /var/log/syslog | grep -Ei 'cvmfs|autofs|Input/output|I/O error|sft\.cern\.ch' | tail -n 120 || true + fi + } + exact_update_marker=/cvmfs/sft.cern.ch/lcg/lastUpdate + if ! ls "${exact_update_marker}"; then + echo "::warning::Exact lcg/lastUpdate access failed; dumping CVMFS/autofs diagnostics before fallback" + show_exact_target_io_diagnostics + fi + exact_bazel_bin=/cvmfs/sft.cern.ch/lcg/contrib/bazel/Linux-x86_64//lib/bazel/bin/bazel + if ! ls "${exact_bazel_bin}"; then + echo "::warning::Exact bazel access failed; dumping CVMFS/autofs diagnostics before fallback" + show_exact_target_io_diagnostics + fi + bazel_bin="${exact_bazel_bin}" + if [ ! -e "${bazel_bin}" ]; then + bazel_bin=$({ + find /cvmfs/sft.cern.ch/lcg/contrib/bazel -path '*/Linux-x86_64*/lib/bazel/bin/bazel' -print 2>/dev/null + find /cvmfs/sft.cern.ch/lcg/contrib/bazel -path '*/lib/bazel/bin/bazel' -print 2>/dev/null + } | sort -u | tail -n 1) + fi + if [ -z "${bazel_bin}" ]; then + echo "::error::Could not find any fallback bazel binary under /cvmfs/sft.cern.ch/lcg/contrib/bazel" + exit 1 + fi + bazel_bin_dir=${bazel_bin%/bazel} + bazel_root_dir=${bazel_bin_dir%/bin} + printf 'Selected bazel binary: %s\n' "${bazel_bin}" + echo "### Try the exact problematic ROOT libTree.so path without making it mandatory ###" + exact_root_lib=/cvmfs/sft.cern.ch/lcg/releases/ROOT/6.36.02-1f134/x86_64-ubuntu2404-gcc13-opt/lib/libTree.so + root_lib_for_read= + if ls "${exact_root_lib}"; then + root_lib_for_read="${exact_root_lib}" + else + echo "::warning::Exact ROOT libTree.so access failed; dumping CVMFS/autofs diagnostics and continuing without making it required" + show_exact_target_io_diagnostics + fi + echo "### Inspect restored cache state via cvmfs_talk before targeted reuse ###" + sudo cvmfs_talk -i sft.cern.ch cache instance || true + sudo cvmfs_talk -i sft.cern.ch cache size || true + sudo cvmfs_talk -i sft.cern.ch cache list > "${RUNNER_TEMP}/cache-list-before.txt" + if [ -e "${exact_update_marker}" ]; then + if grep -F 'lastUpdate' "${RUNNER_TEMP}/cache-list-before.txt"; then + echo "lastUpdate already appears in cache list before the targeted reuse read" + else + echo "::notice::lastUpdate not yet visible in cache list before the targeted reuse read" + fi + else + echo "::notice::Skipping cache-list check for lcg/lastUpdate because the exact path is not currently available" + fi + if grep -F 'bazel' "${RUNNER_TEMP}/cache-list-before.txt"; then + echo "bazel already appears in cache list before the targeted reuse read" + else + echo "::notice::bazel not yet visible in cache list before the targeted reuse read" + fi + show_cvmfs_talk_metrics before-targeted-reuse + echo "### Re-read the checked paths and nearby bazel files to confirm cache reuse on richer content ###" + { + if [ -n "${root_lib_for_read}" ]; then + printf '%s\n' "${root_lib_for_read}" + fi + if [ -e "${exact_update_marker}" ]; then + printf '%s\n' "${exact_update_marker}" + fi + printf '%s\n' "${bazel_bin}" + find "${bazel_bin_dir}" -maxdepth 1 \( -type f -o -type l \) | sort + find "${bazel_root_dir}" -maxdepth 1 \( -type f -o -type l \) | sort + } | awk '!seen[$0]++' > "${RUNNER_TEMP}/bazel-files.txt" + test -s "${RUNNER_TEMP}/bazel-files.txt" + grep -F '/bin/bazel' "${RUNNER_TEMP}/bazel-files.txt" + while IFS= read -r path; do + cat "${path}" > /dev/null + done < "${RUNNER_TEMP}/bazel-files.txt" + printf 'Re-read %s bazel-related entries from %s\n' "$(wc -l < "${RUNNER_TEMP}/bazel-files.txt")" "${bazel_root_dir}" + echo "### Require checked paths in cvmfs_talk cache list during reuse ###" + sudo cvmfs_talk -i sft.cern.ch cache list > "${RUNNER_TEMP}/cache-list-after.txt" + if [ -e "${exact_update_marker}" ] && ! grep -F 'lastUpdate' "${RUNNER_TEMP}/cache-list-after.txt"; then + echo "::error::lastUpdate did not appear in cvmfs_talk cache list after the targeted reuse read" + sed -n '1,120p' "${RUNNER_TEMP}/cache-list-after.txt" + exit 1 + fi + if ! grep -F 'bazel' "${RUNNER_TEMP}/cache-list-after.txt"; then + echo "::error::bazel did not appear in cvmfs_talk cache list after the targeted reuse read" + sed -n '1,120p' "${RUNNER_TEMP}/cache-list-after.txt" + exit 1 + fi + show_cvmfs_talk_metrics after-targeted-reuse + echo "### Show selected cache entries ###" + sudo find "${{ env.CVMFS_CACHE_BASE }}/shared" -maxdepth 2 \( -name cachedb -o -name '[0-9a-f][0-9a-f]' \) | sort | head -n 40 + - name: Make CernVM-FS cache readable for actions/cache post-job save + if: ${{ always() }} + run: | + if [ -d "${{ env.CVMFS_CACHE_BASE }}" ]; then + sudo chmod -R a+rwX "${{ env.CVMFS_CACHE_BASE }}" + sudo find "${{ env.CVMFS_CACHE_BASE }}" -type d -exec chmod a+rwx {} + + fi diff --git a/README.md b/README.md index 2c0d858..9421136 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,7 @@ By default `*.cern.ch, *.egi.eu, *.opensciencegrid.org *.hsf.org` repositories ## Optional Parameters The following parameters are supported: +- `actions_cache`: Enable a GitHub Actions cache for the persistent contents of `cvmfs_cache_base`. When `cvmfs_cache_base` is not explicitly set, it defaults to `/opt/cvmfs-cache`. With the default shared cache, it caches `shared/cachedb` plus `shared/00`...`shared/ff`; with `cvmfs_shared_cache=no`, it caches `cachedb` plus `00`...`ff` directly under `cvmfs_cache_base`. - `cvmfs_alien_cache`: If set, use an alien cache at the given location. - `cvmfs_alt_root_path`: If set to yes, use alternative root catalog path. Only required for fixed catalogs (tag / hash) under the alternative path. - `cvmfs_authz_helper`: Full path to an authz helper, overwrites the helper hint in the catalog. @@ -27,7 +28,7 @@ The following parameters are supported: - `cvmfs_auto_update`: If set to no, disables the automatic update of file catalogs. - `cvmfs_backoff_init`: Seconds for the maximum initial backoff when retrying to download data. - `cvmfs_backoff_max`: Maximum backoff in seconds when retrying to download data. -- `cvmfs_cache_base`: Location (directory) of the CernVM-FS cache. +- `cvmfs_cache_base`: Location (directory) of the CernVM-FS cache. The `cvmfs` user must be able to traverse all parent directories and write this directory; on GitHub-hosted runners prefer a path under `/tmp` over the GitHub workspace path. Defaults to `/opt/cvmfs-cache` when `actions_cache` is `true`. - `cvmfs_catalog_watermark`: Try to release pinned catalogs when their number surpasses the given watermark. Defaults to 1/4 CVMFS_NFILES; explicitly set by shrinkwrap. - `cvmfs_check_permissions`: If set to no, disable checking of file ownership and permissions (open all files). - `cvmfs_claim_ownership`: If set to yes, allows CernVM-FS to claim ownership of files and directories. diff --git a/action.yml b/action.yml index d4d3a66..4bc2d85 100644 --- a/action.yml +++ b/action.yml @@ -12,6 +12,14 @@ inputs: description: 'If set to yes, cache APT package lists in addition to .deb packages. This speeds up the action, but may require manual intervention to clear the cache when gh actions runner images are updated' required: false default: 'no' + actions_cache: + description: 'Enable a GitHub Actions cache for persistent CernVM-FS cache contents under cvmfs_cache_base. With the default shared cache, cachedb and object directories live under the shared subdirectory.' + required: false + default: 'no' + cvmfs_cache_max_size: + description: 'Maximum size in MB of the CernVM-FS cache to persist in the GitHub Actions cache. Before saving, the cache is trimmed with cvmfs_talk cleanup. Set to 0 to disable trimming.' + required: false + default: '4096' cvmfs_alien_cache: description: 'If set, use an alien cache at the given location.' required: false @@ -41,7 +49,7 @@ inputs: required: false default: '' cvmfs_cache_base: - description: 'Location (directory) of the CernVM-FS cache.' + description: 'Location (directory) of the CernVM-FS cache. The cvmfs user must be able to traverse all parent directories and write this directory. When actions_cache is true and this is left empty, it defaults to $HOME/.cvmfs-cache.' required: false default: '' cvmfs_catalog_watermark: @@ -335,6 +343,14 @@ inputs: runs: using: "composite" steps: + - id: resolve-cache-base + run: | + cache_base="${{ inputs.cvmfs_cache_base }}" + if [ -z "$cache_base" ] && [ "${{ inputs.actions_cache }}" == "true" ]; then + cache_base="${HOME}/.cvmfs-cache" + fi + echo "path=${cache_base}" >> $GITHUB_OUTPUT + shell: bash - id: lsb-release run: | if [ "$RUNNER_OS" == "Linux" ]; then @@ -360,6 +376,29 @@ runs: key: cvmfs-apt-cache-${{ steps.lsb-release.outputs.id-release }}-${{ steps.lsb-release.outputs.arch }}-${{ steps.lsb-release.outputs.cvmfs_action_version }} path: | ${{ inputs.apt_cache }} + - if: ${{ steps.resolve-cache-base.outputs.path != '' }} + run: | + sudo mkdir -p "${{ steps.resolve-cache-base.outputs.path }}" + sudo chmod a+rwx "${{ steps.resolve-cache-base.outputs.path }}" + shell: bash + - uses: actions/cache@v5 + if: ${{ inputs.actions_cache == 'true' && steps.resolve-cache-base.outputs.path != '' && inputs.cvmfs_shared_cache != 'no' }} + with: + key: cvmfs-cache-${{ steps.lsb-release.outputs.id-release }}-${{ steps.lsb-release.outputs.arch }}-${{ steps.lsb-release.outputs.cvmfs_action_version }}-${{ github.run_id }} + restore-keys: | + cvmfs-cache-${{ steps.lsb-release.outputs.id-release }}-${{ steps.lsb-release.outputs.arch }}-${{ steps.lsb-release.outputs.cvmfs_action_version }}- + path: | + ${{ steps.resolve-cache-base.outputs.path }}/shared/cachedb + ${{ steps.resolve-cache-base.outputs.path }}/shared/[0-9a-f][0-9a-f] + - uses: actions/cache@v5 + if: ${{ inputs.actions_cache == 'true' && steps.resolve-cache-base.outputs.path != '' && inputs.cvmfs_shared_cache == 'no' }} + with: + key: cvmfs-cache-${{ steps.lsb-release.outputs.id-release }}-${{ steps.lsb-release.outputs.arch }}-${{ steps.lsb-release.outputs.cvmfs_action_version }}-${{ github.run_id }} + restore-keys: | + cvmfs-cache-${{ steps.lsb-release.outputs.id-release }}-${{ steps.lsb-release.outputs.arch }}-${{ steps.lsb-release.outputs.cvmfs_action_version }}- + path: | + ${{ steps.resolve-cache-base.outputs.path }}/cachedb + ${{ steps.resolve-cache-base.outputs.path }}/[0-9a-f][0-9a-f] - run: | ${{ github.action_path }}/setup-cvmfs.sh shell: bash @@ -374,7 +413,7 @@ runs: CVMFS_AUTO_UPDATE: ${{ inputs.cvmfs_auto_update }} CVMFS_BACKOFF_INIT: ${{ inputs.cvmfs_backoff_init }} CVMFS_BACKOFF_MAX: ${{ inputs.cvmfs_backoff_max }} - CVMFS_CACHE_BASE: ${{ inputs.cvmfs_cache_base }} + CVMFS_CACHE_BASE: ${{ steps.resolve-cache-base.outputs.path }} CVMFS_CATALOG_WATERMARK: ${{ inputs.cvmfs_catalog_watermark }} CVMFS_CHECK_PERMISSIONS: ${{ inputs.cvmfs_check_permissions }} CVMFS_CLAIM_OWNERSHIP: ${{ inputs.cvmfs_claim_ownership }} @@ -447,3 +486,14 @@ runs: CVMFS_UBUNTU_DEB_LOCATION: ${{ inputs.cvmfs_ubuntu_deb_location }} CVMFS_MACOS_PKG_LOCATION: ${{ inputs.cvmfs_macos_pkg_location }} CVMFS_CONFIG_PACKAGE: ${{ inputs.cvmfs_config_package }} + - if: ${{ inputs.actions_cache == 'true' && steps.resolve-cache-base.outputs.path != '' && inputs.cvmfs_cache_max_size != '0' }} + run: | + # Trim the CernVM-FS cache to the configured maximum size + if [ -n "${{ inputs.cvmfs_repositories }}" ]; then + IFS=',' read -ra REPOS <<< "${{ inputs.cvmfs_repositories }}" + for repo in "${REPOS[@]}"; do + repo=$(echo "$repo" | xargs) # trim whitespace + sudo cvmfs_talk -i "$repo" cleanup "${{ inputs.cvmfs_cache_max_size }}" 2>/dev/null || true + done + fi + shell: bash diff --git a/setup-cvmfs.sh b/setup-cvmfs.sh index 749d2ee..9ff6648 100755 --- a/setup-cvmfs.sh +++ b/setup-cvmfs.sh @@ -48,6 +48,39 @@ if [ "$(uname)" == "Linux" ]; then fi echo "::endgroup::" fi + if [ -n "${CVMFS_CACHE_BASE}" ]; then + echo "::group::Preparing cvmfs cache base" + mkdir -p "${CVMFS_CACHE_BASE}" + # Ensure the shared sub-directory exists so default ACLs are set on it too + if [ "${CVMFS_SHARED_CACHE}" != "no" ]; then + mkdir -p "${CVMFS_CACHE_BASE}/shared" + fi + sudo chown -R cvmfs:root "${CVMFS_CACHE_BASE}" + sudo chmod -R a+rwX "${CVMFS_CACHE_BASE}" + sudo find "${CVMFS_CACHE_BASE}" -type d -exec chmod a+rwx {} + + # Set default POSIX ACLs so that files/directories created later by the + # cvmfs user (during the job) are world-readable. This is required for + # the actions/cache post-job save step, which runs as the runner user. + if command -v setfacl >/dev/null 2>&1; then + sudo setfacl -R -d -m o::rwX "${CVMFS_CACHE_BASE}" + sudo setfacl -R -m o::rwX "${CVMFS_CACHE_BASE}" + fi + id cvmfs + sudo -u cvmfs id + ls -ld "${CVMFS_CACHE_BASE}" + sudo -u cvmfs test -w "${CVMFS_CACHE_BASE}" + sudo -u cvmfs env CVMFS_CACHE_BASE="${CVMFS_CACHE_BASE}" bash <<'EOF' +set -euo pipefail +probe_file="${CVMFS_CACHE_BASE}/.cvmfs-write-probe" +printf 'probe\n' > "${probe_file}" +rm -f "${probe_file}" +EOF + ls -ld "${CVMFS_CACHE_BASE}" + sudo find "${CVMFS_CACHE_BASE}" -mindepth 1 -maxdepth 1 | sort || true + test -r "${CVMFS_CACHE_BASE}" + test -w "${CVMFS_CACHE_BASE}" + echo "::endgroup::" + fi elif [ "$(uname)" == "Darwin" ]; then # Warn about the phasing out of MacOS support for this action echo "warning The CernVM-FS GitHub Action's support for MacOS \