diff --git a/flake.nix b/flake.nix index d4bec21..51d8820 100644 --- a/flake.nix +++ b/flake.nix @@ -13,19 +13,25 @@ githubActions = nix-github-actions.lib.mkGithubMatrix { checks = nixpkgs.lib.getAttrs [ "x86_64-linux" ] self.checks; }; + + nixosModules.default = self.nixosModules.tailscale-manager; + nixosModules.tailscale-manager = import ./nix/nixos-module.nix; + + overlays.default = final: prev: { + tailscale-manager = self.packages.${prev.system}.tailscale-manager; + }; + } // flake-utils.lib.eachDefaultSystem (system: let - pkgs = nixpkgs.legacyPackages.${system}; + pkgs = nixpkgs.legacyPackages.${system}.extend self.overlays.default; haskellPackages = pkgs.haskellPackages; jailbreakUnbreak = pkg: pkgs.haskell.lib.doJailbreak (pkg.overrideAttrs (_: { meta = { }; })); - - packageName = "tailscale-manager"; in { - packages.${packageName} = ( - haskellPackages.callCabal2nix packageName self rec { + packages.tailscale-manager = ( + haskellPackages.callCabal2nix "tailscale-manager" self rec { # Dependency overrides go here }).overrideAttrs (x: { outputs = x.outputs ++ ["testreport"]; @@ -34,7 +40,7 @@ ''; }); - packages.default = self.packages.${system}.${packageName}; + packages.default = self.packages.${system}.tailscale-manager; checks.tailscale-manager = self.packages.${system}.tailscale-manager; @@ -49,91 +55,5 @@ inputsFrom = map (__getAttr "env") (__attrValues self.packages.${system}); }; - nixosModules.default = self.nixosModules.${system}.tailscale-manager; - nixosModules.tailscale-manager = { config, lib, pkgs, ... }: - with lib; - let - cfg = config.services.tailscale-manager; - configFile = pkgs.writeTextFile { - name = "tailscale-manager.json"; - text = generators.toJSON {} { - routes = cfg.routes; - hostRoutes = cfg.hostRoutes; - extraArgs = cfg.extraArgs; - awsManagedPrefixLists = cfg.awsManagedPrefixLists; - }; - }; - in { - options.services.tailscale-manager = { - enable = mkEnableOption "tailscale-manager"; - package = mkPackageOption self.packages.${system} "tailscale-manager" {}; - interval = mkOption { - type = types.int; - default = 300; - description = "Interval between runs, in seconds"; - }; - routes = mkOption { - type = types.listOf types.str; - default = []; - description = "List of CIDR prefix routes to advertise"; - }; - hostRoutes = mkOption { - type = types.listOf types.str; - default = []; - description = "List of hostnames and IP addresses to add as /32 routes"; - }; - awsManagedPrefixLists = mkOption { - type = types.listOf types.str; - default = []; - description = "AWS prefix list IDs for route discovery"; - }; - extraArgs = mkOption { - type = types.listOf types.str; - default = []; - description = "Extra arguments for `tailscale set`"; - }; - dryRun = mkOption { - type = types.bool; - default = false; - description = "Enable dry-run mode, don't actually apply changes."; - }; - maxShrinkRatio = mkOption { - type = types.float; - default = 0.5; - description = "How much route shrinkage is allowed between subsequent runs (between 0 and 1)"; - }; - socketPath = mkOption { - type = types.path; - default = "/var/run/tailscale/tailscaled.sock"; - description = "Path to the tailscaled socket"; - }; - }; - config = mkIf cfg.enable { - systemd.services.tailscale-manager = { - after = ["tailscaled.service"]; - wants = ["tailscaled.service"]; - wantedBy = ["multi-user.target"]; - # Never give up on trying to restart - startLimitIntervalSec = 0; - serviceConfig = { - Type = "exec"; - Restart = "always"; - # Restart at increasing intervals to avoid things like EC2 - # metadata service rate limits - RestartSec = 1; - RestartSteps = 30; - RestartMaxDelaySec = 60; - ExecStart = lib.escapeShellArgs ( - [ "${cfg.package}/bin/tailscale-manager" configFile - "--tailscale=${config.services.tailscale.package}/bin/tailscale" - "--socket=${cfg.socketPath}" - "--interval=${toString cfg.interval}" - "--max-shrink-ratio=${toString cfg.maxShrinkRatio}" - ] ++ lib.optional cfg.dryRun "--dryrun" - ); - }; - }; - }; - }; }); } diff --git a/nix/nixos-module.nix b/nix/nixos-module.nix new file mode 100644 index 0000000..80a84ba --- /dev/null +++ b/nix/nixos-module.nix @@ -0,0 +1,86 @@ +{ config, lib, pkgs, ... }: + +with lib; +let + cfg = config.services.tailscale-manager; + configFile = pkgs.writeTextFile { + name = "tailscale-manager.json"; + text = generators.toJSON {} { + routes = cfg.routes; + hostRoutes = cfg.hostRoutes; + extraArgs = cfg.extraArgs; + awsManagedPrefixLists = cfg.awsManagedPrefixLists; + }; + }; +in { + options.services.tailscale-manager = { + enable = mkEnableOption "tailscale-manager"; + package = mkPackageOption pkgs "tailscale-manager" {}; + interval = mkOption { + type = types.int; + default = 300; + description = "Interval between runs, in seconds"; + }; + routes = mkOption { + type = types.listOf types.str; + default = []; + description = "List of CIDR prefix routes to advertise"; + }; + hostRoutes = mkOption { + type = types.listOf types.str; + default = []; + description = "List of hostnames and IP addresses to add as /32 routes"; + }; + awsManagedPrefixLists = mkOption { + type = types.listOf types.str; + default = []; + description = "AWS prefix list IDs for route discovery"; + }; + extraArgs = mkOption { + type = types.listOf types.str; + default = []; + description = "Extra arguments for `tailscale set`"; + }; + dryRun = mkOption { + type = types.bool; + default = false; + description = "Enable dry-run mode, don't actually apply changes."; + }; + maxShrinkRatio = mkOption { + type = types.float; + default = 0.5; + description = "How much route shrinkage is allowed between subsequent runs (between 0 and 1)"; + }; + socketPath = mkOption { + type = types.path; + default = "/var/run/tailscale/tailscaled.sock"; + description = "Path to the tailscaled socket"; + }; + }; + config = mkIf cfg.enable { + systemd.services.tailscale-manager = { + after = ["tailscaled.service"]; + wants = ["tailscaled.service"]; + wantedBy = ["multi-user.target"]; + # Never give up on trying to restart + startLimitIntervalSec = 0; + serviceConfig = { + Type = "exec"; + Restart = "always"; + # Restart at increasing intervals to avoid things like EC2 + # metadata service rate limits + RestartSec = 1; + RestartSteps = 30; + RestartMaxDelaySec = 60; + ExecStart = lib.escapeShellArgs ( + [ "${cfg.package}/bin/tailscale-manager" configFile + "--tailscale=${config.services.tailscale.package}/bin/tailscale" + "--socket=${cfg.socketPath}" + "--interval=${toString cfg.interval}" + "--max-shrink-ratio=${toString cfg.maxShrinkRatio}" + ] ++ lib.optional cfg.dryRun "--dryrun" + ); + }; + }; + }; +} diff --git a/nix/vm-test.nix b/nix/vm-test.nix index 4e72044..8d1264a 100644 --- a/nix/vm-test.nix +++ b/nix/vm-test.nix @@ -1,4 +1,4 @@ -{ self, lib, pkgs, system, ... }: +{ self, lib, pkgs, ... }: let fakeTailscale = pkgs.writeScriptBin "tailscale" '' #!/bin/sh @@ -8,7 +8,7 @@ in pkgs.nixosTest { name = "tailscale-manager"; nodes.machine1 = { config, pkgs, ... }: { - imports = [ self.nixosModules.${system}.tailscale-manager ]; + imports = [ self.nixosModules.tailscale-manager ]; services.tailscale.package = fakeTailscale; services.tailscale-manager = { enable = true;