Skip to content

Latest commit

 

History

History
230 lines (185 loc) · 7.83 KB

tutorial.org

File metadata and controls

230 lines (185 loc) · 7.83 KB

Tutorial: foreign recipe to verified EasyBuild package

This tutorial plans conda-forge eOn, explains the artifacts, and routes the result into a build campaign. The QMCPACK path differs only in parser and package configuration. Closure, generation, baseline, and reachability are in the glossary. The same steps, without these fixed paths, are author a new package.

Prepare the runnable local target

The public tutorial target runs EasyBuild inside the repository’s Rocky Linux Podman image. Build the image and copy the upstream robot plus the eOn fixture overlay into the path namespace mounted by the target:

podman build -t eb-stack-rocky9 \
  -f skills/new-package/container/rocky9/Containerfile \
  skills/new-package/container/rocky9

mkdir -p \
  /tmp/eb-stack/robot \
  /tmp/eb-stack/overlay \
  /tmp/eb-stack/sources \
  /tmp/eb-stack/bundles

scripts/fetch-upstream-trees.sh
set -a
source "${EB_UPSTREAM_CACHE:-$HOME/.cache/eb-stack/upstream}/env.sh"
set +a
rsync -a "$EB_EASYCONFIGS"/ \
  /tmp/eb-stack/robot/
rsync -a fixtures/eon_core_rgpot/easyconfigs/ \
  /tmp/eb-stack/overlay/

Set the paths used throughout the tutorial:

export ROBOT=/tmp/eb-stack/robot
export BUNDLE=/tmp/eb-stack/bundles/eon-tutorial
export STATE=/tmp/eb-stack/bundles/eon-tutorial.campaign.json

The bundle path is identical on the host and in the container. Probe every target layer before planning a long build:

eb-stack target doctor \
  --config examples/targets/local-podman.toml \
  --target local-rocky9

Inspect the conda-forge recipe

eb-stack package inspect \
  --source fixtures/foreign_ingest/conda_eon/recipe.yaml \
  --format conda-forge \
  --toolchain foss/2026.1 \
  --package-config examples/packages/common.toml \
  --package-config examples/packages/eon.toml \
  --out-dir /tmp/eon-inspect

Open /tmp/eon-inspect/package.plan.json. Important sections are:

  • origin and package: foreign identity with configured EasyBuild policy;
  • sources: every source artifact and checksum;
  • dependencies: roles, constraints, conditions, and provenance;
  • build: EasyBuild easyblock, toolchain, and configuration;
  • profiles: independently installable products;
  • outputs: requested profile/stack pairs;
  • residuals: dynamic or ambiguous input that needs judgment.

The planned CycloneDX document is emitted at the same boundary. It describes the requested pre-build inventory and never claims installed evidence.

Resolve and emit

eb-stack package plan \
  --source fixtures/foreign_ingest/conda_eon/recipe.yaml \
  --format conda-forge \
  --toolchain foss/2026.1 \
  --package-config examples/packages/common.toml \
  --package-config examples/packages/eon.toml \
  --easyconfigs "$ROBOT" \
  --easyconfigs /tmp/eb-stack/overlay \
  --stack-policy examples/stacks/eon-foss-2026.1.toml \
  --out-dir "$BUNDLE"

The generated tree contains:

package.plan.json
package.sbom.cdx.json
closure.plan.json
closure.sbom.cdx.json
build-order.json
locks/default.lock.json
easyconfigs/e/eOn/eOn-2.16.0-foss-2026.1.eb
easyconfigs/e/eOn/eOn-2.16.0_safemath-eigen5-core-guard.patch

The lock is the actual Resolvo result. Its direct dependencies name selected versions, toolchains, versionsuffixes, source easyconfig paths, build/runtime roles, pin outcomes, and candidate exclusions.

Understand stack pin fallback

