From 5941e0b57a754214b307927b06d990cbb3bf162d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bob=20Dr=C3=B6ge?= Date: Tue, 8 Oct 2024 13:19:30 +0200 Subject: [PATCH 01/14] specify cvmfs repo as script argument --- scripts/ingest-tarball.sh | 51 +++++++++++++++++++++------------------ 1 file changed, 28 insertions(+), 23 deletions(-) diff --git a/scripts/ingest-tarball.sh b/scripts/ingest-tarball.sh index 30781188..6a7f363e 100755 --- a/scripts/ingest-tarball.sh +++ b/scripts/ingest-tarball.sh @@ -12,7 +12,6 @@ # Only if it passes these checks, the tarball gets ingested to the base dir in the repository specified below. -repo=software.eessi.io basedir=versions decompress="gunzip -c" cvmfs_server="cvmfs_server" @@ -42,15 +41,15 @@ function error() { } function is_repo_owner() { - if [ -f "/etc/cvmfs/repositories.d/${repo}/server.conf" ] + if [ -f "/etc/cvmfs/repositories.d/${cvmfs_repo}/server.conf" ] then - . "/etc/cvmfs/repositories.d/${repo}/server.conf" + . "/etc/cvmfs/repositories.d/${cvmfs_repo}/server.conf" [ x"$(whoami)" = x"$CVMFS_USER" ] fi } function check_repo_vars() { - if [ -z "${repo}" ] + if [ -z "${cvmfs_repo}" ] then error "the 'repo' variable has to be set to the name of the CVMFS repository." fi @@ -113,28 +112,28 @@ function check_contents_type() { function cvmfs_regenerate_nested_catalogs() { # Use the .cvmfsdirtab to generate nested catalogs for the ingested tarball echo "Generating the nested catalogs..." - ${cvmfs_server} transaction "${repo}" - ${cvmfs_server} publish -m "Generate catalogs after ingesting ${tar_file_basename}" "${repo}" + ${cvmfs_server} transaction "${cvmfs_repo}" + ${cvmfs_server} publish -m "Generate catalogs after ingesting ${tar_file_basename}" "${cvmfs_repo}" ec=$? if [ $ec -eq 0 ] then - echo_green "Nested catalogs for ${repo} have been created!" + echo_green "Nested catalogs for ${cvmfs_repo} have been created!" else - echo_red "failure when creating nested catalogs for ${repo}." + echo_red "failure when creating nested catalogs for ${cvmfs_repo}." fi } function cvmfs_ingest_tarball() { # Do a regular "cvmfs_server ingest" for a given tarball, # followed by regenerating the nested catalog - echo "Ingesting tarball ${tar_file} to ${repo}..." - ${decompress} "${tar_file}" | ${cvmfs_server} ingest -t - -b "${basedir}" "${repo}" + echo "Ingesting tarball ${tar_file} to ${cvmfs_repo}..." + ${decompress} "${tar_file}" | ${cvmfs_server} ingest -t - -b "${basedir}" "${cvmfs_repo}" ec=$? if [ $ec -eq 0 ] then - echo_green "${tar_file} has been ingested to ${repo}." + echo_green "${tar_file} has been ingested to ${cvmfs_repo}." else - error "${tar_file} could not be ingested to ${repo}." + error "${tar_file} could not be ingested to ${cvmfs_repo}." fi # "cvmfs_server ingest" doesn't automatically rebuild the nested catalogs, @@ -180,9 +179,9 @@ function update_lmod_caches() { then error "the script for updating the Lmod caches (${update_caches_script}) does not have execute permissions!" fi - ${cvmfs_server} transaction "${repo}" - ${update_caches_script} /cvmfs/${repo}/${basedir}/${version} - ${cvmfs_server} publish -m "update Lmod caches after ingesting ${tar_file_basename}" "${repo}" + ${cvmfs_server} transaction "${cvmfs_repo}" + ${update_caches_script} /cvmfs/${cvmfs_repo}/${basedir}/${version} + ${cvmfs_server} publish -m "update Lmod caches after ingesting ${tar_file_basename}" "${cvmfs_repo}" } function ingest_init_tarball() { @@ -207,25 +206,25 @@ function ingest_compat_tarball() { # Handle the ingestion of tarballs containing a compatibility layer check_arch check_os - compat_layer_path="/cvmfs/${repo}/${basedir}/${version}/compat/${os}/${arch}" + compat_layer_path="/cvmfs/${cvmfs_repo}/${basedir}/${version}/compat/${os}/${arch}" # Assume that we already had a compat layer in place if there is a startprefix script in the corresponding CVMFS directory if [ -f "${compat_layer_path}/startprefix" ]; then echo_yellow "Compatibility layer for version ${version}, OS ${os}, and architecture ${arch} already exists!" - ${cvmfs_server} transaction "${repo}" + ${cvmfs_server} transaction "${cvmfs_repo}" last_suffix=$((ls -1d ${compat_layer_path}-* | tail -n 1 | xargs basename | cut -d- -f2) 2> /dev/null) new_suffix=$(printf '%03d\n' $((${last_suffix:-0} + 1))) old_layer_suffixed_path="${compat_layer_path}-${new_suffix}" echo_yellow "Moving the existing compat layer from ${compat_layer_path} to ${old_layer_suffixed_path}..." mv ${compat_layer_path} ${old_layer_suffixed_path} - tar -C "/cvmfs/${repo}/${basedir}/" -xzf "${tar_file}" - ${cvmfs_server} publish -m "updated compat layer for ${version}, ${os}, ${arch}" "${repo}" + tar -C "/cvmfs/${cvmfs_repo}/${basedir}/" -xzf "${tar_file}" + ${cvmfs_server} publish -m "updated compat layer for ${version}, ${os}, ${arch}" "${cvmfs_repo}" ec=$? if [ $ec -eq 0 ] then echo_green "Successfully ingested the new compatibility layer!" else - ${cvmfs_server} abort "${repo}" + ${cvmfs_server} abort "${cvmfs_repo}" error "error while updating the compatibility layer, transaction aborted." fi else @@ -236,11 +235,17 @@ function ingest_compat_tarball() { # Check if a tarball has been specified -if [ "$#" -ne 1 ]; then - error "usage: $0 " +if [ "$#" -ne 2 ]; then + error "usage: $0 " fi -tar_file="$1" +cvmfs_repo="$1" +tar_file="$2" + +# Check if the CVMFS repository exists +if ( ! cvmfs_server list | grep -q "${cvmfs_repo}" ); then + error "CVMFS repository ${cvmfs_repo} does not exist!" +fi # Check if the given tarball exists if [ ! -f "${tar_file}" ]; then From d638715652c485b650ddc731604696cabe179eb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bob=20Dr=C3=B6ge?= Date: Tue, 8 Oct 2024 13:30:25 +0200 Subject: [PATCH 02/14] adapt and add tests for extra cvmfs repo argument --- scripts/test-ingest-tarball.sh | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/scripts/test-ingest-tarball.sh b/scripts/test-ingest-tarball.sh index ee7db376..ccc9f3d7 100755 --- a/scripts/test-ingest-tarball.sh +++ b/scripts/test-ingest-tarball.sh @@ -1,6 +1,7 @@ #!/bin/bash INGEST_SCRIPT=$(dirname "$(realpath $0)")/ingest-tarball.sh +TEST_OUTPUT=/dev/null # change to /dev/stdout to print test outputs for debugging purposes # Temporary base dir for the tests tstdir=$(mktemp -d) @@ -30,11 +31,14 @@ function create_tarball() { # Create a fake cvmfs_server executable, and prepend it to $PATH cat << EOF > "${tstdir}/cvmfs_server" #!/bin/bash -if [ \$# -lt 2 ]; then - echo "cvmfs_server expects at least two arguments!" +if [ \$# -lt 1 ]; then + echo "cvmfs_server expects at least one argument!" exit 1 fi echo "Calling: cvmfs_server \$@" +if [ \$1 == "list" ]; then + echo "my.repo.tld (stratum0 / local)" +fi EOF chmod +x "${tstdir}/cvmfs_server" export PATH="${tstdir}:$PATH" @@ -86,7 +90,7 @@ tarballs_fail=( # Run the tests that should succeed for ((i = 0; i < ${#tarballs_success[@]}; i++)); do t=$(create_tarball ${tarballs_success[$i]}) - "${INGEST_SCRIPT}" "$t" >& /dev/null + "${INGEST_SCRIPT}" "my.repo.tld" "$t" >& "${TEST_OUTPUT}" if [ ! $? -eq 0 ]; then num_tests_failed=$((num_tests_failed + 1)) else @@ -98,7 +102,19 @@ done # Run the tests that should fail for ((i = 0; i < ${#tarballs_fail[@]}; i++)); do t=$(create_tarball ${tarballs_fail[$i]}) - "${INGEST_SCRIPT}" "$t" >& /dev/null + "${INGEST_SCRIPT}" "my.repo.tld" "$t" >& "${TEST_OUTPUT}" + if [ ! $? -eq 1 ]; then + num_tests_failed=$((num_tests_failed + 1)) + else + num_tests_succeeded=$((num_tests_succeeded + 1)) + fi + num_tests=$((num_tests + 1)) +done + +# Run the tests that should succeed again, but with a non-existing repo; now they should fail +for ((i = 0; i < ${#tarballs_success[@]}; i++)); do + t=$(create_tarball ${tarballs_success[$i]}) + "${INGEST_SCRIPT}" "my.nonexistingrepo.tld" "$t" >& "${TEST_OUTPUT}" if [ ! $? -eq 1 ]; then num_tests_failed=$((num_tests_failed + 1)) else From 15759e2c4d6d831f7a7ee3a9ec2bc2133ad9b7f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bob=20Dr=C3=B6ge?= Date: Tue, 8 Oct 2024 13:38:22 +0200 Subject: [PATCH 03/14] pass cvmfs_repo to eessitarball and use it when calling the ingestion script --- scripts/automated_ingestion/eessitarball.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/scripts/automated_ingestion/eessitarball.py b/scripts/automated_ingestion/eessitarball.py index d3118500..5cb79cec 100644 --- a/scripts/automated_ingestion/eessitarball.py +++ b/scripts/automated_ingestion/eessitarball.py @@ -19,7 +19,7 @@ class EessiTarball: for which it interfaces with the S3 bucket, GitHub, and CVMFS. """ - def __init__(self, object_name, config, git_staging_repo, s3, bucket): + def __init__(self, object_name, config, git_staging_repo, s3, bucket, cvmfs_repo): """Initialize the tarball object.""" self.config = config self.git_repo = git_staging_repo @@ -27,6 +27,7 @@ def __init__(self, object_name, config, git_staging_repo, s3, bucket): self.object = object_name self.s3 = s3 self.bucket = bucket + self.cvmfs_repo = cvmfs_repo self.local_path = os.path.join(config['paths']['download_dir'], os.path.basename(object_name)) self.local_metadata_path = self.local_path + config['paths']['metadata_file_extension'] self.url = f'https://{bucket}.s3.amazonaws.com/{object_name}' @@ -177,7 +178,7 @@ def ingest(self): sudo = ['sudo'] if self.config['cvmfs'].getboolean('ingest_as_root', True) else [] logging.info(f'Running the ingestion script for {self.object}...') ingest_cmd = subprocess.run( - sudo + [script, self.local_path], + sudo + [script, self.cvmfs_repo, self.local_path], stdout=subprocess.PIPE, stderr=subprocess.PIPE) if ingest_cmd.returncode == 0: From 4222805db6aab6495bfb0f231fee55676225b87e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bob=20Dr=C3=B6ge?= Date: Tue, 8 Oct 2024 13:39:37 +0200 Subject: [PATCH 04/14] parse staging_buckets as dictionary, and pass cvmfs_repo to eessitarball object --- scripts/automated_ingestion/automated_ingestion.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/automated_ingestion/automated_ingestion.py b/scripts/automated_ingestion/automated_ingestion.py index 561316e9..8ba1da78 100755 --- a/scripts/automated_ingestion/automated_ingestion.py +++ b/scripts/automated_ingestion/automated_ingestion.py @@ -99,15 +99,15 @@ def main(): aws_secret_access_key=config['secrets']['aws_secret_access_key'], ) - buckets = [x.strip() for x in config['aws']['staging_buckets'].split(',')] - for bucket in buckets: + buckets = json.loads(config['aws']['staging_buckets']) + for bucket, cvmfs_repo in buckets.items(): tarballs = find_tarballs(s3, bucket) if args.list_only: for num, tarball in enumerate(tarballs): print(f'[{bucket}] {num}: {tarball}') else: for tarball in tarballs: - tar = EessiTarball(tarball, config, gh_staging_repo, s3, bucket) + tar = EessiTarball(tarball, config, gh_staging_repo, s3, bucket, cvmfs_repo) tar.run_handler() From 0cbd4f58a840477793d600e12def81f6e5d7cb5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bob=20Dr=C3=B6ge?= Date: Tue, 8 Oct 2024 13:39:54 +0200 Subject: [PATCH 05/14] change staging_buckets to dictionary --- scripts/automated_ingestion/automated_ingestion.cfg.example | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/scripts/automated_ingestion/automated_ingestion.cfg.example b/scripts/automated_ingestion/automated_ingestion.cfg.example index b4ff3bbe..a0b52c5e 100644 --- a/scripts/automated_ingestion/automated_ingestion.cfg.example +++ b/scripts/automated_ingestion/automated_ingestion.cfg.example @@ -10,7 +10,10 @@ ingestion_script = /absolute/path/to/ingest-tarball.sh metadata_file_extension = .meta.txt [aws] -staging_buckets = eessi-staging, eessi-staging-2023.06 +staging_buckets = { + "eessi-staging": "software.eessi.io", + "eessi-staging-2023.06": "software.eessi.io", + "dev.eessi.io-2024.09": "dev.eessi.io" } [cvmfs] ingest_as_root = yes From 3dd213aa02f4a37c9b4d55fb6a054ab479793774 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bob=20Dr=C3=B6ge?= Date: Tue, 8 Oct 2024 13:55:46 +0200 Subject: [PATCH 06/14] import json module --- scripts/automated_ingestion/automated_ingestion.py | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/automated_ingestion/automated_ingestion.py b/scripts/automated_ingestion/automated_ingestion.py index 8ba1da78..92dac552 100755 --- a/scripts/automated_ingestion/automated_ingestion.py +++ b/scripts/automated_ingestion/automated_ingestion.py @@ -9,6 +9,7 @@ import botocore import configparser import github +import json import logging import os import pid From 36c50aaa116d07bc2bfdf25d85e9f20fad20a9be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bob=20Dr=C3=B6ge?= Date: Tue, 8 Oct 2024 14:07:10 +0200 Subject: [PATCH 07/14] add cvmfs repo to pr title --- scripts/automated_ingestion/eessitarball.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/automated_ingestion/eessitarball.py b/scripts/automated_ingestion/eessitarball.py index 5cb79cec..879a03df 100644 --- a/scripts/automated_ingestion/eessitarball.py +++ b/scripts/automated_ingestion/eessitarball.py @@ -300,7 +300,8 @@ def make_approval_request(self): tar_overview=self.get_contents_overview(), metadata=metadata, ) - self.git_repo.create_pull(title='Ingest ' + filename, body=pr_body, head=git_branch, base='main') + pr_title = '[%s] Ingest %s' % (self.cvmfs_repo, filename) + self.git_repo.create_pull(title=pr_title, body=pr_body, head=git_branch, base='main') except Exception as err: issue_title = f'Failed to get contents of {self.object}' issue_body = self.config['github']['failed_tarball_overview_issue_body'].format( From e187fe3472cc0321a1db9b47b5fd87f292d05459 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bob=20Dr=C3=B6ge?= Date: Tue, 8 Oct 2024 14:09:24 +0200 Subject: [PATCH 08/14] add cvmfs repo to pr body --- scripts/automated_ingestion/eessitarball.py | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/automated_ingestion/eessitarball.py b/scripts/automated_ingestion/eessitarball.py index 879a03df..3a6bbd30 100644 --- a/scripts/automated_ingestion/eessitarball.py +++ b/scripts/automated_ingestion/eessitarball.py @@ -296,6 +296,7 @@ def make_approval_request(self): try: tarball_contents = self.get_contents_overview() pr_body = self.config['github']['pr_body'].format( + cvmfs_repo=self.cvmfs_repo, pr_url=pr_url, tar_overview=self.get_contents_overview(), metadata=metadata, From a48b54c5a9acd6fa43a9c3e05f39b36ea46acf9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bob=20Dr=C3=B6ge?= Date: Tue, 8 Oct 2024 14:10:44 +0200 Subject: [PATCH 09/14] add cvmfs repo to ingestion message --- scripts/automated_ingestion/eessitarball.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/automated_ingestion/eessitarball.py b/scripts/automated_ingestion/eessitarball.py index 3a6bbd30..963cf0c0 100644 --- a/scripts/automated_ingestion/eessitarball.py +++ b/scripts/automated_ingestion/eessitarball.py @@ -187,7 +187,7 @@ def ingest(self): if self.config.has_section('slack') and self.config['slack'].getboolean('ingestion_notification', False): send_slack_message( self.config['secrets']['slack_webhook'], - self.config['slack']['ingestion_message'].format(tarball=os.path.basename(self.object)) + self.config['slack']['ingestion_message'].format(tarball=os.path.basename(self.object), cvmfs_repo=self.cvmfs_repo) ) else: issue_title = f'Failed to ingest {self.object}' From 75c2c432f95590212fa45873fc8b64ebcb773155 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bob=20Dr=C3=B6ge?= Date: Tue, 8 Oct 2024 14:11:10 +0200 Subject: [PATCH 10/14] add cvmfs repo to ingestion message --- scripts/automated_ingestion/automated_ingestion.cfg.example | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/automated_ingestion/automated_ingestion.cfg.example b/scripts/automated_ingestion/automated_ingestion.cfg.example index a0b52c5e..d4b2f6ac 100644 --- a/scripts/automated_ingestion/automated_ingestion.cfg.example +++ b/scripts/automated_ingestion/automated_ingestion.cfg.example @@ -47,7 +47,7 @@ failed_tarball_overview_issue_body = An error occurred while trying to get the c ``` pr_body = A new tarball has been staged for {pr_url}. Please review the contents of this tarball carefully. - Merging this PR will lead to automatic ingestion of the tarball. + Merging this PR will lead to automatic ingestion of the tarball to the repository {cvmfs_repo}.
Metadata of tarball @@ -67,7 +67,7 @@ pr_body = A new tarball has been staged for {pr_url}. [slack] ingestion_notification = yes -ingestion_message = Tarball `{tarball}` has been ingested into the CVMFS repository. +ingestion_message = Tarball `{tarball}` has been ingested into the CVMFS repository {cvmfs_repo}. [logging] level = WARN From ae8e18fde361d1041ff50aea4b93b3f6b4b5cd99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bob=20Dr=C3=B6ge?= Date: Tue, 8 Oct 2024 14:16:36 +0200 Subject: [PATCH 11/14] display cvmfs repo as code block --- scripts/automated_ingestion/automated_ingestion.cfg.example | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/automated_ingestion/automated_ingestion.cfg.example b/scripts/automated_ingestion/automated_ingestion.cfg.example index d4b2f6ac..43f568c5 100644 --- a/scripts/automated_ingestion/automated_ingestion.cfg.example +++ b/scripts/automated_ingestion/automated_ingestion.cfg.example @@ -67,7 +67,7 @@ pr_body = A new tarball has been staged for {pr_url}. [slack] ingestion_notification = yes -ingestion_message = Tarball `{tarball}` has been ingested into the CVMFS repository {cvmfs_repo}. +ingestion_message = Tarball `{tarball}` has been ingested into the CVMFS repository `{cvmfs_repo}`. [logging] level = WARN From 148ca10fb9fc8c074adb40a7deb792bfd8260169 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bob=20Dr=C3=B6ge?= Date: Tue, 8 Oct 2024 14:28:20 +0200 Subject: [PATCH 12/14] also allow EESSI versions like YYYYMMDD --- scripts/ingest-tarball.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/ingest-tarball.sh b/scripts/ingest-tarball.sh index 6a7f363e..9a9356bb 100755 --- a/scripts/ingest-tarball.sh +++ b/scripts/ingest-tarball.sh @@ -73,7 +73,7 @@ function check_version() { # Check if the EESSI version number encoded in the filename # is valid, i.e. matches the format YYYY.DD - if ! echo "${version}" | egrep -q '^20[0-9][0-9]\.(0[0-9]|1[0-2])$' + if ! echo "${version}" | egrep '(^20[0-9][0-9]\.(0[0-9]|1[0-2])$)|(^20[0-9][0-9][0-9][0-9][0-9][0-9]$)' then error "${version} is not a valid EESSI version." fi From e1808c3bfcad789853eb1cefe474b06abd5a9435 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bob=20Dr=C3=B6ge?= Date: Tue, 8 Oct 2024 14:28:43 +0200 Subject: [PATCH 13/14] fix comment about EESSI versions --- scripts/ingest-tarball.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/ingest-tarball.sh b/scripts/ingest-tarball.sh index 9a9356bb..e6f1321b 100755 --- a/scripts/ingest-tarball.sh +++ b/scripts/ingest-tarball.sh @@ -72,7 +72,7 @@ function check_version() { fi # Check if the EESSI version number encoded in the filename - # is valid, i.e. matches the format YYYY.DD + # is valid, i.e. matches the format YYYY.MM or YYYYMMDD if ! echo "${version}" | egrep '(^20[0-9][0-9]\.(0[0-9]|1[0-2])$)|(^20[0-9][0-9][0-9][0-9][0-9][0-9]$)' then error "${version} is not a valid EESSI version." From 41583417dc784bc39bcc6dd5f49e9d56a320e66c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bob=20Dr=C3=B6ge?= Date: Tue, 8 Oct 2024 14:30:51 +0200 Subject: [PATCH 14/14] update buckets-repo mapping --- scripts/automated_ingestion/automated_ingestion.cfg.example | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/automated_ingestion/automated_ingestion.cfg.example b/scripts/automated_ingestion/automated_ingestion.cfg.example index 43f568c5..c79274b5 100644 --- a/scripts/automated_ingestion/automated_ingestion.cfg.example +++ b/scripts/automated_ingestion/automated_ingestion.cfg.example @@ -11,9 +11,9 @@ metadata_file_extension = .meta.txt [aws] staging_buckets = { - "eessi-staging": "software.eessi.io", - "eessi-staging-2023.06": "software.eessi.io", - "dev.eessi.io-2024.09": "dev.eessi.io" } + "software.eessi.io-2023.06": "software.eessi.io", + "dev.eessi.io-2024.09": "dev.eessi.io", + "riscv.eessi.io-20240402": "riscv.eessi.io" } [cvmfs] ingest_as_root = yes