summary refs log tree commit diff
path: root/modules/foundation/tailnet.nix
diff options
context:
space:
mode:
Diffstat (limited to 'modules/foundation/tailnet.nix')
-rw-r--r--modules/foundation/tailnet.nix101
1 files changed, 101 insertions, 0 deletions
diff --git a/modules/foundation/tailnet.nix b/modules/foundation/tailnet.nix
new file mode 100644
index 0000000..404c5ad
--- /dev/null
+++ b/modules/foundation/tailnet.nix
@@ -0,0 +1,101 @@
+{
+  config,
+  pkgs,
+  lib,
+  ...
+}:
+
+let
+  inherit (lib) mkOption types;
+  inherit (pkgs) tailscale;
+
+  cfg = config.foundation;
+
+  tailnet-wait-for-ip = pkgs.writeShellScriptBin "tailnet-wait-for-ip.sh" ''
+    echo "waiting for tailscale to acquire tailnet ip address..."
+
+    while ! ${lib.getExe tailscale} ip -1; do
+      echo "tailnet ip not yet available... sleeping for 1 second."
+      sleep 1
+    done
+
+    ip=$(${lib.getExe tailscale} ip -1)
+    echo "acquired tailnet address! ip: $ip"
+    exit 0
+  '';
+in
+{
+  options.foundation = {
+    tailnetServices = mkOption {
+      type = with types; listOf str;
+
+      default = [ ];
+      example = [ "nginx" ];
+
+      description = ''
+        services that depend on the tailnet.
+        will be launched only after tailscaled.service
+        is fully up and online.
+      '';
+    };
+  };
+
+  config =
+    let
+      tailnetWaitOnlineService = {
+        enable = true;
+
+        after = [
+          "tailscaled.service"
+          "network.target"
+        ];
+        # kill service if tailscaled dies.
+        bindsTo = [ "tailscaled.service" ];
+
+        serviceConfig = {
+          # unit is marked as active after script exits.
+          Type = "oneshot";
+          RemainAfterExit = true;
+          # consider connection failed after 3 minutes.
+          TimeoutStartSec = "3m";
+
+          ExecStart = "${tailnet-wait-for-ip}/bin/tailnet-wait-for-ip.sh";
+        };
+
+        description = ''
+          wait for tailscale device to be online and ready
+        '';
+      };
+
+      tailnetOnlineTarget = {
+        enable = true;
+
+        after = [
+          "tailnet-wait-online.service"
+          "tailscaled.service"
+        ];
+        requires = [ "tailnet-wait-online.service" ];
+        bindsTo = [ "tailscaled.service" ];
+
+        description = "tailnet is online";
+      };
+
+      tailnetDependantUnit = {
+        after = [ "tailnet-online.target" ];
+        requires = [ "tailnet-online.target" ];
+      };
+
+      tailnetDependantServices = lib.genAttrs cfg.tailnetServices (x: tailnetDependantUnit);
+    in
+    {
+      systemd = {
+        services = {
+          "tailnet-wait-online" = tailnetWaitOnlineService;
+        } // tailnetDependantServices;
+
+        targets = {
+          "tailnet-online" = tailnetOnlineTarget;
+        };
+      };
+    };
+}