diff --git a/container.nix b/container.nix index 30d7e0c..e76d933 100644 --- a/container.nix +++ b/container.nix @@ -1,5 +1,10 @@ { quadletUtils }: -{ config, name, lib, ... }: +{ + config, + name, + lib, + ... +}: with lib; @@ -30,7 +35,12 @@ let }; autoUpdate = quadletUtils.mkOption { - type = types.nullOr (types.enum [ "registry" "local" ]); + type = types.nullOr ( + types.enum [ + "registry" + "local" + ] + ); default = null; example = "registry"; description = "--label \"io.containers.autoupdate=...\""; @@ -56,7 +66,9 @@ let environments = quadletUtils.mkOption { type = types.attrs; default = { }; - example = { foo = "bar"; }; + example = { + foo = "bar"; + }; description = "--env"; property = "Environment"; }; @@ -91,7 +103,7 @@ let description = "--expose"; property = "ExposeHostPort"; }; - + group = quadletUtils.mkOption { type = types.nullOr types.str; default = null; @@ -210,7 +222,7 @@ let description = "--ip"; property = "IP"; }; - + ip6 = quadletUtils.mkOption { type = types.nullOr types.str; default = null; @@ -242,7 +254,7 @@ let description = "--mount"; property = "Mount"; }; - + networks = quadletUtils.mkOption { type = types.listOf types.str; default = [ ]; @@ -376,7 +388,9 @@ let sysctl = quadletUtils.mkOption { type = types.attrs; default = { }; - example = { name = "value"; }; + example = { + name = "value"; + }; description = "--sysctl"; property = "Sysctl"; }; @@ -441,7 +455,8 @@ let Restart = "always"; TimeoutStartSec = 900; }; -in { +in +{ options = { autoStart = mkOption { type = types.bool; @@ -452,7 +467,7 @@ in { containerConfig = containerOpts; unitConfig = mkOption { type = types.attrs; - default = {}; + default = { }; }; serviceConfig = mkOption { type = types.attrs; @@ -464,26 +479,28 @@ in { _configText = mkOption { internal = true; }; }; - config = let - configRelPath = "containers/systemd/${name}.container"; - containerName = if config.containerConfig.name != null - then config.containerConfig.name - else name; - containerConfig = config.containerConfig // { name = containerName; }; - unitConfig = { - Unit = { - Description = "Podman container ${name}"; - } // config.unitConfig; - Install = { - WantedBy = if config.autoStart then [ "default.target" ] else []; + config = + let + configRelPath = "containers/systemd/${name}.container"; + containerName = if config.containerConfig.name != null then config.containerConfig.name else name; + containerConfig = config.containerConfig // { + name = containerName; }; - Container = quadletUtils.configToProperties containerConfig containerOpts; - Service = serviceConfigDefault // config.serviceConfig; - }; - unitConfigText = quadletUtils.unitConfigToText unitConfig; - in { - _configName = "${name}.container"; - _unitName = "${name}.service"; - _configText = quadletUtils.unitConfigToText unitConfig; - }; + unitConfig = { + Unit = { + Description = "Podman container ${name}"; + } // config.unitConfig; + Install = { + WantedBy = if config.autoStart then [ "default.target" ] else [ ]; + }; + Container = quadletUtils.configToProperties containerConfig containerOpts; + Service = serviceConfigDefault // config.serviceConfig; + }; + unitConfigText = quadletUtils.unitConfigToText unitConfig; + in + { + _configName = "${name}.container"; + _unitName = "${name}.service"; + _configText = quadletUtils.unitConfigToText unitConfig; + }; } diff --git a/flake.nix b/flake.nix index 617091d..d0dd655 100644 --- a/flake.nix +++ b/flake.nix @@ -5,10 +5,12 @@ nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; }; - outputs = { nixpkgs, ... }: - let - libUtils = import "${nixpkgs}/nixos/lib/utils.nix"; - in { - nixosModules.quadlet = import ./nixos-module.nix { inherit libUtils; }; - }; + outputs = + { nixpkgs, ... }: + let + libUtils = import "${nixpkgs}/nixos/lib/utils.nix"; + in + { + nixosModules.quadlet = import ./nixos-module.nix { inherit libUtils; }; + }; } diff --git a/network.nix b/network.nix index 893e6c6..c6c1392 100644 --- a/network.nix +++ b/network.nix @@ -1,5 +1,10 @@ { quadletUtils, pkgs }: -{ config, name, lib, ... }: +{ + config, + name, + lib, + ... +}: with lib; @@ -13,7 +18,13 @@ let }; driver = quadletUtils.mkOption { - type = types.nullOr (types.enum [ "bridge" "macvlan" "ipvlan" ]); + type = types.nullOr ( + types.enum [ + "bridge" + "macvlan" + "ipvlan" + ] + ); default = null; example = "bridge"; description = "--driver"; @@ -36,7 +47,13 @@ let }; ipamDriver = quadletUtils.mkOption { - type = types.nullOr (types.enum [ "host-local" "dhcp" "none" ]); + type = types.nullOr ( + types.enum [ + "host-local" + "dhcp" + "none" + ] + ); default = null; example = "dhcp"; description = "--ipam-driver"; @@ -98,7 +115,8 @@ let property = "Subnet"; }; }; -in { +in +{ options = { autoStart = mkOption { type = types.bool; @@ -109,11 +127,11 @@ in { networkConfig = networkOpts; unitConfig = mkOption { type = types.attrs; - default = {}; + default = { }; }; serviceConfig = mkOption { type = types.attrs; - default = {}; + default = { }; }; _configName = mkOption { internal = true; }; @@ -121,27 +139,28 @@ in { _configText = mkOption { internal = true; }; }; - config = let - configRelPath = "containers/systemd/${name}.network"; - networkName = if config.networkConfig.name != null - then config.networkConfig.name - else "systemd-${name}"; - networkConfig = config.networkConfig; - unitConfig = { - Unit = { - Description = "Podman network ${name}"; - } // config.unitConfig; - Install = { - WantedBy = if config.autoStart then [ "default.target" ] else []; + config = + let + configRelPath = "containers/systemd/${name}.network"; + networkName = + if config.networkConfig.name != null then config.networkConfig.name else "systemd-${name}"; + networkConfig = config.networkConfig; + unitConfig = { + Unit = { + Description = "Podman network ${name}"; + } // config.unitConfig; + Install = { + WantedBy = if config.autoStart then [ "default.target" ] else [ ]; + }; + Network = quadletUtils.configToProperties networkConfig networkOpts; + Service = { + ExecStop = "${pkgs.podman}/bin/podman network rm ${networkName}"; + } // config.serviceConfig; }; - Network = quadletUtils.configToProperties networkConfig networkOpts; - Service = { - ExecStop = "${pkgs.podman}/bin/podman network rm ${networkName}"; - } // config.serviceConfig; - }; - in { - _configName = "${name}.network"; - _unitName = "${name}-network.service"; - _configText = quadletUtils.unitConfigToText unitConfig; - }; + in + { + _configName = "${name}.network"; + _unitName = "${name}-network.service"; + _configText = quadletUtils.unitConfigToText unitConfig; + }; } diff --git a/nixos-module.nix b/nixos-module.nix index 09e1621..7e9807a 100644 --- a/nixos-module.nix +++ b/nixos-module.nix @@ -1,5 +1,10 @@ { libUtils }: -{ config, lib, pkgs, ... }@attrs: +{ + config, + lib, + pkgs, + ... +}@attrs: with lib; @@ -7,16 +12,18 @@ let cfg = config.virtualisation.quadlet; quadletUtils = import ./utils.nix { inherit lib; - systemdLib = (libUtils { - inherit lib config pkgs; - }).systemdUtils.lib; + systemdLib = + (libUtils { + inherit lib config pkgs; + }).systemdUtils.lib; }; # TODO: replace with lib.mergeAttrsList once stable. - mergeAttrsList = foldl mergeAttrs {}; + mergeAttrsList = foldl mergeAttrs { }; - containerOpts = types.submodule (import ./container.nix { inherit quadletUtils; } ); - networkOpts = types.submodule (import ./network.nix { inherit quadletUtils pkgs; } ); -in { + containerOpts = types.submodule (import ./container.nix { inherit quadletUtils; }); + networkOpts = types.submodule (import ./network.nix { inherit quadletUtils pkgs; }); +in +{ options = { virtualisation.quadlet = { containers = mkOption { @@ -31,33 +38,38 @@ in { }; }; - config = let - allObjects = (attrValues cfg.containers) ++ (attrValues cfg.networks); - in { - virtualisation.podman.enable = true; - environment.etc = mergeAttrsList ( - map (p: { - "containers/systemd/${p._configName}" = { - text = p._configText; - mode = "0600"; - }; - }) allObjects); - # The symlinks are not necessary for the services to be honored by systemd, - # but necessary for NixOS activation process to pick them up for updates. - systemd.packages = [ - (pkgs.linkFarm "quadlet-service-symlinks" ( + config = + let + allObjects = (attrValues cfg.containers) ++ (attrValues cfg.networks); + in + { + virtualisation.podman.enable = true; + environment.etc = mergeAttrsList ( map (p: { - name = "etc/systemd/system/${p._unitName}"; - path = "/run/systemd/generator/${p._unitName}"; - }) allObjects)) - ]; - # Inject X-RestartIfChanged=${hash} for NixOS to detect changes. - systemd.units = mergeAttrsList ( - map (p: { - ${p._unitName} = { - overrideStrategy = "asDropin"; - text = "[Unit]\nX-RestartIfChanged=${builtins.hashString "sha256" p._configText}"; - }; - }) allObjects); - }; + "containers/systemd/${p._configName}" = { + text = p._configText; + mode = "0600"; + }; + }) allObjects + ); + # The symlinks are not necessary for the services to be honored by systemd, + # but necessary for NixOS activation process to pick them up for updates. + systemd.packages = [ + (pkgs.linkFarm "quadlet-service-symlinks" ( + map (p: { + name = "etc/systemd/system/${p._unitName}"; + path = "/run/systemd/generator/${p._unitName}"; + }) allObjects + )) + ]; + # Inject X-RestartIfChanged=${hash} for NixOS to detect changes. + systemd.units = mergeAttrsList ( + map (p: { + ${p._unitName} = { + overrideStrategy = "asDropin"; + text = "[Unit]\nX-RestartIfChanged=${builtins.hashString "sha256" p._configText}"; + }; + }) allObjects + ); + }; } diff --git a/utils.nix b/utils.nix index 687e756..37f2cac 100644 --- a/utils.nix +++ b/utils.nix @@ -1,19 +1,30 @@ { lib, systemdLib }: let - attrsToList = attrs: if builtins.isAttrs attrs - then lib.mapAttrsToList (name: value: "${name}=${toString value}") attrs - else attrs; -in { - mkOption = { property, ... }@attrs: - (lib.mkOption (lib.filterAttrs (name: _: name != "property") attrs)) // { + attrsToList = + attrs: + if builtins.isAttrs attrs then + lib.mapAttrsToList (name: value: "${name}=${toString value}") attrs + else + attrs; +in +{ + mkOption = + { property, ... }@attrs: + (lib.mkOption (lib.filterAttrs (name: _: name != "property") attrs)) + // { inherit property; }; - configToProperties = config: options: lib.mapAttrs' - (name: value: lib.nameValuePair options.${name}.property (attrsToList value)) - (lib.filterAttrs (_: value: value != null) config); + configToProperties = + config: options: + lib.mapAttrs' (name: value: lib.nameValuePair options.${name}.property (attrsToList value)) ( + lib.filterAttrs (_: value: value != null) config + ); - unitConfigToText = unitConfig: builtins.concatStringsSep "\n\n" ( - lib.mapAttrsToList (name: section: "[${name}]\n${systemdLib.attrsToSection section}") unitConfig); + unitConfigToText = + unitConfig: + builtins.concatStringsSep "\n\n" ( + lib.mapAttrsToList (name: section: "[${name}]\n${systemdLib.attrsToSection section}") unitConfig + ); }