Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 12 additions & 92 deletions flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -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"];
Expand All @@ -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;

Expand All @@ -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"
);
};
};
};
};
});
}
86 changes: 86 additions & 0 deletions nix/nixos-module.nix
Original file line number Diff line number Diff line change
@@ -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"
);
};
};
};
}
4 changes: 2 additions & 2 deletions nix/vm-test.nix
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{ self, lib, pkgs, system, ... }:
{ self, lib, pkgs, ... }:

let fakeTailscale = pkgs.writeScriptBin "tailscale" ''
#!/bin/sh
Expand All @@ -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;
Expand Down
Loading