feat: Auto-cleanup stale Tailscale devices before cluster boot
Adds tailscale-cleanup Ansible role that uses the Tailscale API to delete offline devices matching reserved hostnames (e.g. rancher). Runs during site.yml before Finalize to prevent hostname collisions like rancher-1 on rebuild. Requires TAILSCALE_API_KEY (API access token) passed as extra var.
This commit is contained in:
@@ -230,6 +230,7 @@ jobs:
|
|||||||
-e "tailscale_oauth_client_id=${{ secrets.TAILSCALE_OAUTH_CLIENT_ID }}" \
|
-e "tailscale_oauth_client_id=${{ secrets.TAILSCALE_OAUTH_CLIENT_ID }}" \
|
||||||
-e "tailscale_oauth_client_secret=${{ secrets.TAILSCALE_OAUTH_CLIENT_SECRET }}" \
|
-e "tailscale_oauth_client_secret=${{ secrets.TAILSCALE_OAUTH_CLIENT_SECRET }}" \
|
||||||
-e "doppler_hetznerterra_service_token=${{ secrets.DOPPLER_HETZNERTERRA_SERVICE_TOKEN }}" \
|
-e "doppler_hetznerterra_service_token=${{ secrets.DOPPLER_HETZNERTERRA_SERVICE_TOKEN }}" \
|
||||||
|
-e "tailscale_api_key=${{ secrets.TAILSCALE_API_KEY }}" \
|
||||||
-e "grafana_admin_password=${{ secrets.GRAFANA_ADMIN_PASSWORD }}" \
|
-e "grafana_admin_password=${{ secrets.GRAFANA_ADMIN_PASSWORD }}" \
|
||||||
-e "cluster_name=k8s-cluster"
|
-e "cluster_name=k8s-cluster"
|
||||||
env:
|
env:
|
||||||
|
|||||||
46
ansible/roles/tailscale-cleanup/tasks/main.yml
Normal file
46
ansible/roles/tailscale-cleanup/tasks/main.yml
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
---
|
||||||
|
- name: Delete stale Tailscale devices with reserved hostnames
|
||||||
|
block:
|
||||||
|
- name: Get Tailscale devices from API
|
||||||
|
uri:
|
||||||
|
url: "https://api.tailscale.com/api/v2/tailnet/{{ tailscale_tailnet }}/devices"
|
||||||
|
method: GET
|
||||||
|
headers:
|
||||||
|
Authorization: "Bearer {{ tailscale_api_key }}"
|
||||||
|
return_content: true
|
||||||
|
register: ts_devices
|
||||||
|
|
||||||
|
- name: Find stale devices matching reserved hostnames
|
||||||
|
set_fact:
|
||||||
|
stale_devices: >-
|
||||||
|
{{ ts_devices.json.devices | default([])
|
||||||
|
| selectattr('hostname', 'defined')
|
||||||
|
| selectattr('hostname', 'in', tailscale_reserved_hostnames)
|
||||||
|
| rejectattr('online', 'true')
|
||||||
|
| list }}
|
||||||
|
|
||||||
|
- name: Delete stale devices
|
||||||
|
uri:
|
||||||
|
url: "https://api.tailscale.com/api/v2/device/{{ item.id }}"
|
||||||
|
method: DELETE
|
||||||
|
headers:
|
||||||
|
Authorization: "Bearer {{ tailscale_api_key }}"
|
||||||
|
status_code: 200
|
||||||
|
loop: "{{ stale_devices }}"
|
||||||
|
loop_control:
|
||||||
|
label: "{{ item.name }} ({{ item.id }})"
|
||||||
|
when: stale_devices | length > 0
|
||||||
|
|
||||||
|
- name: Report cleaned devices
|
||||||
|
debug:
|
||||||
|
msg: "Deleted stale Tailscale device: {{ item.name }}"
|
||||||
|
loop: "{{ stale_devices }}"
|
||||||
|
when: stale_devices | length > 0
|
||||||
|
|
||||||
|
- name: No stale devices found
|
||||||
|
debug:
|
||||||
|
msg: "No stale Tailscale devices found."
|
||||||
|
when: stale_devices | length == 0
|
||||||
|
when:
|
||||||
|
- tailscale_api_key is defined
|
||||||
|
- tailscale_api_key | length > 0
|
||||||
@@ -128,6 +128,16 @@
|
|||||||
roles:
|
roles:
|
||||||
- doppler-bootstrap
|
- doppler-bootstrap
|
||||||
|
|
||||||
|
- name: Clean up stale Tailscale devices
|
||||||
|
hosts: localhost
|
||||||
|
connection: local
|
||||||
|
vars:
|
||||||
|
tailscale_reserved_hostnames:
|
||||||
|
- rancher
|
||||||
|
|
||||||
|
roles:
|
||||||
|
- tailscale-cleanup
|
||||||
|
|
||||||
- name: Finalize
|
- name: Finalize
|
||||||
hosts: localhost
|
hosts: localhost
|
||||||
connection: local
|
connection: local
|
||||||
|
|||||||
Reference in New Issue
Block a user