Spack environment recovery after a failed upgrade: lockfile re-concretization vs. preserving the old environment view
0 reputation · 09 Oct 2020, 15:14 UTC
0 reputation · 09 Oct 2020, 15:14 UTC
I manage a Spack environment (spack.yaml + spack.lock under version control) and want a reliable recovery path when an upgrade of a core spec (for example a new compiler or MPI) fails concretization or build. Spack has no built-in rollback command, so the plan depends on installs being immutable and the old DAG remaining usable.
The constraint I cannot resolve: re-concretizing an old spack.yaml on a newer Spack release may not reproduce the original dependency versions or hashes, because concretizer output and package.py definitions drift across releases. Keeping the old environment's view intact avoids that, but only works if the old specs are still installed — and spack gc would remove anything no longer referenced, destroying the fallback.
Assuming a recent Spack release (0.20+), my questions are:
spack gc and spack clean so the fallback spec and its build stage are preserved until the upgrade is verified?31775 reputation · 09 Oct 2020, 18:25 UTC
Recovery should be based on keeping the pre-upgrade environment untouched until the upgrade is verified, not on restoring spack.lock and reinstalling. The lockfile alone does not guarantee bit-for-bit reproducibility across Spack releases because package.py concretizer logic and hash algorithms drift. Pinning the Spack release improves reproducibility but does not eliminate hash differences. The safe ordering is: verify the old specs are still installed, do not run spack gc or global spack clean until the new environment builds and passes tests, then clean up the fallback.
spack.lock records the concretized DAG at the moment of installation. When you later run spack install against that lockfile on a different Spack version (or even a different minor release of the same major version), the concretizer may resolve dependencies differently because:
version or variant directives changed in package.pyspack hash output format)Result: the reinstalled packages can have different hashes, breaking binary compatibility with any downstream packages that were built against the original hashes.
Checking in the exact Spack commit (e.g., via spack.yaml spack: section or a spack.lock metadata field) ensures the same concretizer code runs. However:
package.py can change a dependency version.package.py file hashes themselves.For true reproducibility you need the exact Spack source tree (or a container image) that produced the original lockfile.
spack env activate myenv
spack find --format="{name}/{version}/{hash:7}" # record installed specs
spack spec --long # verify concretization matches lockfile
spack gc or spack clean (without --spec) at any point before the new environment is verified. gc removes any package not referenced by an active spec in any environment; a failed upgrade leaves the old specs unreferenced and they will be deleted.spack.yaml, edit specs, spack concretize, spack install). The original environment's install tree remains untouched.spack env deactivate the old environmentspack gc -y to reclaim space (now the old specs are truly unreferenced)spack clean --spec to remove only the old build stages if desiredRun this one-liner against the original environment to confirm the fallback is intact:
spack env activate myenv && spack find -l --format="{name}/{version}/{hash:7}" | grep -v "^==>"
If the expected core specs (compiler, MPI, etc.) appear with their original hashes, the fallback is safe. Only then proceed with gc/clean.
Are you using multiple environments that share the same install tree (i.e., the same spack.yaml install_tree:root)? If yes, spack gc will only remove packages unreferenced by all environments, so the old specs may survive longer. If no (each environment has its own install tree), the fallback is entirely dependent on not running gc in that environment.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.