{ inputs = { nixops4.follows = "nixops4-nixos/nixops4"; nixops4-nixos.url = "github:nixops4/nixops4-nixos"; }; outputs = inputs: let sources = import ./npins; inherit (sources) nixpkgs; architectures = [ "x86_64-linux" ]; lib = import "${nixpkgs}/lib"; forSystem = lib.genAttrs architectures; overlays = [ ]; pkgsFor = forSystem (system: import nixpkgs { inherit system overlays; }); forPkgs = f: forSystem ( system: f { inherit system; pkgs = pkgsFor.${system}; } ); keys = import ./keys; secrets = import ./secrets; inherit (builtins) readDir readFile fromJSON; inherit (lib) attrNames mkOption evalModules filterAttrs mapAttrs' deepSeq ; inherit (lib.attrsets) genAttrs; commonResourceModule = { # TODO(@fricklerhandwerk): this is terrible but IMO we should just ditch # flake-parts and have our own data model for how the project is organised # internally _module.args = { inherit inputs keys secrets sources ; }; ## FIXME: It would be preferrable to have those `sources`-related imports in ## the modules that use them. However, doing so triggers infinite recursions ## because of the way we propagate `sources`. `sources` must be propagated by ## means of `specialArgs`, but this requires a bigger change. nixos.module.imports = [ "${sources.nixpkgs}/nixos/modules/profiles/qemu-guest.nix" "${sources.agenix}/modules/age.nix" "${sources.disko}/module.nix" "${sources.home-manager}/nixos" ]; imports = [ ./common/resource.nix ]; }; ## Given a list of machine names, make a deployment with those machines' ## configurations as resources. makeDeployment = vmNames: { providers, ... }: { providers.local = inputs.nixops4.modules.nixops4Provider.local; resources = genAttrs vmNames (vmName: { type = providers.local.exec; imports = [ inputs.nixops4-nixos.modules.nixops4Resource.nixos commonResourceModule ../machines/dev/${vmName} ]; }); }; makeDeployment' = vmName: makeDeployment [ vmName ]; ## Given an attrset of test configurations (key = test machine name, value = ## NixOS configuration module), make a deployment with those machines' ## configurations as resources. makeTestDeployment = (import ../deployment) { inherit lib; inherit (inputs) nixops4 nixops4-nixos; fediversity = import ../services/fediversity; } { garageConfigurationResource = { imports = [ commonResourceModule ../machines/operator/test01 ]; }; mastodonConfigurationResource = { imports = [ commonResourceModule ../machines/operator/test06 # somehow `test02` has a problem - use test06 instead ]; }; peertubeConfigurationResource = { imports = [ commonResourceModule ../machines/operator/test05 ]; }; pixelfedConfigurationResource = { imports = [ commonResourceModule ../machines/operator/test04 ]; }; }; nixops4ResourceNixosMockOptions = { ## NOTE: We allow the use of a few options from ## `nixops4-nixos.modules.nixops4Resource.nixos` such that we can ## reuse modules that make use of them. ## ## REVIEW: We can probably do much better and cleaner. On the other hand, ## this is only needed to expose NixOS configurations for provisioning ## purposes, and eventually all of this should be handled by NixOps4. options = { nixos.module = mkOption { type = lib.types.deferredModule; }; # NOTE: not just `nixos` otherwise merging will go wrong nixpkgs = mkOption { }; ssh = mkOption { }; }; }; makeResourceConfig = { vmName, isTestVm }: (evalModules { modules = [ nixops4ResourceNixosMockOptions commonResourceModule (if isTestVm then ../machines/operator/${vmName} else ../machines/dev/${vmName}) ]; }).config; ## Given a VM name, make a NixOS configuration for this machine. makeConfiguration = isTestVm: vmName: import "${sources.nixpkgs}/nixos" { configuration = (makeResourceConfig { inherit vmName isTestVm; }).nixos.module; system = "x86_64-linux"; }; makeVmOptions = isTestVm: vmName: let config = (makeResourceConfig { inherit vmName isTestVm; }).fediversityVm; in if config.isFediversityVm then { inherit (config) vmId description sockets cores memory diskSize hostPublicKey unsafeHostPrivateKey ; } else null; listSubdirectories = path: attrNames (filterAttrs (_: type: type == "directory") (readDir path)); machines = listSubdirectories ../machines/dev; testMachines = listSubdirectories ../machines/operator; nixosConfigurations = genAttrs machines (makeConfiguration false) // genAttrs testMachines (makeConfiguration true); vmOptions = filterAttrs (_: value: value != null) # Filter out non-Fediversity VMs (genAttrs machines (makeVmOptions false) // genAttrs testMachines (makeVmOptions true)); in { nixConfig = { extra-trusted-substituters = "https://cache.saumon.network/proxmox-nixos"; extra-trusted-public-keys = "proxmox-nixos:D9RYSWpQQC/msZUWphOY2I5RLH5Dd6yQcaHIuug7dWM="; }; imports = [ "${sources.git-hooks}/flake-module.nix" inputs.nixops4.modules.flake.default ]; ## - Each normal or test machine gets a NixOS configuration. ## - Each normal or test machine gets a VM options entry. ## - Each normal machine gets a deployment. ## - We add a “default” deployment with all normal machines. ## - We add a “test” deployment with all test machines. nixops4Deployments = genAttrs machines makeDeployment' // { default = makeDeployment machines; test = makeTestDeployment ( fromJSON ( let env = builtins.getEnv "DEPLOYMENT"; in if env != "" then env else builtins.trace "env var DEPLOYMENT not set, falling back to ../deployment/configuration.sample.json!" (readFile ../deployment/configuration.sample.json) ) ); }; flake = { inherit nixosConfigurations vmOptions; }; checks = forPkgs ( { system, pkgs }: { panel = (import ./. { inherit sources system; }).tests.panel.basic; test-mastodon-service = pkgs.testers.runNixOSTest ./services/tests/mastodon.nix; test-peertube-service = pkgs.testers.runNixOSTest ./services/tests/peertube.nix; proxmox-basic = import ./deployment/check/proxmox { inherit (pkgs.testers) runNixOSTest; inherit sources system; }; deployment-basic = import ./deployment/check/basic { inherit (pkgs.testers) runNixOSTest; inherit pkgs inputs sources; }; deployment-cli = import ./deployment/check/cli { inherit (pkgs.testers) runNixOSTest; inherit pkgs inputs sources; }; deployment-panel = import ./deployment/check/panel { inherit (pkgs.testers) runNixOSTest; inherit pkgs inputs sources; }; deployment-model-ssh = import ./deployment/check/data-model-ssh { inherit (pkgs.testers) runNixOSTest; inherit pkgs inputs sources; }; deployment-model-nixops4 = import ./deployment/check/data-model-nixops4 { inherit (pkgs.testers) runNixOSTest; inherit pkgs inputs sources; }; deployment-model-tf = import ./deployment/check/data-model-tf { inherit inputs sources system; }; deployment-model-tf-proxmox = import ./deployment/check/data-model-tf-proxmox { inherit inputs sources system; }; } // mapAttrs' (name: nixosConfiguration: { name = "nixosConfigurations-${name}"; value = nixosConfiguration.config.system.build.toplevel; }) nixosConfigurations // mapAttrs' (name: vmOptions: { name = "vmOptions-${name}"; ## Check that VM options builds/evaluates correctly. `deepSeq e1 ## e2` evaluates `e1` strictly in depth before returning `e2`. We ## use this trick because checks need to be derivations, which VM ## options are not. value = deepSeq vmOptions pkgs.hello; }) vmOptions ); formatter = forPkgs ({ pkgs, ... }: pkgs.nixfmt-rfc-style); pre-commit.settings.hooks = let ## Add a directory here if pre-commit hooks shouldn't apply to it. optout = [ "npins" ]; excludes = map (dir: "^${dir}/") optout; addExcludes = lib.mapAttrs (_: c: c // { inherit excludes; }); in addExcludes { nixfmt-rfc-style.enable = true; deadnix.enable = true; trim-trailing-whitespace.enable = true; shellcheck.enable = true; }; }; }