diff --git a/LICENSE b/LICENSE index d3e245c..7405524 100644 --- a/LICENSE +++ b/LICENSE @@ -1,7 +1,7 @@ BSD 3-Clause License +Copyright (c) 2020 Tailscale Inc & Contributors Copyright (c) 2025 Lee Briggs -Copyright (c) 2025 Tailscale Inc & Contributors All rights reserved. Redistribution and use in source and binary forms, with or without diff --git a/README.md b/README.md index d060596..cbbfd28 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ by adding a step to your workflow. ```yaml - name: Tailscale - uses: tailscale/github-action@v3 + uses: tailscale/github-action@v4 with: oauth-client-id: ${{ secrets.TS_OAUTH_CLIENT_ID }} oauth-secret: ${{ secrets.TS_OAUTH_SECRET }} @@ -40,7 +40,7 @@ You can do this by adding a list of hosts to ping to the action configuration: ```yaml - name: Tailscale - uses: tailscale/github-action@v3 + uses: tailscale/github-action@v4 with: ping: 100.x.y.z,my-machine.my-tailnet.ts.net ``` @@ -51,6 +51,8 @@ or with the [tailscale ping](https://tailscale.com/kb/1080/cli#ping) command if tailscale ping my-target.my-tailnet.ts.net ``` +The `ping` option will wait up to to 3 minutes for a connection (direct or relayed). + > ⚠️ On macOS runners, one can only ping IP addresses, not hostnames. ## Tailnet Lock @@ -67,7 +69,7 @@ Lock](https://tailscale.com/kb/1226/tailnet-lock) enabled network, you need to: ```yaml - name: Tailscale - uses: tailscale/github-action@v3 + uses: tailscale/github-action@v4 with: authkey: tskey-auth-... statedir: /tmp/tailscale-state/ @@ -79,7 +81,7 @@ Which Tailscale version to use can be set like this: ```yaml - name: Tailscale - uses: tailscale/github-action@v3 + uses: tailscale/github-action@v4 with: oauth-client-id: ${{ secrets.TS_OAUTH_CLIENT_ID }} oauth-secret: ${{ secrets.TS_OAUTH_SECRET }} @@ -91,7 +93,7 @@ If you'd like to specify the latest version, simply set the version as `latest` ```yaml - name: Tailscale - uses: tailscale/github-action@v3 + uses: tailscale/github-action@v4 with: oauth-client-id: ${{ secrets.TS_OAUTH_CLIENT_ID }} oauth-secret: ${{ secrets.TS_OAUTH_SECRET }} @@ -115,7 +117,7 @@ Although caching is generally recommended, you can disable it by passing `'false ```yaml - name: Tailscale - uses: tailscale/github-action@v3 + uses: tailscale/github-action@v4 with: oauth-client-id: ${{ secrets.TS_OAUTH_CLIENT_ID }} oauth-secret: ${{ secrets.TS_OAUTH_SECRET }} diff --git a/dist/index.js b/dist/index.js index e2c0dcc..0d1483e 100644 --- a/dist/index.js +++ b/dist/index.js @@ -41270,17 +41270,23 @@ async function pingHostsIfNecessary(config) { if (config.pingHosts.length == 0) { return; } - core.info(`Will ping hosts ${config.pingHosts.join(",")} up to 3 minutes each in order to check connectivity`); - for (const host of config.pingHosts) { - await pingHost(host); + core.info(`Will ping hosts ${config.pingHosts.join(",")} up to 3 minutes each (in parallel) in order to check connectivity`); + let pings = config.pingHosts.map((host) => pingHost(host)); + for (const ping of pings) { + await ping; } } 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 start = new Date().getTime(); + var i = 0; + // Try for up to 180 seconds (3 minutes). + while ((new Date().getTime() - start) / 1000 < 180) { + if (i > 0) { + // Exponential backoff on wait time, with maximum 5 second wait. + let waitTime = Math.min(Math.pow(1.3, i), 5000); + core.debug(`Waiting ${waitTime} milliseconds before pinging`); + await (0, promises_1.setTimeout)(waitTime); } let result = await exec.getExecOutput(cmdTailscale, ["ping", "-c", "1", host], { ignoreReturnCode: true }); if (result.exitCode === 0) { @@ -41288,9 +41294,11 @@ async function pingHost(host) { return; } else if (result.stderr.includes("direct connection not established")) { + // Relayed connectivity is good enough, we don't want to tie up a CI job waiting for a direct connection. core.info(`✅ Ping host ${host} reachable via DERP!`); return; } + i++; } core.setFailed(`❌ Ping host ${host} did not respond`); process.exit(1); diff --git a/src/main.ts b/src/main.ts index ca1dc20..ebce791 100644 --- a/src/main.ts +++ b/src/main.ts @@ -199,19 +199,25 @@ async function pingHostsIfNecessary(config: TailscaleConfig): Promise { core.info( `Will ping hosts ${config.pingHosts.join( "," - )} up to 3 minutes each in order to check connectivity` + )} up to 3 minutes each (in parallel) in order to check connectivity` ); - for (const host of config.pingHosts) { - await pingHost(host); + let pings = config.pingHosts.map((host) => pingHost(host)); + for (const ping of pings) { + await ping; } } 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 start = new Date().getTime(); + var i = 0; + // Try for up to 180 seconds (3 minutes). + while ((new Date().getTime() - start) / 1000 < 180) { + if (i > 0) { + // Exponential backoff on wait time, with maximum 5 second wait. + let waitTime = Math.min(Math.pow(1.3, i), 5000); + core.debug(`Waiting ${waitTime} milliseconds before pinging`); + await wait(waitTime); } let result = await exec.getExecOutput( cmdTailscale, @@ -222,9 +228,11 @@ async function pingHost(host: string): Promise { core.info(`✅ Ping host ${host} reachable via direct connection!`); return; } else if (result.stderr.includes("direct connection not established")) { + // Relayed connectivity is good enough, we don't want to tie up a CI job waiting for a direct connection. core.info(`✅ Ping host ${host} reachable via DERP!`); return; } + i++; } core.setFailed(`❌ Ping host ${host} did not respond`); process.exit(1);