diff --git a/.github/actions/provision-k3s-vm-workers/action.yml b/.github/actions/provision-k3s-vm-workers/action.yml index 6b28e6dd..350ec6b5 100644 --- a/.github/actions/provision-k3s-vm-workers/action.yml +++ b/.github/actions/provision-k3s-vm-workers/action.yml @@ -1,5 +1,5 @@ name: 'Provision k3s VM workers' -description: > +description: | Launches real QEMU/KVM worker VMs on a bridged network and joins them as k3s agents to a given k3s server. Used to turn a single-node CI host into a genuine multi-node cluster (unlike container-based nodes, e.g. k3d, these are independent kernels/machines). @@ -25,177 +25,178 @@ inputs: runs: using: 'composite' + steps: - - name: Install Virtualization Dependencies - shell: bash - run: | - echo "CIDR_PREFIX=${{ inputs.bridge-cidr-prefix }}" >> "$GITHUB_ENV" + - name: Install Virtualization Dependencies + shell: bash + run: | + echo "CIDR_PREFIX=${{ inputs.bridge-cidr-prefix }}" >> "$GITHUB_ENV" - sudo apt-get update + sudo apt-get update - # Pinned to the versions available on the runner's Ubuntu 24.04 (noble) image at the - # time of writing. These come from Ubuntu's regular archive, which does not retain - # superseded versions — a routine security update to any of these will make the pin - # unresolvable and fail the install below. If that happens, check the versions - # currently available (logged on every run) and update the pins to match. - echo "Available versions for pinned packages:" - apt-cache madison qemu-kvm qemu-utils cloud-image-utils + # Pinned to the versions available on the runner's Ubuntu 24.04 (noble) image at the + # time of writing. These come from Ubuntu's regular archive, which does not retain + # superseded versions — a routine security update to any of these will make the pin + # unresolvable and fail the install below. If that happens, check the versions + # currently available (logged on every run) and update the pins to match. + echo "Available versions for pinned packages:" + apt-cache madison qemu-kvm qemu-utils cloud-image-utils - sudo apt-get install -y \ - qemu-kvm=1:8.2.2+ds-0ubuntu1.17 \ - qemu-utils=1:8.2.2+ds-0ubuntu1.17 \ - cloud-image-utils=0.33-1 - sudo usermod -aG kvm $USER + sudo apt-get install -y \ + qemu-kvm=1:8.2.2+ds-0ubuntu1.17 \ + qemu-utils=1:8.2.2+ds-0ubuntu1.17 \ + cloud-image-utils=0.33-1 + sudo usermod -aG kvm $USER - kvm-ok + kvm-ok - - name: Set up bridge network for VMs - shell: bash - run: | - # Create a bridge so both VMs share an L2 segment with unique routable IPs. - # Required because QEMU `-net user` gives every VM the same 10.0.2.15 NAT - # address, which breaks flannel VXLAN between workers. - sudo ip link add name k3kbr0 type bridge - sudo ip addr add ${CIDR_PREFIX}.1/24 dev k3kbr0 - sudo ip link set k3kbr0 up + - name: Set up bridge network for VMs + shell: bash + run: | + # Create a bridge so both VMs share an L2 segment with unique routable IPs. + # Required because QEMU `-net user` gives every VM the same 10.0.2.15 NAT + # address, which breaks flannel VXLAN between workers. + sudo ip link add name k3kbr0 type bridge + sudo ip addr add ${CIDR_PREFIX}.1/24 dev k3kbr0 + sudo ip link set k3kbr0 up - # NAT outbound so VMs can reach the internet (image pulls etc). - sudo sysctl -w net.ipv4.ip_forward=1 - sudo iptables -t nat -A POSTROUTING -s ${CIDR_PREFIX}.0/24 ! -o k3kbr0 -j MASQUERADE - sudo iptables -A FORWARD -i k3kbr0 -j ACCEPT - sudo iptables -A FORWARD -o k3kbr0 -j ACCEPT + # NAT outbound so VMs can reach the internet (image pulls etc). + sudo sysctl -w net.ipv4.ip_forward=1 + sudo iptables -t nat -A POSTROUTING -s ${CIDR_PREFIX}.0/24 ! -o k3kbr0 -j MASQUERADE + sudo iptables -A FORWARD -i k3kbr0 -j ACCEPT + sudo iptables -A FORWARD -o k3kbr0 -j ACCEPT - # One TAP per VM, attached to the bridge. - for i in $(seq 1 ${{ inputs.worker-count }}); do - sudo ip tuntap add tap-w${i} mode tap - sudo ip link set tap-w${i} master k3kbr0 - sudo ip link set tap-w${i} up - done + # One TAP per VM, attached to the bridge. + for i in $(seq 1 ${{ inputs.worker-count }}); do + sudo ip tuntap add tap-w${i} mode tap + sudo ip link set tap-w${i} master k3kbr0 + sudo ip link set tap-w${i} up + done - - name: Download Base Cloud Image - shell: bash - run: | - # PINNED TO UBUNTU 24.04 LTS (noble). - # - # Newer Ubuntu releases (tested: 26.04 "resolute") ship a stricter - # `cri-containerd.apparmor.d` profile that denies inter-thread signal - # delivery. The BIND ISC library used by `nslookup` relies on those - # signals during shutdown (`isc_app_ctxshutdown()` calls `kill()`), - # so when AppArmor denies them nslookup exits 139 with - # "kill: Permission denied". The conformance tests - # `[sig-network] Services should be able to change the type from - # {NodePort,ClusterIP} to ExternalName` - # both run `nslookup` from an exec pod and fail in that case. - # - # Before bumping past 24.04, verify those two conformance tests still - # pass — or that the containerd AppArmor profile on the newer release - # has been relaxed to allow intra-pod signals. - wget -q https://cloud-images.ubuntu.com/noble/current/noble-server-cloudimg-amd64.img -O ubuntu-cloudimg.img + - name: Download Base Cloud Image + shell: bash + run: | + # PINNED TO UBUNTU 24.04 LTS (noble). + # + # Newer Ubuntu releases (tested: 26.04 "resolute") ship a stricter + # `cri-containerd.apparmor.d` profile that denies inter-thread signal + # delivery. The BIND ISC library used by `nslookup` relies on those + # signals during shutdown (`isc_app_ctxshutdown()` calls `kill()`), + # so when AppArmor denies them nslookup exits 139 with + # "kill: Permission denied". The conformance tests + # `[sig-network] Services should be able to change the type from + # {NodePort,ClusterIP} to ExternalName` + # both run `nslookup` from an exec pod and fail in that case. + # + # Before bumping past 24.04, verify those two conformance tests still + # pass — or that the containerd AppArmor profile on the newer release + # has been relaxed to allow intra-pod signals. + wget -q https://cloud-images.ubuntu.com/noble/current/noble-server-cloudimg-amd64.img -O ubuntu-cloudimg.img - - name: Generate SSH Key and Cloud-Init Seeds - shell: bash - run: | - ssh-keygen -t rsa -b 4096 -f ./id_rsa -N "" - PUBKEY="$(cat ./id_rsa.pub)" + - name: Generate SSH Key and Cloud-Init Seeds + shell: bash + run: | + ssh-keygen -t rsa -b 4096 -f ./id_rsa -N "" + PUBKEY="$(cat ./id_rsa.pub)" - # Per-VM cloud-init: each worker gets a unique hostname and a static IP - # on the bridge subnet via netplan. - for i in $(seq 1 ${{ inputs.worker-count }}); do - IP="${CIDR_PREFIX}.1${i}" # e.g. 192.168.100.11 / 192.168.100.12 / ... - cat < user-data-${i} - #cloud-config - hostname: worker-${i} - preserve_hostname: false - manage_etc_hosts: true - # Stop cloud-init from generating its own DHCP netplan that would - # conflict with the static one we write in write_files below. - network: - config: disabled - users: - - name: ubuntu - ssh_authorized_keys: - - ${PUBKEY} - sudo: ['ALL=(ALL) NOPASSWD:ALL'] - shell: /bin/bash - write_files: - - path: /etc/netplan/50-static.yaml - permissions: '0600' - content: | - network: - version: 2 - ethernets: - ens3: - dhcp4: false - addresses: [${IP}/24] - routes: - - to: default - via: ${CIDR_PREFIX}.1 - nameservers: - addresses: [8.8.8.8, 1.1.1.1] - runcmd: - - netplan apply - EOF - cloud-localds seed-${i}.img user-data-${i} - done + # Per-VM cloud-init: each worker gets a unique hostname and a static IP + # on the bridge subnet via netplan. + for i in $(seq 1 ${{ inputs.worker-count }}); do + IP="${CIDR_PREFIX}.1${i}" # e.g. 192.168.100.11 / 192.168.100.12 / ... + cat < user-data-${i} + #cloud-config + hostname: worker-${i} + preserve_hostname: false + manage_etc_hosts: true + # Stop cloud-init from generating its own DHCP netplan that would + # conflict with the static one we write in write_files below. + network: + config: disabled + users: + - name: ubuntu + ssh_authorized_keys: + - ${PUBKEY} + sudo: ['ALL=(ALL) NOPASSWD:ALL'] + shell: /bin/bash + write_files: + - path: /etc/netplan/50-static.yaml + permissions: '0600' + content: | + network: + version: 2 + ethernets: + ens3: + dhcp4: false + addresses: [${IP}/24] + routes: + - to: default + via: ${CIDR_PREFIX}.1 + nameservers: + addresses: [8.8.8.8, 1.1.1.1] + runcmd: + - netplan apply + EOF + cloud-localds seed-${i}.img user-data-${i} + done - - name: Create Worker Disks - shell: bash - run: | - for i in $(seq 1 ${{ inputs.worker-count }}); do - qemu-img create -f qcow2 -b ubuntu-cloudimg.img -F qcow2 worker-${i}.qcow2 20G - done + - name: Create Worker Disks + shell: bash + run: | + for i in $(seq 1 ${{ inputs.worker-count }}); do + qemu-img create -f qcow2 -b ubuntu-cloudimg.img -F qcow2 worker-${i}.qcow2 20G + done - - name: Launch Worker VMs - shell: bash - run: | - for i in $(seq 1 ${{ inputs.worker-count }}); do - # Each VM gets a unique MAC, attached to its own tap on k3kbr0. - MAC=$(printf '52:54:00:12:34:%02x' $((85 + i))) + - name: Launch Worker VMs + shell: bash + run: | + for i in $(seq 1 ${{ inputs.worker-count }}); do + # Each VM gets a unique MAC, attached to its own tap on k3kbr0. + MAC=$(printf '52:54:00:12:34:%02x' $((85 + i))) - sudo qemu-system-x86_64 \ - -m 2048 -smp 2 -cpu host -enable-kvm -nographic \ - -drive file=worker-${i}.qcow2,if=virtio \ - -drive file=seed-${i}.img,format=raw,if=virtio \ - -netdev tap,id=net0,ifname=tap-w${i},script=no,downscript=no \ - -device virtio-net-pci,netdev=net0,mac=${MAC} \ - & + sudo qemu-system-x86_64 \ + -m 2048 -smp 2 -cpu host -enable-kvm -nographic \ + -drive file=worker-${i}.qcow2,if=virtio \ + -drive file=seed-${i}.img,format=raw,if=virtio \ + -netdev tap,id=net0,ifname=tap-w${i},script=no,downscript=no \ + -device virtio-net-pci,netdev=net0,mac=${MAC} \ + & - # Wait a moment before launching the next VM - sleep 5 - done + # Wait a moment before launching the next VM + sleep 5 + done - - name: Wait for SSH Availability - shell: bash - run: | - for i in $(seq 1 ${{ inputs.worker-count }}); do - IP="${CIDR_PREFIX}.1${i}" - echo "Waiting for Worker ${i} (${IP}) to respond..." - timeout 180s bash -c " - until ssh -i ./id_rsa -o StrictHostKeyChecking=no -o ConnectTimeout=2 ubuntu@${IP} true 2>/dev/null; do sleep 3; done - " - done + - name: Wait for SSH Availability + shell: bash + run: | + for i in $(seq 1 ${{ inputs.worker-count }}); do + IP="${CIDR_PREFIX}.1${i}" + echo "Waiting for Worker ${i} (${IP}) to respond..." + timeout 180s bash -c " + until ssh -i ./id_rsa -o StrictHostKeyChecking=no -o ConnectTimeout=2 ubuntu@${IP} true 2>/dev/null; do sleep 3; done + " + done - echo "All VMs are up and running!" + echo "All VMs are up and running!" - - name: Verify Worker VM Configuration - shell: bash - run: | - for i in $(seq 1 ${{ inputs.worker-count }}); do - IP="${CIDR_PREFIX}.1${i}" - echo "=== Worker at ${IP} ===" - ssh -i ./id_rsa -o StrictHostKeyChecking=no ubuntu@${IP} \ - "echo 'Hostname:' \$(hostname) && \ - echo 'IP Address:' \$(ip -4 addr show ens3 | grep -oP '(?<=inet\s)\d+(\.\d+){3}') && \ - echo 'Gateway:' \$(ip route | grep default)" - echo "" - done + - name: Verify Worker VM Configuration + shell: bash + run: | + for i in $(seq 1 ${{ inputs.worker-count }}); do + IP="${CIDR_PREFIX}.1${i}" + echo "=== Worker at ${IP} ===" + ssh -i ./id_rsa -o StrictHostKeyChecking=no ubuntu@${IP} \ + "echo 'Hostname:' \$(hostname) && \ + echo 'IP Address:' \$(ip -4 addr show ens3 | grep -oP '(?<=inet\s)\d+(\.\d+){3}') && \ + echo 'Gateway:' \$(ip route | grep default)" + echo "" + done - - name: Join Workers to K3s Cluster - shell: bash - run: | - for i in $(seq 1 ${{ inputs.worker-count }}); do - IP="${CIDR_PREFIX}.1${i}" - echo "Registering Worker ${i} (k3s ${{ inputs.k3s-version }})..." - ssh -i ./id_rsa -o StrictHostKeyChecking=no ubuntu@${IP} \ - "curl -sfL https://get.k3s.io | INSTALL_K3S_VERSION=${{ inputs.k3s-version }} K3S_URL=${{ inputs.k3s-url }} K3S_TOKEN=${{ inputs.k3s-token }} sh -" - done + - name: Join Workers to K3s Cluster + shell: bash + run: | + for i in $(seq 1 ${{ inputs.worker-count }}); do + IP="${CIDR_PREFIX}.1${i}" + echo "Registering Worker ${i} (k3s ${{ inputs.k3s-version }})..." + ssh -i ./id_rsa -o StrictHostKeyChecking=no ubuntu@${IP} \ + "curl -sfL https://get.k3s.io | INSTALL_K3S_VERSION=${{ inputs.k3s-version }} K3S_URL=${{ inputs.k3s-url }} K3S_TOKEN=${{ inputs.k3s-token }} sh -" + done diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 43acfdc8..726fff07 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -7,7 +7,7 @@ on: types: [opened, synchronize, reopened] permissions: - contents: read + contents: read env: GORELEASER_VERSION: v2.15.2 @@ -29,7 +29,7 @@ jobs: uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6 with: go-version-file: go.mod - + - name: Set up QEMU uses: docker/setup-qemu-action@96fe6ef7f33517b61c61be40b68a1882f3264fb8 # v4 diff --git a/.github/workflows/chart.yml b/.github/workflows/chart.yml index 32425e4a..ca66a90d 100644 --- a/.github/workflows/chart.yml +++ b/.github/workflows/chart.yml @@ -4,7 +4,7 @@ on: workflow_dispatch: permissions: - contents: write + contents: write env: HELM_VERSION: v4.1.3 @@ -17,7 +17,7 @@ jobs: - name: Checkout code uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 with: - fetch-depth: 0 + fetch-depth: 0 - name: Configure Git run: | diff --git a/.github/workflows/release-delete.yml b/.github/workflows/release-delete.yml index 2d2b6402..be1e78e8 100644 --- a/.github/workflows/release-delete.yml +++ b/.github/workflows/release-delete.yml @@ -8,8 +8,8 @@ on: description: The tag of the release permissions: - contents: write - packages: write + contents: write + packages: write env: GH_TOKEN: ${{ github.token }} @@ -22,10 +22,10 @@ jobs: - name: Check tag if: inputs.tag == '' run: echo "::error::Missing tag from input" && exit 1 - + - name: Checkout code uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 - + - name: Check if release is draft run: | CURRENT_TAG=${{ inputs.tag }} @@ -51,7 +51,7 @@ jobs: PACKAGE_ID=$(echo $PACKAGE_TO_DELETE | jq .id) echo "Deleting ${PACKAGE_ID}" - gh api --method DELETE /user/packages/container/${package}/versions/${PACKAGE_ID} + gh api --method DELETE /user/packages/container/${package}/versions/${PACKAGE_ID} done - name: Delete Github release diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 600e3c63..9f346633 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -11,9 +11,9 @@ on: description: Checkout a specific commit permissions: - contents: write - packages: write - id-token: write + contents: write + packages: write + id-token: write env: GORELEASER_VERSION: v2.15.2 diff --git a/.github/workflows/renovate-vault.yml b/.github/workflows/renovate-vault.yml index a581987a..fbc9120e 100644 --- a/.github/workflows/renovate-vault.yml +++ b/.github/workflows/renovate-vault.yml @@ -8,24 +8,24 @@ on: default: info type: choice options: - - info - - debug + - info + - debug overrideSchedule: description: "Override all schedules" required: false default: "false" type: choice options: - - "false" - - "true" + - "false" + - "true" configMigration: description: "Toggle PRs for config migration" required: false default: "true" type: choice options: - - "false" - - "true" + - "false" + - "true" renovateConfig: description: "Define a custom renovate config file" required: false @@ -43,7 +43,7 @@ on: type: string schedule: - - cron: '30 4,6 * * 1-5' + - cron: '30 4,6 * * 1-5' permissions: contents: read diff --git a/.github/workflows/test-conformance-hcp.yaml b/.github/workflows/test-conformance-hcp.yaml index 8849355e..bd5094a2 100644 --- a/.github/workflows/test-conformance-hcp.yaml +++ b/.github/workflows/test-conformance-hcp.yaml @@ -2,7 +2,7 @@ name: Conformance Tests - HCP Mode on: schedule: - - cron: "0 1 * * *" + - cron: "0 1 * * *" workflow_dispatch: inputs: k3k_version: @@ -14,13 +14,13 @@ on: required: false type: choice options: - - "" - - "v1.34.9" - - "v1.35.6" - - "v1.36.2" + - "" + - "v1.34.9" + - "v1.35.6" + - "v1.36.2" permissions: - contents: read + contents: read env: K8S_VERSIONS: "v1.34.9,v1.35.6,v1.36.2" @@ -33,14 +33,14 @@ jobs: outputs: k8s_versions: ${{ steps.set-matrix.outputs.k8s_versions }} steps: - - id: set-matrix - run: | - if [[ -z "${{ inputs.k8s_version }}" ]]; then - JSON_ARRAY=$(jq -nc '"${{ env.K8S_VERSIONS }}" | split(",")') - echo "k8s_versions=${JSON_ARRAY}" >> "$GITHUB_OUTPUT" - else - echo "k8s_versions=[\"${{ inputs.k8s_version }}\"]" >> "$GITHUB_OUTPUT" - fi + - id: set-matrix + run: | + if [[ -z "${{ inputs.k8s_version }}" ]]; then + JSON_ARRAY=$(jq -nc '"${{ env.K8S_VERSIONS }}" | split(",")') + echo "k8s_versions=${JSON_ARRAY}" >> "$GITHUB_OUTPUT" + else + echo "k8s_versions=[\"${{ inputs.k8s_version }}\"]" >> "$GITHUB_OUTPUT" + fi conformance: needs: setup @@ -77,7 +77,7 @@ jobs: rm -fr "${{ env.FILENAME }}" linux-amd64/helm - name: Install hydrophone - run: go install sigs.k8s.io/hydrophone@3de3e886a2f6f09635d8b981c195490af1584d97 #v0.7.0 + run: go install sigs.k8s.io/hydrophone@3de3e886a2f6f09635d8b981c195490af1584d97 # v0.7.0 - name: Install k3s env: @@ -114,7 +114,7 @@ jobs: helm repo add k3k https://rancher.github.io/k3k helm repo update helm install --namespace k3k-system --create-namespace --version "${CHART_VERSION}" k3k k3k/k3k - + wget -qO k3kcli "https://github.com/rancher/k3k/releases/download/${{ inputs.k3k_version }}/k3kcli-linux-amd64" sudo mv k3kcli /usr/local/bin/k3kcli sudo chmod +x /usr/local/bin/k3kcli diff --git a/.github/workflows/test-conformance-shared.yaml b/.github/workflows/test-conformance-shared.yaml index e41116ee..ae8ba434 100644 --- a/.github/workflows/test-conformance-shared.yaml +++ b/.github/workflows/test-conformance-shared.yaml @@ -2,7 +2,7 @@ name: Conformance Tests - Shared Mode on: schedule: - - cron: "0 1 * * *" + - cron: "0 1 * * *" workflow_dispatch: inputs: k3k_version: @@ -14,13 +14,13 @@ on: required: false type: choice options: - - "" - - "v1.34.9" - - "v1.35.6" - - "v1.36.2" + - "" + - "v1.34.9" + - "v1.35.6" + - "v1.36.2" permissions: - contents: read + contents: read env: K8S_VERSIONS: "v1.34.9,v1.35.6,v1.36.2" @@ -35,14 +35,14 @@ jobs: outputs: k8s_versions: ${{ steps.set-matrix.outputs.k8s_versions }} steps: - - id: set-matrix - run: | - if [[ -z "${{ inputs.k8s_version }}" ]]; then - JSON_ARRAY=$(jq -nc '"${{ env.K8S_VERSIONS }}" | split(",")') - echo "k8s_versions=${JSON_ARRAY}" >> "$GITHUB_OUTPUT" - else - echo "k8s_versions=[\"${{ inputs.k8s_version }}\"]" >> "$GITHUB_OUTPUT" - fi + - id: set-matrix + run: | + if [[ -z "${{ inputs.k8s_version }}" ]]; then + JSON_ARRAY=$(jq -nc '"${{ env.K8S_VERSIONS }}" | split(",")') + echo "k8s_versions=${JSON_ARRAY}" >> "$GITHUB_OUTPUT" + else + echo "k8s_versions=[\"${{ inputs.k8s_version }}\"]" >> "$GITHUB_OUTPUT" + fi conformance: needs: setup @@ -79,7 +79,7 @@ jobs: rm -fr "${{ env.FILENAME }}" linux-amd64/helm - name: Install hydrophone - run: go install sigs.k8s.io/hydrophone@3de3e886a2f6f09635d8b981c195490af1584d97 #v0.7.0 + run: go install sigs.k8s.io/hydrophone@3de3e886a2f6f09635d8b981c195490af1584d97 # v0.7.0 - name: Install k3d run: | @@ -103,12 +103,12 @@ jobs: echo "127.0.0.1 ${REPO_NAME}" | sudo tee -a /etc/hosts k3d registry create ${REPO_NAME} --port ${REPO_PORT} - + k3d cluster create k3k --servers 2 \ --image rancher/k3s:${{ env.KUBERNETES_VERSION }}-k3s1 \ -p "30000-30010:30000-30010@server:0" \ --registry-use k3d-${REPO_NAME}:${REPO_PORT} - + kubectl cluster-info kubectl get nodes @@ -141,7 +141,7 @@ jobs: helm repo add k3k https://rancher.github.io/k3k helm repo update helm install --namespace k3k-system --create-namespace --version "${CHART_VERSION}" k3k k3k/k3k - + wget -qO k3kcli "https://github.com/rancher/k3k/releases/download/${{ inputs.k3k_version }}/k3kcli-linux-amd64" sudo mv k3kcli /usr/local/bin/k3kcli sudo chmod +x /usr/local/bin/k3kcli @@ -179,11 +179,11 @@ jobs: k3kcli kubeconfig generate --name mycluster export KUBECONFIG=${{ github.workspace }}/k3k-mycluster-mycluster-kubeconfig.yaml - + kubectl cluster-info kubectl get nodes kubectl get pods -A - + - name: Run conformance tests run: | hydrophone --conformance --parallel 4 \ diff --git a/.github/workflows/test-conformance-virtual.yaml b/.github/workflows/test-conformance-virtual.yaml index 238be083..f56270be 100644 --- a/.github/workflows/test-conformance-virtual.yaml +++ b/.github/workflows/test-conformance-virtual.yaml @@ -2,7 +2,7 @@ name: Conformance Tests - Virtual Mode on: schedule: - - cron: "0 1 * * *" + - cron: "0 1 * * *" workflow_dispatch: inputs: k3k_version: @@ -14,13 +14,13 @@ on: required: false type: choice options: - - "" - - "v1.34.9" - - "v1.35.6" - - "v1.36.2" + - "" + - "v1.34.9" + - "v1.35.6" + - "v1.36.2" permissions: - contents: read + contents: read env: K8S_VERSIONS: "v1.34.9,v1.35.6,v1.36.2" @@ -33,14 +33,14 @@ jobs: outputs: k8s_versions: ${{ steps.set-matrix.outputs.k8s_versions }} steps: - - id: set-matrix - run: | - if [[ -z "${{ inputs.k8s_version }}" ]]; then - JSON_ARRAY=$(jq -nc '"${{ env.K8S_VERSIONS }}" | split(",")') - echo "k8s_versions=${JSON_ARRAY}" >> "$GITHUB_OUTPUT" - else - echo "k8s_versions=[\"${{ inputs.k8s_version }}\"]" >> "$GITHUB_OUTPUT" - fi + - id: set-matrix + run: | + if [[ -z "${{ inputs.k8s_version }}" ]]; then + JSON_ARRAY=$(jq -nc '"${{ env.K8S_VERSIONS }}" | split(",")') + echo "k8s_versions=${JSON_ARRAY}" >> "$GITHUB_OUTPUT" + else + echo "k8s_versions=[\"${{ inputs.k8s_version }}\"]" >> "$GITHUB_OUTPUT" + fi conformance: needs: setup @@ -77,7 +77,7 @@ jobs: rm -fr "${{ env.FILENAME }}" linux-amd64/helm - name: Install hydrophone - run: go install sigs.k8s.io/hydrophone@3de3e886a2f6f09635d8b981c195490af1584d97 #v0.7.0 + run: go install sigs.k8s.io/hydrophone@3de3e886a2f6f09635d8b981c195490af1584d97 # v0.7.0 - name: Install k3s env: @@ -116,7 +116,7 @@ jobs: helm repo add k3k https://rancher.github.io/k3k helm repo update helm install --namespace k3k-system --create-namespace --version "${CHART_VERSION}" k3k k3k/k3k - + wget -qO k3kcli "https://github.com/rancher/k3k/releases/download/${{ inputs.k3k_version }}/k3kcli-linux-amd64" sudo mv k3kcli /usr/local/bin/k3kcli sudo chmod +x /usr/local/bin/k3kcli @@ -137,12 +137,12 @@ jobs: run: | k3kcli cluster create --mode=virtual --servers=2 mycluster - export KUBECONFIG=${{ github.workspace }}/k3k-mycluster-mycluster-kubeconfig.yaml - + export KUBECONFIG=${{ github.workspace }}/k3k-mycluster-mycluster-kubeconfig.yaml + kubectl cluster-info kubectl get nodes kubectl get pods -A - + - name: Run conformance tests run: | hydrophone --conformance --parallel 4 \ diff --git a/.github/workflows/test-e2e.yaml b/.github/workflows/test-e2e.yaml index ab52f83b..158d6a09 100644 --- a/.github/workflows/test-e2e.yaml +++ b/.github/workflows/test-e2e.yaml @@ -8,7 +8,7 @@ on: workflow_dispatch: permissions: - contents: read + contents: read env: KUBERNETES_VERSION: v1.36.2 @@ -29,12 +29,12 @@ jobs: go-version-file: go.mod - name: Install Ginkgo - run: go install github.com/onsi/ginkgo/v2/ginkgo@9ff1646a26f77a4c0d33ddba3e6368c42c0e8842 #v2.32.0 - + run: go install github.com/onsi/ginkgo/v2/ginkgo@9ff1646a26f77a4c0d33ddba3e6368c42c0e8842 # v2.32.0 + - name: Setup environment run: | mkdir ${{ github.workspace }}/covdata - + echo "COVERAGE=true" >> $GITHUB_ENV echo "GOCOVERDIR=${{ github.workspace }}/covdata" >> $GITHUB_ENV echo "REPO=ttl.sh/$(uuidgen)" >> $GITHUB_ENV @@ -92,7 +92,7 @@ jobs: KUBECONFIG: /etc/rancher/k3s/k3s.yaml REPO: ${{ env.REPO }} VERSION: ${{ env.VERSION }} - run: make E2E_LABEL_FILTER="e2e && !slow" test-e2e + run: make E2E_LABEL_FILTER="e2e && !slow" test-e2e - name: Convert coverage data run: go tool covdata textfmt -i=${GOCOVERDIR} -o ${GOCOVERDIR}/cover.out @@ -161,12 +161,12 @@ jobs: go-version-file: go.mod - name: Install Ginkgo - run: go install github.com/onsi/ginkgo/v2/ginkgo@9ff1646a26f77a4c0d33ddba3e6368c42c0e8842 #v2.32.0 - + run: go install github.com/onsi/ginkgo/v2/ginkgo@9ff1646a26f77a4c0d33ddba3e6368c42c0e8842 # v2.32.0 + - name: Setup environment run: | mkdir ${{ github.workspace }}/covdata - + echo "COVERAGE=true" >> $GITHUB_ENV echo "GOCOVERDIR=${{ github.workspace }}/covdata" >> $GITHUB_ENV echo "REPO=ttl.sh/$(uuidgen)" >> $GITHUB_ENV @@ -224,7 +224,7 @@ jobs: KUBECONFIG: /etc/rancher/k3s/k3s.yaml REPO: ${{ env.REPO }} VERSION: ${{ env.VERSION }} - run: make E2E_LABEL_FILTER="e2e && slow" test-e2e + run: make E2E_LABEL_FILTER="e2e && slow" test-e2e - name: Convert coverage data run: go tool covdata textfmt -i=${GOCOVERDIR} -o ${GOCOVERDIR}/cover.out diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index e6d3d444..ff69dceb 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -8,7 +8,7 @@ on: workflow_dispatch: permissions: - contents: read + contents: read env: KUBERNETES_VERSION: v1.36.2 @@ -50,12 +50,12 @@ jobs: go-version-file: go.mod - name: Install Ginkgo - run: go install github.com/onsi/ginkgo/v2/ginkgo@9ff1646a26f77a4c0d33ddba3e6368c42c0e8842 #v2.32.0 - + run: go install github.com/onsi/ginkgo/v2/ginkgo@9ff1646a26f77a4c0d33ddba3e6368c42c0e8842 # v2.32.0 + - name: Setup environment run: | mkdir ${{ github.workspace }}/covdata - + echo "COVERAGE=true" >> $GITHUB_ENV echo "GOCOVERDIR=${{ github.workspace }}/covdata" >> $GITHUB_ENV echo "REPO=ttl.sh/$(uuidgen)" >> $GITHUB_ENV diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index 7dfc05f4..a8faf944 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -14,28 +14,33 @@ jobs: validate: runs-on: ubuntu-latest steps: - - name: Checkout code - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 + - name: Checkout code + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 - - name: Set up Go - uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6 - with: - go-version-file: go.mod - cache: true + - name: Set up Go + uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6 + with: + go-version-file: go.mod + cache: true - - name: Install Pandoc - run: sudo apt-get install pandoc + - name: Install Pandoc + run: sudo apt-get install pandoc - - name: Run linters - uses: golangci/golangci-lint-action@ba0d7d2ec06a0ea1cb5fa41b2e4a3ab91d21278a # v9.3.0 - with: - version: v2.12.2 - args: -v - only-new-issues: true - skip-cache: false + - name: Run linters + uses: golangci/golangci-lint-action@ba0d7d2ec06a0ea1cb5fa41b2e4a3ab91d21278a # v9.3.0 + with: + version: v2.12.2 + args: -v + only-new-issues: true + skip-cache: false - - name: Run formatters - run: golangci-lint -v fmt ./... + - name: Run formatters + run: golangci-lint -v fmt ./... - - name: Validate - run: make validate + - name: Lint YAML + run: | + pipx install yamllint==1.38.0 + make lint-yaml + + - name: Validate + run: make validate diff --git a/.yamllint b/.yamllint new file mode 100644 index 00000000..60d54c06 --- /dev/null +++ b/.yamllint @@ -0,0 +1,24 @@ +# yamllint config for the GitHub Actions YAML files (see `make lint-yaml`). +extends: default + +rules: + # GitHub Actions workflows don't use an explicit document start. + document-start: disable + + # Workflows have long lines (SHA-pinned actions, shell commands); don't enforce. + line-length: disable + + # Allow the workflow trigger key `on:` without a "truthy" warning. + truthy: + check-keys: false + + # Inline SHA pins are written as `uses: action@sha # v1` (one space before #). + comments: + min-spaces-from-content: 1 + + # Enforce the repo's indentless sequence style: + # steps: + # - name: ... + indentation: + spaces: 2 + indent-sequences: false diff --git a/Makefile b/Makefile index 20fc12f9..7b619eba 100644 --- a/Makefile +++ b/Makefile @@ -11,9 +11,12 @@ GINKGO_FLAGS ?= -v -r --coverprofile=cover.out --coverpkg=./... ENVTEST_VERSION ?= v0.0.0-20250505003155-b6c5897febe5 ENVTEST_K8S_VERSION := 1.31.0 CRD_REF_DOCS_VER ?= v0.2.0 +YAMLLINT_VERSION ?= 1.38.0 FLAKE_ATTEMPTS ?= 3 GOLANGCI_LINT ?= go run github.com/golangci/golangci-lint/v2/cmd/golangci-lint@$(GOLANGCI_LINT_VERSION) +# yamllint is a Python tool; install it with `pipx install yamllint==$(YAMLLINT_VERSION)` (or pip) +YAMLLINT ?= yamllint GINKGO ?= go run github.com/onsi/ginkgo/v2/ginkgo@$(GINKGO_VERSION) CRD_REF_DOCS := go run github.com/elastic/crd-ref-docs@$(CRD_REF_DOCS_VER) PANDOC := $(shell which pandoc 2> /dev/null) @@ -129,6 +132,10 @@ ifndef CI $(GOLANGCI_LINT) fmt ./... endif +.PHONY: lint-yaml +lint-yaml: ## Lint the GitHub Actions YAML files + $(YAMLLINT) .github/ + .PHONY: validate validate: generate docs fmt ## Validate the project checking for any dependency or doc mismatch $(GINKGO) unfocus