difftreelog
feat lenient nixosModules type
in: trunk
8 files changed
README.adocdiffbeforeafterboth63 # nixosModules section of fleet config declares modules, which are used for all configured nixos hosts.63 # nixosModules section of fleet config declares modules, which are used for all configured nixos hosts.64 nixosModules = [64 nixosModules = [65 lanzaboote.nixosModules.lanzaboote65 lanzaboote.nixosModules.lanzaboote66 ({66 {67 config,68 lib,69 ...70 }: {71 # Make `nix shell nixpkgs#thing` use the same nixpkgs, as used to build the system.67 # Make `nix shell nixpkgs#thing` use the same nixpkgs, as used to build the system.72 nix.registry.nixpkgs = {68 nix.registry.nixpkgs = {73 from = { id = "nixpkgs"; type = "indirect"; };69 from = { id = "nixpkgs"; type = "indirect"; };74 flake = nixpkgs;70 flake = nixpkgs;75 exact = false;71 exact = false;76 };72 };77 })73 }78 ];74 ];797580 # Those modules are used to configure all the machines in cluster at the same time, good example of global modules76 # Those modules are used to configure all the machines in cluster at the same time, good example of global modules97 ./controlplane-1/hardware-configuration.nix93 ./controlplane-1/hardware-configuration.nix98 ./controlplane-1/configuration.nix94 ./controlplane-1/configuration.nix99 # Configuration may also be specified inline, as in any nixos config.95 # Configuration may also be specified inline, as in any nixos config.100 ({...}: {96 {101 services.ray = {97 services.ray = {102 gpus = 4;98 gpus = 4;103 cpus = 128;99 cpus = 128;104 };100 };105 })101 }106 ];102 ];107 };103 };108 };104 };flake.nixdiffbeforeafterboth16 inputs.nixpkgs.follows = "nixpkgs";16 inputs.nixpkgs.follows = "nixpkgs";17 };17 };18 };18 };19 outputs = {19 outputs = inputs @ {20 self,20 self,21 rust-overlay,22 flake-parts,21 flake-parts,23 nixpkgs,24 nixpkgs-stable-for-tests,25 crane,22 crane,23 ...26 }:24 }:27 flake-parts.lib.mkFlake {25 flake-parts.lib.mkFlake {28 # Not passing inputs through inputs for better visibility.29 inputs = {};26 inherit inputs;30 } {27 } {31 flake = {28 flake = let29 inherit (inputs.nixpkgs.lib) mapAttrs;30 in {32 lib = import ./lib {31 lib = import ./lib {33 fleetPkgsForPkgs = pkgs:32 fleetPkgsForPkgs = pkgs:34 import ./pkgs {33 import ./pkgs {45 '';44 '';46 inventory = output: {45 inventory = output: {47 children =46 children =48 builtins.mapAttrs (configName: cluster: {47 mapAttrs (configName: cluster: {49 what = "fleet cluster configuration";48 what = "fleet cluster configuration";504951 children =50 children =52 builtins.mapAttrs (hostName: host: {51 mapAttrs (hostName: host: {53 what = "host [${host.system}]";52 what = "host [${host.system}]";54 })53 })55 cluster.config.hosts;54 cluster.config.hosts;70 pkgs,69 pkgs,71 ...70 ...72 }: let71 }: let72 inherit (lib) mapAttrs' elem;73 # Can also be built for darwin, through it is not usual to deploy nixos systems from macos machines.73 # Can also be built for darwin, through it is not usual to deploy nixos systems from macos machines.74 # I have no hardware for such testing, thus only adding machines I actually have and use.74 # I have no hardware for such testing, thus only adding machines I actually have and use.75 #75 #76 # It is not possible to deploy any host from armv6/armv7 hardware, and I don't think it even makes sense.76 # It is not possible to deploy any host from armv6/armv7 hardware, and I don't think it even makes sense.77 deployerSystems = ["aarch64-linux" "x86_64-linux"];77 deployerSystems = ["aarch64-linux" "x86_64-linux"];78 deployerSystem = builtins.elem system deployerSystems;78 deployerSystem = elem system deployerSystems;79 lib = pkgs.lib;79 lib = pkgs.lib;80 rust = pkgs.rust-bin.fromRustupToolchainFile ./rust-toolchain.toml;80 rust = pkgs.rust-bin.fromRustupToolchainFile ./rust-toolchain.toml;81 craneLib = (crane.mkLib pkgs).overrideToolchain rust;81 craneLib = (crane.mkLib pkgs).overrideToolchain rust;82 in {82 in {83 _module.args.pkgs = import nixpkgs {83 _module.args.pkgs = import inputs.nixpkgs {84 inherit system;84 inherit system;85 overlays = [(rust-overlay.overlays.default)];85 overlays = [(inputs.rust-overlay.overlays.default)];86 };86 };87 # Reference fleet package should be built with nightly rust, specified in rust-toolchain.toml.87 # Reference fleet package should be built with nightly rust, specified in rust-toolchain.toml.88 packages = lib.mkIf deployerSystem (let88 packages = lib.mkIf deployerSystem (let116 checks = let116 checks = let117 packages = import ./pkgs {117 packages = import ./pkgs {118 inherit (pkgs) callPackage;118 inherit (pkgs) callPackage;119 craneLib = crane.mkLib (import nixpkgs {inherit system;});119 craneLib = crane.mkLib pkgs;120 };120 };121 packages-with-nixpkgs-stable = import ./pkgs {121 packages-with-nixpkgs-stable = import ./pkgs {122 inherit (pkgs) callPackage;122 inherit (pkgs) callPackage;123 craneLib = crane.mkLib (import nixpkgs-stable-for-tests {inherit system;});123 craneLib = crane.mkLib (import inputs.nixpkgs-stable-for-tests {inherit system;});124 };124 };125 prefixAttrs = prefix: attrs:125 prefixAttrs = prefix: attrs:126 nixpkgs.lib.attrsets.mapAttrs' (name: value: {126 mapAttrs' (name: value: {127 name = "${prefix}${name}";127 name = "${prefix}${name}";128 value = value.overrideAttrs (prev: {128 value = value.overrideAttrs (prev: {129 pname = "${prefix}${prev.pname}";129 pname = "${prefix}${prev.pname}";lib/fleetLib.nixdiffbeforeafterboth2{2{3 nixpkgs,3 nixpkgs,4 hostNames,4 hostNames,5}:5}: let6with nixpkgs.lib; rec {6 inherit (nixpkgs) lib;7 inherit (lib) listToAttrs remove unique crossLists sort elemAt mkOptionType mkOverride optionalString;8 inherit (lib.types) listOf coercedTo oneOf submodule;9in rec {7 hostsToAttrs = f:10 hostsToAttrs = f:8 listToAttrs (11 listToAttrs (9 map (name: {12 map (name: {34 then "${this}-${other}"37 then "${this}-${other}"35 else "${other}-${this}";38 else "${other}-${this}";3940 types = rec {41 anyModule = mkOptionType {42 name = "submodule";43 inherit (submodule {}) check;44 merge = lib.options.mergeOneOption;45 description = "Nixos module";46 };47 listOfAnyModuleStrict =48 listOf anyModule;49 listOfAnyModule =50 coercedTo (oneOf [listOfAnyModuleStrict anyModule]) (51 v:52 if builtins.isAttrs v53 then [v]54 else if builtins.isFunction v55 then [v]56 else v57 )58 listOfAnyModuleStrict;59 };366037 # mkDefault = mkOverride 100061 # mkDefault = mkOverride 100038 # For places, where fleet knows better than nixpkgs defaults.62 # For places, where fleet knows better than nixpkgs defaults.modules/fleet/assertions.nixdiffbeforeafterboth1{lib, ...}:1{lib, ...}: let2with lib; {2 inherit (lib) mkOption;3 inherit (lib.types) listOf unspecified str;4in {3 options = {5 options = {4 assertions = mkOption {6 assertions = mkOption {5 type = types.listOf types.unspecified;7 type = listOf unspecified;6 internal = true;8 internal = true;7 default = [];9 default = [];8 example = [10 example = [21 warnings = mkOption {23 warnings = mkOption {22 internal = true;24 internal = true;23 default = [];25 default = [];24 type = types.listOf types.str;26 type = listOf str;25 example = ["The `foo' service is deprecated and will go away soon!"];27 example = ["The `foo' service is deprecated and will go away soon!"];26 description = ''28 description = ''27 This option allows modules to show warnings to users during29 This option allows modules to show warnings to users duringmodules/fleet/meta.nixdiffbeforeafterboth4 config,4 config,5 nixpkgs,5 nixpkgs,6 ...6 ...7}:7}: let8with lib;9with fleetLib; let8 inherit (fleetLib) hostsToAttrs mkFleetGeneratorDefault;9 inherit (fleetLib.types) listOfAnyModule;10 inherit (lib) mkOption mkOptionType;11 inherit (lib.types) str unspecified attrsOf listOf submodule;10 hostModule = with types;12 hostModule = {...} @ hostConfig: let11 {...} @ hostConfig: let12 hostName = hostConfig.config._module.args.name;13 hostName = hostConfig.config._module.args.name;13 in {14 in {14 options = {15 options = {15 nixosModules = mkOption {16 nixosModules = mkOption {17 # Not too strict, but nixos module system will fix everything.16 type = listOf (mkOptionType {18 type =17 name = "submodule";18 inherit (submodule {}) check;19 merge = lib.options.mergeOneOption;20 description = "Nixos module";21 });19 listOfAnyModule;2022 description = "List of nixos modules";21 description = "List of nixos modules";23 default = [];22 default = [];49 fleet = hostsToAttrs (host: config.hosts.${host}.nixosSystem.config);48 fleet = hostsToAttrs (host: config.hosts.${host}.nixosSystem.config);50 };49 };51 };50 };52 nixosModules = [51 nixosModules.networking.hostName = mkFleetGeneratorDefault hostName;53 ({...}: {54 networking.hostName = mkFleetGeneratorDefault hostName;55 })56 ];57 };52 };58 };53 };59 overlayType = mkOptionType {54 overlayType = mkOptionType {60 name = "nixpkgs-overlay";55 name = "nixpkgs-overlay";61 description = "nixpkgs overlay";56 description = "nixpkgs overlay";62 check = lib.isFunction;57 check = lib.isFunction;63 merge = lib.mergeOneOption;58 merge = lib.mergeOneOption;64 };59 };65in {60in {66 options = with types; {61 options = {67 hosts = mkOption {62 hosts = mkOption {68 type = attrsOf (submodule hostModule);63 type = attrsOf (submodule hostModule);69 default = {};64 default = {};70 description = "Configurations of individual hosts";65 description = "Configurations of individual hosts";71 };66 };72 nixosModules = mkOption {67 nixosModules = mkOption {73 type = listOf (mkOptionType {68 type = listOfAnyModule;74 name = "submodule";69 description = "Modules, which should be added to every system";75 inherit (submodule {}) check;70 default = [];76 merge = lib.options.mergeOneOption;71 };77 description = "Nixos modules";72 overlays = mkOption {78 });73 default = [];79 description = "Modules, which should be added to every system";74 type = listOf overlayType;80 default = [];75 };81 };76 };82 overlays = mkOption {77 config = {83 default = [];78 hosts = hostsToAttrs (host: {84 type = listOf overlayType;79 nixosModules =85 };80 config.nixosModules86 };81 ++ [87 config = {82 {88 hosts = hostsToAttrs (host: {83 nixpkgs.overlays = config.overlays;89 nixosModules =84 }90 config.nixosModules85 ];91 ++ [86 });92 ({...}: {87 nixosModules = import ../../nixos/modules/module-list.nix;93 nixpkgs.overlays = config.overlays;88 };94 })89}95 ];96 });97 nixosModules = import ../../nixos/modules/module-list.nix;98 };99}10090modules/fleet/secrets.nixdiffbeforeafterboth3 fleetLib,3 fleetLib,4 config,4 config,5 ...5 ...6}:6}: let7 inherit (fleetLib) hostsToAttrs;7with lib;8 inherit (lib) mkOption mapAttrsToList mapAttrs filterAttrs concatStringsSep;9 inherit (lib.types) lazyAttrsOf unspecified nullOr listOf str bool attrsOf submodule;1011 sharedSecret = {config, ...}: {12 freeformType = lazyAttrsOf unspecified;13 options = {14 expectedOwners = mkOption {15 type = nullOr (listOf str);16 description = ''17 List of hosts to encrypt secret for. null if managed by user (= via owners field from fleet.nix)1819 Secrets would be decrypted and stored to /run/secrets/$\{name} on owners20 '';21 default = null;22 };23 # TODO: Aren't those options may be just desugared to data/expectedData?24 regenerateOnOwnerAdded = mkOption {25 type = bool;26 description = ''27 Is this secret owner-dependent, and needs to be regenerated on ownership set change, or it may be just reencrypted.2829 You want to have this option set to true, when this secret contains some reference to its owners, i.e x509 SANs.30 '';31 };32 regenerateOnOwnerRemoved = mkOption {33 default = config.regenerateOnOwnerAdded;34 type = bool;35 description = ''36 Should this secret be removed on owner removal, or it may be just reencrypted3738 Most probably its value should be equal to regenerateOnOwnerAdded, override only if you know what are you doing.39 Contrary to regenerateOnOwnerAdded, you may want to set this option to false, when host permissions are revoked40 in some other way than by this secret ownership, I.e by firewall/etc.41 '';42 };43 generator = mkOption {44 type = nullOr unspecified;45 description = "Derivation to evaluate for secret generation";46 default = null;47 };48 createdAt = mkOption {49 type = nullOr str;50 description = "When this secret was (re)generated";51 default = null;52 };53 expiresAt = mkOption {54 type = nullOr str;55 description = "On which date this secret will expire, someone should regenerate this secret before it expires.";56 default = null;57 };5859 owners = mkOption {60 type = listOf str;61 description = ''62 For which owners this secret is currently encrypted,63 if not matches expectedOwners - then this secret is considered outdated, and64 should be regenerated/reencrypted.6566 Imported from fleet.nix67 '';68 default = [];69 };70 };8with fleetLib; let71 };9 sharedSecret = with types; ({config, ...}: {72 hostSecret = {10 freeformType = types.lazyAttrsOf unspecified;73 freeformType = lazyAttrsOf unspecified;11 options = {74 options = {12 expectedOwners = mkOption {75 createdAt = mkOption {13 type = nullOr (listOf str);76 type = nullOr str;14 description = ''15 List of hosts to encrypt secret for. null if managed by user (= via owners field from fleet.nix)1617 Secrets would be decrypted and stored to /run/secrets/$\{name} on owners18 '';19 default = null;77 default = null;20 };78 };21 # TODO: Aren't those options may be just desugared to data/expectedData?22 regenerateOnOwnerAdded = mkOption {23 type = bool;24 description = ''25 Is this secret owner-dependent, and needs to be regenerated on ownership set change, or it may be just reencrypted.2627 You want to have this option set to true, when this secret contains some reference to its owners, i.e x509 SANs.28 '';29 };30 regenerateOnOwnerRemoved = mkOption {31 default = config.regenerateOnOwnerAdded;32 type = bool;33 description = ''34 Should this secret be removed on owner removal, or it may be just reencrypted3536 Most probably its value should be equal to regenerateOnOwnerAdded, override only if you know what are you doing.37 Contrary to regenerateOnOwnerAdded, you may want to set this option to false, when host permissions are revoked38 in some other way than by this secret ownership, I.e by firewall/etc.39 '';40 };41 generator = mkOption {42 type = nullOr unspecified;43 description = "Derivation to evaluate for secret generation";44 default = null;45 };46 createdAt = mkOption {79 expiresAt = mkOption {47 type = nullOr str;80 type = nullOr str;48 description = "When this secret was (re)generated";49 default = null;81 default = null;50 };82 };51 expiresAt = mkOption {52 type = nullOr str;53 description = "On which date this secret will expire, someone should regenerate this secret before it expires.";54 default = null;55 };5657 owners = mkOption {58 type = listOf str;59 description = ''60 For which owners this secret is currently encrypted,61 if not matches expectedOwners - then this secret is considered outdated, and62 should be regenerated/reencrypted.6364 Imported from fleet.nix65 '';66 default = [];67 };68 };83 };69 });84 };70 hostSecret = with types; {71 freeformType = types.lazyAttrsOf unspecified;72 options = {73 createdAt = mkOption {74 type = nullOr str;75 default = null;76 };77 expiresAt = mkOption {78 type = nullOr str;79 default = null;80 };81 };82 };83in {85in {84 options = with types; {86 options = {85 version = mkOption {87 version = mkOption {86 type = str;88 type = str;87 default = "";89 default = "";128 });130 });129 # TODO: Should this attribute be moved to `nixpkgs.overlays`?131 # TODO: Should this attribute be moved to `nixpkgs.overlays`?130 overlays = [132 overlays = [131 (final: prev: let133 (final: prev: {132 lib = final.lib;133 inherit (lib) strings;134 inherit (strings) concatStringsSep;135 in {136 mkSecretGenerators = {recipients}: rec {134 mkSecretGenerators = {recipients}: rec {137 # TODO: Merge both generators to one with consistent options syntax?135 # TODO: Merge both generators to one with consistent options syntax?138 # Impure generator is built on local machine, then built closure is copied to remote machine,136 # Impure generator is built on local machine, then built closure is copied to remote machine,nixos/meta.nixdiffbeforeafterboth2 lib,2 lib,3 pkgs,3 pkgs,4 ...4 ...5}:5}: let6with lib; {6 inherit (lib) mkOption;7 inherit (lib.types) listOf str submodule;8in {7 options = with types; {9 options = {8 nixpkgs.resolvedPkgs = mkOption {10 nixpkgs.resolvedPkgs = mkOption {9 type = types.pkgs // {description = "nixpkgs.pkgs";};11 type = lib.types.pkgs // {description = "nixpkgs.pkgs";};10 description = "Value of pkgs";12 description = "Value of pkgs";11 };13 };12 tags = mkOption {14 tags = mkOption {31 };33 };32 description = "Network definition of host";34 description = "Network definition of host";33 };35 };34 buildTarget = mkOption {35 type = enum ["toplevel" "sd-image" "installation-cd"];36 };37 };36 };38 config = {37 config = {39 tags = ["all"];38 tags = ["all"];nixos/secrets.nixdiffbeforeafterboth4 pkgs,4 pkgs,5 ...5 ...6}:6}: let7with lib; let8 inherit (lib.strings) hasPrefix removePrefix;7 inherit (lib.strings) hasPrefix removePrefix;8 inherit (lib) mkOption mkOptionDefault mapAttrs stringAfter;9 inherit (lib.types) submodule str attrsOf nullOr unspecified lazyAttrsOf;9 plaintextPrefix = "<PLAINTEXT>";10 plaintextPrefix = "<PLAINTEXT>";10 plaintextNewlinePrefix = "<PLAINTEXT-NL>";11 plaintextNewlinePrefix = "<PLAINTEXT-NL>";111212 sysConfig = config;13 sysConfig = config;13 secretPartType = secretName:14 secretPartType = secretName:14 types.submodule ({config, ...}: {15 submodule ({config, ...}: {15 options = with types; {16 options = {16 raw = mkOption {17 raw = mkOption {17 description = "Secret in fleet-specific undocumented format, do not use. Import from fleet.nix";18 description = "Secret in fleet-specific undocumented format, do not use. Import from fleet.nix";18 internal = true;19 internal = true;49 stablePath = mkOptionDefault "/run/secrets/${secretName}/${partName}";50 stablePath = mkOptionDefault "/run/secrets/${secretName}/${partName}";50 };51 };51 });52 });52 secretType = types.submodule ({config, ...}: let53 secretType = submodule ({config, ...}: let53 secretName = config._module.args.name;54 secretName = config._module.args.name;54 in {55 in {55 freeformType = types.lazyAttrsOf (secretPartType secretName);56 freeformType = lazyAttrsOf (secretPartType secretName);56 options = with types; {57 options = {57 shared = mkOption {58 shared = mkOption {58 description = "Is this secret owned by this machine, or propagated from shared secrets";59 description = "Is this secret owned by this machine, or propagated from shared secrets";59 default = false;60 default = false;112in {113in {113 options = {114 options = {114 secrets = mkOption {115 secrets = mkOption {115 type = types.attrsOf secretType;116 type = attrsOf secretType;116 default = {};117 default = {};117 description = "Host-local secrets";118 description = "Host-local secrets";118 };119 };