Skip to content

Commit

Permalink
flake.nix: Split nixos module to a separate file
Browse files Browse the repository at this point in the history
- Split out nix/nixos-module.nix. This way it can theoretically be
  imported without using flakes, since some people prefer to do things
  that way.
- Use a nixpkgs overlay to add tailscale-manager to pkgs, so it shows up
  when vm-text.nix imports the module
- Move nixosModules to the system-independent outputs section where it
  belongs
- Remove last references to `packageName` since we were not using it
  consistently

Resources: https://vtimofeenko.com/posts/practical-nix-flake-anatomy-a-guided-tour-of-flake.nix/
  • Loading branch information
benley committed Jan 22, 2025
1 parent ed62b9a commit b72b13f
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 94 deletions.
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

0 comments on commit b72b13f

Please sign in to comment.