diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index f04c976..4ebfd58 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -9,7 +9,7 @@ on: jobs: # Matrix test for all supported platforms and architectures - + integration-tests: name: ${{ matrix.os }} (${{ matrix.arch }}) tailscale-${{ matrix.version }} strategy: @@ -34,13 +34,13 @@ jobs: runner-os: Linux arch: amd64 version: 1.82.0 - + # Linux tests (ARM64) - os: ubuntu-24.04-arm runner-os: Linux arch: arm64 version: latest - + # Windows tests (AMD64) - os: windows-latest runner-os: Windows @@ -52,46 +52,46 @@ jobs: runner-os: Windows arch: amd64 version: unstable - + # Windows tests (ARM64) - os: windows-11-arm runner-os: Windows arch: arm64 version: latest - + # macOS intel - os: macos-13 runner-os: macOS arch: amd64 version: latest ping: 100.99.0.2 # hostnames aren't resolving on MacOS, just ping IP lax-pve.pineapplefish.ts.net,lax-pve - + # macOS ARM - os: macos-14 runner-os: macOS arch: arm64 version: latest - + runs-on: ${{ matrix.os }} - + steps: - name: Checkout uses: actions/checkout@v4 - + - name: Setup Node.js uses: actions/setup-node@v4 with: - node-version: '20' - cache: 'npm' - + node-version: "20" + cache: "npm" + - name: Install Dependencies run: npm ci - + - name: Build Action run: npm run build - + # Test with OAuth authentication - - name: Test Tailscale Setup (OAuth) + - name: Test Action id: tailscale-oauth uses: ./ with: @@ -103,7 +103,7 @@ jobs: timeout: "5m" retry: 3 ping: "${{ matrix.ping }}" - + # Test Tailscale status command - name: Check Tailscale Status if: steps.tailscale-oauth.outcome == 'success' @@ -119,4 +119,3 @@ jobs: tailscale version fi shell: bash - \ No newline at end of file diff --git a/dist/index.js b/dist/index.js index a8643f7..5855a44 100644 --- a/dist/index.js +++ b/dist/index.js @@ -41123,6 +41123,7 @@ const fs = __importStar(__nccwpck_require__(79896)); const http = __importStar(__nccwpck_require__(58611)); const os = __importStar(__nccwpck_require__(70857)); const path = __importStar(__nccwpck_require__(16928)); +const promises_1 = __nccwpck_require__(16460); const cmdTailscale = "tailscale"; const cmdTailscaleFullPath = "/usr/local/bin/tailscale"; const cmdTailscaled = "tailscaled"; @@ -41241,7 +41242,7 @@ async function run() { core.debug(`Tailscale status: ${JSON.stringify(status)}`); if (status.BackendState === "Running") { core.info("✅ Tailscale is running and connected!"); - pingHostsIfNecessary(config); + await pingHostsIfNecessary(config); // Explicitly exit to prevent hanging process.exit(0); } @@ -41254,7 +41255,7 @@ async function run() { core.warning(`Failed to get Tailscale status: ${err}`); // Still exit successfully since the main connection worked core.info("✅ Tailscale daemon is connected!"); - pingHostsIfNecessary(config); + await pingHostsIfNecessary(config); // Explicitly exit to prevent hanging process.exit(0); } @@ -41264,31 +41265,33 @@ async function run() { } } async function pingHostsIfNecessary(config) { - const directConnectionWarning = "direct connection not established"; if (config.pingHosts.length == 0) { return; } - core.info(`Will ping hosts ${config.pingHosts.join(",")} up to 3 minutes in order to check connectivity`); + core.info(`Will ping hosts ${config.pingHosts.join(",")} up to 3 minutes each in order to check connectivity`); for (const host of config.pingHosts) { - core.info(`Pinging host ${host}`); - let result = await exec.getExecOutput(cmdTailscale, [ - "ping", - "-c", - "36", - host, - ]); + await pingHost(host); + } +} +async function pingHost(host) { + core.info(`Pinging host ${host}`); + for (let i = 0; i <= 36; i++) { + if (i < 0) { + // wait 5 seconds before pinging + (0, promises_1.setTimeout)(5000); + } + let result = await exec.getExecOutput(cmdTailscale, ["ping", "-c", "1", host], { ignoreReturnCode: true }); if (result.exitCode === 0) { - core.info(`✅ Ping host ${host} responded!`); + core.info(`✅ Ping host ${host} reachable via direct connection!`); + return; } - else if (result.stderr.includes(directConnectionWarning) || - result.stdout.includes(directConnectionWarning)) { - core.warning(`⚠️ Ping host ${host} reachable only via DERP, not direct connection.`); - } - else { - core.setFailed(`❌ Ping host ${host} did not respond`); - process.exit(1); + else if (result.stderr.includes("direct connection not established")) { + core.info(`✅ Ping host ${host} reachable via DERP!`); + return; } } + core.setFailed(`❌ Ping host ${host} did not respond`); + process.exit(1); } async function getInputs() { let ping = core.getInput("ping"); @@ -42006,6 +42009,14 @@ module.exports = require("timers"); /***/ }), +/***/ 16460: +/***/ ((module) => { + +"use strict"; +module.exports = require("timers/promises"); + +/***/ }), + /***/ 64756: /***/ ((module) => { diff --git a/src/main.ts b/src/main.ts index 72a174c..f643183 100644 --- a/src/main.ts +++ b/src/main.ts @@ -8,6 +8,7 @@ import * as fs from "fs"; import * as http from "http"; import * as os from "os"; import * as path from "path"; +import { setTimeout as wait } from "timers/promises"; const cmdTailscale = "tailscale"; const cmdTailscaleFullPath = "/usr/local/bin/tailscale"; @@ -167,7 +168,7 @@ async function run(): Promise { core.debug(`Tailscale status: ${JSON.stringify(status)}`); if (status.BackendState === "Running") { core.info("✅ Tailscale is running and connected!"); - pingHostsIfNecessary(config); + await pingHostsIfNecessary(config); // Explicitly exit to prevent hanging process.exit(0); } else { @@ -178,7 +179,7 @@ async function run(): Promise { core.warning(`Failed to get Tailscale status: ${err}`); // Still exit successfully since the main connection worked core.info("✅ Tailscale daemon is connected!"); - pingHostsIfNecessary(config); + await pingHostsIfNecessary(config); // Explicitly exit to prevent hanging process.exit(0); } @@ -188,8 +189,6 @@ async function run(): Promise { } async function pingHostsIfNecessary(config: TailscaleConfig): Promise { - const directConnectionWarning = "direct connection not established"; - if (config.pingHosts.length == 0) { return; } @@ -197,30 +196,35 @@ async function pingHostsIfNecessary(config: TailscaleConfig): Promise { core.info( `Will ping hosts ${config.pingHosts.join( "," - )} up to 3 minutes in order to check connectivity` + )} up to 3 minutes each in order to check connectivity` ); for (const host of config.pingHosts) { - core.info(`Pinging host ${host}`); - let result = await exec.getExecOutput(cmdTailscale, [ - "ping", - "-c", - "36", - host, - ]); + await pingHost(host); + } +} + +async function pingHost(host: string): Promise { + core.info(`Pinging host ${host}`); + for (let i = 0; i <= 36; i++) { + if (i < 0) { + // wait 5 seconds before pinging + wait(5000); + } + let result = await exec.getExecOutput( + cmdTailscale, + ["ping", "-c", "1", host], + { ignoreReturnCode: true } + ); if (result.exitCode === 0) { - core.info(`✅ Ping host ${host} responded!`); - } else if ( - result.stderr.includes(directConnectionWarning) || - result.stdout.includes(directConnectionWarning) - ) { - core.warning( - `⚠️ Ping host ${host} reachable only via DERP, not direct connection.` - ); - } else { - core.setFailed(`❌ Ping host ${host} did not respond`); - process.exit(1); + core.info(`✅ Ping host ${host} reachable via direct connection!`); + return; + } else if (result.stderr.includes("direct connection not established")) { + core.info(`✅ Ping host ${host} reachable via DERP!`); + return; } } + core.setFailed(`❌ Ping host ${host} did not respond`); + process.exit(1); } async function getInputs(): Promise {