Compare commits

...

61 commits
main ... main

Author SHA1 Message Date
71b1b660f2
Merge pull request 'feat: custom evaluation' (#1) from custom-activation into main
Reviewed-on: DGNum/colmena#1
2024-12-07 12:43:09 +01:00
92c5f5c33f
feat: generic registry and custom evaluation
This PR bring custom evaluation, but does not offer yet custom
activation.

Therefore, you can evaluate your systems and refer to each of them, but
you cannot ask Colmena to build them for you.

Signed-off-by: Ryan Lahfa <ryan@dgnum.eu>
2024-12-07 12:42:58 +01:00
7fa3062cfb
feat: disable key management modules
Let the user opt-in… !

Signed-off-by: Ryan Lahfa <ryan@dgnum.eu>
2024-12-07 12:38:19 +01:00
Zhaofeng Li
e3ad421380
Merge pull request #251 from zhaofengli/renovate/all-minor-patch
fix(deps): update all non-major dependencies
2024-11-13 12:43:22 -07:00
renovate[bot]
f5ffb64491
fix(deps): update all non-major dependencies 2024-11-12 20:50:29 +00:00
Zhaofeng Li
a2193487bc
Merge pull request #249 from zhaofengli/renovate/all-minor-patch
chore(deps): update jamesives/github-pages-deploy-action action to v4.6.9
2024-11-10 07:43:47 -07:00
renovate[bot]
7ccfa7aae1
chore(deps): update jamesives/github-pages-deploy-action action to v4.6.9 2024-11-09 22:38:48 +00:00
Zhaofeng Li
c4d72269af
Merge pull request #248 from zhaofengli/remove-atty
progress: Detect tty with std::io::IsTerminal, remove atty
2024-11-08 12:17:18 -07:00
Zhaofeng Li
68219763dd
Merge pull request #233 from valkum/fix-symlink
resolve TempDir paths before passing them to the flake bin
2024-11-08 12:03:41 -07:00
Zhaofeng Li
e73c6921fd progress: Detect tty with std::io::IsTerminal, remove atty
Fixes https://github.com/advisories/GHSA-g98v-hv3f-hcfr.
2024-11-08 11:44:10 -07:00
Zhaofeng Li
936ed520eb Cargo.lock: Update 2024-11-08 11:44:10 -07:00
Zhaofeng Li
e5c30066c2 Revert ".github: Run workflows on push event only"
Sadly it breaks CI in fork-originated PRs if the author doesn't enable
Actions on the fork itself.

This reverts commit ce1aa41ff4.
2024-11-08 11:27:40 -07:00
Zhaofeng Li
1a07996142
Merge pull request #247 from zhaofengli/readme-badge-branch
README.md: Fix badge branch
2024-11-08 11:22:57 -07:00
Zhaofeng Li
3d9d22bd7b
Merge pull request #239 from zhaofengli/renovate/all-minor-patch
Update all non-major dependencies
2024-11-08 09:08:34 -07:00
Rudi Floren
00fd486d49 resolve TempDir paths before passing them to the flake bin
On MacOS /tmp is a symlink to /private/tmp.
TempDir creates a dir and returns the path as /tmp.
nix is unhappy with symlink dirs when calling nix flake metadata --json

To fix this we canonicalize the path first, resolving any symlinks on the way.

Fixes #190.
2024-11-08 08:57:28 -07:00
Zhaofeng Li
4dc8155712 Update code for validator 0.19.0 2024-11-08 08:26:29 -07:00
Zhaofeng Li
b46e9dbd4c README.md: Fix badge branch
[ci skip]
2024-11-07 21:00:48 -07:00
renovate[bot]
40429b7ed4
Update all non-major dependencies 2024-11-08 03:48:26 +00:00
Zhaofeng Li
03f1a18a6f
Merge pull request #245 from zhaofengli/renovate/docker-setup-qemu-action-3.x
Update docker/setup-qemu-action action to v3
2024-11-07 20:47:23 -07:00
renovate[bot]
926ae650fb
Update docker/setup-qemu-action action to v3 2024-11-08 03:17:33 +00:00
Zhaofeng Li
ec21d8514b
Merge pull request #243 from zhaofengli/renovate/actions-checkout-4.x
Update actions/checkout action to v4
2024-11-07 20:15:40 -07:00
Zhaofeng Li
123028ce09
Merge pull request #244 from zhaofengli/renovate/cachix-cachix-action-15.x
Update cachix/cachix-action action to v15
2024-11-07 20:15:30 -07:00
Zhaofeng Li
e9ee03aeeb
Merge pull request #240 from zhaofengli/renovate/determinatesystems-nix-installer-action-15.x
Update DeterminateSystems/nix-installer-action action to v15
2024-11-07 18:12:36 -07:00
renovate[bot]
bfc3cc8271
Update cachix/cachix-action action to v15 2024-11-08 01:08:05 +00:00
renovate[bot]
b82ee861dd
Update actions/checkout action to v4 2024-11-08 01:08:00 +00:00
Zhaofeng Li
0e0b682d42
Merge pull request #242 from zhaofengli/aarch64-darwin
.github/build: Update macOS runner, add aarch64-darwin
2024-11-07 18:06:46 -07:00
renovate[bot]
c78d024f3a
Update DeterminateSystems/nix-installer-action action to v15 2024-11-08 00:42:22 +00:00
Zhaofeng Li
9469ed3591
Merge pull request #237 from zhaofengli/renovate/configure
chore: Configure Renovate
2024-11-07 17:40:56 -07:00
Zhaofeng Li
b02d2d6ba7
Merge pull request #238 from zhaofengli/srcignore
Exclude more paths from colmena.src to reduce rebuilds
2024-11-07 17:39:17 -07:00
Zhaofeng Li
998f92d869 .github/build: Update macOS runner, add aarch64-darwin
The new hosted GitHub runners are Apple Silicon-based only, and we
build x86_64-darwin packages via Rosetta 2.
2024-11-07 17:19:59 -07:00
Zhaofeng Li
ce1aa41ff4 .github: Run workflows on push event only 2024-11-07 17:08:49 -07:00
Zhaofeng Li
a70411fd1d Exclude more paths from colmena.src to reduce rebuilds 2024-11-07 16:42:45 -07:00
Zhaofeng Li
596b6d883e .editorconfig: Enforce .json indentation 2024-11-07 16:24:44 -07:00
Zhaofeng Li
4cfa0b6092 renovate.json: Group non-major updates together 2024-11-07 16:24:44 -07:00
Zhaofeng Li
ac23318700 renovate.json: Enable Nix & lock file maintenance 2024-11-07 16:24:44 -07:00
renovate[bot]
6db6b30b01 Add renovate.json 2024-11-07 16:24:44 -07:00
Zhaofeng Li
2c95c1766a
Merge pull request #228 from zhaofengli/direct-flake-eval
Add direct flake evaluation support
2024-11-07 16:03:30 -07:00
Zhaofeng Li
a4604f3371 manual/flakes: Document direct flake evaluation 2024-11-07 15:51:20 -07:00
Zhaofeng Li
33c41abd44 Remove garnix config 2024-11-07 15:24:37 -07:00
Zhaofeng Li
f593c24aa2 .github/nix-matrix-job: Maximize build space 2024-11-07 15:24:37 -07:00
Zhaofeng Li
e17c521c15 Run integration tests on GitHub Actions 2024-11-07 15:24:37 -07:00
Zhaofeng Li
0ef98d060c integration-tests/flakes: Fix error message matching 2024-11-07 15:24:37 -07:00
Zhaofeng Li
45ca75bcea integration-tests/flakes: Switch to direct flake evaluation (experimental) 2024-11-07 15:24:37 -07:00
Zhaofeng Li
0a836dc251 integration-tests/tools: Re-enable switch-to-configuration 2024-11-07 15:24:37 -07:00
Zhaofeng Li
dc80345dee Add direct flake evaluation support 2024-11-07 15:24:37 -07:00
Zhaofeng Li
1f669d4c78 Bump schema version to v0.20241006 2024-11-07 15:24:37 -07:00
Zhaofeng Li
2708c9359f Revert "[FIXME] integration-tests: Temproarily pin to Nix 2.18"
This reverts commit 141fe82f44.
2024-11-07 15:24:37 -07:00
Zhaofeng Li
1f7b8ab80f package.nix: Exclude .github from cleaned source 2024-11-07 15:24:37 -07:00
Zhaofeng Li
8a8f47a1b1 flake.nix: Apply nix-eval-jobs overlay on output package set 2024-11-07 15:24:37 -07:00
Zhaofeng Li
524cd45299 flake.lock: Update 2024-11-07 15:24:37 -07:00
Zhaofeng Li
70462312f2 .editorconfig: Ignore Rust
Too rigid :/ Let's just let rustfmt handle it.
2024-11-07 15:24:37 -07:00
Zhaofeng Li
ec25d799ed .gitignore: Ignore .vscode 2024-11-07 15:24:37 -07:00
Zhaofeng Li
b0a62f234f
Merge pull request #224 from peterablehmann/main
Fix describe_node_list remaining nodes special case
2024-10-06 19:14:38 -06:00
Zhaofeng Li
0fca61acc2
Merge pull request #222 from benaryorg/mddoc
lib.mdDoc has been deprecated since 24.05
2024-10-05 20:11:13 -06:00
Zhaofeng Li
43be9effab flake.nix: Patch nix-eval-jobs for NIX_PATH 2024-10-05 19:57:58 -06:00
Zhaofeng Li
141fe82f44 [FIXME] integration-tests: Temproarily pin to Nix 2.18 2024-10-05 19:57:58 -06:00
Zhaofeng Li
87eb6c2f4c integration-tests/tools: Increase deployer memory to 6 GiB
OOMs with nix-eval-jobs
2024-10-05 19:57:58 -06:00
Peter Lehmann
569c914f95
Fix describe_node_list remaining nodes special case
Colmena truncates left over node names when it reaches a certain char limit.
This in it self is a sensible behaivior, but it should only do so if there is more then one node name remaining.
2024-09-02 22:45:43 +02:00
Zhaofeng Li
aeccdba3b4 flake: Update stable to NixOS 24.05 2024-09-01 13:06:00 -04:00
Zhaofeng Li
8f9986a748 flake: Update nixpkgs unstable 2024-09-01 13:06:00 -04:00
benaryorg
7bb23baf40
lib.mdDoc has been deprecated since 24.05
`lib.mdDoc` emits this trace when called since 24.05:

```quote
trace: warning: lib.mdDoc will be removed from nixpkgs in 24.11. Option descriptions are now in Markdown by default; you can remove any remaining uses of lib.mdDoc.
```

Given that this was introduced with 22.11 and made obsolete in 24.05 with all prior versions being EoL at this point it should be safe to revert that change.
In any case the only result will be that anything ≥22.11 and <24.05 will be rendered without markup which I guess isn't the best, but given those are EoL systems it's not the worst.

Either way it gets rid of a *lot* of noise for 24.05 users in the trace, and for 24.11 and up it will remove dead code.

This reverts commit 7602e548a7.

Signed-off-by: benaryorg <binary@benary.org>
2024-08-23 13:37:06 +00:00
32 changed files with 1334 additions and 651 deletions

View file

@ -10,8 +10,7 @@ insert_final_newline = true
trim_trailing_whitespace = true
charset = utf-8
# Rust
[*.rs]
[*.json]
indent_style = space
indent_size = 2

View file

@ -13,19 +13,23 @@ jobs:
image: ubuntu-latest
system: aarch64-linux
- label: x86_64-darwin
image: macos-12
image: macos-latest
system: x86_64-darwin
- label: aarch64-darwin
image: macos-latest
system: aarch64-darwin
name: ${{ matrix.label }}
runs-on: ${{ matrix.image }}
steps:
- uses: actions/checkout@v3.3.0
- uses: actions/checkout@v4.2.2
- name: Install Nix
uses: DeterminateSystems/nix-installer-action@9b252454a8d70586c4ee7f163bf4bb1e9de3d763 # v2
uses: DeterminateSystems/nix-installer-action@b92f66560d6f97d6576405a7bae901ab57e72b6a # v15
- name: Set up QEMU
uses: docker/setup-qemu-action@v2.1.0
if: matrix.system != ''
uses: docker/setup-qemu-action@v3.2.0
if: matrix.system == 'aarch64-linux'
- name: Generate System Flags
run: |
@ -39,7 +43,7 @@ jobs:
HOST_SYSTEM: '${{ matrix.system }}'
- name: Enable Binary Cache
uses: cachix/cachix-action@v12
uses: cachix/cachix-action@v15
with:
name: colmena
authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'
@ -49,3 +53,60 @@ jobs:
- name: Build manual
run: nix build .#manual -L
nix-matrix:
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.set-matrix.outputs.matrix }}
steps:
- uses: actions/checkout@v4.2.2
- uses: DeterminateSystems/nix-installer-action@v15
continue-on-error: true # Self-hosted runners already have Nix installed
- name: Enable Binary Cache
uses: cachix/cachix-action@v15
with:
name: colmena
authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'
- id: set-matrix
name: Generate Nix Matrix
run: |
set -Eeu
matrix="$(nix eval --json '.#githubActions.matrix')"
echo "matrix=$matrix" >> "$GITHUB_OUTPUT"
nix-matrix-job:
name: ${{ matrix.name }}
runs-on: ${{ matrix.os }}
needs:
- build
- nix-matrix
strategy:
matrix: ${{ fromJSON(needs.nix-matrix.outputs.matrix) }}
steps:
- name: Maximize build space
uses: easimon/maximize-build-space@master
with:
remove-dotnet: 'true'
build-mount-path: /nix
- name: Set /nix permissions
run: |
sudo chown root:root /nix
- uses: actions/checkout@v4.2.2
- uses: DeterminateSystems/nix-installer-action@v15
continue-on-error: true # Self-hosted runners already have Nix installed
- name: Enable Binary Cache
uses: cachix/cachix-action@v15
with:
name: colmena
authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'
- name: Build ${{ matrix.attr }}
run: |
nix build --no-link --print-out-paths -L '.#${{ matrix.attr }}'

