Unverified Commit 5d91651e authored by Sandro Jäckel's avatar Sandro Jäckel Committed by GitHub
Browse files

nixos/tailscale: interface should be up prior to service finish (#396399)

parents 0b96957f b67bf160
Loading
Loading
Loading
Loading
+36 −10
Original line number Diff line number Diff line
@@ -84,6 +84,8 @@ in
      description = ''
        A file containing the auth key.
        Tailscale will be automatically started if provided.

        Services that bind to Tailscale IPs should order using {option}`systemd.services.<name>.after` `tailscaled-autoconnect.service`.
      '';
    };

@@ -116,7 +118,7 @@ in

    extraUpFlags = mkOption {
      description = ''
        Extra flags to pass to {command}`tailscale up`. Only applied if `authKeyFile` is specified.";
        Extra flags to pass to {command}`tailscale up`. Only applied if {option}`services.tailscale.authKeyFile` is specified.
      '';
      type = types.listOf types.str;
      default = [ ];
@@ -183,12 +185,15 @@ in
      wants = [ "tailscaled.service" ];
      wantedBy = [ "multi-user.target" ];
      serviceConfig = {
        Type = "oneshot";
        Type = "notify";
      };
      # https://github.com/tailscale/tailscale/blob/v1.72.1/ipn/backend.go#L24-L32
      path = [
        cfg.package
        pkgs.jq
      ];
      enableStrictShellChecks = true;
      script =
        let
          statusCommand = "${lib.getExe cfg.package} status --json --peers=false | ${lib.getExe pkgs.jq} -r '.BackendState'";
          paramToString = v: if (builtins.isBool v) then (lib.boolToString v) else (toString v);
          params = lib.pipe cfg.authKeyParameters [
            (lib.filterAttrs (_: v: v != null))
@@ -197,14 +202,35 @@ in
            (params: if params != "" then "?${params}" else "")
          ];
        in
        # bash
        ''
          while [[ "$(${statusCommand})" == "NoState" ]]; do
            sleep 0.5
          done
          status=$(${statusCommand})
          if [[ "$status" == "NeedsLogin" || "$status" == "NeedsMachineAuth" ]]; then
            ${lib.getExe cfg.package} up --auth-key "$(cat ${cfg.authKeyFile})${params}" ${escapeShellArgs cfg.extraUpFlags}
          getState() {
            tailscale status --json --peers=false | jq -r '.BackendState'
          }

          lastState=""
          while state="$(getState)"; do
            if [[ "$state" != "$lastState" ]]; then
              # https://github.com/tailscale/tailscale/blob/v1.72.1/ipn/backend.go#L24-L32
              case "$state" in
                NeedsLogin)
                  echo "Server needs authentication, sending auth key"
                  tailscale up --auth-key "$(cat ${cfg.authKeyFile})${params}" ${escapeShellArgs cfg.extraUpFlags}
                  ;;
                Running)
                  echo "Tailscale is running"
                  systemd-notify --ready
                  exit 0
                  ;;
                *)
                  echo "Waiting for Tailscale State = Running or systemd timeout"
                  ;;
              esac
            fi
            echo "State = $state"
            lastState="$state"
            sleep .5
          done
        '';
    };