from __future__ import annotations
def build_container(singularity_def, SINGULARITY_IMAGE):
from spython.main import Client
from pathlib import Path
import os
job_id = os.environ.get("SLURM_JOB_ID", "local")
user = os.environ["USER"]
tmp_root = Path(f"/tmp/{user}-rse-workbench-{job_id}")
singularity_tmp = tmp_root / "singularity-tmp"
singularity_cache = tmp_root / "singularity-cache"
singularity_tmp.mkdir(parents=True, exist_ok=True)
singularity_cache.mkdir(parents=True, exist_ok=True)
os.environ["SINGULARITY_TMPDIR"] = str(singularity_tmp)
os.environ["SINGULARITY_CACHEDIR"] = str(singularity_cache)
os.environ["APPTAINER_TMPDIR"] = str(singularity_tmp)
os.environ["APPTAINER_CACHEDIR"] = str(singularity_cache)
return Client.build(
image=str(SINGULARITY_IMAGE),
recipe=str(singularity_def),
options=["--fakeroot", "--force"],
sudo=False,
return_result=True,
)30 Build Final SIF
This notebook builds the final read-only SIF from the validated platform definition.
import submitit
from rse_workbench.helpers import show_submitit_job, spython_exec, show_spython
from rse_workbench.build_install import build_containerBuild:
executor = submitit.AutoExecutor(folder=str(project_contract.submitit_dir / "%j"))
executor.update_parameters(
timeout_min=project_contract.slurm_build_hours * 60,
slurm_partition=project_contract.slurm_build_partition,
mem_gb=float(project_contract.slurm_build_mem.rstrip("G")),
cpus_per_task=project_contract.slurm_build_cpus,
slurm_job_name=f"build-{project_contract.project_name}-container",
mail_user=project_contract.slurm_email,
)job = executor.submit(build_container, project_contract.singularity_def, project_contract.singularity_image)
job.job_idresult = show_submitit_job(job)
if result is not None:
print(result)Install Spack and System Dependencies:
job = executor.submit(
install_in_container,
project_dir=project_contract.project_dir,
SINGULARITY_IMAGE=project_contract.singularity_image,
runtime_command=project_contract.spack_install_command,
)
job.job_idresult = show_submitit_job(job)
if result is not None:
print(''.join(result['message']))Install Data Science Languages and Packages:
job = executor.submit(
install_in_container,
project_dir=project_contract.project_dir,
SINGULARITY_IMAGE=project_contract.singularity_image,
runtime_command=project_contract.language_install_command,
)
job.job_idresult = show_submitit_job(job)
if result is not None:
print(''.join(result['message']))This section verifies that each layer of the environment is functioning correctly independently before testing that the layers communicate correctly.
The architecture is expected to look like:
Container
↓
Spack
↓
R / Rscript
↓
rv-managed R package library
↓
Quarto
↓
Project render
At each stage we test a single contract before moving to the next.
30.1 1. Verify the container runtime
The container should provide the basic executables required for the project.
command = r"""
set -euo pipefail
echo "============================================================"
echo "1. Base container tools (before activation)"
echo "============================================================"
command -v spack
command -v rv
command -v uv
command -v quarto
quarto --version
echo
echo "============================================================"
echo "2. Activate project"
echo "============================================================"
cd /work
source /work/env/activate.sh
echo
echo "============================================================"
echo "3. Tool discovery after activation"
echo "============================================================"
command -v spack
command -v R
command -v Rscript
command -v rv
command -v quarto
echo
echo "============================================================"
echo "4. Spack"
echo "============================================================"
spack env status
spack find r
echo
echo "============================================================"
echo "5. rv"
echo "============================================================"
rv cache
rv sync
echo
echo "============================================================"
echo "6. R"
echo "============================================================"
Rscript -e '
cat("R.home():\n")
print(R.home())
cat("\n.libPaths():\n")
print(.libPaths())
pkgs <- c(
"rlang",
"knitr",
"rmarkdown"
)
for (pkg in pkgs) {
cat("\n=====================================\n")
cat(pkg, "\n")
cat("=====================================\n")
cat("find.package():\n")
print(find.package(pkg, quiet = TRUE))
cat("\nrequireNamespace():\n")
print(requireNamespace(pkg, quietly = FALSE))
cat("\nlibrary():\n")
try(library(pkg, character.only = TRUE))
cat("\npackageVersion():\n")
print(packageVersion(pkg))
}
'
echo
echo "============================================================"
echo "7. Quarto discovery"
echo "============================================================"
export QUARTO_R="$(command -v Rscript)"
echo "QUARTO_R=${QUARTO_R}"
quarto check knitr --log-level DEBUG
"""Expected:
- every executable is found
- Quarto prints its version
30.2 2. Verify that Spack owns the R installation
Activate the project environment and inspect the R installation.
show_spython(
spython_exec(
command=r'''
cd /work
source /work/env/activate.sh
spack env status
spack find r
Rscript -e '
cat("R.home():\n")
print(R.home())
cat("\n.libPaths():\n")
print(.libPaths())
'
''',
image=SINGULARITY_IMAGE,
options=[
"--home", f"{CONTAINER_HOME}:/home/rse",
"--bind", f"{CONTAINER_TMP}:/tmp",
],
bind_project=PROJECT_DIR,
),
)Expected:
- the project Spack environment is active
R.home()points inside.spack-env.libPaths()contains
/work/.rv/library
/work/.spack-env/.../R/library
30.3 3. Verify that rv owns the project R packages
Synchronize the project packages and verify that they can be loaded.
show_spython(
spython_exec(
command=r'''
rv sync
Rscript -e '
cat(".libPaths():\n")
print(.libPaths())
pkgs <- c("rlang", "knitr", "rmarkdown")
for (pkg in pkgs) {
cat("\n=============================\n")
cat(pkg, "\n")
cat("=============================\n")
print(find.package(pkg, quiet = TRUE))
print(requireNamespace(pkg, quietly = FALSE))
}
'
''',
image=SINGULARITY_IMAGE,
options=[
"--home", f"{CONTAINER_HOME}:/home/rse",
"--bind", f"{CONTAINER_TMP}:/tmp",
],
bind_project=PROJECT_DIR,
),
)Expected:
TRUE
TRUE
TRUE
for all three packages.
30.4 4. Verify that Quarto discovers the same R installation
Explicitly tell Quarto which R executable to use.
export QUARTO_R="$(command -v Rscript)"
quarto check knitr --log-level DEBUGExpected:
- Quarto reports the same R installation
- knitr is detected
- rmarkdown is detected