View file

@ -10,13 +10,13 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3.3.0
- uses: actions/checkout@v4.2.2
- name: Install Nix
uses: DeterminateSystems/nix-installer-action@9b252454a8d70586c4ee7f163bf4bb1e9de3d763 # v2
uses: DeterminateSystems/nix-installer-action@b92f66560d6f97d6576405a7bae901ab57e72b6a # v15
- name: Enable binary cache
uses: cachix/cachix-action@v12
uses: cachix/cachix-action@v15
with:
name: colmena
authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'

View file

@ -16,13 +16,13 @@ jobs:
if: github.repository == 'zhaofengli/colmena'
steps:
- uses: actions/checkout@v3.3.0
- uses: actions/checkout@v4.2.2
- name: Install Nix
uses: DeterminateSystems/nix-installer-action@9b252454a8d70586c4ee7f163bf4bb1e9de3d763 # v2
uses: DeterminateSystems/nix-installer-action@b92f66560d6f97d6576405a7bae901ab57e72b6a # v15
- name: Enable Binary Cache
uses: cachix/cachix-action@v12
uses: cachix/cachix-action@v15
with:
name: colmena
authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'
@ -38,7 +38,7 @@ jobs:
run: nix build .#manual -L
- name: Deploy manual
uses: JamesIves/github-pages-deploy-action@4.1.6
uses: JamesIves/github-pages-deploy-action@v4.6.9
with:
branch: gh-pages
folder: result
@ -52,7 +52,7 @@ jobs:
if: ${{ env.api_version == env.latest_stable_api }}
- name: Deploy redirect farm
uses: JamesIves/github-pages-deploy-action@4.1.6
uses: JamesIves/github-pages-deploy-action@v4.6.9
with:
branch: gh-pages
folder: result-redirectFarm