examples/stacks/eon-foss-2026.1.toml records the Eigen 5 identity required by the safemath core-guard patch without imposing it on unrelated package plans. It is a preferred pin with the complete EasyBuild toolchain and versionsuffix identity. Resolvo admits the pinned artifact’s dependency closure, then first tries that favored candidate. If another declared requirement or known exclusion makes it infeasible, the solver selects a compatible alternative and sets fallback = true with a reason in the lock. Change the mode to locked only when the stack requires that exact candidate and must fail otherwise. The core + rgpot product needs no cross-generation pins; every dependency sits on the foss-2026.1 / GCCcore-15.2.0 generation.

A version range is not build evidence. A candidate can be SAT-compatible and still fail configure, compile, link, tests, install, or sanity. Those outcomes belong to the campaign finding model.

Check the emitted recipe

RECIPE="$BUNDLE/easyconfigs/e/eOn/eOn-2.16.0-foss-2026.1.eb"

eb-stack recipe format "$RECIPE"
eb-stack recipe lint "$RECIPE"
eb-stack recipe check \
  --recipe "$RECIPE" \
  --easyconfigs "$ROBOT" \
  --easyconfigs /tmp/eb-stack/overlay \
  --easyconfigs "$BUNDLE/easyconfigs"

At this point the bundle may claim resolves. No build has occurred.

Probe the target

eb-stack target list \
  --config examples/targets/local-podman.toml

eb-stack target doctor \
  --config examples/targets/local-podman.toml \
  --target local-rocky9

Read all four checks. A healthy transport does not imply a healthy executor, runtime, or EasyBuild command.

Run and repair the campaign

eb-stack campaign run \
  --bundle "$BUNDLE" \
  --config examples/targets/local-podman.toml \
  --target local-rocky9 \
  --state "$STATE"

eb-stack campaign status --state "$STATE"

campaign run stays in the foreground. Keep that shell under the process supervisor used by the target site and use another shell for campaign status. If the controlling process is interrupted, first confirm that the routed container, scheduler job, or host command has stopped, then rerun with the same state path. The state remains the audit record; do not start a duplicate state for the same bundle.

If the campaign fails, campaign status prints the finding id. Claim that id and record the repair with the commands in Repair a failed campaign. Run the campaign again with the same state. Successful stages supersede stale open findings. builds becomes true only after all emitted recipes succeed. binary_verified becomes true only when at least one declared verification command exists and all such commands succeed.

Route the same bundle again

The same public target runs a second time against the bundle this tutorial already planned. examples/targets/site.example.toml is the file to copy when a site fills in its own host, image, and scheduler. This checkout runs the local target:

eb-stack target doctor \
  --config examples/targets/local-podman.toml \
  --target local-rocky9

eb-stack campaign run \
  --bundle "$BUNDLE" \
  --config examples/targets/local-podman.toml \
  --target local-rocky9 \
  --state "$STATE"

The bundle must be visible at the same absolute path used by the selected runtime. The local target mounts /tmp/eb-stack, which is why $BUNDLE lives there.

Try QMCPACK variants

Replace the source and package-config arguments:

eb-stack package plan \
  --source fixtures/foreign_ingest/spack_qmcpack/package.py \
  --format spack \
  --toolchain foss/2026.1 \
  --package-config examples/packages/common.toml \
  --package-config examples/packages/qmcpack.toml \
  --source-checksum 511d5f368db002f2f77504619e1ada8d4a3034200d25feef6773d12a6ed6d18e \
  --easyconfigs "$ROBOT" \
  --easyconfigs fixtures/qmcpack_foss_2026_1/easyconfigs \
  --stack-policy examples/stacks/foss-2026.1.toml \
  --out-dir /tmp/qmcpack-tutorial

QMCPACK emits one unsuffixed default recipe and one -complex recipe because the latter is an independently loadable product variant. Both profiles get their own lock and must build in the campaign. The source checksum is explicit because this Spack package pins the release by Git commit rather than by the SHA-256 of its GitHub archive.