|
211 | 211 | }; |
212 | 212 |
|
213 | 213 | repoSeedSnapshotDir = mkOption { |
214 | | - type = types.nullOr types.path; |
| 214 | + type = types.nullOr types.str; |
215 | 215 | default = null; |
216 | 216 | description = "Optional path to a preseeded repo snapshot (directory of repos). When set, no network cloning happens at boot."; |
217 | 217 | }; |
218 | 218 |
|
| 219 | + bootstrap = { |
| 220 | + enable = mkEnableOption "Bootstrap secrets + repo seeds from S3"; |
| 221 | + |
| 222 | + s3Bucket = mkOption { |
| 223 | + type = types.str; |
| 224 | + description = "S3 bucket holding bootstrap artifacts."; |
| 225 | + }; |
| 226 | + |
| 227 | + s3Prefix = mkOption { |
| 228 | + type = types.str; |
| 229 | + default = "bootstrap/${cfg.instanceName}"; |
| 230 | + description = "S3 prefix for bootstrap artifacts (relative to bucket)."; |
| 231 | + }; |
| 232 | + |
| 233 | + region = mkOption { |
| 234 | + type = types.str; |
| 235 | + default = "eu-central-1"; |
| 236 | + description = "AWS region for S3 bootstrap bucket."; |
| 237 | + }; |
| 238 | + |
| 239 | + secretsArchive = mkOption { |
| 240 | + type = types.str; |
| 241 | + default = "secrets.tar.zst"; |
| 242 | + description = "Secrets archive name inside the bootstrap prefix."; |
| 243 | + }; |
| 244 | + |
| 245 | + repoSeedsArchive = mkOption { |
| 246 | + type = types.str; |
| 247 | + default = "repo-seeds.tar.zst"; |
| 248 | + description = "Repo seeds archive name inside the bootstrap prefix."; |
| 249 | + }; |
| 250 | + |
| 251 | + ageKeyPath = mkOption { |
| 252 | + type = types.str; |
| 253 | + default = "/etc/agenix/keys/clawdinator.agekey"; |
| 254 | + description = "Destination path for the agenix identity key."; |
| 255 | + }; |
| 256 | + |
| 257 | + secretsDir = mkOption { |
| 258 | + type = types.str; |
| 259 | + default = "/var/lib/clawd/nix-secrets"; |
| 260 | + description = "Destination directory for encrypted age secrets."; |
| 261 | + }; |
| 262 | + |
| 263 | + repoSeedsDir = mkOption { |
| 264 | + type = types.str; |
| 265 | + default = "/var/lib/clawd/repo-seeds"; |
| 266 | + description = "Destination directory for repo seed snapshots."; |
| 267 | + }; |
| 268 | + }; |
| 269 | + |
219 | 270 | workspaceTemplateDir = mkOption { |
220 | 271 | type = types.path; |
221 | 272 | default = ../../clawdinator/workspace; |
|
482 | 533 | wantedBy = [ "multi-user.target" ]; |
483 | 534 | after = |
484 | 535 | [ "network.target" ] |
| 536 | + ++ lib.optional cfg.bootstrap.enable "clawdinator-bootstrap.service" |
485 | 537 | ++ lib.optional cfg.githubApp.enable "clawdinator-github-app-token.service" |
486 | 538 | ++ lib.optional (cfg.repoSeedSnapshotDir != null) "clawdinator-repo-seed.service"; |
487 | 539 | wants = |
| 540 | + lib.optional cfg.bootstrap.enable "clawdinator-bootstrap.service" |
488 | 541 | lib.optional cfg.githubApp.enable "clawdinator-github-app-token.service" |
489 | 542 | ++ lib.optional (cfg.repoSeedSnapshotDir != null) "clawdinator-repo-seed.service"; |
490 | 543 |
|
|
527 | 580 | description = "CLAWDINATOR repo seed (snapshot copy)"; |
528 | 581 | wantedBy = [ "multi-user.target" ]; |
529 | 582 | before = [ "clawdinator.service" ]; |
530 | | - after = [ "local-fs.target" ]; |
| 583 | + after = |
| 584 | + [ "local-fs.target" ] |
| 585 | + ++ lib.optional cfg.bootstrap.enable "clawdinator-bootstrap.service"; |
| 586 | + requires = lib.optional cfg.bootstrap.enable "clawdinator-bootstrap.service"; |
531 | 587 | serviceConfig = { |
532 | 588 | Type = "oneshot"; |
533 | 589 | User = "root"; |
|
536 | 592 | script = "${pkgs.bash}/bin/bash ${../../scripts/seed-repos-from-snapshot.sh} ${cfg.repoSeedSnapshotDir} ${repoSeedBaseDir} ${cfg.user} ${cfg.group}"; |
537 | 593 | }; |
538 | 594 |
|
| 595 | + systemd.services.clawdinator-bootstrap = lib.mkIf cfg.bootstrap.enable { |
| 596 | + description = "CLAWDINATOR bootstrap (S3 secrets + repo seeds)"; |
| 597 | + wantedBy = [ "multi-user.target" ]; |
| 598 | + after = [ "network-online.target" ]; |
| 599 | + wants = [ "network-online.target" ]; |
| 600 | + serviceConfig = { |
| 601 | + Type = "oneshot"; |
| 602 | + RemainAfterExit = true; |
| 603 | + }; |
| 604 | + environment = { |
| 605 | + AWS_REGION = cfg.bootstrap.region; |
| 606 | + AWS_DEFAULT_REGION = cfg.bootstrap.region; |
| 607 | + }; |
| 608 | + path = [ pkgs.awscli2 pkgs.coreutils pkgs.gnutar pkgs.zstd ]; |
| 609 | + script = "${pkgs.bash}/bin/bash ${../../scripts/bootstrap-runtime.sh} ${cfg.bootstrap.s3Bucket} ${cfg.bootstrap.s3Prefix} ${cfg.bootstrap.secretsDir} ${cfg.bootstrap.repoSeedsDir} ${cfg.bootstrap.ageKeyPath} ${cfg.bootstrap.secretsArchive} ${cfg.bootstrap.repoSeedsArchive}"; |
| 610 | + }; |
| 611 | + |
| 612 | + systemd.services.agenix = lib.mkIf cfg.bootstrap.enable { |
| 613 | + requires = [ "clawdinator-bootstrap.service" ]; |
| 614 | + after = [ "clawdinator-bootstrap.service" ]; |
| 615 | + }; |
| 616 | + |
539 | 617 | systemd.services.clawdinator-efs-stunnel = lib.mkIf cfg.memoryEfs.enable { |
540 | 618 | description = "CLAWDINATOR EFS TLS tunnel"; |
541 | 619 | wantedBy = [ "multi-user.target" ]; |
|
0 commit comments