Files
homelab-optimized/ansible/playbooks/tailscale_management.yml
Gitea Mirror Bot e7652c8dab
Some checks failed
Documentation / Build Docusaurus (push) Failing after 5m3s
Documentation / Deploy to GitHub Pages (push) Has been skipped
Sanitized mirror from private repository - 2026-04-20 01:32:01 UTC
2026-04-20 01:32:01 +00:00

373 lines
13 KiB
YAML

---
- name: Tailscale Network Management
hosts: all
gather_facts: yes
vars:
tailscale_timestamp: "{{ ansible_date_time.iso8601 }}"
tailscale_report_dir: "/tmp/tailscale_reports"
tasks:
- name: Create Tailscale reports directory
file:
path: "{{ tailscale_report_dir }}"
state: directory
mode: '0755'
delegate_to: localhost
run_once: true
- name: Check if Tailscale is installed
shell: command -v tailscale >/dev/null 2>&1
register: tailscale_available
changed_when: false
ignore_errors: yes
- name: Skip Tailscale tasks if not available
set_fact:
skip_tailscale: "{{ tailscale_available.rc != 0 }}"
- name: Get Tailscale status
shell: |
if ! command -v tailscale >/dev/null 2>&1; then
echo "Tailscale not installed"
exit 0
fi
echo "=== TAILSCALE STATUS ==="
tailscale status --json 2>/dev/null || tailscale status 2>/dev/null || echo "Tailscale not accessible"
register: tailscale_status
changed_when: false
when: not skip_tailscale
- name: Get Tailscale network information
shell: |
if ! command -v tailscale >/dev/null 2>&1; then
echo "Tailscale not installed"
exit 0
fi
echo "=== TAILSCALE NETWORK INFO ==="
# Get IP addresses
echo "Tailscale IPs:"
tailscale ip -4 2>/dev/null || echo "IPv4 not available"
tailscale ip -6 2>/dev/null || echo "IPv6 not available"
echo ""
# Get peer information
echo "Peer Status:"
tailscale status --peers 2>/dev/null || echo "Peer status not available"
echo ""
# Get routes
echo "Routes:"
tailscale status --self=false 2>/dev/null | grep -E "^[0-9]" | head -10 || echo "Route information not available"
echo ""
# Check connectivity to key peers
echo "Connectivity Tests:"
key_peers="100.83.230.112 100.103.48.78 100.125.0.20" # atlantis, calypso, setillo
for peer in $key_peers; do
if ping -c 1 -W 2 "$peer" >/dev/null 2>&1; then
echo "✅ $peer - reachable"
else
echo "❌ $peer - unreachable"
fi
done
register: tailscale_network
changed_when: false
when: not skip_tailscale
ignore_errors: yes
- name: Check Tailscale service health
shell: |
if ! command -v tailscale >/dev/null 2>&1; then
echo "Tailscale not installed"
exit 0
fi
echo "=== TAILSCALE SERVICE HEALTH ==="
# Check daemon status
if command -v systemctl >/dev/null 2>&1; then
echo "Service Status:"
systemctl is-active tailscaled 2>/dev/null || echo "tailscaled service status unknown"
systemctl is-enabled tailscaled 2>/dev/null || echo "tailscaled service enablement unknown"
echo ""
fi
# Check authentication status
echo "Authentication:"
if tailscale status --json 2>/dev/null | grep -q '"BackendState":"Running"'; then
echo "✅ Authenticated and running"
elif tailscale status 2>/dev/null | grep -q "Logged out"; then
echo "❌ Not logged in"
else
echo "⚠️ Status unclear"
fi
echo ""
# Check for exit node status
echo "Exit Node Status:"
if tailscale status --json 2>/dev/null | grep -q '"ExitNodeID"'; then
echo "Using exit node"
else
echo "Not using exit node"
fi
echo ""
# Check MagicDNS
echo "MagicDNS:"
if tailscale status --json 2>/dev/null | grep -q '"MagicDNSSuffix"'; then
suffix=$(tailscale status --json 2>/dev/null | grep -o '"MagicDNSSuffix":"[^"]*"' | cut -d'"' -f4)
echo "✅ Enabled (suffix: $suffix)"
else
echo "❌ Disabled or not available"
fi
register: tailscale_health
changed_when: false
when: not skip_tailscale
- name: Analyze Tailscale configuration
shell: |
if ! command -v tailscale >/dev/null 2>&1; then
echo "Tailscale not installed"
exit 0
fi
echo "=== TAILSCALE CONFIGURATION ==="
# Get preferences
echo "Preferences:"
tailscale debug prefs 2>/dev/null | head -20 || echo "Preferences not accessible"
echo ""
# Check for subnet routes
echo "Subnet Routes:"
tailscale status --json 2>/dev/null | grep -o '"AdvertiseRoutes":\[[^\]]*\]' || echo "No advertised routes"
echo ""
# Check ACL status (if accessible)
echo "ACL Information:"
tailscale debug netmap 2>/dev/null | grep -i acl | head -5 || echo "ACL information not accessible"
echo ""
# Check for Tailscale SSH
echo "Tailscale SSH:"
if tailscale status --json 2>/dev/null | grep -q '"SSH"'; then
echo "SSH feature available"
else
echo "SSH feature not detected"
fi
register: tailscale_config
changed_when: false
when: not skip_tailscale
ignore_errors: yes
- name: Tailscale network diagnostics
shell: |
if ! command -v tailscale >/dev/null 2>&1; then
echo "Tailscale not installed"
exit 0
fi
echo "=== NETWORK DIAGNOSTICS ==="
# Check DERP (relay) connectivity
echo "DERP Connectivity:"
tailscale netcheck 2>/dev/null | head -10 || echo "Network check not available"
echo ""
# Check for direct connections
echo "Direct Connections:"
tailscale status --json 2>/dev/null | grep -o '"CurAddr":"[^"]*"' | head -5 || echo "Connection info not available"
echo ""
# Interface information
echo "Network Interfaces:"
ip addr show tailscale0 2>/dev/null || echo "Tailscale interface not found"
echo ""
# Routing table
echo "Tailscale Routes:"
ip route show | grep tailscale0 2>/dev/null || echo "No Tailscale routes found"
register: tailscale_diagnostics
changed_when: false
when: not skip_tailscale
ignore_errors: yes
- name: Create Tailscale report
set_fact:
tailscale_report:
timestamp: "{{ tailscale_timestamp }}"
hostname: "{{ inventory_hostname }}"
tailscale_available: "{{ not skip_tailscale }}"
status: "{{ tailscale_status.stdout if not skip_tailscale else 'Not available' }}"
network: "{{ tailscale_network.stdout if not skip_tailscale else 'Not available' }}"
health: "{{ tailscale_health.stdout if not skip_tailscale else 'Not available' }}"
configuration: "{{ tailscale_config.stdout if not skip_tailscale else 'Not available' }}"
diagnostics: "{{ tailscale_diagnostics.stdout if not skip_tailscale else 'Not available' }}"
- name: Display Tailscale report
debug:
msg: |
==========================================
🌐 TAILSCALE REPORT - {{ inventory_hostname }}
==========================================
📊 AVAILABILITY: {{ 'Available' if tailscale_report.tailscale_available else 'Not Available' }}
📡 STATUS:
{{ tailscale_report.status }}
🔗 NETWORK INFO:
{{ tailscale_report.network }}
🏥 HEALTH CHECK:
{{ tailscale_report.health }}
⚙️ CONFIGURATION:
{{ tailscale_report.configuration }}
🔍 DIAGNOSTICS:
{{ tailscale_report.diagnostics }}
==========================================
- name: Generate JSON Tailscale report
copy:
content: |
{
"timestamp": "{{ tailscale_report.timestamp }}",
"hostname": "{{ tailscale_report.hostname }}",
"tailscale_available": {{ tailscale_report.tailscale_available | lower }},
"status": {{ tailscale_report.status | to_json }},
"network": {{ tailscale_report.network | to_json }},
"health": {{ tailscale_report.health | to_json }},
"configuration": {{ tailscale_report.configuration | to_json }},
"diagnostics": {{ tailscale_report.diagnostics | to_json }},
"recommendations": [
{% if not tailscale_report.tailscale_available %}
"Install Tailscale for network connectivity",
{% endif %}
{% if 'Not logged in' in tailscale_report.health %}
"Authenticate Tailscale client",
{% endif %}
{% if 'unreachable' in tailscale_report.network %}
"Investigate network connectivity issues",
{% endif %}
"Regular Tailscale health monitoring recommended"
]
}
dest: "{{ tailscale_report_dir }}/{{ inventory_hostname }}_tailscale_{{ ansible_date_time.epoch }}.json"
delegate_to: localhost
- name: Tailscale management operations (when action is specified)
block:
- name: Validate action parameter
fail:
msg: "Invalid action. Supported actions: status, login, logout, up, down, ping"
when: tailscale_action not in ['status', 'login', 'logout', 'up', 'down', 'ping']
- name: Execute Tailscale action
shell: |
case "{{ tailscale_action }}" in
"status")
tailscale status --peers
;;
"login")
echo "Login requires interactive authentication"
tailscale login --timeout=30s
;;
"logout")
tailscale logout
;;
"up")
tailscale up {{ tailscale_args | default('') }}
;;
"down")
tailscale down
;;
"ping")
if [ -n "{{ tailscale_target | default('') }}" ]; then
tailscale ping "{{ tailscale_target }}"
else
echo "Error: tailscale_target required for ping action"
exit 1
fi
;;
esac
register: tailscale_action_result
when: not skip_tailscale
- name: Display action result
debug:
msg: |
🔧 Tailscale action '{{ tailscale_action }}' completed on {{ inventory_hostname }}
Result:
{{ tailscale_action_result.stdout }}
{% if tailscale_action_result.stderr %}
Errors:
{{ tailscale_action_result.stderr }}
{% endif %}
when: tailscale_action is defined and not skip_tailscale
- name: Generate network topology map (run once)
shell: |
cd "{{ tailscale_report_dir }}"
echo "# Tailscale Network Topology" > network_topology.md
echo "" >> network_topology.md
echo "**Generated:** {{ tailscale_timestamp }}" >> network_topology.md
echo "" >> network_topology.md
# Process all Tailscale JSON reports
for json_file in *_tailscale_*.json; do
if [ -f "$json_file" ]; then
hostname=$(basename "$json_file" | cut -d'_' -f1)
echo "## 🖥️ $hostname" >> network_topology.md
echo "" >> network_topology.md
# Extract key information
if command -v jq >/dev/null 2>&1; then
available=$(jq -r '.tailscale_available' "$json_file" 2>/dev/null || echo "unknown")
echo "- **Tailscale:** $available" >> network_topology.md
# Try to extract IP if available
if [ "$available" = "true" ]; then
echo "- **Status:** Connected" >> network_topology.md
else
echo "- **Status:** Not available" >> network_topology.md
fi
fi
echo "- **Report:** [$json_file](./$json_file)" >> network_topology.md
echo "" >> network_topology.md
fi
done
echo "---" >> network_topology.md
echo "*Auto-generated by Ansible tailscale_management.yml playbook*" >> network_topology.md
delegate_to: localhost
run_once: true
- name: Summary message
debug:
msg: |
🌐 Tailscale management complete for {{ inventory_hostname }}
📄 Report saved to: {{ tailscale_report_dir }}/{{ inventory_hostname }}_tailscale_{{ ansible_date_time.epoch }}.json
🗺️ Network topology: {{ tailscale_report_dir }}/network_topology.md
{% if tailscale_action is defined %}
🔧 Action performed: {{ tailscale_action }}
{% endif %}
💡 Use -e tailscale_action=<action> for management operations
💡 Supported actions: status, login, logout, up, down, ping
💡 Use -e tailscale_target=<ip> with ping action