View file

@ -16,13 +16,13 @@ jobs:
if: github.repository == 'zhaofengli/colmena'
steps:
- uses: actions/checkout@v3.3.0
- uses: actions/checkout@v4.2.2
- name: Install Nix
uses: DeterminateSystems/nix-installer-action@9b252454a8d70586c4ee7f163bf4bb1e9de3d763 # v2
uses: DeterminateSystems/nix-installer-action@b92f66560d6f97d6576405a7bae901ab57e72b6a # v15
- name: Enable Binary Cache
uses: cachix/cachix-action@v12
uses: cachix/cachix-action@v15
with:
name: colmena
authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'
@ -32,7 +32,7 @@ jobs:
run: nix build .#manual -L
- name: Deploy manual
uses: JamesIves/github-pages-deploy-action@v4.3.4
uses: JamesIves/github-pages-deploy-action@v4.6.9
with:
branch: gh-pages
folder: result
@ -47,7 +47,7 @@ jobs:
run: nix build .#manual.redirectFarm -L
- name: Deploy redirect farm
uses: JamesIves/github-pages-deploy-action@4.1.6
uses: JamesIves/github-pages-deploy-action@v4.6.9
with:
branch: gh-pages
folder: result-redirectFarm

View file

@ -13,15 +13,15 @@ jobs:
name: ${{ matrix.os.label }}
runs-on: ${{ matrix.os.image }}
steps:
- uses: actions/checkout@v3.3.0
- uses: actions/checkout@v4.2.2
with:
fetch-depth: 0
- name: Install Nix
uses: DeterminateSystems/nix-installer-action@9b252454a8d70586c4ee7f163bf4bb1e9de3d763 # v2
uses: DeterminateSystems/nix-installer-action@b92f66560d6f97d6576405a7bae901ab57e72b6a # v15
- name: Enable Binary Cache
uses: cachix/cachix-action@v12
uses: cachix/cachix-action@v15
with:
name: colmena
authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'

1
.gitignore vendored
View file

@ -1,3 +1,4 @@
result*
/target
/.direnv
/.vscode

18
.srcignore Normal file
View file

@ -0,0 +1,18 @@
# Exclusions from source distribution
#
# Files listed here will not be part of colmena.src
/.github
/CNAME
/renovate.json
/manual
/integration-tests
/nix
/default.nix
/flake-compat.nix
/package.nix
/shell.nix
# vim: set ft=gitignore:

1247
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -9,18 +9,17 @@ edition = "2021"
[dependencies]
async-stream = "0.3.5"
async-trait = "0.1.68"
atty = "0.2"
clap = { version = "4.3", features = ["derive"] }
clap_complete = "4.3"
clicolors-control = "1"
console = "0.15.5"
const_format = "0.2.30"
env_logger = "0.10.0"
env_logger = "0.11.0"
futures = "0.3.28"
glob = "0.3.1"
hostname = "0.3.1"
hostname = "0.4.0"
indicatif = "0.17.3"
itertools = "0.11.0"
itertools = "0.13.0"
libc = "0.2.144"
log = "0.4.17"
quit = "2.0.0"
@ -28,12 +27,12 @@ regex = "1"
serde = { version = "1.0.163", features = ["derive"] }
serde_json = "1.0"
shell-escape = "0.1.5"
snafu = { version = "0.7.4", features = ["backtrace", "backtraces-impl-backtrace-crate"] }
snafu = { version = "0.8.0", features = ["backtrace", "backtraces-impl-backtrace-crate"] }
sys-info = "0.9.1"
tempfile = "3.5.0"
tokio-stream = "0.1.14"
uuid = { version = "1.3.2", features = ["serde", "v4"] }
validator = { version = "0.16.0", features = ["derive"] }
validator = { version = "0.19.0", features = ["derive"] }
[dev-dependencies]
ntest = "0.9.0"

View file

