name: Integration Test Template on: workflow_call: inputs: test: required: true type: string postgres_flag: required: false type: string default: "" database_name: required: true type: string jobs: test: runs-on: ubuntu-24.04-arm env: # Github does not allow us to access secrets in pull requests, # so this env var is used to check if we have the secret or not. # If we have the secrets, meaning we are running on push in a fork, # there might be secrets available for more debugging. # If TS_OAUTH_CLIENT_ID and TS_OAUTH_SECRET is set, then the job # will join a debug tailscale network, set up SSH and a tmux session. # The SSH will be configured to use the SSH key of the Github user # that triggered the build. HAS_TAILSCALE_SECRET: ${{ secrets.TS_OAUTH_CLIENT_ID }} steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: fetch-depth: 2 - name: Tailscale if: ${{ env.HAS_TAILSCALE_SECRET }} uses: tailscale/github-action@d1b6cd204f8dceda5b3eaad7f1f767be390056cd # v4.2.0 with: oauth-client-id: ${{ secrets.TS_OAUTH_CLIENT_ID }} oauth-secret: ${{ secrets.TS_OAUTH_SECRET }} tags: tag:gh - name: Setup SSH server for Actor if: ${{ env.HAS_TAILSCALE_SECRET }} uses: alexellis/setup-sshd-actor@master - name: Download headscale image uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: name: headscale-image path: /tmp/artifacts - name: Download tailscale HEAD image uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: name: tailscale-head-image path: /tmp/artifacts - name: Download tailscale released images uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: name: tailscale-released-images path: /tmp/artifacts - name: Download hi binary uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: name: hi-binary path: /tmp/artifacts - name: Download Go cache uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: name: go-cache path: /tmp/artifacts - name: Download postgres image if: ${{ inputs.postgres_flag == '--postgres=1' }} uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: name: postgres-image path: /tmp/artifacts - name: Force overlay2 storage driver run: | sudo mkdir -p /etc/docker echo '{"storage-driver":"overlay2"}' | sudo tee /etc/docker/daemon.json sudo systemctl restart docker docker version - name: Load br_netfilter for in-cluster service routing if: inputs.test == 'TestK8sOperator' # TestK8sOperator runs k3s in a container; without br_netfilter on the # host, bridged pod-to-pod traffic skips kube-proxy's ClusterIP DNAT and # in-cluster DNS (kube-dns) is unreachable. The module cannot be loaded # from inside the unprivileged-module rancher/k3s image, so load it here. run: sudo modprobe br_netfilter - name: Login to Docker Hub env: DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_CI_USERNAME }} DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_CI_TOKEN }} if: env.DOCKERHUB_USERNAME != '' uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0 with: username: ${{ env.DOCKERHUB_USERNAME }} password: ${{ env.DOCKERHUB_TOKEN }} - name: Load Docker images, Go cache, and prepare binary run: | gunzip -c /tmp/artifacts/headscale-image.tar.gz | docker load gunzip -c /tmp/artifacts/tailscale-head-image.tar.gz | docker load gunzip -c /tmp/artifacts/tailscale-released-images.tar.gz | docker load if [ -f /tmp/artifacts/postgres-image.tar.gz ]; then gunzip -c /tmp/artifacts/postgres-image.tar.gz | docker load fi chmod +x /tmp/artifacts/hi docker images # Extract Go cache to host directories for bind mounting mkdir -p /tmp/go-cache tar -xzf /tmp/artifacts/go-cache.tar.gz -C /tmp/go-cache ls -la /tmp/go-cache/ /tmp/go-cache/.cache/ - name: Run Integration Test env: HEADSCALE_INTEGRATION_HEADSCALE_IMAGE: headscale:${{ github.sha }} HEADSCALE_INTEGRATION_TAILSCALE_IMAGE: tailscale-head:${{ github.sha }} HEADSCALE_INTEGRATION_POSTGRES_IMAGE: ${{ inputs.postgres_flag == '--postgres=1' && format('postgres:{0}', github.sha) || '' }} HEADSCALE_INTEGRATION_GO_CACHE: /tmp/go-cache/go HEADSCALE_INTEGRATION_GO_BUILD_CACHE: /tmp/go-cache/.cache/go-build # Mirror the docker/login-action secrets into env so the # dockertestutil.Credentials resolver picks them up directly # (otherwise it falls back to parsing ~/.docker/config.json, # which works but is one step further from the source). DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_CI_USERNAME }} DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_CI_TOKEN }} run: /tmp/artifacts/hi run --stats --ts-memory-limit=300 --hs-memory-limit=1500 "^${{ inputs.test }}$" \ --timeout=120m \ ${{ inputs.postgres_flag }} # Sanitize test name for artifact upload (replace invalid characters: " : < > | * ? \ / with -) - name: Sanitize test name for artifacts if: always() id: sanitize run: echo "name=${TEST_NAME//[\":<>|*?\\\/]/-}" >> $GITHUB_OUTPUT env: TEST_NAME: ${{ inputs.test }} - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 if: always() with: name: ${{ inputs.database_name }}-${{ steps.sanitize.outputs.name }}-logs path: "control_logs/*/*.log" - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 if: always() with: name: ${{ inputs.database_name }}-${{ steps.sanitize.outputs.name }}-artifacts path: control_logs/ - name: Setup a blocking tmux session if: ${{ env.HAS_TAILSCALE_SECRET }} uses: alexellis/block-with-tmux-action@master