From 4ae38d698cf9e9bf3583be4315f0b94a2d78a49d Mon Sep 17 00:00:00 2001 From: Paolo Salvatori Date: Fri, 23 Oct 2026 16:03:19 +0200 Subject: [PATCH 1/8] Run two samples on a Windows runner from Git Bash A manual run with the new windows input, instead of the Linux matrix, creates the AKS cluster, then deploys and tests the Cosmos DB and Blob Storage samples on windows-latest from Git Bash, with MSYS_NO_PATHCONV=1 set as the README asks Windows users to do. The emulator is a Linux image and Docker on the Windows runner runs Windows containers, so the job runs it in Docker Engine inside an Ubuntu WSL 2 distribution, which the Windows docker CLI, lstk and kubectl reach over ports WSL forwards to localhost. yq, which the runner image lacks, comes from a pinned release checked against its SHA-256. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01DhZ2ojsEXd2SGMo7s9uiZh --- .github/workflows/samples.yml | 172 +++++++++++++++++++++++++++++++++- 1 file changed, 170 insertions(+), 2 deletions(-) diff --git a/.github/workflows/samples.yml b/.github/workflows/samples.yml index 99996f0..8ef7fb4 100644 --- a/.github/workflows/samples.yml +++ b/.github/workflows/samples.yml @@ -25,6 +25,11 @@ on: - all - changed default: changed + windows: + description: "Run only the Windows job, two samples from Git Bash with MSYS_NO_PATHCONV=1, instead of the Linux matrix" + required: false + type: boolean + default: false permissions: {} @@ -37,8 +42,11 @@ concurrency: jobs: setup: name: Select samples - # Pull requests from forks get no secrets, so lstk could not start the emulator there - if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository + # Pull requests from forks get no secrets, so lstk could not start the emulator there. A manual run with + # the windows input runs the Windows job alone; skipping this job skips the matrix + if: >- + (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository) + && (github.event_name != 'workflow_dispatch' || !inputs.windows) runs-on: ubuntu-latest permissions: contents: read @@ -187,3 +195,163 @@ jobs: kubectl logs --namespace "$ns" --all-containers --tail=100 -l "app=$ns" || true done lstk logs | tail -300 || true + + # Runs two samples on Windows, from Git Bash with MSYS_NO_PATHCONV=1 set as the README asks Windows + # users to do, on manual runs with the windows input only. The emulator is a Linux image and Docker on + # the Windows runner runs Windows containers, so the emulator runs in Docker Engine inside a WSL 2 + # distribution on the same runner; the Windows docker CLI, lstk and kubectl reach it through ports WSL + # forwards to the runner's localhost. + windows: + name: Windows (Git Bash) ${{ matrix.sample }} (${{ matrix.language }}) + if: github.event_name == 'workflow_dispatch' && inputs.windows + runs-on: windows-latest + timeout-minutes: 90 + permissions: + contents: read + strategy: + fail-fast: false + matrix: + include: + # The Cosmos DB partition key, besides the resource IDs and the SSH key every sample needs + - sample: web-app-cosmosdb-nosql-api + language: python + # The sample activities, uploaded from a mktemp directory + - sample: web-app-blob-storage + language: python + defaults: + run: + shell: bash + env: + SAMPLE: ${{ matrix.sample }} + LANGUAGE: ${{ matrix.language }} + IMAGE: localstack/localstack-azure:latest + # The Docker Engine in WSL 2, for the Windows docker CLI and lstk + DOCKER_HOST: tcp://127.0.0.1:2375 + # What the README asks Windows users of Git Bash and MSYS2 to export + MSYS_NO_PATHCONV: "1" + + steps: + - name: Check out repo + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + persist-credentials: false + + - name: Configure WSL + # Once a step's wsl.exe session ends, WSL stops the idle distribution after 15 seconds, and + # dockerd with it; -1 keeps it running for the whole job. The memory leaves room for the AKS + # cluster and the sample's workloads. + shell: pwsh + run: | + Set-Content -Path "$env:USERPROFILE\.wslconfig" -Value "[wsl2]`nmemory=12GB`n`n[general]`ninstanceIdleTimeout=-1" + wsl --shutdown + + - name: Set up Ubuntu in WSL 2 + uses: Vampire/setup-wsl@d1da7f2c0322a5ee4f24975344f67fc0f5baf364 # v7.0.0 + with: + distribution: Ubuntu-24.04 + wsl-version: 2 + wsl-shell-user: root + additional-packages: docker.io + + - name: Start Docker Engine in WSL 2 + # The Unix socket is what the emulator container mounts to start the cluster and its backing + # containers; the TCP endpoint, bound to localhost, is what WSL forwards to Windows. + shell: wsl-bash {0} + run: | + setsid nohup dockerd --host unix:///var/run/docker.sock --host tcp://127.0.0.1:2375 --tls=false \ + > /var/log/dockerd.log 2>&1 < /dev/null & + for _ in $(seq 1 60); do + docker info > /dev/null 2>&1 && break + sleep 2 + done + docker info --format 'Docker {{.ServerVersion}} on {{.OperatingSystem}}, kernel {{.KernelVersion}}' + + - name: Check that the Windows docker CLI reaches it + run: docker version + + - name: Install lstk + # The release the Linux job pins + run: npm install -g @localstack/lstk@1.4.0 + + - name: Install yq + # The deployment scripts render the Kubernetes manifests with yq, which the Windows runner image + # does not ship. The release and its SHA-256 are pinned. + env: + YQ_VERSION: v4.54.1 + YQ_SHA256: b645f47ebb3a0d2fbab52998550bbd0a1706f23b5ca5f5b48e638c580bb70928 + run: | + mkdir -p "$RUNNER_TEMP/bin" + cd "$RUNNER_TEMP/bin" + curl --silent --show-error --fail --location --retry 3 --output yq.exe \ + "https://github.com/mikefarah/yq/releases/download/${YQ_VERSION}/yq_windows_amd64.exe" + echo "${YQ_SHA256} yq.exe" | sha256sum --check + echo "$RUNNER_TEMP/bin" >> "$GITHUB_PATH" + + - name: Create the SSH key the cluster script provisions the node pools with + run: ssh-keygen -t rsa -b 4096 -N '' -f ~/.ssh/id_rsa -q + + - name: Start the LocalStack for Azure emulator in WSL 2 + # Started with the docker CLI rather than lstk: lstk on Windows would mount a Windows volume path, + # and no Docker socket, into the Linux engine. The two mounts are paths inside WSL, which + # MSYS_NO_PATHCONV keeps Git Bash from rewriting. lstk then finds the container by its name to + # route the Azure CLI to it. + env: + LOCALSTACK_AUTH_TOKEN: ${{ secrets.LOCALSTACK_AUTH_TOKEN }} + # The emulator looks up the k3d release behind each AKS cluster on api.github.com, as on Linux + GITHUB_API_TOKEN: ${{ github.token }} + run: | + docker pull "$IMAGE" + docker run --detach --name localstack-azure \ + --publish 127.0.0.1:4566:4566 --publish 127.0.0.1:443:443 \ + --publish 127.0.0.1:4510-4559:4510-4559 \ + --volume /var/run/docker.sock:/var/run/docker.sock \ + --volume /var/lib/localstack-azure:/var/lib/localstack \ + --env LOCALSTACK_AUTH_TOKEN --env GITHUB_API_TOKEN --env MSSQL_ACCEPT_EULA=Y \ + "$IMAGE" + ready=0 + for _ in $(seq 1 200); do + if curl --silent --fail --max-time 5 http://127.0.0.1:4566/_localstack/health > /dev/null; then + ready=1 + break + fi + sleep 2 + done + if [[ $ready != 1 ]]; then + echo "::error::The emulator did not answer on 127.0.0.1:4566 within 400s" + docker logs --tail 100 localstack-azure + exit 1 + fi + lstk az start-interception + + # The script prompts for the network configuration and both node pool sizes: + # pick option 1 (Azure network plugin and policy) and keep the default sizes + - name: Create the AKS cluster + working-directory: scripts + run: printf '1\n\n\n' | ./01-system-assigned-managed-identity.sh + + - name: Deploy the sample + working-directory: samples/${{ matrix.sample }}/${{ matrix.language }}/scripts + run: | + ./01-deploy-resources.sh + ./02-build-docker-image.sh + ./04-push-docker-image.sh + ./05-deploy-app.sh + + - name: Test the web app + run: | + variables="samples/$SAMPLE/$LANGUAGE/scripts/00-variables.sh" + namespace=$(sed -n "s/^NAMESPACE=\"\(.*\)\"/\1/p" "$variables") + service=$(sed -n "s/^SERVICE_NAME=\"\(.*\)\"/\1/p" "$variables") + ./tests/test-vacation-planner.sh "$namespace" "$service" + + - name: Show cluster state and emulator logs + if: failure() + run: | + kubectl get pods --all-namespaces -o wide || true + kubectl get events --all-namespaces --sort-by=.lastTimestamp | tail -50 || true + docker logs localstack-azure 2>&1 | tail -n 300 || true + + - name: Get the Docker Engine log + if: failure() + shell: wsl-bash {0} + run: tail -n 100 /var/log/dockerd.log || true From 679c084765918b6d9c034e5417e6c9cbc1e38be9 Mon Sep 17 00:00:00 2001 From: Paolo Salvatori Date: Fri, 23 Oct 2026 16:32:28 +0200 Subject: [PATCH 2/8] Start the Windows job's Docker Engine on TCP after stopping the packaged one Installing docker.io in the WSL distribution already starts a Docker daemon on the Unix socket alone, so the daemon the job started with TCP port 2375 exited at once ("process with PID 1063 is still running"), the readiness check passed against the packaged daemon, and the Windows docker CLI found nothing on the port. The step now stops the packaged daemon (its systemd units, or its PID file without systemd), starts its own, and waits on the TCP endpoint. The Docker Engine log step runs only once WSL is set up, since its wsl-bash shell does not exist before that. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01DhZ2ojsEXd2SGMo7s9uiZh --- .github/workflows/samples.yml | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/.github/workflows/samples.yml b/.github/workflows/samples.yml index 8ef7fb4..fd8762d 100644 --- a/.github/workflows/samples.yml +++ b/.github/workflows/samples.yml @@ -246,6 +246,7 @@ jobs: wsl --shutdown - name: Set up Ubuntu in WSL 2 + id: wsl uses: Vampire/setup-wsl@d1da7f2c0322a5ee4f24975344f67fc0f5baf364 # v7.0.0 with: distribution: Ubuntu-24.04 @@ -254,17 +255,34 @@ jobs: additional-packages: docker.io - name: Start Docker Engine in WSL 2 - # The Unix socket is what the emulator container mounts to start the cluster and its backing - # containers; the TCP endpoint, bound to localhost, is what WSL forwards to Windows. + # Installing docker.io already started a daemon on the Unix socket alone, and a second one cannot + # start beside it, so it is stopped and replaced by one that also listens on TCP. The Unix socket + # is what the emulator container mounts to start the cluster and its backing containers; the TCP + # endpoint, bound to localhost, is what WSL forwards to Windows. The wait asks the TCP endpoint, + # so the step fails when that daemon did not start. shell: wsl-bash {0} run: | + if [ -d /run/systemd/system ]; then + systemctl disable --now docker.socket docker.service + elif [ -e /var/run/docker.pid ]; then + kill "$(cat /var/run/docker.pid)" + fi + for _ in $(seq 1 30); do + [ -e /var/run/docker.pid ] || break + sleep 1 + done + if [ -e /var/run/docker.pid ]; then + echo "::error::The Docker daemon that installing docker.io started is still running" + exit 1 + fi setsid nohup dockerd --host unix:///var/run/docker.sock --host tcp://127.0.0.1:2375 --tls=false \ > /var/log/dockerd.log 2>&1 < /dev/null & for _ in $(seq 1 60); do - docker info > /dev/null 2>&1 && break + docker --host tcp://127.0.0.1:2375 info > /dev/null 2>&1 && break sleep 2 done - docker info --format 'Docker {{.ServerVersion}} on {{.OperatingSystem}}, kernel {{.KernelVersion}}' + docker --host tcp://127.0.0.1:2375 info \ + --format 'Docker {{.ServerVersion}} on {{.OperatingSystem}}, kernel {{.KernelVersion}}' - name: Check that the Windows docker CLI reaches it run: docker version @@ -352,6 +370,7 @@ jobs: docker logs localstack-azure 2>&1 | tail -n 300 || true - name: Get the Docker Engine log - if: failure() + # The wsl-bash shell exists only once WSL is set up + if: failure() && steps.wsl.outcome == 'success' shell: wsl-bash {0} run: tail -n 100 /var/log/dockerd.log || true From 84918ebe34a7d72bfa6e73189a310f2c1b79107c Mon Sep 17 00:00:00 2001 From: Paolo Salvatori Date: Fri, 23 Oct 2026 17:00:22 +0200 Subject: [PATCH 3/8] Run every sample in the Windows job The Windows job takes its matrix from the setup job, which on a manual run with the windows input selects every app, and the Linux matrix stays out of that run. It now provides what the remaining apps need, as the Linux job does: sqlcmd for the Azure SQL Database sample (the Go sqlcmd release, pinned with its SHA-256) and the answers to the Azure Files sample's provisioning menus; on failure it prints the same cluster state. lstk 1.4.0 cannot register its Azure CLI cloud on Windows when the CLI sits under C:\Program Files: cmd.exe cuts the command line that carries the cloud configuration's JSON at that space. A junction without spaces, first on the PATH, works around it. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01DhZ2ojsEXd2SGMo7s9uiZh --- .github/workflows/samples.yml | 68 ++++++++++++++++++++++++----------- 1 file changed, 48 insertions(+), 20 deletions(-) diff --git a/.github/workflows/samples.yml b/.github/workflows/samples.yml index fd8762d..a79b7b3 100644 --- a/.github/workflows/samples.yml +++ b/.github/workflows/samples.yml @@ -26,7 +26,7 @@ on: - changed default: changed windows: - description: "Run only the Windows job, two samples from Git Bash with MSYS_NO_PATHCONV=1, instead of the Linux matrix" + description: "Run only the Windows job, every sample from Git Bash with MSYS_NO_PATHCONV=1, instead of the Linux matrix (run_mode does not apply)" required: false type: boolean default: false @@ -42,11 +42,8 @@ concurrency: jobs: setup: name: Select samples - # Pull requests from forks get no secrets, so lstk could not start the emulator there. A manual run with - # the windows input runs the Windows job alone; skipping this job skips the matrix - if: >- - (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository) - && (github.event_name != 'workflow_dispatch' || !inputs.windows) + # Pull requests from forks get no secrets, so lstk could not start the emulator there + if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository runs-on: ubuntu-latest permissions: contents: read @@ -65,8 +62,9 @@ jobs: - name: Select the samples to run id: select env: - # Pull requests and pushes have no inputs: they run the samples they change - RUN_MODE: ${{ inputs.run_mode || 'changed' }} + # Pull requests and pushes have no inputs: they run the samples they change. A manual run with the + # windows input runs every sample, on Windows + RUN_MODE: ${{ inputs.windows && 'all' || inputs.run_mode || 'changed' }} EVENT_NAME: ${{ github.event_name }} PR_BASE_SHA: ${{ github.event.pull_request.base.sha }} PUSH_BEFORE_SHA: ${{ github.event.before }} @@ -109,8 +107,9 @@ jobs: sample: name: ${{ matrix.sample }} (${{ matrix.language }}) needs: setup - # Skip the job when the run changes no sample - if: needs.setup.outputs.has_samples == 'true' + # Skip the job when the run changes no sample, and on a manual run with the windows input, which runs the + # Windows job instead + if: needs.setup.outputs.has_samples == 'true' && !(github.event_name == 'workflow_dispatch' && inputs.windows) runs-on: ubuntu-latest timeout-minutes: 60 permissions: @@ -196,28 +195,23 @@ jobs: done lstk logs | tail -300 || true - # Runs two samples on Windows, from Git Bash with MSYS_NO_PATHCONV=1 set as the README asks Windows + # Runs every sample on Windows, from Git Bash with MSYS_NO_PATHCONV=1 set as the README asks Windows # users to do, on manual runs with the windows input only. The emulator is a Linux image and Docker on # the Windows runner runs Windows containers, so the emulator runs in Docker Engine inside a WSL 2 # distribution on the same runner; the Windows docker CLI, lstk and kubectl reach it through ports WSL # forwards to the runner's localhost. windows: name: Windows (Git Bash) ${{ matrix.sample }} (${{ matrix.language }}) - if: github.event_name == 'workflow_dispatch' && inputs.windows + needs: setup + if: github.event_name == 'workflow_dispatch' && inputs.windows && needs.setup.outputs.has_samples == 'true' runs-on: windows-latest timeout-minutes: 90 permissions: contents: read strategy: fail-fast: false - matrix: - include: - # The Cosmos DB partition key, besides the resource IDs and the SSH key every sample needs - - sample: web-app-cosmosdb-nosql-api - language: python - # The sample activities, uploaded from a mktemp directory - - sample: web-app-blob-storage - language: python + # Every app: on a manual run with the windows input, the setup job selects all of them + matrix: ${{ fromJSON(needs.setup.outputs.matrix) }} defaults: run: shell: bash @@ -291,6 +285,18 @@ jobs: # The release the Linux job pins run: npm install -g @localstack/lstk@1.4.0 + - name: Give lstk an Azure CLI path without spaces + # lstk sets up the Azure CLI with `az cloud register --cloud-config `, run through az.cmd, and + # cmd.exe cuts that command line at the space of "C:\Program Files" once the JSON's quotes are in it + # ("'C:\Program' is not recognized"), so `lstk az start-interception` (lstk 1.4.0) fails wherever the + # Azure CLI sits in its default folder. A junction without spaces, first on the PATH, works around it + # until lstk passes the JSON another way; Git Bash runs the same Azure CLI through it. + shell: pwsh + run: | + $cliDir = Split-Path -Parent (Split-Path -Parent (Get-Command az.cmd).Source) + New-Item -ItemType Junction -Path C:\azure-cli -Target $cliDir | Out-Null + Add-Content -Path $env:GITHUB_PATH -Value 'C:\azure-cli\wbin' + - name: Install yq # The deployment scripts render the Kubernetes manifests with yq, which the Windows runner image # does not ship. The release and its SHA-256 are pinned. @@ -305,6 +311,20 @@ jobs: echo "${YQ_SHA256} yq.exe" | sha256sum --check echo "$RUNNER_TEMP/bin" >> "$GITHUB_PATH" + - name: Install sqlcmd + # The Azure SQL Database sample seeds its database with sqlcmd, which the runner image does not ship: + # the Go sqlcmd release, pinned with its SHA-256 + if: matrix.sample == 'web-app-sql-database' + env: + SQLCMD_VERSION: v1.10.0 + SQLCMD_SHA256: a4c28332fcc6e497d655e53ac8f4939f4ab170f9cfd32d0fa5081b60f4d9d691 + run: | + curl --silent --show-error --fail --location --retry 3 --output "$RUNNER_TEMP/sqlcmd.zip" \ + "https://github.com/microsoft/go-sqlcmd/releases/download/${SQLCMD_VERSION}/sqlcmd-windows-amd64.zip" + echo "${SQLCMD_SHA256} $RUNNER_TEMP/sqlcmd.zip" | sha256sum --check + unzip -o -q -j "$RUNNER_TEMP/sqlcmd.zip" sqlcmd.exe -d "$RUNNER_TEMP/bin" + sqlcmd --version + - name: Create the SSH key the cluster script provisions the node pools with run: ssh-keygen -t rsa -b 4096 -N '' -f ~/.ssh/id_rsa -q @@ -349,6 +369,10 @@ jobs: - name: Deploy the sample working-directory: samples/${{ matrix.sample }}/${{ matrix.language }}/scripts + env: + # Answer the Azure Files sample's two provisioning menus, as the Linux job does + PROVISIONING_MODE: static + FILE_SHARE_PROTOCOL: smb run: | ./01-deploy-resources.sh ./02-build-docker-image.sh @@ -367,6 +391,10 @@ jobs: run: | kubectl get pods --all-namespaces -o wide || true kubectl get events --all-namespaces --sort-by=.lastTimestamp | tail -50 || true + for ns in $(kubectl get namespaces -o name | sed 's|namespace/||' | grep vacation-planner); do + kubectl describe pods --namespace "$ns" | tail -80 || true + kubectl logs --namespace "$ns" --all-containers --tail=100 -l "app=$ns" || true + done docker logs localstack-azure 2>&1 | tail -n 300 || true - name: Get the Docker Engine log From 087a4e3172058d1526ac388d05523e025069a7cd Mon Sep 17 00:00:00 2001 From: Paolo Salvatori Date: Fri, 23 Oct 2026 17:20:58 +0200 Subject: [PATCH 4/8] Put psql on the PATH in the Windows job The PostgreSQL and App Configuration samples seed their databases with psql; the Windows runner image installs PostgreSQL with psql off the PATH, where the Linux runner image has the client on it, so five apps stopped with "psql is not installed on the host". Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01DhZ2ojsEXd2SGMo7s9uiZh --- .github/workflows/samples.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/workflows/samples.yml b/.github/workflows/samples.yml index a79b7b3..d2acb1e 100644 --- a/.github/workflows/samples.yml +++ b/.github/workflows/samples.yml @@ -311,6 +311,13 @@ jobs: echo "${YQ_SHA256} yq.exe" | sha256sum --check echo "$RUNNER_TEMP/bin" >> "$GITHUB_PATH" + - name: Put psql on the PATH + # The PostgreSQL and App Configuration samples seed their databases with psql, which comes with the + # PostgreSQL the Windows runner image installs off the PATH; the Linux runner image has it on the PATH + run: | + echo "$PGBIN" >> "$GITHUB_PATH" + "$PGBIN/psql" --version + - name: Install sqlcmd # The Azure SQL Database sample seeds its database with sqlcmd, which the runner image does not ship: # the Go sqlcmd release, pinned with its SHA-256 From 3294d09db3c0482ba2dff37ff2eae3e622a3acb3 Mon Sep 17 00:00:00 2001 From: Paolo Salvatori Date: Fri, 23 Oct 2026 17:28:25 +0200 Subject: [PATCH 5/8] Drop the carriage returns of Windows programs in the Windows job, as the README asks The README asks Windows users for set -o igncr and export SHELLOPTS. Exporting SHELLOPTS in a step would also hand the step's own -e and pipefail to the sample scripts, so the job turns the option on for every bash through BASH_ENV instead. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01DhZ2ojsEXd2SGMo7s9uiZh --- .github/workflows/samples.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.github/workflows/samples.yml b/.github/workflows/samples.yml index d2acb1e..1199d11 100644 --- a/.github/workflows/samples.yml +++ b/.github/workflows/samples.yml @@ -230,6 +230,15 @@ jobs: with: persist-credentials: false + - name: Drop the carriage returns of Windows programs + # The README asks Windows users for `set -o igncr` and `export SHELLOPTS`, so that the bash of Git Bash + # and MSYS2 drops the carriage returns the Azure CLI and jq print from $(...) and read. Exporting + # SHELLOPTS here would also hand each step's own -e and pipefail to the sample scripts, so every bash + # turns the option on through BASH_ENV instead; a bash without the option skips the line. + run: | + printf '(set -o igncr) 2>/dev/null && set -o igncr\n' > "$RUNNER_TEMP/igncr.sh" + echo "BASH_ENV=$(cygpath -m "$RUNNER_TEMP/igncr.sh")" >> "$GITHUB_ENV" + - name: Configure WSL # Once a step's wsl.exe session ends, WSL stops the idle distribution after 15 seconds, and # dockerd with it; -1 keeps it running for the whole job. The memory leaves room for the AKS From fc86bb6e2b17dc54096d9a7787a15e7e6e1fc841 Mon Sep 17 00:00:00 2001 From: Paolo Salvatori Date: Fri, 23 Oct 2026 18:45:23 +0200 Subject: [PATCH 6/8] Turn off WSL's DNS tunneling in the Windows job With DNS tunneling, on by default, the containers of the Docker Engine in WSL could not reach the 10.255.255.254 resolver WSL configures, so their lookups timed out: the Docker Engine log held dozens of "failed to query external DNS server" errors, and the Container Apps runtime could not pull the sample's image (ImagePullBackOff). Without tunneling, WSL hands out the NAT device on the host as the DNS server, which containers reach too (https://learn.microsoft.com/windows/wsl/troubleshooting#common-issues). Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01DhZ2ojsEXd2SGMo7s9uiZh --- .github/workflows/samples.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/samples.yml b/.github/workflows/samples.yml index 1199d11..1696e18 100644 --- a/.github/workflows/samples.yml +++ b/.github/workflows/samples.yml @@ -243,9 +243,12 @@ jobs: # Once a step's wsl.exe session ends, WSL stops the idle distribution after 15 seconds, and # dockerd with it; -1 keeps it running for the whole job. The memory leaves room for the AKS # cluster and the sample's workloads. + # DNS tunneling, on by default, answers DNS for WSL itself, but the containers of the Docker Engine + # in WSL cannot reach its 10.255.255.254 resolver, so their lookups time out; without it, WSL + # hands out the NAT device on the host, which containers reach too. shell: pwsh run: | - Set-Content -Path "$env:USERPROFILE\.wslconfig" -Value "[wsl2]`nmemory=12GB`n`n[general]`ninstanceIdleTimeout=-1" + Set-Content -Path "$env:USERPROFILE\.wslconfig" -Value "[wsl2]`nmemory=12GB`ndnsTunneling=false`n`n[general]`ninstanceIdleTimeout=-1" wsl --shutdown - name: Set up Ubuntu in WSL 2 From 2cea6ef53238671547deca04130d5de4915d8b58 Mon Sep 17 00:00:00 2001 From: Paolo Salvatori Date: Mon, 26 Oct 2026 14:17:59 +0100 Subject: [PATCH 7/8] Choose Linux, Windows or both with a platform dropdown instead of the windows checkbox A manual run now picks where the selected apps run with the platform input: Linux (the default), Windows, or all, which runs the Linux and Windows jobs side by side in the same run. run_mode selects the apps on both platforms, so a Windows run follows it too instead of always running every app. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01DhZ2ojsEXd2SGMo7s9uiZh --- .github/workflows/samples.yml | 32 +++++++++++++++++--------------- README.md | 1 + 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/.github/workflows/samples.yml b/.github/workflows/samples.yml index 1696e18..f6b14ac 100644 --- a/.github/workflows/samples.yml +++ b/.github/workflows/samples.yml @@ -4,7 +4,7 @@ name: Test samples on LocalStack for Azure # app with its numbered scripts, one job per app, and checks the app end to end with # tests/test-vacation-planner.sh. As in the Samples CI of localstack-azure-samples, a pull request or a # push runs the apps it changes (every app when a file all of them use changes), and a manual run can -# choose to run every app. +# choose to run every app, on Linux, on Windows or on both. on: push: @@ -25,11 +25,15 @@ on: - all - changed default: changed - windows: - description: "Run only the Windows job, every sample from Git Bash with MSYS_NO_PATHCONV=1, instead of the Linux matrix (run_mode does not apply)" + platform: + description: "Where the selected samples run: Linux, Windows (from Git Bash with MSYS_NO_PATHCONV=1), or all (both, in parallel jobs of the same run)" required: false - type: boolean - default: false + type: choice + options: + - Windows + - Linux + - all + default: Linux permissions: {} @@ -62,9 +66,8 @@ jobs: - name: Select the samples to run id: select env: - # Pull requests and pushes have no inputs: they run the samples they change. A manual run with the - # windows input runs every sample, on Windows - RUN_MODE: ${{ inputs.windows && 'all' || inputs.run_mode || 'changed' }} + # Pull requests and pushes have no inputs: they run the samples they change + RUN_MODE: ${{ inputs.run_mode || 'changed' }} EVENT_NAME: ${{ github.event_name }} PR_BASE_SHA: ${{ github.event.pull_request.base.sha }} PUSH_BEFORE_SHA: ${{ github.event.before }} @@ -107,9 +110,8 @@ jobs: sample: name: ${{ matrix.sample }} (${{ matrix.language }}) needs: setup - # Skip the job when the run changes no sample, and on a manual run with the windows input, which runs the - # Windows job instead - if: needs.setup.outputs.has_samples == 'true' && !(github.event_name == 'workflow_dispatch' && inputs.windows) + # Skip the job when the run changes no sample, and on a manual run that asks for Windows only + if: needs.setup.outputs.has_samples == 'true' && !(github.event_name == 'workflow_dispatch' && inputs.platform == 'Windows') runs-on: ubuntu-latest timeout-minutes: 60 permissions: @@ -195,22 +197,22 @@ jobs: done lstk logs | tail -300 || true - # Runs every sample on Windows, from Git Bash with MSYS_NO_PATHCONV=1 set as the README asks Windows - # users to do, on manual runs with the windows input only. The emulator is a Linux image and Docker on + # Runs the selected samples on Windows, from Git Bash with MSYS_NO_PATHCONV=1 set as the README asks Windows + # users to do, on manual runs whose platform is Windows or all. The emulator is a Linux image and Docker on # the Windows runner runs Windows containers, so the emulator runs in Docker Engine inside a WSL 2 # distribution on the same runner; the Windows docker CLI, lstk and kubectl reach it through ports WSL # forwards to the runner's localhost. windows: name: Windows (Git Bash) ${{ matrix.sample }} (${{ matrix.language }}) needs: setup - if: github.event_name == 'workflow_dispatch' && inputs.windows && needs.setup.outputs.has_samples == 'true' + if: github.event_name == 'workflow_dispatch' && (inputs.platform == 'Windows' || inputs.platform == 'all') && needs.setup.outputs.has_samples == 'true' runs-on: windows-latest timeout-minutes: 90 permissions: contents: read strategy: fail-fast: false - # Every app: on a manual run with the windows input, the setup job selects all of them + # The same apps as the Linux job: those the setup job selected matrix: ${{ fromJSON(needs.setup.outputs.matrix) }} defaults: run: diff --git a/README.md b/README.md index 5559b9d..7f344e0 100644 --- a/README.md +++ b/README.md @@ -238,6 +238,7 @@ Alternatively, you can use a terminal UI such as [k9s](https://k9scli.io/) to se ``` The [Test samples on LocalStack for Azure](.github/workflows/samples.yml) workflow runs this against the emulator, one job per sample app, in Python and .NET. Each job creates the cluster with `scripts/01-system-assigned-managed-identity.sh`, deploys the app with its numbered scripts, and runs the test. A pull request or a push to `main` runs the apps whose folders it changes, and all 20 when it changes the cluster script, the test or the workflow. A manual run tests the changed apps by default, or all 20 with `run_mode: all`. +It also picks where they run with `platform`: `Linux` (the default), `Windows`, from Git Bash, or `all`, which runs both at once, in parallel jobs of the same run. ## Tutorials From e28d0d42a93ba4794b42d0b2615cd9b9c50ffaf2 Mon Sep 17 00:00:00 2001 From: Paolo Salvatori Date: Mon, 26 Oct 2026 14:41:47 +0100 Subject: [PATCH 8/8] Run the Windows jobs as entries of the same matrix as the Linux ones GitHub lists a matrix job it skips under its unexpanded name, so a pull request run showed "Windows (Git Bash) ${{ matrix.sample }} (${{ matrix.language }})" and a Windows run the Linux equivalent. The setup job now puts one entry per app and platform in a single matrix, each naming its runner and its job, and one job runs them all, its Windows-only and Linux-only steps gated on the entry's platform. A run lists only the jobs it runs, and the Linux jobs keep their names. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01DhZ2ojsEXd2SGMo7s9uiZh --- .github/workflows/samples.yml | 202 +++++++++++++++------------------- 1 file changed, 86 insertions(+), 116 deletions(-) diff --git a/.github/workflows/samples.yml b/.github/workflows/samples.yml index f6b14ac..2d353f6 100644 --- a/.github/workflows/samples.yml +++ b/.github/workflows/samples.yml @@ -1,7 +1,7 @@ name: Test samples on LocalStack for Azure # Creates the AKS cluster on the LocalStack for Azure emulator, deploys a sample's Python or .NET web -# app with its numbered scripts, one job per app, and checks the app end to end with +# app with its numbered scripts, one job per app and platform, and checks the app end to end with # tests/test-vacation-planner.sh. As in the Samples CI of localstack-azure-samples, a pull request or a # push runs the apps it changes (every app when a file all of them use changes), and a manual run can # choose to run every app, on Linux, on Windows or on both. @@ -66,8 +66,9 @@ jobs: - name: Select the samples to run id: select env: - # Pull requests and pushes have no inputs: they run the samples they change + # Pull requests and pushes have no inputs: they run the samples they change, on Linux RUN_MODE: ${{ inputs.run_mode || 'changed' }} + PLATFORM: ${{ inputs.platform || 'Linux' }} EVENT_NAME: ${{ github.event_name }} PR_BASE_SHA: ${{ github.event.pull_request.base.sha }} PUSH_BEFORE_SHA: ${{ github.event.before }} @@ -100,131 +101,52 @@ jobs: fi fi - matrix=$(jq -n -R -c '[inputs | select(length > 0) | split("/") | {sample: .[1], language: .[2]}] | {include: .}' <<< "$selected") - echo "Samples to run: $(jq -r '[.include[] | "\(.sample) (\(.language))"] | if length > 0 then join(", ") else "none" end' <<< "$matrix")" + case $PLATFORM in + Linux | Windows | all) ;; + *) echo "::error::Unknown platform '$PLATFORM' (expected Linux, Windows or all)"; exit 1 ;; + esac + + # One job per app and platform: the entry names the runner and the job, so a run lists only the jobs + # it runs, under their own names + matrix=$(jq -n -R -c --arg platform "$PLATFORM" ' + [inputs | select(length > 0) | split("/") | {sample: .[1], language: .[2]}] as $apps + | {include: ( + (if $platform == "Windows" then [] else + [$apps[] | . + {os: "linux", runner: "ubuntu-latest", name: "\(.sample) (\(.language))"}] end) + + (if $platform == "Linux" then [] else + [$apps[] | . + {os: "windows", runner: "windows-latest", name: "Windows (Git Bash) \(.sample) (\(.language))"}] end) + )}' <<< "$selected") + echo "Jobs to run: $(jq -r '[.include[].name] | if length > 0 then join(", ") else "none" end' <<< "$matrix")" { echo "matrix=$matrix" echo "has_samples=$(jq '.include | length > 0' <<< "$matrix")" } >> "$GITHUB_OUTPUT" + # One job per app and platform, as the setup job's matrix lists them. On Linux, lstk starts the emulator on the + # runner. On Windows, the job runs the samples from Git Bash with MSYS_NO_PATHCONV=1 set as the README asks + # Windows users to do. The emulator is a Linux image and Docker on the Windows runner runs Windows containers, so + # there the emulator runs in Docker Engine inside a WSL 2 distribution on the same runner; the Windows docker + # CLI, lstk and kubectl reach it through ports WSL forwards to the runner's localhost. sample: - name: ${{ matrix.sample }} (${{ matrix.language }}) + name: ${{ matrix.name }} needs: setup - # Skip the job when the run changes no sample, and on a manual run that asks for Windows only - if: needs.setup.outputs.has_samples == 'true' && !(github.event_name == 'workflow_dispatch' && inputs.platform == 'Windows') - runs-on: ubuntu-latest - timeout-minutes: 60 - permissions: - contents: read - strategy: - fail-fast: false - matrix: ${{ fromJSON(needs.setup.outputs.matrix) }} - env: - SAMPLE: ${{ matrix.sample }} - LANGUAGE: ${{ matrix.language }} - - steps: - - name: Check out repo - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - with: - persist-credentials: false - - - name: Install lstk - # Pinned like actions/checkout, so an lstk release cannot change every run at once: bump it deliberately - run: npm install -g @localstack/lstk@1.4.0 - - - name: Install sqlcmd - # The Azure SQL Database sample seeds its database with sqlcmd, which the runner image does not ship - if: matrix.sample == 'web-app-sql-database' - run: | - sudo rm -f /etc/apt/sources.list.d/microsoft-prod.list - curl -fsSL https://packages.microsoft.com/keys/microsoft.asc | sudo tee /etc/apt/trusted.gpg.d/microsoft.asc > /dev/null - curl -fsSL "https://packages.microsoft.com/config/ubuntu/$(lsb_release -rs)/prod.list" | sudo tee /etc/apt/sources.list.d/mssql-release.list > /dev/null - sudo apt-get update - sudo ACCEPT_EULA=Y apt-get install -y mssql-tools18 - echo "/opt/mssql-tools18/bin" >> "$GITHUB_PATH" - - - name: Create the SSH key the cluster script provisions the node pools with - run: ssh-keygen -t rsa -b 4096 -N '' -f ~/.ssh/id_rsa -q - - - name: Start the LocalStack for Azure emulator - env: - LOCALSTACK_AUTH_TOKEN: ${{ secrets.LOCALSTACK_AUTH_TOKEN }} - # lstk forwards LOCALSTACK_-prefixed variables to the emulator. The Azure SQL Database sample - # needs the SQL Server EULA accepted, as its README and the localstack-azure-samples CI do - LOCALSTACK_MSSQL_ACCEPT_EULA: "Y" - # The emulator looks up the k3d release behind each AKS cluster on api.github.com. Anonymous - # calls share the runner IP's 60 requests an hour, which twenty parallel jobs can exhaust, so pass - # the run's own read-only token, as the localstack-azure-samples CI does - LOCALSTACK_GITHUB_API_TOKEN: ${{ github.token }} - run: | - lstk start --type azure --non-interactive - lstk az start-interception - - # The script prompts for the network configuration and both node pool sizes: - # pick option 1 (Azure network plugin and policy) and keep the default sizes - - name: Create the AKS cluster - working-directory: scripts - run: printf '1\n\n\n' | ./01-system-assigned-managed-identity.sh - - - name: Deploy the sample - working-directory: samples/${{ matrix.sample }}/${{ matrix.language }}/scripts - env: - # Answer the Azure Files sample's two provisioning menus; the other samples do not read these - PROVISIONING_MODE: static - FILE_SHARE_PROTOCOL: smb - run: | - ./01-deploy-resources.sh - ./02-build-docker-image.sh - ./04-push-docker-image.sh - ./05-deploy-app.sh - - - name: Test the web app - run: | - variables="samples/$SAMPLE/$LANGUAGE/scripts/00-variables.sh" - namespace=$(sed -n "s/^NAMESPACE=\"\(.*\)\"/\1/p" "$variables") - service=$(sed -n "s/^SERVICE_NAME=\"\(.*\)\"/\1/p" "$variables") - ./tests/test-vacation-planner.sh "$namespace" "$service" - - - name: Show cluster state and emulator logs - if: failure() - run: | - kubectl get pods --all-namespaces -o wide || true - kubectl get events --all-namespaces --sort-by=.lastTimestamp | tail -50 || true - for ns in $(kubectl get namespaces -o name | sed 's|namespace/||' | grep vacation-planner); do - kubectl describe pods --namespace "$ns" | tail -80 || true - kubectl logs --namespace "$ns" --all-containers --tail=100 -l "app=$ns" || true - done - lstk logs | tail -300 || true - - # Runs the selected samples on Windows, from Git Bash with MSYS_NO_PATHCONV=1 set as the README asks Windows - # users to do, on manual runs whose platform is Windows or all. The emulator is a Linux image and Docker on - # the Windows runner runs Windows containers, so the emulator runs in Docker Engine inside a WSL 2 - # distribution on the same runner; the Windows docker CLI, lstk and kubectl reach it through ports WSL - # forwards to the runner's localhost. - windows: - name: Windows (Git Bash) ${{ matrix.sample }} (${{ matrix.language }}) - needs: setup - if: github.event_name == 'workflow_dispatch' && (inputs.platform == 'Windows' || inputs.platform == 'all') && needs.setup.outputs.has_samples == 'true' - runs-on: windows-latest - timeout-minutes: 90 + # Skip the job when the run selects no sample + if: needs.setup.outputs.has_samples == 'true' + runs-on: ${{ matrix.runner }} + # A Windows job also sets up WSL 2 and Docker Engine before the sample + timeout-minutes: ${{ matrix.os == 'windows' && 90 || 60 }} permissions: contents: read strategy: fail-fast: false - # The same apps as the Linux job: those the setup job selected matrix: ${{ fromJSON(needs.setup.outputs.matrix) }} defaults: run: + # Git Bash on Windows, whose default shell is PowerShell shell: bash env: SAMPLE: ${{ matrix.sample }} LANGUAGE: ${{ matrix.language }} - IMAGE: localstack/localstack-azure:latest - # The Docker Engine in WSL 2, for the Windows docker CLI and lstk - DOCKER_HOST: tcp://127.0.0.1:2375 - # What the README asks Windows users of Git Bash and MSYS2 to export - MSYS_NO_PATHCONV: "1" steps: - name: Check out repo @@ -232,11 +154,20 @@ jobs: with: persist-credentials: false + - name: Point the Windows tools at Docker Engine in WSL 2 + # The Windows docker CLI and lstk reach the Docker Engine the next steps start in WSL 2 over TCP, and every + # later step runs with MSYS_NO_PATHCONV=1, what the README asks Windows users of Git Bash and MSYS2 to export + if: matrix.os == 'windows' + run: | + echo "DOCKER_HOST=tcp://127.0.0.1:2375" >> "$GITHUB_ENV" + echo "MSYS_NO_PATHCONV=1" >> "$GITHUB_ENV" + - name: Drop the carriage returns of Windows programs # The README asks Windows users for `set -o igncr` and `export SHELLOPTS`, so that the bash of Git Bash # and MSYS2 drops the carriage returns the Azure CLI and jq print from $(...) and read. Exporting # SHELLOPTS here would also hand each step's own -e and pipefail to the sample scripts, so every bash # turns the option on through BASH_ENV instead; a bash without the option skips the line. + if: matrix.os == 'windows' run: | printf '(set -o igncr) 2>/dev/null && set -o igncr\n' > "$RUNNER_TEMP/igncr.sh" echo "BASH_ENV=$(cygpath -m "$RUNNER_TEMP/igncr.sh")" >> "$GITHUB_ENV" @@ -248,6 +179,7 @@ jobs: # DNS tunneling, on by default, answers DNS for WSL itself, but the containers of the Docker Engine # in WSL cannot reach its 10.255.255.254 resolver, so their lookups time out; without it, WSL # hands out the NAT device on the host, which containers reach too. + if: matrix.os == 'windows' shell: pwsh run: | Set-Content -Path "$env:USERPROFILE\.wslconfig" -Value "[wsl2]`nmemory=12GB`ndnsTunneling=false`n`n[general]`ninstanceIdleTimeout=-1" @@ -255,6 +187,7 @@ jobs: - name: Set up Ubuntu in WSL 2 id: wsl + if: matrix.os == 'windows' uses: Vampire/setup-wsl@d1da7f2c0322a5ee4f24975344f67fc0f5baf364 # v7.0.0 with: distribution: Ubuntu-24.04 @@ -268,6 +201,7 @@ jobs: # is what the emulator container mounts to start the cluster and its backing containers; the TCP # endpoint, bound to localhost, is what WSL forwards to Windows. The wait asks the TCP endpoint, # so the step fails when that daemon did not start. + if: matrix.os == 'windows' shell: wsl-bash {0} run: | if [ -d /run/systemd/system ]; then @@ -293,10 +227,11 @@ jobs: --format 'Docker {{.ServerVersion}} on {{.OperatingSystem}}, kernel {{.KernelVersion}}' - name: Check that the Windows docker CLI reaches it + if: matrix.os == 'windows' run: docker version - name: Install lstk - # The release the Linux job pins + # Pinned like actions/checkout, so an lstk release cannot change every run at once: bump it deliberately run: npm install -g @localstack/lstk@1.4.0 - name: Give lstk an Azure CLI path without spaces @@ -305,6 +240,7 @@ jobs: # ("'C:\Program' is not recognized"), so `lstk az start-interception` (lstk 1.4.0) fails wherever the # Azure CLI sits in its default folder. A junction without spaces, first on the PATH, works around it # until lstk passes the JSON another way; Git Bash runs the same Azure CLI through it. + if: matrix.os == 'windows' shell: pwsh run: | $cliDir = Split-Path -Parent (Split-Path -Parent (Get-Command az.cmd).Source) @@ -314,6 +250,7 @@ jobs: - name: Install yq # The deployment scripts render the Kubernetes manifests with yq, which the Windows runner image # does not ship. The release and its SHA-256 are pinned. + if: matrix.os == 'windows' env: YQ_VERSION: v4.54.1 YQ_SHA256: b645f47ebb3a0d2fbab52998550bbd0a1706f23b5ca5f5b48e638c580bb70928 @@ -328,14 +265,25 @@ jobs: - name: Put psql on the PATH # The PostgreSQL and App Configuration samples seed their databases with psql, which comes with the # PostgreSQL the Windows runner image installs off the PATH; the Linux runner image has it on the PATH + if: matrix.os == 'windows' run: | echo "$PGBIN" >> "$GITHUB_PATH" "$PGBIN/psql" --version - name: Install sqlcmd - # The Azure SQL Database sample seeds its database with sqlcmd, which the runner image does not ship: - # the Go sqlcmd release, pinned with its SHA-256 - if: matrix.sample == 'web-app-sql-database' + # The Azure SQL Database sample seeds its database with sqlcmd, which the runner image does not ship + if: matrix.os == 'linux' && matrix.sample == 'web-app-sql-database' + run: | + sudo rm -f /etc/apt/sources.list.d/microsoft-prod.list + curl -fsSL https://packages.microsoft.com/keys/microsoft.asc | sudo tee /etc/apt/trusted.gpg.d/microsoft.asc > /dev/null + curl -fsSL "https://packages.microsoft.com/config/ubuntu/$(lsb_release -rs)/prod.list" | sudo tee /etc/apt/sources.list.d/mssql-release.list > /dev/null + sudo apt-get update + sudo ACCEPT_EULA=Y apt-get install -y mssql-tools18 + echo "/opt/mssql-tools18/bin" >> "$GITHUB_PATH" + + - name: Install sqlcmd on Windows + # The Windows runner image does not ship sqlcmd either: the Go sqlcmd release, pinned with its SHA-256 + if: matrix.os == 'windows' && matrix.sample == 'web-app-sql-database' env: SQLCMD_VERSION: v1.10.0 SQLCMD_SHA256: a4c28332fcc6e497d655e53ac8f4939f4ab170f9cfd32d0fa5081b60f4d9d691 @@ -349,12 +297,29 @@ jobs: - name: Create the SSH key the cluster script provisions the node pools with run: ssh-keygen -t rsa -b 4096 -N '' -f ~/.ssh/id_rsa -q + - name: Start the LocalStack for Azure emulator + if: matrix.os == 'linux' + env: + LOCALSTACK_AUTH_TOKEN: ${{ secrets.LOCALSTACK_AUTH_TOKEN }} + # lstk forwards LOCALSTACK_-prefixed variables to the emulator. The Azure SQL Database sample + # needs the SQL Server EULA accepted, as its README and the localstack-azure-samples CI do + LOCALSTACK_MSSQL_ACCEPT_EULA: "Y" + # The emulator looks up the k3d release behind each AKS cluster on api.github.com. Anonymous + # calls share the runner IP's 60 requests an hour, which twenty parallel jobs can exhaust, so pass + # the run's own read-only token, as the localstack-azure-samples CI does + LOCALSTACK_GITHUB_API_TOKEN: ${{ github.token }} + run: | + lstk start --type azure --non-interactive + lstk az start-interception + - name: Start the LocalStack for Azure emulator in WSL 2 # Started with the docker CLI rather than lstk: lstk on Windows would mount a Windows volume path, # and no Docker socket, into the Linux engine. The two mounts are paths inside WSL, which # MSYS_NO_PATHCONV keeps Git Bash from rewriting. lstk then finds the container by its name to # route the Azure CLI to it. + if: matrix.os == 'windows' env: + IMAGE: localstack/localstack-azure:latest LOCALSTACK_AUTH_TOKEN: ${{ secrets.LOCALSTACK_AUTH_TOKEN }} # The emulator looks up the k3d release behind each AKS cluster on api.github.com, as on Linux GITHUB_API_TOKEN: ${{ github.token }} @@ -391,7 +356,7 @@ jobs: - name: Deploy the sample working-directory: samples/${{ matrix.sample }}/${{ matrix.language }}/scripts env: - # Answer the Azure Files sample's two provisioning menus, as the Linux job does + # Answer the Azure Files sample's two provisioning menus; the other samples do not read these PROVISIONING_MODE: static FILE_SHARE_PROTOCOL: smb run: | @@ -416,10 +381,15 @@ jobs: kubectl describe pods --namespace "$ns" | tail -80 || true kubectl logs --namespace "$ns" --all-containers --tail=100 -l "app=$ns" || true done - docker logs localstack-azure 2>&1 | tail -n 300 || true + if [ "$RUNNER_OS" = Windows ]; then + # Started with the docker CLI in WSL 2, not by lstk + docker logs localstack-azure 2>&1 | tail -n 300 || true + else + lstk logs | tail -300 || true + fi - name: Get the Docker Engine log # The wsl-bash shell exists only once WSL is set up - if: failure() && steps.wsl.outcome == 'success' + if: failure() && matrix.os == 'windows' && steps.wsl.outcome == 'success' shell: wsl-bash {0} run: tail -n 100 /var/log/dockerd.log || true