@ -3,7 +3,7 @@
[![Matrix Channel](https://img.shields.io/badge/Matrix-%23colmena%3Anixos.org-blueviolet)](https://matrix.to/#/#colmena:nixos.org)
[![Stable Manual](https://img.shields.io/badge/Manual-Stable-informational)](https://colmena.cli.rs/stable)
[![Unstable Manual](https://img.shields.io/badge/Manual-Unstable-orange)](https://colmena.cli.rs/unstable)
[![Build](https://github.com/zhaofengli/colmena/workflows/Build/badge.svg)](https://github.com/zhaofengli/colmena/actions/workflows/build.yml)
[![Build](https://github.com/zhaofengli/colmena/actions/workflows/build.yml/badge.svg)](https://github.com/zhaofengli/colmena/actions/workflows/build.yml)
Colmena is a simple, stateless [NixOS](https://nixos.org) deployment tool modeled after [NixOps](https://github.com/NixOS/nixops) and [morph](https://github.com/DBCDK/morph), written in Rust.
It's a thin wrapper over Nix commands like `nix-instantiate` and `nix-copy-closure`, and supports parallel deployment.

View file

@ -31,13 +31,33 @@
"type": "github"
}
},
"nix-github-actions": {
"inputs": {
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1729742964,
"narHash": "sha256-B4mzTcQ0FZHdpeWcpDYPERtyjJd/NIuaQ9+BV1h+MpA=",
"owner": "nix-community",
"repo": "nix-github-actions",
"rev": "e04df33f62cdcf93d73e9a04142464753a16db67",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "nix-github-actions",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1696019113,
"narHash": "sha256-X3+DKYWJm93DRSdC5M6K5hLqzSya9BjibtBsuARoPco=",
"lastModified": 1730785428,
"narHash": "sha256-Zwl8YgTVJTEum+L+0zVAWvXAGbWAuXHax3KzuejaDyo=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "f5892ddac112a1e9b3612c39af1b72987ee5783a",
"rev": "4aa36568d413aca0ea84a1684d2d46f55dbabad7",
"type": "github"
},
"original": {
@ -51,22 +71,23 @@
"inputs": {
"flake-compat": "flake-compat",
"flake-utils": "flake-utils",
"nix-github-actions": "nix-github-actions",
"nixpkgs": "nixpkgs",
"stable": "stable"
}
},
"stable": {
"locked": {
"lastModified": 1696039360,
"narHash": "sha256-g7nIUV4uq1TOVeVIDEZLb005suTWCUjSY0zYOlSBsyE=",
"lastModified": 1730883749,
"narHash": "sha256-mwrFF0vElHJP8X3pFCByJR365Q2463ATp2qGIrDUdlE=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "32dcb45f66c0487e92db8303a798ebc548cadedc",
"rev": "dba414932936fde69f0606b4f1d87c5bc0003ede",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-23.05",
"ref": "nixos-24.05",
"repo": "nixpkgs",
"type": "github"
}

View file

@ -3,7 +3,12 @@
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
stable.url = "github:NixOS/nixpkgs/nixos-23.05";
stable.url = "github:NixOS/nixpkgs/nixos-24.05";
nix-github-actions = {
url = "github:nix-community/nix-github-actions";
inputs.nixpkgs.follows = "nixpkgs";
};
flake-utils.url = "github:numtide/flake-utils";
@ -13,12 +18,41 @@
};
};
outputs = { self, nixpkgs, stable, flake-utils, ... } @ inputs: let
outputs = {
self,
nixpkgs,
stable,
flake-utils,
nix-github-actions,
...
} @ inputs: let
supportedSystems = [ "x86_64-linux" "i686-linux" "aarch64-linux" "x86_64-darwin" "aarch64-darwin" ];
colmenaOptions = import ./src/nix/hive/options.nix;
colmenaModules = import ./src/nix/hive/modules.nix;
# Temporary fork of nix-eval-jobs with changes to be upstreamed
# Mostly for the integration test setup and not needed in most use cases
_evalJobsOverlay = final: prev: let
patched = prev.nix-eval-jobs.overrideAttrs (old: {
version = old.version + "-colmena";
patches = (old.patches or []) ++ [
# Allows NIX_PATH to be honored
(final.fetchpatch {
url = "https://github.com/zhaofengli/nix-eval-jobs/commit/6ff5972724230ac2b96eb1ec355cd25ca512ef57.patch";
hash = "sha256-2NiMYpw27N+X7Ixh2HkP3fcWvopDJWQDVjgRdhOL2QQ";
})
];
});
in {
nix-eval-jobs = patched;
};
in flake-utils.lib.eachSystem supportedSystems (system: let
pkgs = nixpkgs.legacyPackages.${system};
pkgs = import nixpkgs {
inherit system;
overlays = [
_evalJobsOverlay
];
};
in rec {
# We still maintain the expression in a Nixpkgs-acceptable form
defaultPackage = self.packages.${system}.colmena;
@ -83,11 +117,21 @@
in if pkgs.stdenv.isLinux then import ./integration-tests {
pkgs = import nixpkgs {
inherit system;
overlays = [ self.overlays.default inputsOverlay ];
overlays = [
self.overlays.default
inputsOverlay
_evalJobsOverlay
];
};
pkgsStable = import stable {
inherit system;
overlays = [ self.overlays.default inputsOverlay ];
overlays = [
self.overlays.default
inputsOverlay
_evalJobsOverlay
];
};
} else {};
}) // {
@ -104,6 +148,12 @@
inherit rawHive colmenaOptions colmenaModules;
hermetic = true;
};
githubActions = nix-github-actions.lib.mkGithubMatrix {
checks = {
inherit (self.checks) x86_64-linux;
};
};
};
nixConfig = {

View file

@ -1,3 +0,0 @@
builds:
include:
- 'checks.x86_64-linux.*'

View file

@ -8,8 +8,18 @@
apply-local = import ./apply-local { inherit pkgs; };
build-on-target = import ./build-on-target { inherit pkgs; };
exec = import ./exec { inherit pkgs; };
flakes = import ./flakes { inherit pkgs; };
flakes-streaming = import ./flakes { inherit pkgs; evaluator = "streaming"; };
# FIXME: The old evaluation method doesn't work purely with Nix 2.21+
flakes = import ./flakes {
inherit pkgs;
extraApplyFlags = "--experimental-flake-eval";
};
flakes-impure = import ./flakes {
inherit pkgs;
pure = false;
};
#flakes-streaming = import ./flakes { inherit pkgs; evaluator = "streaming"; };
parallel = import ./parallel { inherit pkgs; };
allow-apply-all = import ./allow-apply-all { inherit pkgs; };

View file

@ -1,13 +1,29 @@
{ pkgs
, evaluator ? "chunked"
, extraApplyFlags ? ""
, pure ? true
}:
let
inherit (pkgs) lib;
tools = pkgs.callPackage ../tools.nix {
targets = [ "alpha" ];
};
applyFlags = "--evaluator ${evaluator} ${extraApplyFlags}"
+ lib.optionalString (!pure) "--impure";
# From integration-tests/nixpkgs.nix
colmenaFlakeInputs = pkgs._inputs;
in tools.runTest {
name = "colmena-flakes-${evaluator}";
name = "colmena-flakes-${evaluator}"
+ lib.optionalString (!pure) "-impure";
nodes.deployer = {
virtualisation.additionalPaths =
lib.mapAttrsToList (k: v: v.outPath) colmenaFlakeInputs;
};
colmena.test = {
bundle = ./.;
@ -16,12 +32,13 @@ in tools.runTest {
import re
deployer.succeed("sed -i 's @nixpkgs@ path:${pkgs._inputs.nixpkgs.outPath}?narHash=${pkgs._inputs.nixpkgs.narHash} g' /tmp/bundle/flake.nix")
deployer.succeed("sed -i 's @colmena@ path:${tools.colmena.src} g' /tmp/bundle/flake.nix")
with subtest("Lock flake dependencies"):
deployer.succeed("cd /tmp/bundle && nix --extra-experimental-features \"nix-command flakes\" flake lock")
with subtest("Deploy with a plain flake without git"):
deployer.succeed("cd /tmp/bundle && ${tools.colmenaExec} apply --on @target --evaluator ${evaluator}")
deployer.succeed("cd /tmp/bundle && ${tools.colmenaExec} apply --on @target ${applyFlags}")
alpha.succeed("grep FIRST /etc/deployment")
with subtest("Deploy with a git flake"):
@ -29,21 +46,22 @@ in tools.runTest {
# don't put probe.nix in source control - should fail
deployer.succeed("cd /tmp/bundle && git init && git add flake.nix flake.lock hive.nix tools.nix")
logs = deployer.fail("cd /tmp/bundle && run-copy-stderr ${tools.colmenaExec} apply --on @target --evaluator ${evaluator}")
assert re.search(r"probe.nix.*No such file or directory", logs)
logs = deployer.fail("cd /tmp/bundle && run-copy-stderr ${tools.colmenaExec} apply --on @target ${applyFlags}")
assert re.search(r"probe.nix.*(No such file or directory|does not exist)", logs), "Expected error message not found in log"
# now it should succeed
deployer.succeed("cd /tmp/bundle && git add probe.nix")
deployer.succeed("cd /tmp/bundle && ${tools.colmenaExec} apply --on @target --evaluator ${evaluator}")
deployer.succeed("cd /tmp/bundle && ${tools.colmenaExec} apply --on @target ${applyFlags}")
alpha.succeed("grep SECOND /etc/deployment")
'' + lib.optionalString pure ''
with subtest("Check that impure expressions are forbidden"):
deployer.succeed("sed -i 's|SECOND|''${builtins.readFile /etc/hostname}|g' /tmp/bundle/probe.nix")
logs = deployer.fail("cd /tmp/bundle && run-copy-stderr ${tools.colmenaExec} apply --on @target --evaluator ${evaluator}")
assert re.search(r"access to absolute path.*forbidden in pure eval mode", logs)
logs = deployer.fail("cd /tmp/bundle && run-copy-stderr ${tools.colmenaExec} apply --on @target ${applyFlags}")
assert re.search(r"access to absolute path.*forbidden in pure (eval|evaluation) mode", logs), "Expected error message not found in log"
with subtest("Check that impure expressions can be allowed with --impure"):
deployer.succeed("cd /tmp/bundle && ${tools.colmenaExec} apply --on @target --evaluator ${evaluator} --impure")
deployer.succeed("cd /tmp/bundle && ${tools.colmenaExec} apply --on @target ${applyFlags} --impure")
alpha.succeed("grep deployer /etc/deployment")
'';
};

View file

@ -3,13 +3,15 @@
inputs = {
nixpkgs.url = "@nixpkgs@";
colmena.url = "@colmena@";
};
outputs = { self, nixpkgs }: let
outputs = { self, nixpkgs, colmena }: let
pkgs = import nixpkgs {
system = "x86_64-linux";
};
in {
colmena = import ./hive.nix { inherit pkgs; };
colmenaHive = colmena.lib.makeHive self.outputs.colmena;
};
}

View file

@ -140,7 +140,7 @@ let
nix.settings.substituters = lib.mkForce [];
virtualisation = {
memorySize = 4096;
memorySize = 6144;
writableStore = true;
additionalPaths = [
"${pkgs.path}"
@ -165,6 +165,9 @@ let
exec "$@" 2> >(tee /dev/stderr)
'')
];
# Re-enable switch-to-configuration
system.switch.enable = true;
};
# Setup for target nodes
@ -180,6 +183,9 @@ let
sshKeys.snakeOilPublicKey
];
virtualisation.writableStore = true;
# Re-enable switch-to-configuration
system.switch.enable = true;
};
nodes = let

View file

@ -90,6 +90,34 @@ To build and deploy to all nodes:
colmena apply
```
## Direct Flake Evaluation (Experimental)
By default, Colmena uses `nix-instantiate` to evaluate your flake which does not work purely on Nix 2.21+, necessitating the use of `--impure`.
There is experimental support for evaluating flakes directly with `nix eval`, enabled via `--experimental-flake-eval`.
To use this new evaluation mode, your flake needs to depend on Colmena itself as an input and expose a new output called `colmenaHive`:
```diff
{
inputs = {
+ # ADDED: Colmena input
+ colmena.url = "github:zhaofengli/colmena";
# ... Rest of configuration ...
};
outputs = { self, colmena, ... }: {
+ # ADDED: New colmenaHive output
+ colmenaHive = colmena.lib.makeHive self.outputs.colmena;
# Your existing colmena output
colmena = {
# ... Rest of configuration ...
};
};
}
```
## Next Steps
- Head to the [Features](../features/index.md) section to see what else Colmena can do.

View file

@ -1,13 +1,16 @@
{ lib, stdenv, rustPlatform, installShellFiles, nix-eval-jobs }:
{ lib
, stdenv
, rustPlatform
, nix-gitignore
, installShellFiles
, nix-eval-jobs
}:
rustPlatform.buildRustPackage rec {
pname = "colmena";
version = "0.5.0-pre";
src = lib.cleanSourceWith {
filter = name: type: !(type == "directory" && builtins.elem (baseNameOf name) [ "target" "manual" "integration-tests" ]);
src = lib.cleanSource ./.;
};
src = nix-gitignore.gitignoreSource [ ./.srcignore ] ./.;
cargoLock = {
lockFile = ./Cargo.lock;

14
renovate.json Normal file
View file

@ -0,0 +1,14 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": [
"config:recommended",
"group:allNonMajor"
],
"lockFileMaintenance": {
"enabled": true,
"extends": ["schedule:weekly"]
},
"nix": {
"enabled": true
}
}

View file

@ -10,7 +10,7 @@ use env_logger::fmt::WriteStyle;
use crate::{
command::{self, apply::DeployOpts},
error::ColmenaResult,
nix::{Hive, HivePath},
nix::{hive::EvaluationMethod, Hive, HivePath},
};
/// Base URL of the manual, without the trailing slash.
@ -137,6 +137,21 @@ This only works when building locally.
value_names = ["NAME", "VALUE"],
)]
nix_option: Vec<String>,
#[arg(
long,
default_value_t,
help = "Use direct flake evaluation (experimental)",
long_help = r#"If enabled, flakes will be evaluated using `nix eval`. This requires the flake to depend on Colmena as an input and expose a compatible `colmenaHive` output:
outputs = { self, colmena, ... }: {
colmenaHive = colmena.lib.makeHive self.outputs.colmena;
colmena = ...;
};
This is an experimental feature."#,
global = true
)]
experimental_flake_eval: bool,
#[arg(
long,
value_name = "WHEN",
@ -262,6 +277,11 @@ async fn get_hive(opts: &Opts) -> ColmenaResult<Hive> {
hive.set_impure(true);
}
if opts.experimental_flake_eval {
log::warn!("Using direct flake evaluation (experimental)");
hive.set_evaluation_method(EvaluationMethod::DirectFlakeEval);
}
for chunks in opts.nix_option.chunks_exact(2) {
let [name, value] = chunks else {
unreachable!()

View file

@ -64,6 +64,12 @@ pub enum ColmenaError {
#[snafu(display("Don't know how to connect to the node"))]
NoTargetHost,
#[snafu(display(
"Don't know how to deploy node: {} -- does your system type support deployment?",
node_name
))]
UndeployableHost { node_name: String },
#[snafu(display("Node name cannot be empty"))]
EmptyNodeName,

View file

@ -874,11 +874,17 @@ fn describe_node_list(nodes: &[NodeName]) -> Option<String> {
}
let (idx, next) = next.unwrap();
let remaining = rough_limit - s.len();
let remaining_text = rough_limit - s.len();
let remaining_nodes = total - idx;
if next.len() + other_text.len() >= remaining {
write!(s, ", and {} other nodes", total - idx).unwrap();
break;
if next.len() + other_text.len() >= remaining_text {
if remaining_nodes == 1 {
write!(s, ", and {}", next.as_str()).unwrap();
break;
} else {
write!(s, ", and {} other nodes", remaining_nodes).unwrap();
break;
}
}
}

View file

@ -51,7 +51,10 @@ impl Assets {
// We explicitly specify `path:` instead of letting Nix resolve
// automatically, which would involve checking parent directories
// for a git repository.
let uri = format!("path:{}", temp_dir.path().to_str().unwrap());
let uri = format!(
"path:{}",
temp_dir.path().canonicalize().unwrap().to_str().unwrap()
);
let _ = lock_flake_quiet(&uri).await;
let assets_flake = Flake::from_uri(uri).await?;
assets_flake_uri = Some(assets_flake.locked_uri().to_owned());

View file

@ -38,19 +38,25 @@ let
else if uncheckedHive ? network then uncheckedHive.network
else {};
uncheckedRegistries = if uncheckedHive ? registry then uncheckedHive.registry else {};
# The final hive will always have the meta key instead of network.
hive = let
userMeta = (lib.modules.evalModules {
modules = [ colmenaOptions.metaOptions uncheckedUserMeta ];
}).config;
registry = (lib.modules.evalModules {
modules = [ colmenaOptions.registryOptions { registry = uncheckedRegistries; } ];
}).config.registry;
mergedHive =
assert lib.assertMsg (!(uncheckedHive ? __schema)) ''
You cannot pass in an already-evaluated Hive into the evaluator.
Hint: Use the `colmenaHive` output instead of `colmena`.
'';
removeAttrs (defaultHive // uncheckedHive) [ "meta" "network" ];
removeAttrs (defaultHive // uncheckedHive) [ "meta" "network" "registry" ];
meta = {
meta =
@ -58,7 +64,7 @@ let
then userMeta // { nixpkgs = <nixpkgs>; }
else userMeta;
};
in mergedHive // meta;
in mergedHive // meta // { inherit registry; };
configsFor = node: let
nodeConfig = hive.${node};
@ -112,14 +118,23 @@ let
in mkNixpkgs "meta.nixpkgs" nixpkgsConf;
lib = nixpkgs.lib;
reservedNames = [ "defaults" "network" "meta" ];
reservedNames = [ "defaults" "network" "meta" "registry" ];
evalNode = name: configs: let
evalNode = name: configs:
# Some help on error messages.
assert (lib.assertMsg (lib.hasAttrByPath [ "deployment" "systemType" ] hive.${name})
"${name} does not have a deployment system type!");
assert (lib.assertMsg (builtins.typeOf hive.registry == "set"))
"The hive's registry is not a set, but of type '${builtins.typeOf hive.registry}'";
assert (lib.assertMsg (lib.hasAttr hive.${name}.deployment.systemType hive.registry)
"${builtins.toJSON (hive.${name}.deployment.systemType)} does not exist in the registry of systems!");
let
# We cannot use `configs` because we need to access to the raw configuration fragment.
inherit (hive.registry.${hive.${name}.deployment.systemType}) evalConfig;
npkgs =
if hasAttr name hive.meta.nodeNixpkgs
then mkNixpkgs "meta.nodeNixpkgs.${name}" hive.meta.nodeNixpkgs.${name}
else nixpkgs;
evalConfig = import (npkgs.path + "/nixos/lib/eval-config.nix");
# Here we need to merge the configurations in meta.nixpkgs
# and in machine config.
@ -139,17 +154,19 @@ let
in
lib.optional (!hasTypedConfig && length remainingKeys != 0)
"The following Nixpkgs configuration keys set in meta.nixpkgs will be ignored: ${toString remainingKeys}";
};
} // lib.optionalAttrs (builtins.hasAttr "localSystem" npkgs || builtins.hasAttr "crossSystem" npkgs) {
nixpkgs.localSystem = lib.mkBefore npkgs.localSystem;
nixpkgs.crossSystem = lib.mkBefore npkgs.crossSystem;
};
in evalConfig {
inherit (npkgs) system;
# This doesn't exist for `evalModules` the generic way.
# inherit (npkgs) system;
modules = [
nixpkgsModule
colmenaModules.assertionModule
colmenaModules.keyChownModule
colmenaModules.keyServiceModule
colmenaOptions.deploymentOptions
hive.defaults
(hive.registry.${hive.${name}.deployment.systemType}.defaults or hive.defaults)
] ++ configs;
specialArgs = {
inherit name;
@ -179,9 +196,13 @@ let
"allowApplyAll"
];
serializableSystemTypeConfigKeys = [
"supportsDeployment"
];
in rec {
# Exported attributes
__schema = "v0";
__schema = "v0.20241006";
nodes = listToAttrs (map (name: { inherit name; value = evalNode name (configsFor name); }) nodeNames);
toplevel = lib.mapAttrs (_: v: v.config.system.build.toplevel) nodes;
@ -190,5 +211,9 @@ in rec {
evalSelected = names: lib.filterAttrs (name: _: elem name names) toplevel;
evalSelectedDrvPaths = names: lib.mapAttrs (_: v: v.drvPath) (evalSelected names);
metaConfig = lib.filterAttrs (n: v: elem n metaConfigKeys) hive.meta;
introspect = f: f { inherit lib; pkgs = nixpkgs; nodes = uncheckedNodes; };
# We cannot perform a `metaConfigKeys`-style simple check here
# because registry is arbitrarily deep and may evaluate nixpkgs indirectly.
registryConfig = lib.mapAttrs (systemTypeName: systemType:
lib.filterAttrs (n: v: elem n serializableSystemTypeConfigKeys) systemType) hive.registry;
introspect = f: f { inherit lib; pkgs = nixpkgs; inherit nodes; };
}

View file

@ -7,7 +7,7 @@
outputs = { self, hive }: {
processFlake = let
compatibleSchema = "v0";
compatibleSchema = "v0.20241006";
# Evaluates a raw hive.
#

View file

@ -8,6 +8,7 @@ use std::convert::AsRef;
use std::path::{Path, PathBuf};
use std::str::FromStr;
use const_format::formatcp;
use tokio::process::Command;
use tokio::sync::OnceCell;
use validator::Validate;
@ -15,13 +16,28 @@ use validator::Validate;
use super::deployment::TargetNode;
use super::{
Flake, MetaConfig, NixExpression, NixFlags, NodeConfig, NodeFilter, NodeName,
ProfileDerivation, SerializedNixExpression, StorePath,
ProfileDerivation, RegistryConfig, SerializedNixExpression, StorePath,
};
use crate::error::{ColmenaError, ColmenaResult};
use crate::job::JobHandle;
use crate::util::{CommandExecution, CommandExt};
use assets::Assets;
/// The version of the Hive schema we are compatible with.
///
/// Currently we are tied to one specific version.
const HIVE_SCHEMA: &str = "v0.20241006";
/// The snippet to be used for `nix eval --apply`.
const FLAKE_APPLY_SNIPPET: &str = formatcp!(
r#"with builtins; hive: assert (hive.__schema == "{}" || throw ''
The colmenaHive output (schema ${{hive.__schema}}) isn't compatible with this version of Colmena.
Hint: Use the same version of Colmena as in the Flake input.
''); "#,
HIVE_SCHEMA
);
#[derive(Debug, Clone)]
pub enum HivePath {
/// A Nix Flake.
@ -63,11 +79,33 @@ impl FromStr for HivePath {
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum EvaluationMethod {
/// Use nix-instantiate and specify the entire Nix expression.
///
/// This is the default method.
///
/// For flakes, we use `builtins.getFlakes`. Pure evaluation no longer works
/// with this method in Nix 2.21+.
NixInstantiate,
/// Use `nix eval --apply` on top of a flake.
///
/// This can be activated with --experimental-flake-eval.
///
/// In this method, we can no longer pull in our bundled assets and
/// the flake must expose a compatible `colmenaHive` output.
DirectFlakeEval,
}
#[derive(Debug)]
pub struct Hive {
/// Path to the hive.
path: HivePath,
/// Method to evaluate the hive with.
evaluation_method: EvaluationMethod,
/// Path to the context directory.
///
/// Normally this is directory containing the "hive.nix"
@ -87,6 +125,8 @@ pub struct Hive {
nix_options: HashMap<String, String>,
meta_config: OnceCell<MetaConfig>,
registry_config: OnceCell<RegistryConfig>,
}
struct NixInstantiate<'hive> {
@ -134,12 +174,14 @@ impl Hive {
Ok(Self {
path,
evaluation_method: EvaluationMethod::NixInstantiate,
context_dir,
assets,
show_trace: false,
impure: false,
nix_options: HashMap::new(),
meta_config: OnceCell::new(),
registry_config: OnceCell::new(),
})
}
@ -158,6 +200,25 @@ impl Hive {
.await
}
pub fn set_evaluation_method(&mut self, method: EvaluationMethod) {
if !self.is_flake() && method == EvaluationMethod::DirectFlakeEval {
return;
}
self.evaluation_method = method;
}
pub async fn get_registry_config(&self) -> ColmenaResult<&RegistryConfig> {
self.registry_config
.get_or_try_init(|| async {
self.nix_instantiate("hive.registryConfig")
.eval()
.capture_json()
.await
})
.await
}
pub fn set_show_trace(&mut self, value: bool) {
self.show_trace = value;
}
@ -201,6 +262,9 @@ impl Hive {
) -> ColmenaResult<HashMap<NodeName, TargetNode>> {
let mut node_configs = None;
log::info!("Enumerating systems...");
let registry = self.get_registry_config().await?;
log::info!("Enumerating nodes...");
let all_nodes = self.node_names().await?;
@ -234,6 +298,24 @@ impl Hive {
self.deployment_info_selected(&selected_nodes).await?
};
for node_config in &node_configs {
if let Some(system_type) = node_config.1.system_type.as_ref() {
let Some(system_config) = registry.systems.get(system_type) else {
// TODO: convert me to proper error?
log::warn!("'{:?}' is not a known system type in the registry, double check your expressions!", system_type);
return Err(ColmenaError::Unknown {
message: "unknown system type".to_string(),
});
};
if !system_config.supports_deployment {
return Err(ColmenaError::UndeployableHost {
node_name: node_config.0.to_string(),
});
}
}
}
let mut targets = HashMap::new();
let mut n_ssh = 0;
for node in selected_nodes.into_iter() {
@ -421,7 +503,10 @@ impl Hive {
/// Returns the base expression from which the evaluated Hive can be used.
fn get_base_expression(&self) -> String {
self.assets.get_base_expression()
match self.evaluation_method {
EvaluationMethod::NixInstantiate => self.assets.get_base_expression(),
EvaluationMethod::DirectFlakeEval => FLAKE_APPLY_SNIPPET.to_string(),
}
}
/// Returns whether this Hive is a flake.
@ -444,6 +529,11 @@ impl<'hive> NixInstantiate<'hive> {
}
fn instantiate(&self) -> Command {
// TODO: Better error handling
if self.hive.evaluation_method == EvaluationMethod::DirectFlakeEval {
panic!("Instantiation is not supported with DirectFlakeEval");
}
let mut command = Command::new("nix-instantiate");
if self.hive.is_flake() {
@ -462,17 +552,48 @@ impl<'hive> NixInstantiate<'hive> {
}
fn eval(self) -> Command {
let mut command = self.instantiate();
let flags = self.hive.nix_flags();
command
.arg("--eval")
.arg("--json")
.arg("--strict")
// Ensures the derivations are instantiated
// Required for system profile evaluation and IFD
.arg("--read-write-mode")
.args(flags.to_args());
command
match self.hive.evaluation_method {
EvaluationMethod::NixInstantiate => {
let mut command = self.instantiate();
command
.arg("--eval")
.arg("--json")
.arg("--strict")
// Ensures the derivations are instantiated
// Required for system profile evaluation and IFD
.arg("--read-write-mode")
.args(flags.to_args());
command
}
EvaluationMethod::DirectFlakeEval => {
let mut command = Command::new("nix");
let flake = if let HivePath::Flake(flake) = self.hive.path() {
flake
} else {
panic!("The DirectFlakeEval evaluation method only support flakes");
};
let hive_installable = format!("{}#colmenaHive", flake.uri());
let mut full_expression = self.hive.get_base_expression();
full_expression += &self.expression;
command
.arg("eval") // nix eval
.args(["--extra-experimental-features", "flakes nix-command"])
.arg(hive_installable)
.arg("--json")
.arg("--apply")
.arg(&full_expression)
.args(flags.to_args());
command
}
}
}
async fn instantiate_with_builders(self) -> ColmenaResult<Command> {

View file

@ -1,18 +1,17 @@
with builtins; rec {
keyType = { lib, name, config, ... }: let
inherit (lib) types;
mdDoc = lib.mdDoc or (md: md);
in {
options = {
name = lib.mkOption {
description = mdDoc ''
description = ''
File name of the key.
'';
default = name;
type = types.str;
};
text = lib.mkOption {
description = mdDoc ''
description = ''
Content of the key.
One of `text`, `keyCommand` and `keyFile` must be set.
'';
@ -20,7 +19,7 @@ with builtins; rec {
type = types.nullOr types.str;
};
keyFile = lib.mkOption {
description = mdDoc ''
description = ''
Path of the local file to read the key from.
One of `text`, `keyCommand` and `keyFile` must be set.
'';
@ -29,7 +28,7 @@ with builtins; rec {
type = types.nullOr types.path;
};
keyCommand = lib.mkOption {
description = mdDoc ''
description = ''
Command to run to generate the key.
One of `text`, `keyCommand` and `keyFile` must be set.
'';
@ -39,14 +38,14 @@ with builtins; rec {
in types.nullOr nonEmptyList;
};
destDir = lib.mkOption {
description = mdDoc ''
description = ''
Destination directory on the host.
'';
default = "/run/keys";
type = types.path;
};
path = lib.mkOption {
description = mdDoc ''
description = ''
Full path to the destination.
'';
default = "${config.destDir}/${config.name}";
@ -54,28 +53,28 @@ with builtins; rec {
internal = true;
};
user = lib.mkOption {
description = mdDoc ''
description = ''
The group that will own the file.
'';
default = "root";
type = types.str;
};
group = lib.mkOption {
description = mdDoc ''
description = ''
The group that will own the file.
'';
default = "root";
type = types.str;
};
permissions = lib.mkOption {
description = mdDoc ''
description = ''
Permissions to set for the file.
'';
default = "0600";
type = types.str;
};
uploadAt = lib.mkOption {
description = mdDoc ''
description = ''
When to upload the keys.
- pre-activation (default): Upload the keys before activating the new system profile.
@ -94,12 +93,19 @@ with builtins; rec {
# Largely compatible with NixOps/Morph.
deploymentOptions = { name, lib, ... }: let
inherit (lib) types;
mdDoc = lib.mdDoc or (md: md);
in {
options = {
deployment = {
targetHost = lib.mkOption {
systemType = lib.mkOption {
description = mdDoc ''
System type used for this node, e.g. NixOS.
'';
default = "nixos";
# TODO: enum among all registered systems?
type = types.str;
};
targetHost = lib.mkOption {
description = ''
The target SSH node for deployment.
By default, the node's attribute name will be used.
@ -109,7 +115,7 @@ with builtins; rec {
default = name;
};
targetPort = lib.mkOption {
description = mdDoc ''
description = ''
The target SSH port for deployment.
By default, the port is the standard port (22) or taken
@ -119,7 +125,7 @@ with builtins; rec {
default = null;
};
targetUser = lib.mkOption {
description = mdDoc ''
description = ''
The user to use to log into the remote node. If set to null, the
target user will not be specified in SSH invocations.
'';
@ -127,7 +133,7 @@ with builtins; rec {
default = "root";
};
allowLocalDeployment = lib.mkOption {
description = mdDoc ''
description = ''
Allow the configuration to be applied locally on the host running
Colmena.
@ -144,7 +150,7 @@ with builtins; rec {
default = false;
};
buildOnTarget = lib.mkOption {
description = mdDoc ''
description = ''
Whether to build the system profiles on the target node itself.
When enabled, Colmena will copy the derivation to the target
@ -164,7 +170,7 @@ with builtins; rec {
default = false;
};
tags = lib.mkOption {
description = mdDoc ''
description = ''
A list of tags for the node.
Can be used to select a group of nodes for deployment.
@ -173,7 +179,7 @@ with builtins; rec {
default = [];
};
keys = lib.mkOption {
description = mdDoc ''
description = ''
A set of secrets to be deployed to the node.
Secrets are transferred to the node out-of-band and
@ -183,7 +189,7 @@ with builtins; rec {
default = {};
};
replaceUnknownProfiles = lib.mkOption {
description = mdDoc ''
description = ''
Allow a configuration to be applied to a host running a profile we
have no knowledge of. By setting this option to false, you reduce
the likelyhood of rolling back changes made via another Colmena user.
@ -199,7 +205,7 @@ with builtins; rec {
default = true;
};
privilegeEscalationCommand = lib.mkOption {
description = mdDoc ''
description = ''
Command to use to elevate privileges when activating the new profiles on SSH hosts.
This is used on SSH hosts when `deployment.targetUser` is not `root`.
@ -209,7 +215,7 @@ with builtins; rec {
default = [ "sudo" "-H" "--" ];
};
sshOptions = lib.mkOption {
description = mdDoc ''
description = ''
Extra SSH options to pass to the SSH command.
'';
type = types.listOf types.str;
@ -218,32 +224,77 @@ with builtins; rec {
};
};
};
# Options for a registered system type
systemTypeOptions = { name, lib, ... }: let
inherit (lib) types;
mdDoc = lib.mdDoc or lib.id;
in
{
options = {
evalConfig = lib.mkOption {
description = mdDoc ''
Evaluation function which share the same interface as `nixos/lib/eval-config.nix`
which can be tailored to your own usecases or to target another type of system,
e.g. nix-darwin.
'';
type = types.functionTo types.unspecified;
};
supportsDeployment = lib.mkOption {
description = mdDoc ''
Whether this system type supports deployment or not.
If it supports deployment, it needs to have appropriate activation code,
refer to how to write custom activators.
'';
default = name == "nixos";
defaultText = "If a NixOS system, then true, otherwise false by default";
};
defaults = lib.mkOption {
description = mdDoc ''
Default configuration for that system type.
'';
type = types.functionTo types.unspecified;
default = _: {};
};
};
};
registryOptions = { lib, ... }: let
inherit (lib) types;
mdDoc = lib.mdDoc or lib.id;
in
{
options.registry = lib.mkOption {
description = mdDoc ''
A registry of all system types.
'';
type = types.attrsOf (types.submodule systemTypeOptions);
};
};
# Hive-wide options
metaOptions = { lib, ... }: let
inherit (lib) types;
mdDoc = lib.mdDoc or (md: md);
in {
options = {
name = lib.mkOption {
description = mdDoc ''
description = ''
The name of the configuration.
'';
type = types.str;
default = "hive";
};
description = lib.mkOption {
description = mdDoc ''
description = ''
A short description for the configuration.
'';
type = types.str;
default = "A Colmena Hive";
};
nixpkgs = lib.mkOption {
description = mdDoc ''
description = ''
The pinned Nixpkgs package set. Accepts one of the following:
- A path to a Nixpkgs checkout
- The Nixpkgs lambda (e.g., import \<nixpkgs\>)
- The Nixpkgs lambda (e.g., import <nixpkgs>)
- An initialized Nixpkgs attribute set
This option must be specified when using Flakes.
@ -252,21 +303,21 @@ with builtins; rec {
default = null;
};
nodeNixpkgs = lib.mkOption {
description = mdDoc ''
description = ''
Node-specific Nixpkgs pins.
'';
type = types.attrsOf types.unspecified;
default = {};
};
nodeSpecialArgs = lib.mkOption {
description = mdDoc ''
description = ''
Node-specific special args.
'';
type = types.attrsOf types.unspecified;
default = {};
};
machinesFile = lib.mkOption {
description = mdDoc ''
description = ''
Use the machines listed in this file when building this hive configuration.
If your Colmena host has nix configured to allow for remote builds
@ -290,7 +341,7 @@ with builtins; rec {
type = types.nullOr types.path;
};
specialArgs = lib.mkOption {
description = mdDoc ''
description = ''
A set of special arguments to be passed to NixOS modules.
This will be merged into the `specialArgs` used to evaluate
@ -300,7 +351,7 @@ with builtins; rec {
type = types.attrsOf types.unspecified;
};
allowApplyAll = lib.mkOption {
description = mdDoc ''
description = ''
Whether to allow deployments without a node filter set.
If set to false, a node filter must be specified with `--on` when

View file

@ -87,14 +87,14 @@ pub struct Key {
#[serde(flatten)]
source: KeySource,
#[validate(custom = "validate_dest_dir")]
#[validate(custom(function = "validate_dest_dir"))]
#[serde(rename = "destDir")]
dest_dir: PathBuf,
#[validate(custom = "validate_unix_name")]
#[validate(custom(function = "validate_unix_name"))]
user: String,
#[validate(custom = "validate_unix_name")]
#[validate(custom(function = "validate_unix_name"))]
group: String,
permissions: String,

View file

@ -55,6 +55,9 @@ pub struct NodeName(#[serde(deserialize_with = "NodeName::deserialize")] String)
#[derive(Debug, Clone, Validate, Deserialize)]
pub struct NodeConfig {
#[serde(rename = "systemType")]
system_type: Option<String>,
#[serde(rename = "targetHost")]
target_host: Option<String>,
@ -81,7 +84,7 @@ pub struct NodeConfig {
#[serde(rename = "sshOptions")]
extra_ssh_options: Vec<String>,
#[validate(custom = "validate_keys")]
#[validate(custom(function = "validate_keys"))]
keys: HashMap<String, Key>,
}
@ -94,6 +97,18 @@ pub struct MetaConfig {
pub machines_file: Option<String>,
}
#[derive(Debug, Clone, Validate, Deserialize)]
pub struct SystemTypeConfig {
#[serde(rename = "supportsDeployment")]
pub supports_deployment: bool,
}
#[derive(Debug, Clone, Validate, Deserialize)]
pub struct RegistryConfig {
#[serde(flatten)]
pub systems: HashMap<String, SystemTypeConfig>,
}
/// Nix CLI flags.
#[derive(Debug, Clone, Default)]
pub struct NixFlags {

View file

@ -7,6 +7,8 @@
pub mod plain;
pub mod spinner;
use std::io::IsTerminal;
use async_trait::async_trait;
use tokio::sync::mpsc::{self, UnboundedReceiver as TokioReceiver, UnboundedSender as TokioSender};
@ -90,7 +92,7 @@ pub enum LineStyle {
impl SimpleProgressOutput {
pub fn new(verbose: bool) -> Self {
let tty = atty::is(atty::Stream::Stdout);
let tty = std::io::stdout().is_terminal();
if verbose || !tty {
Self::Plain(PlainOutput::new())