*: AI policy #7098
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: github-ci | |
| on: | |
| pull_request: | |
| push: | |
| branches: | |
| - 'master' | |
| - 'stable/**' | |
| - 'rc/**' | |
| - 'ci/**' | |
| # Cancel older in-progress runs for the same ref to save runners. | |
| concurrency: | |
| group: github-ci-${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| # Restrict default GITHUB_TOKEN to read-only repository contents. | |
| permissions: | |
| contents: read | |
| defaults: | |
| run: | |
| shell: bash | |
| jobs: | |
| # Classify changes: doc/ vs everything else (skip Docker build/tests when only doc/ changed). | |
| doc-path-filter: | |
| if: ${{ github.event_name != 'pull_request' || github.actor != 'mergify[bot]' }} | |
| runs-on: ubuntu-latest | |
| name: Documentation path filter | |
| permissions: | |
| contents: read | |
| pull-requests: read | |
| outputs: | |
| doc: ${{ steps.filter.outputs.doc }} | |
| non_doc: ${{ steps.filter.outputs.non_doc }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v5 | |
| with: | |
| fetch-depth: 0 | |
| - uses: dorny/paths-filter@v4 | |
| id: filter | |
| with: | |
| filters: | | |
| doc: | |
| - 'doc/**' | |
| non_doc: | |
| - '**' | |
| - '!doc/**' | |
| Prepare-MIB-Cache: | |
| needs: doc-path-filter | |
| if: ${{ needs.doc-path-filter.outputs.non_doc == 'true' }} | |
| runs-on: ubuntu-latest | |
| name: Prepare shared MIB cache | |
| timeout-minutes: 20 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v5 | |
| with: | |
| fetch-depth: 1 | |
| - name: Ensure local MIB cache directory exists | |
| run: mkdir -p docker/ubuntu-ci/mib-cache | |
| - name: Restore cached MIB files | |
| uses: actions/cache@v5 | |
| with: | |
| path: docker/ubuntu-ci/mib-cache | |
| key: mib-cache-v1-ubuntu24 | |
| - name: Populate missing MIB cache files | |
| run: | | |
| set -euo pipefail | |
| fetch_to_cache() { | |
| src_url="$1" | |
| cache_name="$2" | |
| dest_path="docker/ubuntu-ci/mib-cache/${cache_name}" | |
| if [ -s "${dest_path}" ]; then | |
| echo "Using cached ${cache_name}" | |
| return 0 | |
| fi | |
| attempt=1 | |
| max_attempts=8 | |
| while [ "${attempt}" -le "${max_attempts}" ]; do | |
| wget --tries=1 --timeout=30 --retry-connrefused "${src_url}" -O "${dest_path}.tmp" && mv "${dest_path}.tmp" "${dest_path}" && return 0 | |
| rm -f "${dest_path}.tmp" | |
| sleep_time=$((attempt * 5)) | |
| echo "Retrying cache fetch (${attempt}/${max_attempts}) for ${cache_name} in ${sleep_time}s" >&2 | |
| sleep "${sleep_time}" | |
| attempt=$((attempt + 1)) | |
| done | |
| rm -f "${dest_path}.tmp" "${dest_path}" | |
| echo "ERROR: Failed to cache ${cache_name} from ${src_url}" >&2 | |
| return 1 | |
| } | |
| fetch_to_cache https://www.iana.org/assignments/ianasmf-mib/ianasmf-mib IANA-SMF-MIB | |
| fetch_to_cache https://www.iana.org/assignments/ianaentity-mib/ianaentity-mib IANA-ENTITY-MIB | |
| fetch_to_cache https://www.iana.org/assignments/ianapowerstateset-mib/ianapowerstateset-mib IANAPowerStateSet-MIB | |
| fetch_to_cache https://www.iana.org/assignments/ianaolsrv2linkmetrictype-mib/ianaolsrv2linkmetrictype-mib IANA-OLSRv2-LINK-METRIC-TYPE-MIB | |
| fetch_to_cache https://www.iana.org/assignments/ianaenergyrelation-mib/ianaenergyrelation-mib IANA-ENERGY-RELATION-MIB | |
| fetch_to_cache https://www.iana.org/assignments/ianabfdtcstd-mib/ianabfdtcstd-mib IANA-BFD-TC-STD-MIB | |
| fetch_to_cache https://www.iana.org/assignments/ianastoragemediatype-mib/ianastoragemediatype-mib IANA-STORAGE-MEDIA-TYPE-MIB | |
| fetch_to_cache https://www.ieee802.org/1/files/public/MIBs/IEEE8021-CFM-MIB.mib IEEE8021-CFM-MIB | |
| fetch_to_cache https://www.ieee802.org/1/files/public/MIBs/LLDP-MIB-200505060000Z.mib LLDP-MIB | |
| Documentation-HTML: | |
| needs: doc-path-filter | |
| if: ${{ needs.doc-path-filter.outputs.doc == 'true' }} | |
| runs-on: ubuntu-latest | |
| name: HTML documentation (user + developer) | |
| timeout-minutes: 20 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v5 | |
| with: | |
| fetch-depth: 1 | |
| - name: Install Sphinx dependencies | |
| run: | | |
| set -euo pipefail | |
| sudo apt-get update -y | |
| sudo apt-get install -y python3-sphinx python3-sphinx-rtd-theme graphviz | |
| - name: Build HTML documentation | |
| run: | | |
| set -euo pipefail | |
| python3 -m sphinx -b html -d doc/user/_build/.doctrees \ | |
| doc/user doc/user/_build/html | |
| python3 -m sphinx -b html -d doc/developer/_build/.doctrees \ | |
| doc/developer doc/developer/_build/html | |
| - name: Stage HTML for artifact | |
| run: | | |
| set -euo pipefail | |
| mkdir -p artifact | |
| cp -a doc/user/_build/html artifact/user | |
| cp -a doc/developer/_build/html artifact/developer | |
| - name: Upload HTML documentation | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: documentation-html | |
| path: artifact/ | |
| retention-days: 14 | |
| if-no-files-found: error | |
| Build: | |
| runs-on: ${{ matrix.cfg.os }} | |
| needs: Prepare-MIB-Cache | |
| name: ${{ matrix.cfg.name }} | |
| # Guardrail in case a build leg hangs. | |
| timeout-minutes: 45 | |
| strategy: | |
| # Keep all matrix legs running so we get full failure signal. | |
| fail-fast: false | |
| matrix: | |
| # cache_base controls Buildx cache sharing across related variants. | |
| # Most legs use their own scope; LTTng reuses the amd64_u24 base scope. | |
| cfg: | |
| - { os: 'ubuntu-latest', rel: '22.04', name: 'Ubuntu 22.04 amd64 Build', platform: 'amd64_u22', cache_base: 'amd64_u22' } | |
| - { os: 'ubuntu-latest', rel: '24.04', name: 'Ubuntu 24.04 amd64 Build', platform: 'amd64_u24', cache_base: 'amd64_u24' } | |
| - { os: 'ubuntu-22.04-arm', rel: '22.04', name: 'Ubuntu 22.04 arm64 Build', platform: 'arm64_u22', cache_base: 'arm64_u22' } | |
| - { os: 'ubuntu-22.04-arm', rel: '24.04', name: 'Ubuntu 24.04 arm64 Build', platform: 'arm64_u24', cache_base: 'arm64_u24' } | |
| - { os: 'ubuntu-latest', rel: '24.04', name: 'Ubuntu 24.04 amd64 LTTng Build', platform: 'amd64_u24_lttng', cache_base: 'amd64_u24', lttng: 'true' } | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v5 | |
| with: | |
| fetch-depth: 1 | |
| - name: Ensure local MIB cache directory exists | |
| run: mkdir -p docker/ubuntu-ci/mib-cache | |
| - name: Restore cached MIB files | |
| if: ${{ matrix.cfg.rel == '24.04' }} | |
| uses: actions/cache/restore@v5 | |
| with: | |
| path: docker/ubuntu-ci/mib-cache | |
| key: mib-cache-v1-ubuntu24 | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v3 | |
| - name: Build docker image (cached) | |
| uses: docker/build-push-action@v6 | |
| env: | |
| # Temporary diagnostic to make Buildx cache behavior visible in job summary. | |
| DOCKER_BUILD_SUMMARY: true | |
| with: | |
| context: . | |
| file: docker/ubuntu-ci/Dockerfile | |
| tags: frr-${{ matrix.cfg.platform }} | |
| build-args: | | |
| UBUNTU_VERSION=${{ matrix.cfg.rel }} | |
| ENABLE_LTTNG=${{ matrix.cfg.lttng || 'false' }} | |
| FRR_SOURCE_REV=${{ github.sha }} | |
| # Keep existing test flow: export as docker image tar artifact. | |
| outputs: type=docker,dest=/tmp/frr-${{ matrix.cfg.platform }}.tar | |
| # Reuse/persist BuildKit layers per CI platform variant. | |
| cache-from: type=gha,scope=github-ci-${{ matrix.cfg.cache_base }} | |
| cache-to: type=gha,mode=max,scope=github-ci-${{ matrix.cfg.cache_base }} | |
| - name: Upload docker image artifact | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: ${{ matrix.cfg.platform }}-image | |
| path: /tmp/frr-${{ matrix.cfg.platform }}.tar | |
| # Docker images are intermediate CI artifacts; keep for a short period. | |
| retention-days: 7 | |
| if-no-files-found: error | |
| - name: Clear any previous results | |
| # So if all jobs are re-run then all tests will be re-run | |
| run: | | |
| rm -rf test-results-${{ matrix.cfg.platform }}* | |
| mkdir -p test-results-${{ matrix.cfg.platform }} | |
| touch test-results-${{ matrix.cfg.platform }}/cleared-results.txt | |
| - name: Save cleared previous results | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: test-results-${{ matrix.cfg.platform }} | |
| path: test-results-${{ matrix.cfg.platform }} | |
| overwrite: true | |
| retention-days: 14 | |
| if-no-files-found: error | |
| - name: Cleanup | |
| if: ${{ always() }} | |
| run: rm -rf test-results-${{ matrix.cfg.platform }}* /tmp/frr-${{ matrix.cfg.platform }}.tar | |
| Test: | |
| runs-on: ${{ matrix.cfg.os }} | |
| needs: Build | |
| name: ${{ matrix.cfg.name }} | |
| # Topotest runs can be long; still cap runtime for stuck jobs. | |
| timeout-minutes: 180 | |
| strategy: | |
| # Keep running remaining platforms when one leg fails. | |
| fail-fast: false | |
| matrix: | |
| cfg: | |
| - { os: 'ubuntu-latest', rel: '22.04', name: 'Ubuntu 22.04 amd64 Test',platform : 'amd64_u22' } | |
| - { os: 'ubuntu-latest' ,rel: '24.04', name: 'Ubuntu 24.04 amd64 Test',platform : 'amd64_u24' } | |
| - { os: 'ubuntu-22.04-arm' ,rel: '22.04', name: 'Ubuntu 22.04 arm64 Test',platform : 'arm64_u22' } | |
| - { os: 'ubuntu-22.04-arm' ,rel: '24.04', name: 'Ubuntu 24.04 arm64 Test',platform : 'arm64_u24' } | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v5 | |
| with: | |
| fetch-depth: 1 | |
| - name: Fetch docker image artifact | |
| uses: actions/download-artifact@v7 | |
| with: | |
| name: ${{ matrix.cfg.platform }}-image | |
| path: /tmp | |
| - name: Fetch previous results | |
| if: ${{ github.run_attempt > 1 }} | |
| uses: actions/download-artifact@v7 | |
| with: | |
| name: test-results-${{ matrix.cfg.platform }} | |
| path: test-results-${{ matrix.cfg.platform }} | |
| - name: Run topotests | |
| run: | | |
| # Fail fast on command errors, undefined vars, and pipeline failures. | |
| set -euo pipefail | |
| uname -a | |
| MODPKGVER=$(uname -r) | |
| # Retry loop for apt-get update in case of transient mirror failures | |
| APT_RETRIES=3 | |
| for i in $(seq 1 ${APT_RETRIES}); do sudo apt-get update -y && break || sleep 10; done | |
| # Retry install as well; mirrors can fail between update and install. | |
| install_ok=0 | |
| for i in $(seq 1 ${APT_RETRIES}); do | |
| sudo apt-get install -y linux-modules-extra-azure linux-modules-${MODPKGVER} linux-modules-extra-${MODPKGVER} python3-xmltodict && install_ok=1 && break || sleep 10 | |
| done | |
| [ "${install_ok}" -eq 1 ] || { echo "ERROR: apt-get install failed after ${APT_RETRIES} attempts" >&2; exit 1; } | |
| # Github is running old kernels but installing newer packages :( | |
| sudo modprobe vrf || true | |
| sudo modprobe mpls-iptunnel | |
| sudo modprobe mpls-router | |
| docker load --input /tmp/frr-${{ matrix.cfg.platform }}.tar | |
| ADD_DOCKER_ENV="" | |
| if ! grep CONFIG_IP_MROUTE_MULTIPLE_TABLES=y /boot/config*; then | |
| ADD_DOCKER_ENV+="-e MROUTE_VRF_MISSING=1" | |
| fi | |
| echo "ADD_DOCKER_ENV: ${ADD_DOCKER_ENV}" | |
| if [ -f test-results-${{ matrix.cfg.platform }}/topotests.xml ]; then | |
| ./tests/topotests/analyze.py -r test-results-${{ matrix.cfg.platform }} | |
| ls -l test-results-${{ matrix.cfg.platform }}/topotests.xml | |
| run_tests=$(./tests/topotests/analyze.py -r test-results-${{ matrix.cfg.platform }}| cut -f1 -d: | sort -u) | |
| else | |
| echo "No test results dir" | |
| run_tests="" | |
| fi | |
| rm -rf test-results-${{ matrix.cfg.platform }}* /tmp/topotests | |
| echo RUN_TESTS: $run_tests | |
| if docker run --init -i --privileged --name frr-${{ matrix.cfg.platform }}-cont ${ADD_DOCKER_ENV} -v /lib/modules:/lib/modules frr-${{ matrix.cfg.platform }} \ | |
| bash -c 'cd ~/frr/tests/topotests ; sudo -E pytest -n$(($(nproc) * 5 / 2)) --dist=loadfile '$run_tests; then | |
| echo "All tests passed." | |
| exit 0 | |
| fi | |
| # Grab the results from the container | |
| if ! ./tests/topotests/analyze.py -Ar test-results-${{ matrix.cfg.platform }} -C frr-${{ matrix.cfg.platform }}-cont; then | |
| if [ ! -d test-results-${{ matrix.cfg.platform }} ]; then | |
| echo "ERROR: Basic failure in docker run, no test results directory available." >&2 | |
| exit 1; | |
| fi | |
| if [ ! -f test-results-${{ matrix.cfg.platform }}/topotests.xml ]; then | |
| # In this case we may be missing topotests.xml | |
| echo "ERROR: No topotests.xml available perhaps docker run aborted?" >&2 | |
| exit 1; | |
| fi | |
| echo "WARNING: analyze.py returned error but grabbed results anyway." >&2 | |
| fi | |
| # Save some information useful for debugging | |
| cp /boot/config* test-results-${{ matrix.cfg.platform }}/ | |
| sysctl -a > test-results-${{ matrix.cfg.platform }}/sysctl.out 2> /dev/null | |
| # Now get the failed tests (if any) from the archived results directory. | |
| rerun_tests=$(./tests/topotests/analyze.py -r test-results-${{ matrix.cfg.platform }} | cut -f1 -d: | sort -u) | |
| if [ -z "$rerun_tests" ]; then | |
| echo "ERROR: Parallel pytest run failed but no failures found in topotests.xml." >&2 | |
| exit 1 | |
| fi | |
| echo "ERROR: Some tests failed during parallel run, rerunning serially." >&2 | |
| echo RERUN_TESTS: $rerun_tests >&2 | |
| docker stop frr-${{ matrix.cfg.platform }}-cont | |
| docker rm frr-${{ matrix.cfg.platform }}-cont | |
| mv test-results-${{ matrix.cfg.platform }} test-results-${{ matrix.cfg.platform }}-initial | |
| if docker run --init -i --privileged --name frr-${{ matrix.cfg.platform }}-cont ${ADD_DOCKER_ENV} -v /lib/modules:/lib/modules frr-${{ matrix.cfg.platform }} \ | |
| bash -c 'cd ~/frr/tests/topotests ; sudo -E pytest '$rerun_tests; then | |
| echo "All rerun tests passed." | |
| exit 0 | |
| fi | |
| echo "Some rerun tests still failed." | |
| exit 1 | |
| - name: Gather results | |
| if: ${{ always() }} | |
| run: | | |
| if [ ! -d test-results-${{ matrix.cfg.platform }} ]; then | |
| if ! ./tests/topotests/analyze.py -Ar test-results-${{ matrix.cfg.platform }} -C frr-${{ matrix.cfg.platform }}-cont; then | |
| echo "ERROR: gathering results produced an error, perhaps due earlier run cancellation." >&2 | |
| fi | |
| fi | |
| - name: Upload test results | |
| if: ${{ always() }} | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: test-results-${{ matrix.cfg.platform }} | |
| path: | | |
| test-results-${{ matrix.cfg.platform }} | |
| test-results-${{ matrix.cfg.platform }}-initial | |
| overwrite: true | |
| # Keep test artifacts longer to aid flaky test/debug investigations. | |
| retention-days: 14 | |
| if-no-files-found: warn | |
| - name: Cleanup | |
| if: ${{ always() }} | |
| run: | | |
| rm -rf test-results-${{ matrix.cfg.platform }}* /tmp/frr-${{ matrix.cfg.platform }}.tar | |
| docker stop frr-${{ matrix.cfg.platform }}-cont || true | |
| docker rm frr-${{ matrix.cfg.platform }}-cont || true |