summaryrefslogtreecommitdiff
path: root/modules/flake/deploy-rs.nix
diff options
context:
space:
mode:
authorSeth Flynn <[email protected]>2025-03-05 03:10:35 -0500
committerSeth Flynn <[email protected]>2025-03-05 03:10:35 -0500
commitc294ae90127005d023bbe3f6a5da95c9a94c4e45 (patch)
tree9d6a617656b077386c4d2c3995aac1422e3f8f89 /modules/flake/deploy-rs.nix
parent5572f3bd3a401405215d4d2b863dfeb0f198812d (diff)
flake/deploy-rs: init, but don't output
I haven't tested this enough yet
Diffstat (limited to 'modules/flake/deploy-rs.nix')
-rw-r--r--modules/flake/deploy-rs.nix240
1 files changed, 240 insertions, 0 deletions
diff --git a/modules/flake/deploy-rs.nix b/modules/flake/deploy-rs.nix
new file mode 100644
index 0000000..e5de1b7
--- /dev/null
+++ b/modules/flake/deploy-rs.nix
@@ -0,0 +1,240 @@
+{
+ config,
+ lib,
+ inputs,
+ self,
+ ...
+}:
+
+let
+ cfg = config.deploy;
+
+ deployLib = inputs.deploy-rs.lib;
+
+ hasNodes = cfg.nodes != [ ];
+ hasSettings = cfg.settings != { };
+
+ genericOptions = {
+ freeformType = lib.types.attrsOf (
+ lib.types.oneOf [
+ lib.types.str
+ lib.types.bool
+ lib.types.int
+ lib.types.null
+ ]
+ );
+
+ options = {
+ activationTimeout = lib.mkOption {
+ type = lib.types.nullOr lib.types.int;
+ default = null;
+ defaultText = lib.literalExpression "240";
+ description = "Timeout for profile activation in seconds.";
+ };
+
+ autoRollback = lib.mkEnableOption "rollback if activation fails" // {
+ type = lib.types.nullOr lib.types.bool;
+ default = null;
+ defaultText = lib.literalExpression "true";
+ };
+
+ confirmationTimeout = lib.mkOption {
+ type = lib.types.nullOr lib.types.int;
+ default = null;
+ defaultText = lib.literalExpression "30";
+ description = "Timeout for profile activation confirmation in seconds.";
+ };
+
+ fastConnection = lib.mkOption {
+ type = lib.types.nullOr lib.types.bool;
+ default = null;
+ defaultText = lib.literalExpression "false";
+ description = ''
+ Whether to enable fast connection to the node.
+
+ If this is true, copy the whole closure instead of letting the node substitute.
+ '';
+ };
+
+ interactiveSudo = lib.mkEnableOption "interactive sudo (password based sudo)" // {
+ type = lib.types.nullOr lib.types.bool;
+ default = null;
+ defaultText = lib.literalExpression "false";
+ };
+
+ magicRollback = lib.mkEnableOption "magic rollback" // {
+ type = lib.types.nullOr lib.types.bool;
+ default = null;
+ defaultText = lib.literalExpression "true";
+ };
+
+ remoteBuild = lib.mkEnableOption "building on the target system" // {
+ type = lib.types.nullOr lib.types.bool;
+ default = null;
+ defaultText = lib.literalExpression "false";
+ };
+
+ sshUser = lib.mkOption {
+ type = lib.types.nullOr lib.types.str;
+ default = null;
+ description = ''
+ The user that deploy-rs will use when connecting.
+
+ This will default to your own username if not specified anywhere.
+ '';
+ };
+
+ sshOpts = lib.mkOption {
+ type = lib.types.nullOr (lib.types.listOf lib.types.str);
+ default = null;
+ description = "An optional list of arguments that will be passed to SSH.";
+ };
+
+ sudo = lib.mkOption {
+ type = lib.types.nullOr lib.types.str;
+ default = null;
+ defaultText = "sudo -u";
+ description = ''
+ Which sudo command to use.
+
+ Must accept at least two arguments:
+ The user name to execute commands as and the rest is the command to execute.
+ '';
+ };
+
+ user = lib.mkOption {
+ type = lib.types.nullOr lib.types.str;
+ default = null;
+ defaultText = lib.literalExpression "config.sshUser";
+ description = ''
+ The user that the profile will be deployed to.
+
+ Will use sudo if not the same as `sshUser`
+ '';
+ };
+
+ tempPath = lib.mkOption {
+ type = lib.types.nullOr lib.types.str;
+ default = null;
+ defaultText = "/tmp";
+ description = ''
+ The path which deploy-rs will use for temporary files.
+
+ If `magicRollback` is in use, this *must* be writable by `user`.
+ '';
+ };
+ };
+ };
+
+ nodeSubmodule =
+ { name, ... }:
+ {
+ imports = [ genericOptions ];
+
+ options = {
+ hostname = lib.mkOption {
+ type = lib.types.str;
+ default = name;
+ description = "The hostname of your server.";
+ };
+
+ profilesOrder = lib.mkOption {
+ type = lib.types.listOf lib.types.str;
+ default = [ ];
+ description = ''
+ An optional list containing the order you want profiles to be deployed.
+
+ This will take effect whenever you run `deploy` without specifying a profile, causing it to deploy every profile automatically.
+ Any profiles not in this list will still be deployed (in an arbitrary order) after those which are listed.
+ '';
+ };
+
+ profiles = lib.mkOption {
+ type = lib.types.attrsOf (
+ lib.types.submodule {
+ imports = [ genericOptions ];
+
+ # TODO: Add `profilePath`
+ options = {
+ path = lib.mkOption {
+ type = lib.types.lazyAttrsOf lib.types.raw;
+ description = "NixOS closure path to activate on target";
+ default = self.nixosConfigurations.${name};
+ apply =
+ configuration:
+ let
+ inherit (configuration.pkgs.stdenv.hostPlatform) system;
+ in
+ deployLib.${system}.activate.nixos configuration;
+ defaultText = lib.literalExpression "self.nixosConfigurations.${name}";
+ };
+ };
+ }
+ );
+ default = {
+ system = { };
+ };
+ defaultText = lib.literalExpression "{ system = { self.nixosConfigurations.\${name}; }; }";
+ };
+ };
+
+ config = {
+ sshUser = lib.mkDefault "root";
+ };
+ };
+
+ settingsSubmodule = {
+ imports = [ genericOptions ];
+
+ options = {
+ nodes = lib.mkOption {
+ type = lib.types.attrsOf (lib.types.submodule nodeSubmodule);
+ default = { };
+ };
+ };
+ };
+in
+
+{
+ options.deploy = {
+ nodes = lib.mkOption {
+ type = lib.types.listOf lib.types.str;
+ default = [ ];
+ description = "List of nixosConfiguration names to create deploy-rs nodes for";
+ };
+
+ useChecks = lib.mkEnableOption "deploy-rs checks";
+
+ settings = lib.mkOption {
+ type = lib.types.submodule settingsSubmodule;
+ default = { };
+ description = ''
+ Options for deploy-rs.
+
+ See https://github.com/serokell/deploy-rs?tab=readme-ov-file#api
+ for supported values.
+ '';
+ };
+ };
+
+ config = lib.mkMerge [
+ (lib.mkIf hasNodes {
+ deploy.settings = {
+ nodes = lib.genAttrs cfg.nodes (lib.const { });
+ };
+ })
+
+ (lib.mkIf hasSettings {
+ flake.deploy = lib.filterAttrsRecursive (lib.const (value: value != null)) cfg.settings;
+ })
+
+ (lib.mkIf (hasSettings && cfg.useChecks) {
+ perSystem =
+ { system, ... }:
+
+ lib.mkIf (lib.elem system (lib.attrNames inputs.deploy-rs.lib)) {
+ checks = deployLib.${system}.deployChecks self.deploy;
+ };
+ })
+ ];
+}