Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
70 commits
Select commit Hold shift + click to select a range
f1618bf
added spack source mirrors capability, needs testing
grodzki-lanl Feb 17, 2026
954a690
removed lanl stuff
grodzki-lanl Feb 18, 2026
97d43a0
add source mirrors via config.yaml
Feb 24, 2026
15e97f1
add source mirrors via config.yaml
Feb 24, 2026
d125185
Merge branch 'main' of https://github.com/grodzki-lanl/stackinator
Feb 24, 2026
f91fbad
add source mirrors via config.yaml and retain spack default mirror
grodzki-lanl Feb 24, 2026
2a6571e
fixed spaces/tabs typo
grodzki-lanl Feb 24, 2026
06f9dac
Added mirror configuration json schema.
Paul-Ferrell Mar 6, 2026
7692677
Incorporating Makefile changes.
Paul-Ferrell Mar 6, 2026
940886b
mirrors
grodzki-lanl Mar 6, 2026
ffb6083
mirrors
grodzki-lanl Mar 6, 2026
04f9908
validate mirror config
grodzki-lanl Mar 6, 2026
b45039d
Updating recipe to handle new mirrors format.
Paul-Ferrell Mar 6, 2026
d3ee8e4
Updating mirror configuration more.
Paul-Ferrell Mar 6, 2026
0ed23d8
mirror yaml generator
grodzki-lanl Mar 6, 2026
e2a67ab
update mirrors
grodzki-lanl Mar 6, 2026
7346386
validate keys in mirror config and fixed yaml generator
grodzki-lanl Mar 7, 2026
e722f49
validate keys in mirror config and fixed yaml generator
grodzki-lanl Mar 7, 2026
eb2685f
connecting mirrors to builder.py
grodzki-lanl Mar 9, 2026
9d40a83
Put the mirror manipulation code in a class.
Paul-Ferrell Mar 12, 2026
2a7bd1d
preserve cache for makefile
grodzki-lanl Mar 12, 2026
8589cff
Adding bootstrap mirror configs.
Paul-Ferrell Mar 12, 2026
d6a3df7
Reverted to defining the key store path in builder.
Paul-Ferrell Mar 12, 2026
ee0d45f
Compressed mirror config setup into a single interface.
Paul-Ferrell Mar 12, 2026
90d7733
Catching builder exceptions.
Paul-Ferrell Mar 12, 2026
7362cbc
fixing key setup
grodzki-lanl Mar 12, 2026
2a4632d
In progress.
Paul-Ferrell Mar 12, 2026
3915036
Enforce gcc~builtins (#284)
albestro Feb 26, 2026
e11685c
added GPG key verification
grodzki-lanl Mar 13, 2026
593159f
unit tests for mirrors
grodzki-lanl Mar 13, 2026
e1a40fd
mirrors.yaml is now a name:{<config>} mapping
Paul-Ferrell Mar 13, 2026
fb3289d
Now add mount specific paths to certain mirrors.
Paul-Ferrell Mar 13, 2026
d47e2f3
updated test mirror format
grodzki-lanl Mar 13, 2026
c8fb6f9
Fixed build cache enabling via cmdline.
Paul-Ferrell Mar 13, 2026
951aeb4
Error handling
Paul-Ferrell Mar 13, 2026
2ea49e9
Adding a unittest.
Paul-Ferrell Mar 13, 2026
c668b5b
updated yaml formatting
grodzki-lanl Mar 13, 2026
45b1331
Fixed error message.
Paul-Ferrell Mar 13, 2026
533a606
debugging
grodzki-lanl Mar 13, 2026
34d0c65
Minor fix.
Paul-Ferrell Mar 13, 2026
f989631
Fixing urls.
Paul-Ferrell Mar 13, 2026
7822fb7
fixed url for testing
grodzki-lanl Mar 13, 2026
8c814aa
validated mirror tests
grodzki-lanl Mar 13, 2026
5ab3279
added test description
grodzki-lanl Mar 13, 2026
5999ba4
Adding unit tests.
Paul-Ferrell Mar 16, 2026
3c7bc0a
Unit test tweaking.
Paul-Ferrell Mar 16, 2026
e19b868
Added unittests for key setup
Paul-Ferrell Mar 16, 2026
86047ca
Added test for bad keys.
Paul-Ferrell Mar 16, 2026
3d840d0
added more mirror tests
grodzki-lanl Mar 16, 2026
0a25459
added test for bad urls
grodzki-lanl Mar 16, 2026
35591bc
added requirements.txt
grodzki-lanl Mar 16, 2026
431cc9d
Fixed unittest.
Paul-Ferrell Mar 16, 2026
0c59ee9
Added one more unittest.
Paul-Ferrell Mar 16, 2026
d9cdfc4
Linting
Paul-Ferrell Mar 16, 2026
30521d3
Got rid of cache.py
Paul-Ferrell Mar 16, 2026
191af6f
use pyproject for dependencies
bcumming Mar 17, 2026
2fc29d6
add unit test and lint hints to readme
bcumming Mar 17, 2026
d8594a3
tweak presentation of build cache by recipe
bcumming Mar 17, 2026
ef9d7e8
fix build cache configuration
bcumming Mar 20, 2026
8b1e0af
modified bootstrap yaml setup and removed hardcoded alpscache
grodzki-lanl Mar 20, 2026
3c21789
mirrors documentation
grodzki-lanl Mar 26, 2026
596f50e
Switched to the requests libs from urlopen, as urlopen doesn't handle…
Paul-Ferrell Apr 1, 2026
ff42460
restrict number of buildcaches and bootstraps in mirror schema
grodzki-lanl Apr 8, 2026
e10f0c9
fixed mistake
grodzki-lanl Apr 8, 2026
6a203c3
refactored mirrors.py to match new schema
grodzki-lanl Apr 14, 2026
099878a
fixing unit tests, _key_init() still broken
grodzki-lanl Apr 21, 2026
17f4bc6
reverted to old key_setup, add handling for private keys, refactored …
grodzki-lanl Apr 23, 2026
4206e68
linting
grodzki-lanl Apr 23, 2026
fa7ef2f
added 'requests' to pyproject.toml
grodzki-lanl Apr 23, 2026
41e7630
removed old reference
grodzki-lanl Apr 27, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,17 @@ A tool for building a scientific software stack from a recipe for vClusters on C
Read the [documentation](https://eth-cscs.github.io/stackinator/) to get started.

Create a ticket in our [GitHub issues](https://github.com/eth-cscs/stackinator/issues) if you find a bug, have a feature request or have a question.

## running tests:

Use uv to run the tests, which will in turn ensure that the correct dependencies from `pyproject.toml` are used:

```
uv run pytest
```

Before pushing, apply the linting rules (this calls uv under the hood):

```
./lint
```
2 changes: 2 additions & 0 deletions bin/stack-config
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
# /// script
# requires-python = ">=3.12"
# dependencies = [
# "requests",
# "python-magic",
# "jinja2",
# "jsonschema",
# "pyYAML",
Expand Down
21 changes: 21 additions & 0 deletions docs/cluster-config.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,27 @@ packages:
version: ["git.59b6de6a91d9637809677c50cc48b607a91a9acb=main"]
```

### Configuring Spack mirrors: `mirrors.yaml`

On air-gapped systems, Spack is unable to reach its default mirror to fetch packages. The `mirrors.yaml` configuration can be used to connect Spack to local mirrors for fetching and building packages.

`mirrors.yaml` treats source mirrors, buildcaches, and bootstrap mirrors the same, and they may all be included in this file. Spack will search the topmost mirror first and the bottom-most mirror last, and will append the default Spack mirror to the bottom of the list when the Spack mirror config is generated.

If using a buildcache, public and private keys must be provided for signing and verifying packages.

```yaml title="mirrors.yaml"
local_filesystem:
url: file:///home/username/spack-mirror-2014-06-24
site_server:
url: https://example.com/some/web-hosted/directory
buildcache-mirror:
url: https://example.com/some/buildcache/mirror
public_key: ../buildcache-key.public.gpg
private_key: /user-home/.gnupg/private-keys-v1.d/my-private-key.asc
cache: true
bootstrap: true
```

## Site and System Configurations

The `repo.yaml` configuration can be used to provide a list of additional Spack package repositories to use on the target system.
Expand Down
21 changes: 21 additions & 0 deletions nohup.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
Stackinator
 recipe path: /usr/projects/hpctools/grodzki/uenv/my-recipes/recipes/prgenv-gnu-openmpi
 build path : /dev/shm/grodzki/build
 system : /usr/projects/hpctools/grodzki/uenv/my-recipes/cluster-config/venadito
 mount : default
 build cache: None
 develop : False
spack: https://github.com/spack/spack.git already cloned to /dev/shm/grodzki/build/spack
spack: fetching releases/v1.0
spack: checking out releases/v1.0
spack: commit hash is f36409b78591f8b02e8332eb4ad78da62c02571e
spack-packages: https://github.com/spack/spack-packages.git already cloned to /dev/shm/grodzki/build/spack-packages
spack-packages: fetching develop
spack-packages: checking out develop
spack-packages: commit hash is fc656595ff4c7e9c7e5045625dfdd3e92e97b10e

Configuration finished, run the following to build the environment:

cd /dev/shm/grodzki/build
env --ignore-environment PATH=/usr/bin:/bin:`pwd -P`/spack/bin HOME=$HOME make store.squashfs -j32
see logfile for more information /tmp/grodzki/log_stackinator_20260428-112546
2 changes: 2 additions & 0 deletions output.log
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
nohup: ignoring input
/usr/bin/env: ‘uv’: No such file or directory
2 changes: 2 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ license-files = ["LICENSE"]
dynamic = ["version"]
requires-python = ">=3.12"
dependencies = [
"requests",
"python-magic",
"Jinja2",
"jsonschema",
"PyYAML",
Expand Down
13 changes: 13 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
attrs==25.4.0
iniconfig==2.3.0
jsonschema==4.26.0
jsonschema-specifications==2025.9.1
packaging==26.0
pluggy==1.6.0
pygments==2.19.2
pytest==9.0.2
python-magic==0.4.27
pyyaml==6.0.3
referencing==0.37.0
requests==2.32.5
rpds-py==0.30.0
21 changes: 12 additions & 9 deletions stackinator/builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
import jinja2
import yaml

from . import VERSION, cache, root_logger, spack_util
from . import VERSION, root_logger, spack_util, mirror


def install(src, dst, *, ignore=None, symlinks=False):
Expand Down Expand Up @@ -164,13 +164,16 @@ def environment_meta(self, recipe):
self._environment_meta = meta

def generate(self, recipe):
"""Setup the recipe build environment."""
# make the paths, in case bwrap is not used, directly write to recipe.mount
store_path = self.path / "store" if not recipe.no_bwrap else pathlib.Path(recipe.mount)
tmp_path = self.path / "tmp"
config_path = self.path / "config"

self.path.mkdir(exist_ok=True, parents=True)
store_path.mkdir(exist_ok=True)
tmp_path.mkdir(exist_ok=True)
config_path.mkdir(exist_ok=True)

# check out the version of spack
spack_version = recipe.spack_version
Expand Down Expand Up @@ -226,12 +229,13 @@ def generate(self, recipe):
with (self.path / "Makefile").open("w") as f:
f.write(
makefile_template.render(
cache=recipe.mirror,
modules=recipe.with_modules,
post_install_hook=recipe.post_install_hook,
pre_install_hook=recipe.pre_install_hook,
spack_version=spack_version,
spack_meta=spack_meta,
gpg_keys=recipe.mirrors.keys,
cache=recipe.build_cache_mirror,
exclude_from_cache=["nvhpc", "cuda", "perl"],
verbose=False,
)
Expand Down Expand Up @@ -299,8 +303,6 @@ def generate(self, recipe):

# Generate the system configuration: the compilers, environments, etc.
# that are defined for the target cluster.
config_path = self.path / "config"
config_path.mkdir(exist_ok=True)
packages_path = config_path / "packages.yaml"

# the packages.yaml configuration that will be used when building all environments
Expand All @@ -312,11 +314,12 @@ def generate(self, recipe):
fid.write(global_packages_yaml)

# generate a mirrors.yaml file if build caches have been configured
if recipe.mirror:
dst = config_path / "mirrors.yaml"
self._logger.debug(f"generate the build cache mirror: {dst}")
with dst.open("w") as fid:
fid.write(cache.generate_mirrors_yaml(recipe.mirror))
self._logger.debug(f"Generating the spack mirror configs in '{config_path}'")
try:
recipe.mirrors.setup_configs(config_path)
except mirror.MirrorError as err:
self._logger.error(f"Could not set up mirrors.\n{err}")
return 1

# Add custom spack package recipes, configured via Spack repos.
# Step 1: copy Spack repos to store_path where they will be used to
Expand Down
58 changes: 0 additions & 58 deletions stackinator/cache.py

This file was deleted.

28 changes: 23 additions & 5 deletions stackinator/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,13 +81,31 @@ def log_header(args):
def make_argparser():
parser = argparse.ArgumentParser(description=("Generate a build configuration for a spack stack from a recipe."))
parser.add_argument("--version", action="version", version=f"stackinator version {VERSION}")
parser.add_argument("-b", "--build", required=True, type=str)
parser.add_argument(
"-b",
"--build",
required=True,
type=str,
help="Where to set up the stackinator build directory. ('/tmp' is not allowed, use '/var/tmp')",
)
parser.add_argument("--no-bwrap", action="store_true", required=False)
parser.add_argument("-r", "--recipe", required=True, type=str)
parser.add_argument("-s", "--system", required=True, type=str)
parser.add_argument(
"-r", "--recipe", required=True, type=str, help="Name of (and/or path to) the Stackinator recipe."
)
parser.add_argument(
"-s", "--system", required=True, type=str, help="Name of (and/or path to) the Stackinator system configuration."
)
parser.add_argument("-d", "--debug", action="store_true")
parser.add_argument("-m", "--mount", required=False, type=str)
parser.add_argument("-c", "--cache", required=False, type=str)
parser.add_argument(
"-m", "--mount", required=False, type=str, help="The mount point where the environment will be located."
)
parser.add_argument(
"-c",
"--cache",
required=False,
type=str,
help="Buildcache location or name (from system config's mirrors.yaml).",
)
parser.add_argument("--develop", action="store_true", required=False)

return parser
Expand Down
Loading