mirror of
https://github.com/tailscale/github-action.git
synced 2026-08-20 08:29:22 +00:00
add support for testing peer connectivity
The new argument `ping` allows users to specify a comma-seperated list of hosts (IP or hostname) to ping in order to verify connectivity. Ping is considered successful as soon as the peer is reachable either directly or via DERP. Updates tailscale/corp#32817 Signed-off-by: Percy Wegmann <percy@tailscale.com>
This commit is contained in:
parent
90629cdeb4
commit
75aaac9f12
5 changed files with 92 additions and 4 deletions
4
.github/workflows/test.yml
vendored
4
.github/workflows/test.yml
vendored
|
|
@ -21,6 +21,7 @@ jobs:
|
|||
runner-os: Linux
|
||||
arch: amd64
|
||||
version: latest
|
||||
ping: 100.99.0.2,lax-pve.pineapplefish.ts.net,lax-pve
|
||||
|
||||
# Try unstable too
|
||||
- os: ubuntu-latest
|
||||
|
|
@ -45,6 +46,7 @@ jobs:
|
|||
runner-os: Windows
|
||||
arch: amd64
|
||||
version: latest
|
||||
ping: 100.99.0.2,lax-pve.pineapplefish.ts.net,lax-pve
|
||||
|
||||
- os: windows-latest
|
||||
runner-os: Windows
|
||||
|
|
@ -62,6 +64,7 @@ jobs:
|
|||
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
|
||||
|
|
@ -99,6 +102,7 @@ jobs:
|
|||
use-cache: false
|
||||
timeout: "5m"
|
||||
retry: 3
|
||||
ping: "${{ matrix.ping }}"
|
||||
|
||||
# Test Tailscale status command
|
||||
- name: Check Tailscale Status
|
||||
|
|
|
|||
|
|
@ -80,6 +80,7 @@ This action is written in Typescript using official GitHub SDKs. It provides som
|
|||
| `tailscaled-args` | Additional `tailscaled` arguments | false | |
|
||||
| `statedir` | State directory (if empty, uses memory) | false | |
|
||||
| `sha256sum` | Expected SHA256 checksum | false | |
|
||||
| `ping` | Comma separated list of hosts (Tailscale IP addresses or machine names if MagicDNS is enabled on the tailnet) to `tailscale ping` for connectivity verification after `tailscale up` completes | false | |
|
||||
|
||||
## Authentication
|
||||
|
||||
|
|
@ -209,4 +210,6 @@ For security issues, please see our [security policy](SECURITY.md).
|
|||
|
||||
## CI Notes
|
||||
|
||||
CI tests run against the tailscalegithubactionbot.github tailnet. Check our usual credential store for credentials.
|
||||
CI tests run against the pineapplefish-tailnet.org.github tailnet. Check our usual credential store for credentials.
|
||||
|
||||
`tag:ci` must have access to the `lax-pve` server.
|
||||
|
|
@ -53,7 +53,11 @@ inputs:
|
|||
description: 'Expected SHA256 checksum of the Tailscale package. If not provided, it will be fetched automatically.'
|
||||
required: false
|
||||
default: ''
|
||||
|
||||
ping:
|
||||
description: 'Comma separated list of hosts (Tailscale IP addresses or machine names if MagicDNS is enabled on the tailnet) to `tailscale ping` for connectivity verification after `tailscale up` completes.'
|
||||
required: false
|
||||
default: ''
|
||||
|
||||
runs:
|
||||
using: 'node20'
|
||||
main: 'dist/index.js'
|
||||
|
|
|
|||
35
dist/index.js
vendored
35
dist/index.js
vendored
|
|
@ -41241,6 +41241,7 @@ async function run() {
|
|||
core.debug(`Tailscale status: ${JSON.stringify(status)}`);
|
||||
if (status.BackendState === "Running") {
|
||||
core.info("✅ Tailscale is running and connected!");
|
||||
pingHostsIfNecessary(config);
|
||||
// Explicitly exit to prevent hanging
|
||||
process.exit(0);
|
||||
}
|
||||
|
|
@ -41252,7 +41253,9 @@ async function run() {
|
|||
catch (err) {
|
||||
core.warning(`Failed to get Tailscale status: ${err}`);
|
||||
// Still exit successfully since the main connection worked
|
||||
core.info("✅ Tailscale connection completed successfully!");
|
||||
core.info("✅ Tailscale daemon is connected!");
|
||||
pingHostsIfNecessary(config);
|
||||
// Explicitly exit to prevent hanging
|
||||
process.exit(0);
|
||||
}
|
||||
}
|
||||
|
|
@ -41260,7 +41263,36 @@ async function run() {
|
|||
core.setFailed(error instanceof Error ? error.message : String(error));
|
||||
}
|
||||
}
|
||||
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`);
|
||||
for (const host of config.pingHosts) {
|
||||
core.info(`Pinging host ${host}`);
|
||||
let result = await exec.getExecOutput(cmdTailscale, [
|
||||
"ping",
|
||||
"-c",
|
||||
"36",
|
||||
host,
|
||||
]);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
async function getInputs() {
|
||||
let ping = core.getInput("ping");
|
||||
let pingHosts = ping?.length > 0 ? ping.split(",") : [];
|
||||
return {
|
||||
version: core.getInput("version") || "1.82.0",
|
||||
resolvedVersion: "",
|
||||
|
|
@ -41277,6 +41309,7 @@ async function getInputs() {
|
|||
retry: parseInt(core.getInput("retry") || "5"),
|
||||
useCache: core.getBooleanInput("use-cache"),
|
||||
sha256Sum: core.getInput("sha256sum") || "",
|
||||
pingHosts: pingHosts,
|
||||
};
|
||||
}
|
||||
function validateAuth(config) {
|
||||
|
|
|
|||
46
src/main.ts
46
src/main.ts
|
|
@ -40,6 +40,7 @@ interface TailscaleConfig {
|
|||
retry: number;
|
||||
useCache: boolean;
|
||||
sha256Sum: string;
|
||||
pingHosts: string[];
|
||||
}
|
||||
|
||||
// Cross-platform Tailscale local API status check
|
||||
|
|
@ -166,6 +167,7 @@ async function run(): Promise<void> {
|
|||
core.debug(`Tailscale status: ${JSON.stringify(status)}`);
|
||||
if (status.BackendState === "Running") {
|
||||
core.info("✅ Tailscale is running and connected!");
|
||||
pingHostsIfNecessary(config);
|
||||
// Explicitly exit to prevent hanging
|
||||
process.exit(0);
|
||||
} else {
|
||||
|
|
@ -175,7 +177,9 @@ async function run(): Promise<void> {
|
|||
} catch (err) {
|
||||
core.warning(`Failed to get Tailscale status: ${err}`);
|
||||
// Still exit successfully since the main connection worked
|
||||
core.info("✅ Tailscale connection completed successfully!");
|
||||
core.info("✅ Tailscale daemon is connected!");
|
||||
pingHostsIfNecessary(config);
|
||||
// Explicitly exit to prevent hanging
|
||||
process.exit(0);
|
||||
}
|
||||
} catch (error) {
|
||||
|
|
@ -183,7 +187,46 @@ async function run(): Promise<void> {
|
|||
}
|
||||
}
|
||||
|
||||
async function pingHostsIfNecessary(config: TailscaleConfig): Promise<void> {
|
||||
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`
|
||||
);
|
||||
for (const host of config.pingHosts) {
|
||||
core.info(`Pinging host ${host}`);
|
||||
let result = await exec.getExecOutput(cmdTailscale, [
|
||||
"ping",
|
||||
"-c",
|
||||
"36",
|
||||
host,
|
||||
]);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function getInputs(): Promise<TailscaleConfig> {
|
||||
let ping = core.getInput("ping");
|
||||
let pingHosts = ping?.length > 0 ? ping.split(",") : [];
|
||||
|
||||
return {
|
||||
version: core.getInput("version") || "1.82.0",
|
||||
resolvedVersion: "",
|
||||
|
|
@ -200,6 +243,7 @@ async function getInputs(): Promise<TailscaleConfig> {
|
|||
retry: parseInt(core.getInput("retry") || "5"),
|
||||
useCache: core.getBooleanInput("use-cache"),
|
||||
sha256Sum: core.getInput("sha256sum") || "",
|
||||
pingHosts: pingHosts,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue