--- - name: Determine if Tailscale operator is enabled set_fact: tailscale_operator_enabled: "{{ (tailscale_oauth_client_id | default('') | length) > 0 and (tailscale_oauth_client_secret | default('') | length) > 0 }}" changed_when: false - name: Skip Tailscale operator when OAuth credentials are missing debug: msg: "Skipping Tailscale Kubernetes Operator: set TAILSCALE_OAUTH_CLIENT_ID and TAILSCALE_OAUTH_CLIENT_SECRET to enable it." when: not tailscale_operator_enabled - name: End Tailscale operator role when disabled meta: end_host when: not tailscale_operator_enabled - name: Check if Helm is installed command: helm version --short register: helm_check changed_when: false failed_when: false - name: Install Helm shell: curl -fsSL https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash when: helm_check.rc != 0 changed_when: true - name: Create Tailscale operator namespace command: kubectl create namespace {{ tailscale_operator_namespace }} register: create_ns failed_when: create_ns.rc != 0 and "AlreadyExists" not in create_ns.stderr changed_when: create_ns.rc == 0 - name: Add Tailscale Helm repo command: helm repo add tailscale https://pkgs.tailscale.com/unstable/helmcharts register: add_repo failed_when: add_repo.rc != 0 and "already exists" not in add_repo.stderr changed_when: add_repo.rc == 0 - name: Update Helm repos command: helm repo update changed_when: false - name: Write Tailscale operator values template: src: operator-values.yaml.j2 dest: /tmp/tailscale-operator-values.yaml mode: "0644" - name: Create or update Tailscale operator OAuth secret shell: >- kubectl -n {{ tailscale_operator_namespace }} create secret generic operator-oauth --from-literal=client_id='{{ tailscale_oauth_client_id }}' --from-literal=client_secret='{{ tailscale_oauth_client_secret }}' --dry-run=client -o yaml | kubectl apply -f - register: oauth_secret_result changed_when: "'created' in oauth_secret_result.stdout or 'configured' in oauth_secret_result.stdout" - name: Install Tailscale Kubernetes Operator command: >- helm upgrade --install tailscale-operator tailscale/tailscale-operator --namespace {{ tailscale_operator_namespace }} --version {{ tailscale_operator_version }} --values /tmp/tailscale-operator-values.yaml --timeout 5m register: tailscale_install failed_when: false changed_when: true - name: Show Tailscale operator pods on install failure command: kubectl -n {{ tailscale_operator_namespace }} get pods -o wide register: tailscale_pods changed_when: false failed_when: false when: tailscale_install.rc != 0 - name: Show Tailscale operator events on install failure command: kubectl -n {{ tailscale_operator_namespace }} get events --sort-by=.lastTimestamp register: tailscale_events changed_when: false failed_when: false when: tailscale_install.rc != 0 - name: Fail with Tailscale operator diagnostics fail: msg: | Tailscale operator install failed. Helm stderr: {{ tailscale_install.stderr | default('') }} Pods: {{ tailscale_pods.stdout | default('n/a') }} Events: {{ tailscale_events.stdout | default('n/a') }} when: tailscale_install.rc != 0 - name: Wait for Tailscale operator to be ready command: kubectl -n {{ tailscale_operator_namespace }} rollout status deployment/operator --timeout=5m register: tailscale_rollout failed_when: false changed_when: false - name: Show Tailscale operator deployment status command: kubectl -n {{ tailscale_operator_namespace }} get deployment operator -o wide register: tailscale_deploy changed_when: false failed_when: false - name: Get Tailscale operator logs command: kubectl -n {{ tailscale_operator_namespace }} logs deployment/operator --tail=200 register: tailscale_operator_logs changed_when: false failed_when: false - name: Fail when Tailscale OAuth permissions are insufficient fail: msg: | Tailscale operator started but cannot create auth keys (403 permission error). Fix your Tailscale OAuth client/tag permissions. Required checks in Tailscale admin: - OAuth client has devices:core write access - OAuth client can create tagged devices for: {{ tailscale_operator_default_tags | join(', ') }} - ACL/tag ownership allows those tags for this OAuth client Operator log excerpt: {{ tailscale_operator_logs.stdout | default('n/a') }} when: "tailscale_operator_logs.stdout is defined and ('does not have enough permissions' in tailscale_operator_logs.stdout or 'Status: 403' in tailscale_operator_logs.stdout)" - name: Warn if Tailscale operator is not ready yet debug: msg: | Tailscale operator deployment is still converging. This is non-blocking for CI; service endpoints may appear shortly. Rollout output: {{ tailscale_rollout.stdout | default('') }} {{ tailscale_deploy.stdout | default('') }} when: tailscale_rollout.rc != 0