diff --git a/.github/dependabot.yml b/.github/dependabot.yml index cc5bb5a6e9c..c90c7c6b185 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -7,6 +7,8 @@ updates: open-pull-requests-limit: 5 ignore: - dependency-name: "k8s.io/*" + - dependency-name: "sigs.k8s.io/*" + - dependency-name: "github.com/containernetworking/*" - dependency-name: "github.com/vmware/go-ipfix" - dependency-name: "github.com/TomCodeLV/OVSDB-golang-lib" - dependency-name: "github.com/vmware-tanzu/octant" diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index e162bac0eb1..2ff0fba4217 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Set up Go 1.17 - uses: actions/setup-go@v2 + uses: actions/setup-go@v3 with: go-version: 1.17 diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 394e150cde6..ad31cfeef8c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -5,10 +5,12 @@ on: branches: - main - release-* + - feature/* push: branches: - main - release-* + - feature/* jobs: check-changes: diff --git a/.github/workflows/clair.yml b/.github/workflows/clair.yml index 15118916539..beb632c02be 100644 --- a/.github/workflows/clair.yml +++ b/.github/workflows/clair.yml @@ -11,7 +11,7 @@ jobs: runs-on: [ubuntu-latest] steps: - uses: actions/checkout@v3 - - uses: actions/setup-go@v2 + - uses: actions/setup-go@v3 with: go-version: 1.17 - name: Scan Antrea Docker image for vulnerabilities @@ -23,7 +23,7 @@ jobs: ./ci/clair-scan/run.sh ./clair-reports - name: Upload Clair scan reports if: ${{ always() }} - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: name: clair-scan-reports path: clair-reports/*.json diff --git a/.github/workflows/dependabot.yml b/.github/workflows/dependabot.yml index c0014e72916..8baeffeacc3 100644 --- a/.github/workflows/dependabot.yml +++ b/.github/workflows/dependabot.yml @@ -32,7 +32,7 @@ jobs: runs-on: [ubuntu-latest] steps: - name: Set up Go 1.17 - uses: actions/setup-go@v2 + uses: actions/setup-go@v3 with: go-version: 1.17 - uses: actions/checkout@v3 diff --git a/.github/workflows/docker_update_ethtool.yml b/.github/workflows/docker_update_ethtool.yml index 8ec7637d3d3..0d7bbdd713a 100644 --- a/.github/workflows/docker_update_ethtool.yml +++ b/.github/workflows/docker_update_ethtool.yml @@ -26,16 +26,16 @@ jobs: with: ref: ${{ github.event.inputs.antrea-ref }} - name: Set up QEMU - uses: docker/setup-qemu-action@v1 + uses: docker/setup-qemu-action@v2 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v1 + uses: docker/setup-buildx-action@v2 - name: Login to DockerHub - uses: docker/login-action@v1 + uses: docker/login-action@v2 with: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }} - name: Build and push Docker image - uses: docker/build-push-action@v2 + uses: docker/build-push-action@v3 with: context: build/images/ethtool platforms: linux/amd64,linux/arm64,linux/arm/v7 diff --git a/.github/workflows/docker_update_flow_visibility.yml b/.github/workflows/docker_update_flow_visibility.yml index 0784213c8b2..95e81832508 100644 --- a/.github/workflows/docker_update_flow_visibility.yml +++ b/.github/workflows/docker_update_flow_visibility.yml @@ -22,7 +22,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Login to DockerHub - uses: docker/login-action@v1 + uses: docker/login-action@v2 with: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }} diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 559e48b2f26..b8a1412f9be 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -4,10 +4,12 @@ on: branches: - main - release-* + - feature/* push: branches: - main - release-* + - feature/* env: go-cache-name: go @@ -37,7 +39,7 @@ jobs: runs-on: ${{ matrix.os }} steps: - name: Set up Go 1.17 - uses: actions/setup-go@v2 + uses: actions/setup-go@v3 with: go-version: 1.17 - name: Check-out code @@ -59,7 +61,7 @@ jobs: - name: Run unit tests run: make test-unit - name: Codecov - uses: codecov/codecov-action@v1 + uses: codecov/codecov-action@v3 with: token: ${{ secrets.CODECOV_TOKEN }} file: .coverage/coverage-unit.txt @@ -76,7 +78,7 @@ jobs: runs-on: ${{ matrix.platform }} steps: - name: Set up Go 1.17 - uses: actions/setup-go@v2 + uses: actions/setup-go@v3 with: go-version: 1.17 - name: Check-out code @@ -108,7 +110,7 @@ jobs: runs-on: [ubuntu-latest] steps: - name: Set up Go 1.17 - uses: actions/setup-go@v2 + uses: actions/setup-go@v3 with: go-version: 1.17 - name: Check-out code @@ -147,7 +149,7 @@ jobs: runs-on: [ubuntu-latest] steps: - name: Set up Go 1.17 - uses: actions/setup-go@v2 + uses: actions/setup-go@v3 with: go-version: 1.17 - name: Check-out code @@ -176,7 +178,7 @@ jobs: runs-on: [ubuntu-latest] steps: - name: Set up Go 1.17 - uses: actions/setup-go@v2 + uses: actions/setup-go@v3 with: go-version: 1.17 - name: Check-out code @@ -196,7 +198,7 @@ jobs: runs-on: [ubuntu-latest] steps: - name: Set up Go 1.17 - uses: actions/setup-go@v2 + uses: actions/setup-go@v3 with: go-version: 1.17 - name: Check-out code @@ -204,15 +206,26 @@ jobs: - name: Run verify scripts run: make verify - name: Checking for broken Markdown links + if: ${{ github.event_name == 'pull_request' }} uses: gaurav-nelson/github-action-markdown-link-check@v1 with: - folder-path: './docs' - file-path: './README.md, ./CHANGELOG.md, ./CONTRIBUTING.md, ./GOVERNANCE.md, ./MAINTAINERS.md, ./ROADMAP.md, ./SECURITY.md' + # Check modified files only for pull requests. Cronjob "Verify docs" takes care of checking all markdown files. + check-modified-files-only: yes + base-branch: ${{ github.base_ref }} config-file: 'hack/.md_links_config.json' - name: Markdownlint run: | sudo npm install -g markdownlint-cli@0.31.1 make markdownlint + - name: Checking whether autogenerated Helm chart documentation is up-to-date + working-directory: build/charts/ + run: | + make helm-docs + DIFF=$(git diff .) + if [ -n "$DIFF" ]; then + echo "The Helm chart documentation is out-of-date; please run 'make helm-docs' in 'build/charts/' and commit the changes" + exit 1 + fi benchmark: needs: check-changes @@ -221,7 +234,7 @@ jobs: runs-on: [ubuntu-latest] steps: - name: Set up Go 1.17 - uses: actions/setup-go@v2 + uses: actions/setup-go@v3 with: go-version: 1.17 - name: Check-out code diff --git a/.github/workflows/golicense.yml b/.github/workflows/golicense.yml index 4c7ecdf598e..2d8ab81ff09 100644 --- a/.github/workflows/golicense.yml +++ b/.github/workflows/golicense.yml @@ -4,10 +4,12 @@ on: branches: - main - release-* + - feature/* push: branches: - main - release-* + - feature/* release: types: - created @@ -33,7 +35,7 @@ jobs: runs-on: [ubuntu-latest] steps: - name: Set up Go 1.17 - uses: actions/setup-go@v2 + uses: actions/setup-go@v3 with: go-version: 1.17 - uses: actions/checkout@v3 @@ -59,7 +61,7 @@ jobs: ./ci/golicense/run.sh ./antrea-bins ./license-reports - name: Upload licensing information if: ${{ always() }} - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: name: licenses.deps path: license-reports/ALL.deps.txt diff --git a/.github/workflows/kind.yml b/.github/workflows/kind.yml index 0f09464591d..3ba9f45a4bb 100644 --- a/.github/workflows/kind.yml +++ b/.github/workflows/kind.yml @@ -4,13 +4,15 @@ on: branches: - main - release-* + - feature/* push: branches: - main - release-* + - feature/* env: - KIND_VERSION: v0.11.1 + KIND_VERSION: v0.12.0 jobs: check-changes: @@ -40,7 +42,7 @@ jobs: - name: Save Antrea image to tarball run: docker save -o antrea-ubuntu.tar antrea/antrea-ubuntu-coverage:latest - name: Upload Antrea image for subsequent jobs - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: name: antrea-ubuntu-cov path: antrea-ubuntu.tar @@ -57,7 +59,7 @@ jobs: - name: Save Flow Aggregator image to tarball run: docker save -o flow-aggregator.tar antrea/flow-aggregator-coverage:latest - name: Upload Flow Aggregator image for subsequent jobs - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: name: flow-aggregator-cov path: flow-aggregator.tar @@ -65,7 +67,7 @@ jobs: test-e2e-encap: name: E2e tests on a Kind cluster on Linux - needs: [build-antrea-coverage-image, build-flow-aggregator-coverage-image] + needs: [build-antrea-coverage-image] runs-on: [ubuntu-latest] steps: - name: Free disk space @@ -74,15 +76,14 @@ jobs: sudo apt-get clean df -h - uses: actions/checkout@v3 - - uses: actions/setup-go@v2 + - uses: actions/setup-go@v3 with: go-version: 1.17 - name: Download Antrea images from previous jobs - uses: actions/download-artifact@v2 + uses: actions/download-artifact@v3 - name: Load Antrea image run: | docker load -i antrea-ubuntu-cov/antrea-ubuntu.tar - docker load -i flow-aggregator-cov/flow-aggregator.tar - name: Install Kind run: | curl -Lo ./kind https://github.com/kubernetes-sigs/kind/releases/download/${KIND_VERSION}/kind-$(uname)-amd64 @@ -96,13 +97,13 @@ jobs: - name: Tar coverage files run: tar -czf test-e2e-encap-coverage.tar.gz test-e2e-encap-coverage - name: Upload coverage for test-e2e-encap-coverage - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: name: test-e2e-encap-coverage path: test-e2e-encap-coverage.tar.gz retention-days: 30 - name: Codecov - uses: codecov/codecov-action@v1 + uses: codecov/codecov-action@v3 with: token: ${{ secrets.CODECOV_TOKEN }} file: '*.cov.out*' @@ -113,7 +114,7 @@ jobs: if: ${{ failure() }} run: tar -czf log.tar.gz log - name: Upload test log - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 if: ${{ failure() }} with: name: e2e-kind-encap.tar.gz @@ -122,7 +123,7 @@ jobs: test-e2e-encap-no-proxy: name: E2e tests on a Kind cluster on Linux with AntreaProxy disabled - needs: [build-antrea-coverage-image, build-flow-aggregator-coverage-image] + needs: [build-antrea-coverage-image] runs-on: [ubuntu-latest] steps: - name: Free disk space @@ -131,15 +132,14 @@ jobs: sudo apt-get clean df -h - uses: actions/checkout@v3 - - uses: actions/setup-go@v2 + - uses: actions/setup-go@v3 with: go-version: 1.17 - name: Download Antrea images from previous jobs - uses: actions/download-artifact@v2 + uses: actions/download-artifact@v3 - name: Load Antrea image run: | docker load -i antrea-ubuntu-cov/antrea-ubuntu.tar - docker load -i flow-aggregator-cov/flow-aggregator.tar - name: Install Kind run: | curl -Lo ./kind https://github.com/kubernetes-sigs/kind/releases/download/${KIND_VERSION}/kind-$(uname)-amd64 @@ -153,13 +153,13 @@ jobs: - name: Tar coverage files run: tar -czf test-e2e-encap-no-proxy-coverage.tar.gz test-e2e-encap-no-proxy-coverage - name: Upload coverage for test-e2e-encap-no-proxy-coverage - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: name: test-e2e-encap-no-proxy-coverage path: test-e2e-encap-no-proxy-coverage.tar.gz retention-days: 30 - name: Codecov - uses: codecov/codecov-action@v1 + uses: codecov/codecov-action@v3 with: token: ${{ secrets.CODECOV_TOKEN }} file: '*.cov.out*' @@ -170,7 +170,7 @@ jobs: if: ${{ failure() }} run: tar -czf log.tar.gz log - name: Upload test log - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 if: ${{ failure() }} with: name: e2e-kind-encap-no-proxy.tar.gz @@ -179,7 +179,7 @@ jobs: test-e2e-encap-proxy-all: name: E2e tests on a Kind cluster on Linux with AntreaProxy all Service support - needs: [ build-antrea-coverage-image, build-flow-aggregator-coverage-image ] + needs: [ build-antrea-coverage-image ] runs-on: [ ubuntu-latest ] steps: - name: Free disk space @@ -188,21 +188,14 @@ jobs: sudo apt-get clean df -h - uses: actions/checkout@v3 - - uses: actions/setup-go@v2 + - uses: actions/setup-go@v3 with: go-version: 1.17 - - name: Download Antrea image from previous job - uses: actions/download-artifact@v1 - with: - name: antrea-ubuntu-cov - - name: Download Flow Aggregator image from previous job - uses: actions/download-artifact@v1 - with: - name: flow-aggregator-cov + - name: Download Antrea images from previous jobs + uses: actions/download-artifact@v3 - name: Load Antrea image run: | docker load -i antrea-ubuntu-cov/antrea-ubuntu.tar - docker load -i flow-aggregator-cov/flow-aggregator.tar - name: Install Kind run: | curl -Lo ./kind https://github.com/kubernetes-sigs/kind/releases/download/${KIND_VERSION}/kind-$(uname)-amd64 @@ -216,13 +209,13 @@ jobs: - name: Tar coverage files run: tar -czf test-e2e-encap-proxy-all-coverage.tar.gz test-e2e-encap-proxy-all-coverage - name: Upload coverage for test-e2e-encap-proxy-all-coverage - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: name: test-e2e-encap-proxy-all-coverage path: test-e2e-encap-proxy-all-coverage.tar.gz retention-days: 30 - name: Codecov - uses: codecov/codecov-action@v1 + uses: codecov/codecov-action@v3 with: token: ${{ secrets.CODECOV_TOKEN }} file: '*.cov.out*' @@ -233,7 +226,7 @@ jobs: if: ${{ failure() }} run: tar -czf log.tar.gz log - name: Upload test log - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 if: ${{ failure() }} with: name: e2e-kind-encap-proxy-all.tar.gz @@ -242,7 +235,7 @@ jobs: test-e2e-noencap: name: E2e tests on a Kind cluster on Linux (noEncap) - needs: [build-antrea-coverage-image, build-flow-aggregator-coverage-image] + needs: [build-antrea-coverage-image] runs-on: [ubuntu-latest] steps: - name: Free disk space @@ -251,15 +244,14 @@ jobs: sudo apt-get clean df -h - uses: actions/checkout@v3 - - uses: actions/setup-go@v2 + - uses: actions/setup-go@v3 with: go-version: 1.17 - name: Download Antrea images from previous jobs - uses: actions/download-artifact@v2 + uses: actions/download-artifact@v3 - name: Load Antrea image run: | docker load -i antrea-ubuntu-cov/antrea-ubuntu.tar - docker load -i flow-aggregator-cov/flow-aggregator.tar - name: Install Kind run: | curl -Lo ./kind https://github.com/kubernetes-sigs/kind/releases/download/${KIND_VERSION}/kind-$(uname)-amd64 @@ -273,13 +265,13 @@ jobs: - name: Tar coverage files run: tar -czf test-e2e-noencap-coverage.tar.gz test-e2e-noencap-coverage - name: Upload coverage for test-e2e-noencap-coverage - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: name: test-e2e-noencap-coverage path: test-e2e-noencap-coverage.tar.gz retention-days: 30 - name: Codecov - uses: codecov/codecov-action@v1 + uses: codecov/codecov-action@v3 with: token: ${{ secrets.CODECOV_TOKEN }} file: '*.cov.out*' @@ -290,7 +282,7 @@ jobs: if: ${{ failure() }} run: tar -czf log.tar.gz log - name: Upload test log - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 if: ${{ failure() }} with: name: e2e-kind-noencap.tar.gz @@ -299,7 +291,7 @@ jobs: test-e2e-hybrid: name: E2e tests on a Kind cluster on Linux (hybrid) - needs: [build-antrea-coverage-image, build-flow-aggregator-coverage-image] + needs: [build-antrea-coverage-image] runs-on: [ubuntu-latest] steps: - name: Free disk space @@ -308,15 +300,14 @@ jobs: sudo apt-get clean df -h - uses: actions/checkout@v3 - - uses: actions/setup-go@v2 + - uses: actions/setup-go@v3 with: go-version: 1.17 - name: Download Antrea images from previous jobs - uses: actions/download-artifact@v2 + uses: actions/download-artifact@v3 - name: Load Antrea image run: | docker load -i antrea-ubuntu-cov/antrea-ubuntu.tar - docker load -i flow-aggregator-cov/flow-aggregator.tar - name: Install Kind run: | curl -Lo ./kind https://github.com/kubernetes-sigs/kind/releases/download/${KIND_VERSION}/kind-$(uname)-amd64 @@ -330,13 +321,13 @@ jobs: - name: Tar coverage files run: tar -czf test-e2e-hybrid-coverage.tar.gz test-e2e-hybrid-coverage - name: Upload coverage for test-e2e-hybrid-coverage - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: name: test-e2e-hybrid-coverage path: test-e2e-hybrid-coverage.tar.gz retention-days: 30 - name: Codecov - uses: codecov/codecov-action@v1 + uses: codecov/codecov-action@v3 with: token: ${{ secrets.CODECOV_TOKEN }} file: '*.cov.out*' @@ -347,7 +338,7 @@ jobs: if: ${{ failure() }} run: tar -czf log.tar.gz log - name: Upload test log - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 if: ${{ failure() }} with: name: e2e-kind-hybrid.tar.gz @@ -359,7 +350,7 @@ jobs: # test uses a Geneve overlay. test-e2e-encap-no-np: name: E2e tests on a Kind cluster on Linux with Antrea-native policies disabled - needs: [build-antrea-coverage-image, build-flow-aggregator-coverage-image] + needs: [build-antrea-coverage-image] runs-on: [ubuntu-latest] steps: - name: Free disk space @@ -368,15 +359,14 @@ jobs: sudo apt-get clean df -h - uses: actions/checkout@v3 - - uses: actions/setup-go@v2 + - uses: actions/setup-go@v3 with: go-version: 1.17 - name: Download Antrea images from previous jobs - uses: actions/download-artifact@v2 + uses: actions/download-artifact@v3 - name: Load Antrea image run: | docker load -i antrea-ubuntu-cov/antrea-ubuntu.tar - docker load -i flow-aggregator-cov/flow-aggregator.tar - name: Install Kind run: | curl -Lo ./kind https://github.com/kubernetes-sigs/kind/releases/download/${KIND_VERSION}/kind-$(uname)-amd64 @@ -390,13 +380,13 @@ jobs: - name: Tar coverage files run: tar -czf test-e2e-encap-no-np-coverage.tar.gz test-e2e-encap-no-np-coverage - name: Upload coverage for test-e2e-encap-no-np-coverage - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: name: test-e2e-encap-no-np-coverage path: test-e2e-encap-no-np-coverage.tar.gz retention-days: 30 - name: Codecov - uses: codecov/codecov-action@v1 + uses: codecov/codecov-action@v3 with: token: ${{ secrets.CODECOV_TOKEN }} file: '*.cov.out*' @@ -407,13 +397,70 @@ jobs: if: ${{ failure() }} run: tar -czf log.tar.gz log - name: Upload test log - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 if: ${{ failure() }} with: name: e2e-kind-encap-no-np.tar.gz path: log.tar.gz retention-days: 30 + test-e2e-flow-visibility: + name: E2e tests on a Kind cluster on Linux for Flow Visibility + needs: [build-antrea-coverage-image, build-flow-aggregator-coverage-image] + runs-on: [ubuntu-latest] + steps: + - name: Free disk space + # https://github.com/actions/virtual-environments/issues/709 + run: | + sudo apt-get clean + df -h + - uses: actions/checkout@v3 + - uses: actions/setup-go@v3 + with: + go-version: 1.17 + - name: Download Antrea images from previous jobs + uses: actions/download-artifact@v3 + - name: Load Antrea image + run: | + docker load -i antrea-ubuntu-cov/antrea-ubuntu.tar + docker load -i flow-aggregator-cov/flow-aggregator.tar + - name: Install Kind + run: | + curl -Lo ./kind https://github.com/kubernetes-sigs/kind/releases/download/${KIND_VERSION}/kind-$(uname)-amd64 + chmod +x ./kind + sudo mv kind /usr/local/bin + - name: Run e2e tests + run: | + mkdir log + mkdir test-e2e-fa-coverage + ANTREA_LOG_DIR=$PWD/log ANTREA_COV_DIR=$PWD/test-e2e-fa-coverage ./ci/kind/test-e2e-kind.sh --encap-mode encap --coverage --flow-visibility + - name: Tar coverage files + run: tar -czf test-e2e-fa-coverage.tar.gz test-e2e-fa-coverage + - name: Upload coverage for test-e2e-fa-coverage + uses: actions/upload-artifact@v3 + with: + name: test-e2e-fa-coverage + path: test-e2e-fa-coverage.tar.gz + retention-days: 30 + - name: Codecov + uses: codecov/codecov-action@v3 + with: + token: ${{ secrets.CODECOV_TOKEN }} + file: '*.cov.out*' + flags: kind-e2e-tests + name: codecov-test-e2e-fa + directory: test-e2e-fa-coverage + - name: Tar log files + if: ${{ failure() }} + run: tar -czf log.tar.gz log + - name: Upload test log + uses: actions/upload-artifact@v3 + if: ${{ failure() }} + with: + name: e2e-kind-fa.tar.gz + path: log.tar.gz + retention-days: 30 + test-netpol-tmp: name: Run experimental network policy tests (netpol) on Kind cluster needs: build-antrea-coverage-image @@ -425,13 +472,14 @@ jobs: sudo apt-get clean df -h - uses: actions/checkout@v3 - - uses: actions/setup-go@v2 + - uses: actions/setup-go@v3 with: go-version: 1.17 - name: Download Antrea image from previous job - uses: actions/download-artifact@v1 + uses: actions/download-artifact@v3 with: name: antrea-ubuntu-cov + path: antrea-ubuntu-cov - name: Load Antrea image run: | docker load -i antrea-ubuntu-cov/antrea-ubuntu.tar @@ -460,13 +508,14 @@ jobs: sudo apt-get clean df -h - uses: actions/checkout@v3 - - uses: actions/setup-go@v2 + - uses: actions/setup-go@v3 with: go-version: 1.17 - name: Download Antrea image from previous job - uses: actions/download-artifact@v1 + uses: actions/download-artifact@v3 with: name: antrea-ubuntu-cov + path: antrea-ubuntu-cov - name: Load Antrea image run: | docker load -i antrea-ubuntu-cov/antrea-ubuntu.tar @@ -487,7 +536,7 @@ jobs: # yet. artifact-cleanup: name: Delete uploaded images - needs: [build-antrea-coverage-image, build-flow-aggregator-coverage-image, test-e2e-encap, test-e2e-encap-no-proxy, test-e2e-encap-proxy-all, test-e2e-noencap, test-e2e-hybrid, test-e2e-encap-no-np, test-netpol-tmp, validate-prometheus-metrics-doc] + needs: [build-antrea-coverage-image, build-flow-aggregator-coverage-image, test-e2e-encap, test-e2e-encap-no-proxy, test-e2e-encap-proxy-all, test-e2e-noencap, test-e2e-hybrid, test-e2e-encap-no-np, test-netpol-tmp, validate-prometheus-metrics-doc, test-e2e-flow-visibility] if: ${{ always() && (needs.build-antrea-coverage-image.result == 'success' || needs.build-flow-aggregator-coverage-image.result == 'success') }} runs-on: [ubuntu-latest] steps: diff --git a/.github/workflows/kind_upgrade.yml b/.github/workflows/kind_upgrade.yml index 03bb3df3431..ed6a24065c1 100644 --- a/.github/workflows/kind_upgrade.yml +++ b/.github/workflows/kind_upgrade.yml @@ -4,13 +4,15 @@ on: branches: - main - release-* + - feature/* push: branches: - main - release-* + - feature/* env: - KIND_VERSION: v0.11.1 + KIND_VERSION: v0.12.0 jobs: check-changes: @@ -40,7 +42,7 @@ jobs: - name: Save Antrea image to tarball run: docker save -o antrea-ubuntu.tar projects.registry.vmware.com/antrea/antrea-ubuntu:latest - name: Upload Antrea image for subsequent jobs - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: name: antrea-ubuntu path: antrea-ubuntu.tar @@ -59,13 +61,14 @@ jobs: sudo apt-get clean df -h - uses: actions/checkout@v3 - - uses: actions/setup-go@v2 + - uses: actions/setup-go@v3 with: go-version: 1.17 - name: Download Antrea image from previous job - uses: actions/download-artifact@v1 + uses: actions/download-artifact@v3 with: name: antrea-ubuntu + path: antrea-ubuntu - name: Load Antrea image run: docker load -i antrea-ubuntu/antrea-ubuntu.tar - name: Install Kind @@ -81,7 +84,7 @@ jobs: if: ${{ failure() }} run: tar -czf log.tar.gz log - name: Upload test log - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 if: ${{ failure() }} with: name: upgrade-from-antrea-version-n-1.tar.gz @@ -99,13 +102,14 @@ jobs: sudo apt-get clean df -h - uses: actions/checkout@v3 - - uses: actions/setup-go@v2 + - uses: actions/setup-go@v3 with: go-version: 1.17 - name: Download Antrea image from previous job - uses: actions/download-artifact@v1 + uses: actions/download-artifact@v3 with: name: antrea-ubuntu + path: antrea-ubuntu - name: Load Antrea image run: docker load -i antrea-ubuntu/antrea-ubuntu.tar - name: Install Kind @@ -121,7 +125,7 @@ jobs: if: ${{ failure() }} run: tar -czf log.tar.gz log - name: Upload test log - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 if: ${{ failure() }} with: name: upgrade-from-antrea-version-n-2.tar.gz @@ -139,13 +143,14 @@ jobs: sudo apt-get clean df -h - uses: actions/checkout@v3 - - uses: actions/setup-go@v2 + - uses: actions/setup-go@v3 with: go-version: 1.17 - name: Download Antrea image from previous job - uses: actions/download-artifact@v1 + uses: actions/download-artifact@v3 with: name: antrea-ubuntu + path: antrea-ubuntu - name: Load Antrea image run: docker load -i antrea-ubuntu/antrea-ubuntu.tar - name: Install Kind @@ -161,7 +166,7 @@ jobs: if: ${{ failure() }} run: tar -czf log.tar.gz log - name: Upload test log - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 if: ${{ failure() }} with: name: api-compatible-with-client-version-n-1.tar.gz @@ -179,13 +184,14 @@ jobs: sudo apt-get clean df -h - uses: actions/checkout@v3 - - uses: actions/setup-go@v2 + - uses: actions/setup-go@v3 with: go-version: 1.17 - name: Download Antrea image from previous job - uses: actions/download-artifact@v1 + uses: actions/download-artifact@v3 with: name: antrea-ubuntu + path: antrea-ubuntu - name: Load Antrea image run: docker load -i antrea-ubuntu/antrea-ubuntu.tar - name: Install Kind @@ -201,7 +207,7 @@ jobs: if: ${{ failure() }} run: tar -czf log.tar.gz log - name: Upload test log - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 if: ${{ failure() }} with: name: api-compatible-with-client-version-n-2.tar.gz diff --git a/.github/workflows/lifecycle_management.yml b/.github/workflows/lifecycle_management.yml index 36f38596e1c..81685e06fba 100644 --- a/.github/workflows/lifecycle_management.yml +++ b/.github/workflows/lifecycle_management.yml @@ -9,7 +9,7 @@ jobs: if: github.repository == 'antrea-io/antrea' runs-on: ubuntu-latest steps: - - uses: actions/stale@v4 + - uses: actions/stale@v5 with: repo-token: ${{ secrets.GITHUB_TOKEN }} stale-issue-message: 'This issue is stale because it has been open 90 days with no activity. Remove stale label or comment, or this will be closed in 90 days' diff --git a/.github/workflows/netpol_cyclonus.yml b/.github/workflows/netpol_cyclonus.yml index c3718029c76..a0cad16436c 100644 --- a/.github/workflows/netpol_cyclonus.yml +++ b/.github/workflows/netpol_cyclonus.yml @@ -5,7 +5,7 @@ on: - cron: '0 0 * * *' env: - KIND_VERSION: v0.11.1 + KIND_VERSION: v0.12.0 jobs: diff --git a/.github/workflows/upload_release_assets.yml b/.github/workflows/upload_release_assets.yml index 50060dd4c86..722b9b50490 100644 --- a/.github/workflows/upload_release_assets.yml +++ b/.github/workflows/upload_release_assets.yml @@ -10,7 +10,7 @@ jobs: runs-on: [ubuntu-latest] steps: - name: Set up Go 1.17 - uses: actions/setup-go@v2 + uses: actions/setup-go@v3 with: go-version: 1.17 - uses: actions/checkout@v3 diff --git a/.github/workflows/verify_docs.yml b/.github/workflows/verify_docs.yml new file mode 100644 index 00000000000..50dbf839cca --- /dev/null +++ b/.github/workflows/verify_docs.yml @@ -0,0 +1,30 @@ +name: Verify docs + +on: + schedule: + # every day at 9am + - cron: '0 9 * * *' + +jobs: + verify: + name: Verify docs and spelling + runs-on: [ubuntu-latest] + steps: + - name: Set up Go 1.17 + uses: actions/setup-go@v3 + with: + go-version: 1.17 + - name: Check-out code + uses: actions/checkout@v3 + - name: Run verify scripts + run: make verify + - name: Checking for broken Markdown links for main branch + uses: gaurav-nelson/github-action-markdown-link-check@v1 + with: + folder-path: './docs' + file-path: './README.md, ./CHANGELOG.md, ./CONTRIBUTING.md, ./GOVERNANCE.md, ./MAINTAINERS.md, ./ROADMAP.md, ./SECURITY.md' + config-file: 'hack/.md_links_config.json' + - name: Markdownlint + run: | + sudo npm install -g markdownlint-cli@0.31.1 + make markdownlint diff --git a/ADOPTERS.md b/ADOPTERS.md index 31b95397600..7d306e0412f 100644 --- a/ADOPTERS.md +++ b/ADOPTERS.md @@ -4,6 +4,14 @@ glasnostic.com      + +https://www.transwarp.io      + + +https://www.terasky.com      + ## Success Stories Below is a list of adopters of Antrea that have publicly shared the details @@ -17,6 +25,33 @@ teams can deploy reliably, prevent failure and assure the customer experience. We use Antrea's Open vSwitch support to tune how services interact in Kubernetes clusters. We are @glasnostic on Twitter. +**[Transwarp](https://www.transwarp.io)** + +Transwarp is committed to building enterprise-level big data infrastructure +software, providing enterprises with infrastructure software and supporting +around the whole data lifecycle to build a data world of the future. + +1. We use Antrea's AntreaClusterNetworkPolicy and AntreaNetworkPolicy to protect +big data software for every tenant of our kubernetes platform. +2. We use Antrea's Open vSwitch to support Pod-To-Pod network between flannel and +antrea clusters, and also between antrea clusters +3. We use Antrea's Open vSwitch to support Pod-To-Pod network between flannel and +antrea nodes in one cluster for upgrading. +4. We use Antrea's Egress feature to keep the original source ip to ensure +Internal Pods can get the real source IP of the request. + +You can contact us with mkt@transwarp.io + +**[TeraSky](https://terasky.com)** + +TeraSky is a Global Advanced Technology Solutions Provider. +Antrea is used in our internal Kubernetes clusters as well as by many of our customers. +Antrea helps us to apply a very strong and flexible security models in Kubernetes. +We are very heavily utilizing Antrea Cluster Network Policies, Antrea Network Policies, +and the Egress functionality. + +We are @TeraSkycom1 on Twitter. + ## Adding yourself as an Adopter It would be great to have your success story and logo on our list of diff --git a/CHANGELOG/CHANGELOG-1.2.md b/CHANGELOG/CHANGELOG-1.2.md index 3c2048d9df1..6e5c44624fe 100644 --- a/CHANGELOG/CHANGELOG-1.2.md +++ b/CHANGELOG/CHANGELOG-1.2.md @@ -1,5 +1,26 @@ # Changelog 1.2 +## 1.2.4 - 2022-04-29 + +### Changed +- Use iptables-wrapper in Antrea container. Now antrea-agent can work with distros that lack the iptables kernel module of "legacy" mode (ip_tables). ([#3276](https://github.com/antrea-io/antrea/pull/3276), [@antoninbas]) +- Reduce permissions of Antrea ServiceAccount for updating annotations. ([#3393](https://github.com/antrea-io/antrea/pull/3393), [@tnqn]) +- [Windows] Use uplink MAC as source MAC when transmitting packets to underlay network from Windows Nodes. Therefore, MAC address spoofing configuration like "Forged transmits" in VMware vSphere doesn't need to be enabled. ([#3516](https://github.com/antrea-io/antrea/pull/3516), [@wenyingd]) + +### Fixed +- Fix DNS resolution error of antrea-agent on AKS by using `ClusterFirst` dnsPolicy. ([#3701](https://github.com/antrea-io/antrea/pull/3701), [@tnqn]) +- Fix status report of Antrea-native policies with multiple rules that have different AppliedTo. ([#3074](https://github.com/antrea-io/antrea/pull/3074), [@tnqn]) +- Upgrade Go version to 1.17 to pick up security fix for CVE-2021-44716. ([#3189](https://github.com/antrea-io/antrea/pull/3189), [@antoninbas]) +- Fix NetworkPolicy resources dump for Agent's supportbundle. ([#3083](https://github.com/antrea-io/antrea/pull/3083), [@antoninbas]) +- Fix gateway interface MTU configuration error on Windows. ([#3043](https://github.com/antrea-io/antrea/pull/3043), [@lzhecheng]) [Windows] +- Fix initialization error of antrea-agent on Windows by specifying hostname explicitly in VMSwitch commands. ([#3169](https://github.com/antrea-io/antrea/pull/3169), [@XinShuYang]) [Windows] +- Ensure that the Windows Node name obtained from the environment or from hostname is converted to lower-case. ([#2672](https://github.com/antrea-io/antrea/pull/2672), [@shettyg]) [Windows] +- Fix typos in the example YAML in antrea-network-policy doc. ([#3079](https://github.com/antrea-io/antrea/pull/3079) [#3092](https://github.com/antrea-io/antrea/pull/3092), [@antoninbas] [@Jexf]) +- Fix ipBlock referenced in nested ClusterGroup not processed correctly. ([#3383](https://github.com/antrea-io/antrea/pull/3383), [@Dyanngg]) +- Fix NetworkPolicy may not be enforced correctly after restarting a Node. ([#3467](https://github.com/antrea-io/antrea/pull/3467), [@tnqn]) +- Fix antrea-agent crash caused by interface detection in AKS/EKS with NetworkPolicyOnly mode. ([#3219](https://github.com/antrea-io/antrea/pull/3219), [@wenyingd]) +- Fix locally generated packets from Node net namespace might be SNATed mistakenly when Egress is enabled. ([#3430](https://github.com/antrea-io/antrea/pull/3430), [@tnqn]) + ## 1.2.3 - 2021-09-24 ### Changed @@ -103,20 +124,23 @@ The NetworkPolicyStats feature is graduated from Alpha to Beta and is therefore [go-ipfix]: https://github.com/vmware/go-ipfix [whereabouts]: https://github.com/k8snetworkplumbingwg/whereabouts -[@abhiraut]: https://github.com/abhiraut -[@antoninbas]: https://github.com/antoninbas [@Dhruv-J]: https://github.com/Dhruv-J -[@dreamtalen]: https://github.com/dreamtalen [@Dyanngg]: https://github.com/Dyanngg [@GraysonWu]: https://github.com/GraysonWu +[@Jexf]: https://github.com/Jexf +[@PeterEltgroth]: https://github.com/PeterEltgroth +[@XinShuYang]: https://github.com/XinShuYang +[@abhiraut]: https://github.com/abhiraut +[@antoninbas]: https://github.com/antoninbas +[@dreamtalen]: https://github.com/dreamtalen [@hangyan]: https://github.com/hangyan [@hongliangl]: https://github.com/hongliangl [@liu4480]: https://github.com/liu4480 [@luolanzone]: https://github.com/luolanzone [@lzhecheng]: https://github.com/lzhecheng [@monotosh-avi]: https://github.com/monotosh-avi -[@PeterEltgroth]: https://github.com/PeterEltgroth [@ramay1]: https://github.com/ramay1 +[@shettyg]: https://github.com/shettyg [@srikartati]: https://github.com/srikartati [@tnqn]: https://github.com/tnqn [@wenqiq]: https://github.com/wenqiq diff --git a/CHANGELOG/CHANGELOG-1.5.md b/CHANGELOG/CHANGELOG-1.5.md index 163a614a1b4..5f301748ce7 100644 --- a/CHANGELOG/CHANGELOG-1.5.md +++ b/CHANGELOG/CHANGELOG-1.5.md @@ -1,5 +1,15 @@ # Changelog 1.5 +## 1.5.3 - 2022-05-12 + +### Fixed + +- Fix export/import of Services with named ports when using the Antrea Multi-cluster feature. ([#3561](https://github.com/antrea-io/antrea/pull/3561), [@luolanzone]) +- Fix handling of the "reject" packets generated by the Antrea Agent to avoid infinite looping. ([#3569](https://github.com/antrea-io/antrea/pull/3569), [@GraysonWu]) +- Fix DNS resolution error of Antrea Agent on AKS by using `ClusterFirst` dnsPolicy. ([#3701](https://github.com/antrea-io/antrea/pull/3701), [@tnqn]) +- Fix tolerations for Pods running on control-plane for Kubernetes >= 1.24. ([#3731](https://github.com/antrea-io/antrea/pull/3731), [@xliuxu]) +- Reduce permissions of Antrea Agent ServiceAccount. ([#3691](https://github.com/antrea-io/antrea/pull/3691), [@xliuxu]) + ## 1.5.2 - 2022-03-21 ### Fixed @@ -117,4 +127,5 @@ [@WenzelZ]: https://github.com/WenzelZ [@xiaoxiaobaba]: https://github.com/xiaoxiaobaba [@XinShuYang]: https://github.com/XinShuYang +[@xliuxu]: https://github.com/xliuxu [@yanjunz97]: https://github.com/yanjunz97 diff --git a/CHANGELOG/CHANGELOG-1.6.md b/CHANGELOG/CHANGELOG-1.6.md index 61d14f1b2b6..5ed64b8fad5 100644 --- a/CHANGELOG/CHANGELOG-1.6.md +++ b/CHANGELOG/CHANGELOG-1.6.md @@ -1,8 +1,26 @@ # Changelog 1.6 +## 1.6.1 - 2022-05-11 + +### Added + +- Add [documentation](https://github.com/antrea-io/antrea/blob/release-1.6/docs/security.md#protecting-your-cluster-against-privilege-escalations) for the Antrea Agent RBAC permissions and how to restrict them using Gatekeeper/OPA. ([#3694](https://github.com/antrea-io/antrea/pull/3694), [@antoninbas]) + +### Fixed + +- Clean up stale routes installed by AntreaProxy when ProxyAll is disabled. ([#3465](https://github.com/antrea-io/antrea/pull/3465), [@hongliangl]) +- Fix export/import of Services with named ports when using the Antrea Multi-cluster feature. ([#3561](https://github.com/antrea-io/antrea/pull/3561), [@luolanzone]) +- Fix handling of the "reject" packets generated by the Antrea Agent to avoid infinite looping. ([#3569](https://github.com/antrea-io/antrea/pull/3569), [@GraysonWu]) +- Fix DNS resolution error of Antrea Agent on AKS by using `ClusterFirst` dnsPolicy. ([#3701](https://github.com/antrea-io/antrea/pull/3701), [@tnqn]) +- Fix tolerations for Pods running on control-plane for Kubernetes >= 1.24. ([#3731](https://github.com/antrea-io/antrea/pull/3731), [@xliuxu]) +- Reduce permissions of Antrea Agent ServiceAccount. ([#3691](https://github.com/antrea-io/antrea/pull/3691), [@xliuxu]) +- [Windows] Ensure that Service traffic does not bypass NetworkPolicies when ProxyAll is enabled. ([#3510](https://github.com/antrea-io/antrea/pull/3510), [@hongliangl]) +- Fix Antrea wildcard FQDN NetworkPolicies not working when NodeLocal DNSCache is enabled. ([#3510](https://github.com/antrea-io/antrea/pull/3510), [@hongliangl]) + ## 1.6.0 - 2022-03-29 -The Egress feature is graduated from Alpha to Beta and is therefore enabled by default. +- The Egress feature is graduated from Alpha to Beta and is therefore enabled by default. +- The support for proxying all Service traffic by Antrea Proxy (enabled by `antreaProxy.proxyAll`) is now Beta. ### Added @@ -78,7 +96,7 @@ The Egress feature is graduated from Alpha to Beta and is therefore enabled by d - Fix CT mark matching without range in flow exporter. ([#3348](https://github.com/antrea-io/antrea/pull/3348), [@hongliangl]) - [Windows] Enable IP forwarding of the Windows bridge local interface to fix support for Service of type LoadBalancer. ([#3137](https://github.com/antrea-io/antrea/pull/3137), [@hongliangl]) -[Antrea Multi-cluster]: https://github.com/antrea-io/antrea/blob/v1.6.0/docs/multicluster/getting-started.md +[Antrea Multi-cluster]: https://github.com/antrea-io/antrea/blob/v1.6.0/docs/multicluster/user-guide.md [Antrea IPAM]: https://github.com/antrea-io/antrea/blob/v1.6.0/docs/antrea-ipam.md [AntreaPolicy]: https://github.com/antrea-io/antrea/blob/v1.6.0/docs/antrea-network-policy.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 60ce7aca971..f4fa7ce75ee 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -9,6 +9,7 @@ to effectively get it merged upstream. - [Getting Started](#getting-started) - [Accounts Setup](#accounts-setup) - [Contribute](#contribute) + - [Pre-Commit Hook](#pre-commit-hook) - [GitHub Workflow](#github-workflow) - [Getting reviewers](#getting-reviewers) - [Getting your PR verified by CI](#getting-your-pr-verified-by-ci) @@ -33,7 +34,6 @@ contributing to project Antrea: 2. Check out the [Architecture document](docs/design/architecture.md) for the Antrea architecture and design. 3. Set up necessary [accounts](#accounts-setup). -4. Set up your [development environment](docs/contributors/manual-installation.md) Now that you're setup, skip ahead to learn how to [contribute](#contribute). @@ -58,6 +58,13 @@ In order to help you get your hands "dirty", there is a list of [starter](https://github.com/antrea-io/antrea/labels/Good%20first%20issue) issues from which you can choose. +### Pre-Commit Hook + +There is a recommended pre-commit git hook which we advise you use. You can find +it here: +[hack/git_client_side_hooks/pre-commit](hack/git_client_side_hooks/pre-commit). +You can run `make install-hooks` to copy it to your local `.git/hooks/` folder, and remove it via `make uninstall-hooks` + ### GitHub Workflow Developers work in their own forked copy of the repository and when ready, diff --git a/Makefile b/Makefile index e5e672a1deb..ccd11ff1dc8 100644 --- a/Makefile +++ b/Makefile @@ -25,6 +25,16 @@ UNAME_S := $(shell uname -s) USERID := $(shell id -u) GRPID := $(shell id -g) +.PHONY: install-hooks +install-hooks: + @echo "===> Copying Antrea git hooks to local <===" + install hack/git_client_side_hooks/pre-commit .git/hooks/ + +.PHONY: uninstall-hooks +uninstall-hooks: + @echo "===> Removing Antrea git hooks from local <===" + rm .git/hooks/pre-commit + .PHONY: bin bin: @mkdir -p $(BINDIR) @@ -275,6 +285,11 @@ codegen: @echo "===> Updating generated code <===" $(CURDIR)/hack/update-codegen.sh +.PHONY: mockgen +mockgen: + @echo "===> Updating generated mock code <===" + $(CURDIR)/hack/update-codegen.sh mockgen + ### Docker images ### .PHONY: ubuntu @@ -346,11 +361,7 @@ build-scale-simulator: .PHONY: manifest manifest: @echo "===> Generating dev manifest for Antrea <===" - $(CURDIR)/hack/generate-manifest.sh --mode dev > build/yamls/antrea.yml - $(CURDIR)/hack/generate-manifest.sh --mode dev --ipsec > build/yamls/antrea-ipsec.yml - $(CURDIR)/hack/generate-manifest.sh --mode dev --cloud EKS --encap-mode networkPolicyOnly > build/yamls/antrea-eks.yml - $(CURDIR)/hack/generate-manifest.sh --mode dev --cloud GKE --encap-mode noEncap > build/yamls/antrea-gke.yml - $(CURDIR)/hack/generate-manifest.sh --mode dev --cloud AKS --encap-mode networkPolicyOnly > build/yamls/antrea-aks.yml + $(CURDIR)/hack/generate-standard-manifests.sh --mode dev --out build/yamls $(CURDIR)/hack/generate-manifest-octant.sh --mode dev > build/yamls/antrea-octant.yml $(CURDIR)/hack/generate-manifest-windows.sh --mode dev > build/yamls/antrea-windows.yml $(CURDIR)/hack/generate-manifest-flow-aggregator.sh --mode dev > build/yamls/flow-aggregator.yml @@ -434,12 +445,12 @@ toc: .PHONE: markdownlint markdownlint: @echo "===> Running markdownlint <===" - markdownlint -c .markdownlint-config.yml -i CHANGELOG/ -i CHANGELOG.md -i hack/netpol -i CODE_OF_CONDUCT.md . + markdownlint -c hack/.markdownlint-config.yml -p hack/.markdownlint-ignore . .PHONE: markdownlint-fix markdownlint-fix: @echo "===> Running markdownlint <===" - markdownlint --fix -c .markdownlint-config.yml -i CHANGELOG/ -i CHANGELOG.md -i hack/netpol -i CODE_OF_CONDUCT.md . + markdownlint --fix -c hack/.markdownlint-config.yml -p hack/.markdownlint-ignore . .PHONY: spelling-fix spelling-fix: diff --git a/README.md b/README.md index 05f4cd029ab..d1a7ab34283 100644 --- a/README.md +++ b/README.md @@ -98,12 +98,14 @@ Also check out [@ProjectAntrea](https://twitter.com/ProjectAntrea) on Twitter! analysis, flow inspection). It exposes Prometheus metrics and supports exporting network flow information which can be visualized in Kibana dashboards. -* **Encryption**: Encryption of inter-Node Pod traffic with IPsec tunnels when - using an overlay Pod network. +* **Encryption**: Encryption of inter-Node Pod traffic with IPsec or WireGuard + tunnels. * **Easy deployment**: Antrea is deployed by applying a single YAML manifest file. -Refer to the [Changelogs](CHANGELOG/README.md) for a detailed list of features +To explore more Antrea features and their usage, check the [Getting started](docs/getting-started.md#features) +document and user guides in the [Antrea documentation folder](docs/). Refer to +the [Changelogs](CHANGELOG/README.md) for a detailed list of features introduced for each version release. ## Adopters diff --git a/ROADMAP.md b/ROADMAP.md index 129a2fa1713..f8d2c3efdd8 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -39,13 +39,6 @@ enhance existing features and add new features to help diagnose K8s networking and NetworkPolicy implementation, and to provide good visibility into the Antrea network. -* **Flexible IPAM** -So far Antrea leverages K8s NodeIPAM for IPAM which allocates a single subnet -for each K8s Node. NodeIPAM can either run as part of the Antrea Controller, or -run within kube-controller-manager. -In future, Antrea will implement its own IPAM, and support more IPAM strategies -besides subnet per Node, like multiple IP pools per Node or per Namespace. - * **NFV and Telco use cases** We plan to explore and provide support for NFV and Telco use cases. We will add native Pod multi-interface support in Antrea, and support Pod interfaces on @@ -60,12 +53,17 @@ observability features to get into application level visibility. * **Multi-cluster networking** We would extend Antrea from CNI of a single Kubernetes cluster to multi-cluster networking, and implement multi-cluster features like multi-cluster Services, -cross-cluster connectivity, multi-cluster NetworkPolicies. +cross-cluster connectivity, multi-cluster NetworkPolicies. Antrea multi-cluster +functionalities are under active development. Check the [Antrea Multi-cluster +user guide](docs/multicluster/user-guide.md) to learn what features are already +supported. * **Analytics** With the network flows exported by Antrea, we plan to further build an analytics solution that consumes the network flows, and provides traffic analysis, -NetworkPolicy recommendation, security and network performance monitoring. +NetworkPolicy recommendation, security and network performance monitoring. We +already started a sub-project of Antrea - [Theia](https://github.com/antrea-io/theia) - +for network flow visibility and analytics. Stay tunned! * **K8s Node security** So far Antrea focuses on K8s Pod networking and security, but we would like to diff --git a/VERSION b/VERSION index b9b03961486..c172a83800b 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -v1.6.0-dev +v1.7.0-dev diff --git a/build/charts/Makefile b/build/charts/Makefile new file mode 100644 index 00000000000..608a7eafa98 --- /dev/null +++ b/build/charts/Makefile @@ -0,0 +1,6 @@ +USERID := $(shell id -u) +GRPID := $(shell id -g) + +.PHONY: helm-docs +helm-docs: + docker run --rm --volume "$(CURDIR):/helm-docs" --user=$(USERID):$(GRPID) jnorwood/helm-docs:v1.7.0 diff --git a/build/charts/antrea/.helmignore b/build/charts/antrea/.helmignore new file mode 100644 index 00000000000..0e8a0eb36f4 --- /dev/null +++ b/build/charts/antrea/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/build/charts/antrea/Chart.yaml b/build/charts/antrea/Chart.yaml new file mode 100644 index 00000000000..d835cf2b082 --- /dev/null +++ b/build/charts/antrea/Chart.yaml @@ -0,0 +1,18 @@ +apiVersion: v2 +name: antrea +type: application +displayName: Antrea +home: https://antrea.io/ +version: 1.17.0-dev +appVersion: 1.17.0-dev +kubeVersion: ">= 1.16.0-0" +icon: https://raw.githubusercontent.com/antrea-io/antrea/main/docs/assets/logo/antrea_logo.svg +description: Kubernetes networking based on Open vSwitch +keywords: + - Kubernetes + - CNCF + - Networking + - CNI + - Security +sources: + - https://github.com/antrea-io/antrea diff --git a/build/charts/antrea/README.md b/build/charts/antrea/README.md new file mode 100644 index 00000000000..d68c2d0faae --- /dev/null +++ b/build/charts/antrea/README.md @@ -0,0 +1,108 @@ +# antrea + +![Version: 1.17.0-dev](https://img.shields.io/badge/Version-1.17.0--dev-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 1.17.0-dev](https://img.shields.io/badge/AppVersion-1.17.0--dev-informational?style=flat-square) + +Kubernetes networking based on Open vSwitch + +**Homepage:** + +## Source Code + +* + +## Requirements + +Kubernetes: `>= 1.16.0-0` + +## Values + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| agent.affinity | object | `{}` | Affinity for the antrea-agent Pods. | +| agent.antreaAgent.extraArgs | list | `[]` | Extra command-line arguments for antrea-agent. | +| agent.antreaAgent.extraEnv | object | `{}` | Extra environment variables to be injected into antrea-agent. | +| agent.antreaAgent.extraVolumeMounts | list | `[]` | Additional volumeMounts for the antrea-agent container. | +| agent.antreaAgent.logFileMaxNum | int | `4` | Max number of log files. | +| agent.antreaAgent.logFileMaxSize | int | `100` | Max size in MBs of any single log file. | +| agent.antreaAgent.resources | object | `{"requests":{"cpu":"200m"}}` | Resource requests and limits for the antrea-agent container. | +| agent.antreaIPsec.resources | object | `{"requests":{"cpu":"50m"}}` | Resource requests and limits for the antrea-ipsec container (when IPsec is enabled). | +| agent.antreaOVS.extraArgs | list | `[]` | Extra command-line arguments for antrea-ovs. | +| agent.antreaOVS.logFileMaxNum | int | `4` | Max number of log files. | +| agent.antreaOVS.logFileMaxSize | int | `100` | Max size in MBs of any single log file. | +| agent.antreaOVS.resources | object | `{"requests":{"cpu":"200m"}}` | Resource requests and limits for the antrea-ovs container. | +| agent.apiPort | int | `10350` | Port for the antrea-agent APIServer to serve on. | +| agent.dnsPolicy | string | `"ClusterFirstWithHostNet"` | DNS Policy for the antrea-agent Pods. | +| agent.enablePrometheusMetrics | bool | `true` | Enable metrics exposure via Prometheus. | +| agent.extraVolumes | list | `[]` | Additional volumes for antrea-agent Pods. | +| agent.installCNI.resources | object | `{"requests":{"cpu":"100m"}}` | Resource requests and limits for the install-cni initContainer. | +| agent.nodeSelector | object | `{"kubernetes.io/os":"linux"}` | Node selector for the antrea-agent Pods. | +| agent.podAnnotations | object | `{}` | Annotations to be added to antrea-agent Pods. | +| agent.podLabels | object | `{}` | Labels to be added to antrea-agent Pods. | +| agent.priorityClassName | string | `"system-node-critical"` | Prority class to use for the antrea-agent Pods. | +| agent.tolerations | list | `[{"key":"CriticalAddonsOnly","operator":"Exists"},{"effect":"NoSchedule","operator":"Exists"},{"effect":"NoExecute","operator":"Exists"}]` | Tolerations for the antrea-agent Pods. | +| agent.updateStrategy | object | `{"type":"RollingUpdate"}` | Update strategy for the antrea-agent DaemonSet. | +| antreaProxy.nodePortAddresses | list | `[]` | String array of values which specifies the host IPv4/IPv6 addresses for NodePort. By default, all host addresses are used. | +| antreaProxy.proxyAll | bool | `false` | Proxy all Service traffic, for all Service types, regardless of where it comes from. | +| antreaProxy.proxyLoadBalancerIPs | bool | `true` | When set to false, AntreaProxy no longer load-balances traffic destined to the External IPs of LoadBalancer Services. | +| antreaProxy.skipServices | list | `[]` | | +| cni.hostBinPath | string | `"/opt/cni/bin"` | Installation path of CNI binaries on the host. | +| cni.plugins | object | `{"bandwidth":true,"portmap":true}` | Chained plugins to use alongside antrea-cni. | +| cni.skipBinaries | list | `[]` | CNI binaries shipped with Antrea for which installation should be skipped. | +| controller.affinity | object | `{}` | Affinity for the antrea-controller Pod. | +| controller.antreaController.extraArgs | list | `[]` | Extra command-line arguments for antrea-controller. | +| controller.antreaController.extraEnv | object | `{}` | Extra environment variables to be injected into antrea-controller. | +| controller.antreaController.logFileMaxNum | int | `4` | Max number of log files. | +| controller.antreaController.logFileMaxSize | int | `100` | Max size in MBs of any single log file. | +| controller.antreaController.resources | object | `{"requests":{"cpu":"200m"}}` | Resource requests and limits for the antrea-controller container. | +| controller.apiPort | int | `10349` | Port for the antrea-controller APIServer to serve on. | +| controller.enablePrometheusMetrics | bool | `true` | Enable metrics exposure via Prometheus. | +| controller.nodeSelector | object | `{"kubernetes.io/os":"linux"}` | Node selector for the antrea-controller Pod. | +| controller.podAnnotations | object | `{}` | Annotations to be added to antrea-controller Pod. | +| controller.podLabels | object | `{}` | Labels to be added to antrea-controller Pod. | +| controller.priorityClassName | string | `"system-cluster-critical"` | Prority class to use for the antrea-controller Pod. | +| controller.selfSignedCert | bool | `true` | Indicates whether to use auto-generated self-signed TLS certificates. If false, a Secret named "antrea-controller-tls" must be provided with the following keys: ca.crt, tls.crt, tls.key. | +| controller.tolerations | list | `[{"key":"CriticalAddonsOnly","operator":"Exists"},{"effect":"NoSchedule","key":"node-role.kubernetes.io/master"},{"effect":"NoSchedule","key":"node-role.kubernetes.io/control-plane"}]` | Tolerations for the antrea-controller Pod. | +| defaultMTU | int | `0` | Default MTU to use for the host gateway interface and the network interface of each Pod. By default, antrea-agent will discover the MTU of the Node's primary interface and adjust it to accommodate for tunnel encapsulation overhead if applicable. | +| disableTXChecksumOffload | bool | `false` | Disable TX checksum offloading for container network interfaces. It's supposed to be set to true when the datapath doesn't support TX checksum offloading, which causes packets to be dropped due to bad checksum. It affects Pods running on Linux Nodes only. | +| egress.exceptCIDRs | list | `[]` | CIDR ranges to which outbound Pod traffic will not be SNAT'd by Egresses. | +| enableBridgingMode | bool | `false` | Enable bridging mode of Pod network on Nodes, in which the Node's transport interface is connected to the OVS bridge. | +| featureGates | object | `{}` | To explicitly enable or disable a FeatureGate and bypass the Antrea defaults, add an entry to the dictionary with the FeatureGate's name as the key and a boolean as the value. | +| flowCollector.activeFlowExportTimeout | string | `"5s"` | timeout after which a flow record is sent to the collector for active flows. | +| flowCollector.collectorAddr | string | `"flow-aggregator.flow-aggregator.svc:4739:tls"` | IPFIX collector address as a string with format :[][:]. | +| flowCollector.flowPollInterval | string | `"5s"` | Determines how often the flow exporter polls for new connections. | +| flowCollector.idleFlowExportTimeout | string | `"15s"` | timeout after which a flow record is sent to the collector for idle flows. | +| hostGateway | string | `"antrea-gw0"` | Name of the interface antrea-agent will create and use for host <-> Pod communication. | +| image | object | `{"pullPolicy":"IfNotPresent","repository":"projects.registry.vmware.com/antrea/antrea-ubuntu","tag":"latest"}` | Container image to use for Antrea components. | +| ipsec.psk | string | `"changeme"` | Preshared Key (PSK) for IKE authentication. It will be stored in a secret and passed to antrea-agent as an environment variable. | +| kubeAPIServerOverride | string | `""` | Address of Kubernetes apiserver, to override any value provided in kubeconfig or InClusterConfig. | +| logVerbosity | int | `0` | | +| multicast.igmpQueryInterval | string | `"125s"` | The interval at which the antrea-agent sends IGMP queries to Pods. Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". | +| multicast.multicastInterfaces | list | `[]` | Names of the interfaces on Nodes that are used to forward multicast traffic. | +| noSNAT | bool | `false` | Whether or not to SNAT (using the Node IP) the egress traffic from a Pod to the external network. | +| nodeIPAM.clusterCIDRs | list | `[]` | CIDR ranges to use when allocating Pod IP addresses. | +| nodeIPAM.enable | bool | `false` | Enable Node IPAM in Antrea | +| nodeIPAM.nodeCIDRMaskSizeIPv4 | int | `24` | Mask size for IPv4 Node CIDR in IPv4 or dual-stack cluster. | +| nodeIPAM.nodeCIDRMaskSizeIPv6 | int | `64` | Mask size for IPv6 Node CIDR in IPv6 or dual-stack cluster. | +| nodeIPAM.serviceCIDR | string | `""` | IPv4 CIDR ranges reserved for Services. | +| nodeIPAM.serviceCIDRv6 | string | `""` | IPv6 CIDR ranges reserved for Services. | +| nodePortLocal.enable | bool | `false` | Enable the NodePortLocal feature. | +| nodePortLocal.portRange | string | `"61000-62000"` | Port range used by NodePortLocal when creating Pod port mappings. | +| ovs.bridgeName | string | `"br-int"` | Name of the OVS bridge antrea-agent will create and use. | +| ovs.hwOffload | bool | `false` | Enable hardware offload for the OVS bridge (required additional configuration). | +| serviceCIDR | string | `""` | IPv4 CIDR range used for Services. Required when AntreaProxy is disabled. | +| serviceCIDRv6 | string | `""` | IPv6 CIDR range used for Services. Required when AntreaProxy is disabled. | +| testing.coverage | bool | `false` | | +| testing.simulator.enable | bool | `false` | | +| tlsCipherSuites | string | `""` | Comma-separated list of cipher suites that will be used by the Antrea APIservers. If empty, the default Go Cipher Suites will be used. See https://golang.org/pkg/crypto/tls/#pkg-constants. | +| tlsMinVersion | string | `""` | TLS min version from: VersionTLS10, VersionTLS11, VersionTLS12, VersionTLS13. | +| trafficEncapMode | string | `"encap"` | Determines how traffic is encapsulated. It must be one of "encap", "noEncap", "hybrid", or "networkPolicyOnly". | +| trafficEncryptionMode | string | `"none"` | Determines how tunnel traffic is encrypted. Currently encryption only works with encap mode.It must be one of "none", "ipsec", "wireGuard". | +| transportInterface | string | `""` | Name of the interface on Node which is used for tunneling or routing the traffic across Nodes. | +| transportInterfaceCIDRs | list | `[]` | Network CIDRs of the interface on Node which is used for tunneling or routing the traffic across Nodes. | +| tunnelType | string | `"geneve"` | Tunnel protocol used for encapsulating traffic across Nodes. It must be one of "geneve", "vxlan", "gre", "stt". | +| webhooks.labelsMutator.enable | bool | `false` | | +| whereabouts.enable | bool | `false` | | +| wireGuard.port | int | `51820` | Port for WireGuard to send and receive traffic. | + +---------------------------------------------- +Autogenerated from chart metadata using [helm-docs v1.7.0](https://github.com/norwoodj/helm-docs/releases/v1.7.0) diff --git a/build/yamls/base/conf/antrea-agent.conf b/build/charts/antrea/conf/antrea-agent.conf similarity index 71% rename from build/yamls/base/conf/antrea-agent.conf rename to build/charts/antrea/conf/antrea-agent.conf index 912cd971bf9..d60c167177e 100644 --- a/build/yamls/base/conf/antrea-agent.conf +++ b/build/charts/antrea/conf/antrea-agent.conf @@ -3,64 +3,67 @@ featureGates: # Enable AntreaProxy which provides ServiceLB for in-cluster Services in antrea-agent. # It should be enabled on Windows, otherwise NetworkPolicy will not take effect on # Service traffic. -# AntreaProxy: true +{{- include "featureGate" (dict "featureGates" .Values.featureGates "name" "AntreaProxy" "default" true) }} # Enable EndpointSlice support in AntreaProxy. Don't enable this feature unless that EndpointSlice # API version v1beta1 is supported and set as enabled in Kubernetes. If AntreaProxy is not enabled, # this flag will not take effect. -# EndpointSlice: false +{{- include "featureGate" (dict "featureGates" .Values.featureGates "name" "EndpointSlice" "default" false) }} # Enable traceflow which provides packet tracing feature to diagnose network issue. -# Traceflow: true +{{- include "featureGate" (dict "featureGates" .Values.featureGates "name" "Traceflow" "default" true) }} # Enable NodePortLocal feature to make the Pods reachable externally through NodePort -# NodePortLocal: true +{{- include "featureGate" (dict "featureGates" .Values.featureGates "name" "NodePortLocal" "default" true) }} # Enable Antrea ClusterNetworkPolicy feature to complement K8s NetworkPolicy for cluster admins # to define security policies which apply to the entire cluster, and Antrea NetworkPolicy # feature that supports priorities, rule actions and externalEntities in the future. -# AntreaPolicy: true +{{- include "featureGate" (dict "featureGates" .Values.featureGates "name" "AntreaPolicy" "default" true) }} # Enable flowexporter which exports polled conntrack connections as IPFIX flow records from each # agent to a configured collector. -# FlowExporter: false +{{- include "featureGate" (dict "featureGates" .Values.featureGates "name" "FlowExporter" "default" false) }} # Enable collecting and exposing NetworkPolicy statistics. -# NetworkPolicyStats: true +{{- include "featureGate" (dict "featureGates" .Values.featureGates "name" "NetworkPolicyStats" "default" true) }} # Enable controlling SNAT IPs of Pod egress traffic. -# Egress: true +{{- include "featureGate" (dict "featureGates" .Values.featureGates "name" "Egress" "default" true) }} # Enable AntreaIPAM, which can allocate IP addresses from IPPools. AntreaIPAM is required by the -# bridging mode and allocates IPs to Pods in bridging mode. -# AntreaIPAM: false +# bridging mode and allocates IPs to Pods in bridging mode. It is also required to use Antrea for +# IPAM when configuring secondary network interfaces with Multus. +{{- include "featureGate" (dict "featureGates" .Values.featureGates "name" "AntreaIPAM" "default" false) }} # Enable multicast traffic. This feature is supported only with noEncap mode. -# Multicast: false +{{- include "featureGate" (dict "featureGates" .Values.featureGates "name" "Multicast" "default" false) }} # Enable support for provisioning secondary network interfaces for Pods (using # Pod annotations). At the moment, Antrea can only create secondary network # interfaces using SR-IOV VFs on baremetal Nodes. -# SecondaryNetwork: false +{{- include "featureGate" (dict "featureGates" .Values.featureGates "name" "SecondaryNetwork" "default" false) }} # Enable managing external IPs of Services of LoadBalancer type. -# ServiceExternalIP: false +{{- include "featureGate" (dict "featureGates" .Values.featureGates "name" "ServiceExternalIP" "default" false) }} + +# Enable mirroring or redirecting the traffic Pods send or receive. +{{- include "featureGate" (dict "featureGates" .Values.featureGates "name" "TrafficControl" "default" false) }} # Name of the OpenVSwitch bridge antrea-agent will create and use. # Make sure it doesn't conflict with your existing OpenVSwitch bridges. -#ovsBridge: br-int +ovsBridge: {{ .Values.ovs.bridgeName | quote }} # Datapath type to use for the OpenVSwitch bridge created by Antrea. Supported values are: # - system # - netdev # 'system' is the default value and corresponds to the kernel datapath. Use 'netdev' to run -# OVS in userspace mode (not fully supported yet). Userspace mode requires the tun device driver to -# be available. +# OVS in userspace mode. Userspace mode requires the tun device driver to be available. #ovsDatapathType: system # Name of the interface antrea-agent will create and use for host <--> pod communication. # Make sure it doesn't conflict with your existing interfaces. -#hostGateway: antrea-gw0 +hostGateway: {{ .Values.hostGateway | quote }} # Determines how traffic is encapsulated. It has the following options: # encap(default): Inter-node Pod traffic is always encapsulated and Pod to external network @@ -72,14 +75,14 @@ featureGates: # networkPolicyOnly: Antrea enforces NetworkPolicy only, and utilizes CNI chaining and delegates Pod # IPAM and connectivity to the primary CNI. # -#trafficEncapMode: encap +trafficEncapMode: {{ .Values.trafficEncapMode | quote }} # Whether or not to SNAT (using the Node IP) the egress traffic from a Pod to the external network. # This option is for the noEncap traffic mode only, and the default value is false. In the noEncap # mode, if the cluster's Pod CIDR is reachable from the external network, then the Pod traffic to # the external network needs not be SNAT'd. In the networkPolicyOnly mode, antrea-agent never # performs SNAT and this option will be ignored; for other modes it must be set to false. -#noSNAT: false +noSNAT: {{ .Values.noSNAT }} # Tunnel protocols used for encapsulating traffic across Nodes. If WireGuard is enabled in trafficEncryptionMode, # this option will not take effect. Supported values: @@ -88,7 +91,7 @@ featureGates: # - gre # - stt # Note that "gre" is not supported for IPv6 clusters (IPv6-only or dual-stack clusters). -#tunnelType: geneve +tunnelType: {{ .Values.tunnelType | quote }} # Determines how tunnel traffic is encrypted. Currently encryption only works with encap mode. # It has the following options: @@ -98,49 +101,61 @@ featureGates: # the PSK value must be passed to Antrea Agent through an environment # variable: ANTREA_IPSEC_PSK. # - wireGuard: Enable WireGuard for tunnel traffic encryption. -#trafficEncryptionMode: none +trafficEncryptionMode: {{ .Values.trafficEncryptionMode | quote }} # Enable bridging mode of Pod network on Nodes, in which the Node's transport interface is connected -# to the OVS bridge, and cross-Node/VLAN traffic from AntreaIPAM Pods (Pods whose IP addresses are -# allocated by AntreaIPAM from IPPools) is sent to the underlay network via the uplink, and -# forwarded/routed by the underlay network. +# to the OVS bridge, and cross-Node/VLAN traffic of AntreaIPAM Pods (Pods whose IP addresses are +# allocated by AntreaIPAM from IPPools) is sent to the underlay network, and forwarded/routed by the +# underlay network. # This option requires the `AntreaIPAM` feature gate to be enabled. At this moment, it supports only # IPv4 and Linux Nodes, and can be enabled only when `ovsDatapathType` is `system`, # `trafficEncapMode` is `noEncap`, and `noSNAT` is true. -#enableBridgingMode: false +enableBridgingMode: {{ .Values.enableBridgingMode }} + +# Disable TX checksum offloading for container network interfaces. It's supposed to be set to true when the +# datapath doesn't support TX checksum offloading, which causes packets to be dropped due to bad checksum. +# It affects Pods running on Linux Nodes only. +disableTXChecksumOffload: {{ .Values.disableTXChecksumOffload }} # Default MTU to use for the host gateway interface and the network interface of each Pod. # If omitted, antrea-agent will discover the MTU of the Node's primary interface and # also adjust MTU to accommodate for tunnel encapsulation overhead (if applicable). -#defaultMTU: 0 +defaultMTU: {{ .Values.defaultMTU }} # wireGuard specifies WireGuard related configurations. wireGuard: -# The port for WireGuard to receive traffic. -# port: 51820 +{{- with .Values.wireGuard }} + # The port for WireGuard to receive traffic. + port: {{ .port }} +{{- end }} egress: -# exceptCIDRs is the CIDR ranges to which outbound Pod traffic will not be SNAT'd by Egresses. -# exceptCIDRs: [] +{{- with .Values.egress }} + # exceptCIDRs is the CIDR ranges to which outbound Pod traffic will not be SNAT'd by Egresses. + exceptCIDRs: + {{- with .exceptCIDRs }} + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} # ClusterIP CIDR range for Services. It's required when AntreaProxy is not enabled, and should be # set to the same value as the one specified by --service-cluster-ip-range for kube-apiserver. When # AntreaProxy is enabled, this parameter is not needed and will be ignored if provided. -#serviceCIDR: 10.96.0.0/12 +serviceCIDR: {{ .Values.serviceCIDR | quote }} # ClusterIP CIDR range for IPv6 Services. It's required when using kube-proxy to provide IPv6 Service in a Dual-Stack # cluster or an IPv6 only cluster. The value should be the same as the configuration for kube-apiserver specified by # --service-cluster-ip-range. When AntreaProxy is enabled, this parameter is not needed. # No default value for this field. -#serviceCIDRv6: +serviceCIDRv6: {{ .Values.serviceCIDRv6 | quote }} # The port for the antrea-agent APIServer to serve on. # Note that if it's set to another value, the `containerPort` of the `api` port of the # `antrea-agent` container must be set to the same value. -#apiPort: 10350 +apiPort: {{ .Values.agent.apiPort }} # Enable metrics exposure via Prometheus. Initializes Prometheus metrics listener. -#enablePrometheusMetrics: true +enablePrometheusMetrics: {{ .Values.agent.enablePrometheusMetrics }} # Provide the IPFIX collector address as a string with format :[][:]. # HOST can either be the DNS name or the IP of the Flow Collector. For example, @@ -151,50 +166,52 @@ egress: # If no PROTO is given, we consider "tls" as default. We support "tls", "tcp" and # "udp" protocols. "tls" is used for securing communication between flow exporter and # flow aggregator. -#flowCollectorAddr: "flow-aggregator.flow-aggregator.svc:4739:tls" +flowCollectorAddr: {{ .Values.flowCollector.collectorAddr | quote }} # Provide flow poll interval as a duration string. This determines how often the # flow exporter dumps connections from the conntrack module. Flow poll interval # should be greater than or equal to 1s (one second). # Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". -#flowPollInterval: "5s" +flowPollInterval: {{ .Values.flowCollector.flowPollInterval | quote }} # Provide the active flow export timeout, which is the timeout after which a flow # record is sent to the collector for active flows. Thus, for flows with a continuous # stream of packets, a flow record will be exported to the collector once the elapsed # time since the last export event is equal to the value of this timeout. # Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". -#activeFlowExportTimeout: "30s" +activeFlowExportTimeout: {{ .Values.flowCollector.activeFlowExportTimeout | quote }} # Provide the idle flow export timeout, which is the timeout after which a flow # record is sent to the collector for idle flows. A flow is considered idle if no # packet matching this flow has been observed since the last export event. # Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". -#idleFlowExportTimeout: "15s" +idleFlowExportTimeout: {{ .Values.flowCollector.idleFlowExportTimeout | quote }} nodePortLocal: +{{- with .Values.nodePortLocal }} # Enable NodePortLocal, a feature used to make Pods reachable using port forwarding on the host. To # enable this feature, you need to set "enable" to true, and ensure that the NodePortLocal feature # gate is also enabled (which is the default). -# enable: false + enable: {{ .enable }} # Provide the port range used by NodePortLocal. When the NodePortLocal feature is enabled, a port # from that range will be assigned whenever a Pod's container defines a specific port to be exposed # (each container can define a list of ports as pod.spec.containers[].ports), and all Node traffic # directed to that port will be forwarded to the Pod. -# portRange: 61000-62000 + portRange: {{ .portRange | quote }} +{{- end }} # Provide the address of Kubernetes apiserver, to override any value provided in kubeconfig or InClusterConfig. # Defaults to "". It must be a host string, a host:port pair, or a URL to the base of the apiserver. -#kubeAPIServerOverride: "" +kubeAPIServerOverride: {{ .Values.kubeAPIServerOverride | quote }} # Comma-separated list of Cipher Suites. If omitted, the default Go Cipher Suites will be used. # https://golang.org/pkg/crypto/tls/#pkg-constants # Note that TLS1.3 Cipher Suites cannot be added to the list. But the apiserver will always # prefer TLS1.3 Cipher Suites whenever possible. -#tlsCipherSuites: +tlsCipherSuites: {{ .Values.tlsCipherSuites | quote }} # TLS min version from: VersionTLS10, VersionTLS11, VersionTLS12, VersionTLS13. -#tlsMinVersion: +tlsMinVersion: {{ .Values.tlsMinVersion | quote }} # The name of the interface on Node which is used for tunneling or routing the traffic across Nodes. # If there are multiple IP addresses configured on the interface, the first one is used. The IP @@ -203,11 +220,21 @@ nodePortLocal: # 1. transportInterface # 2. transportInterfaceCIDRs # 3. The Node IP -#transportInterface: +transportInterface: {{ .Values.transportInterface | quote }} +multicast: +{{- with .Values.multicast }} # The names of the interfaces on Nodes that are used to forward multicast traffic. # Defaults to transport interface if not set. -#multicastInterfaces: [] + multicastInterfaces: + {{- with .multicastInterfaces }} + {{- toYaml . | nindent 4 }} + {{- end }} + +# The interval at which the antrea-agent sends IGMP queries to Pods. +# Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". + igmpQueryInterval: {{ .igmpQueryInterval | quote }} +{{- end}} # The network CIDRs of the interface on Node which is used for tunneling or routing the traffic across # Nodes. If there are multiple interfaces configured the same network CIDR, the first one is used. The @@ -216,28 +243,39 @@ nodePortLocal: # 1. transportInterface # 2. transportInterfaceCIDRs # 3. The Node IP -#transportInterfaceCIDRs: [,] +transportInterfaceCIDRs: +{{- with .Values.transportInterfaceCIDRs }} +{{- toYaml . | nindent 2 }} +{{- end }} # Option antreaProxy contains AntreaProxy related configuration options. antreaProxy: +{{- with .Values.antreaProxy }} # ProxyAll tells antrea-agent to proxy all Service traffic, including NodePort, LoadBalancer, and ClusterIP traffic, # regardless of where they come from. Therefore, running kube-proxy is no longer required. This requires the AntreaProxy # feature to be enabled. # Note that this option is experimental. If kube-proxy is removed, option kubeAPIServerOverride must be used to access # apiserver directly. - #proxyAll: false + proxyAll: {{ .proxyAll }} # A string array of values which specifies the host IPv4/IPv6 addresses for NodePort. Values can be valid IP blocks. # (e.g. 1.2.3.0/24, 1.2.3.4/32). An empty string slice is meant to select all host IPv4/IPv6 addresses. # Note that the option is only valid when proxyAll is true. - #nodePortAddresses: [] + nodePortAddresses: + {{- with .nodePortAddresses }} + {{- toYaml . | nindent 4 }} + {{- end }} # An array of string values to specify a list of Services which should be ignored by AntreaProxy (traffic to these # Services will not be load-balanced). Values can be a valid ClusterIP (e.g. 10.11.1.2) or a Service name # with Namespace (e.g. kube-system/kube-dns) - #skipServices: [] + skipServices: + {{- with .skipServices }} + {{- toYaml . | nindent 4 }} + {{- end }} # When ProxyLoadBalancerIPs is set to false, AntreaProxy no longer load-balances traffic destined to the # External IPs of LoadBalancer Services. This is useful when the external LoadBalancer provides additional # capabilities (e.g. TLS termination) and it is desirable for Pod-to-ExternalIP traffic to be sent to the # external LoadBalancer instead of being load-balanced to an Endpoint directly by AntreaProxy. # Note that setting ProxyLoadBalancerIPs to false usually only makes sense when ProxyAll is set to true and # kube-proxy is removed from the cluser, otherwise kube-proxy will still load-balance this traffic. - #proxyLoadBalancerIPs: true + proxyLoadBalancerIPs: {{ .proxyLoadBalancerIPs }} +{{- end }} diff --git a/build/yamls/base/conf/antrea-cni.conflist b/build/charts/antrea/conf/antrea-cni.conflist similarity index 68% rename from build/yamls/base/conf/antrea-cni.conflist rename to build/charts/antrea/conf/antrea-cni.conflist index 14d84678be0..9047fc33409 100644 --- a/build/yamls/base/conf/antrea-cni.conflist +++ b/build/charts/antrea/conf/antrea-cni.conflist @@ -7,14 +7,20 @@ "ipam": { "type": "host-local" } - }, + } + {{- if .Values.cni.plugins.portmap }} + , { "type": "portmap", "capabilities": {"portMappings": true} - }, + } + {{- end }} + {{- if .Values.cni.plugins.bandwidth }} + , { "type": "bandwidth", "capabilities": {"bandwidth": true} } + {{- end }} ] } diff --git a/build/charts/antrea/conf/antrea-controller.conf b/build/charts/antrea/conf/antrea-controller.conf new file mode 100644 index 00000000000..f54bf5ce864 --- /dev/null +++ b/build/charts/antrea/conf/antrea-controller.conf @@ -0,0 +1,73 @@ +# FeatureGates is a map of feature names to bools that enable or disable experimental features. +featureGates: +# Enable traceflow which provides packet tracing feature to diagnose network issue. +{{- include "featureGate" (dict "featureGates" .Values.featureGates "name" "Traceflow" "default" true) }} + +# Enable Antrea ClusterNetworkPolicy feature to complement K8s NetworkPolicy for cluster admins +# to define security policies which apply to the entire cluster, and Antrea NetworkPolicy +# feature that supports priorities, rule actions and externalEntities in the future. +{{- include "featureGate" (dict "featureGates" .Values.featureGates "name" "AntreaPolicy" "default" true) }} + +# Enable collecting and exposing NetworkPolicy statistics. +{{- include "featureGate" (dict "featureGates" .Values.featureGates "name" "NetworkPolicyStats" "default" true) }} + +# Enable controlling SNAT IPs of Pod egress traffic. +{{- include "featureGate" (dict "featureGates" .Values.featureGates "name" "Egress" "default" true) }} + +# Run Kubernetes NodeIPAMController with Antrea. +{{- include "featureGate" (dict "featureGates" .Values.featureGates "name" "NodeIPAM" "default" false) }} + +# Enable AntreaIPAM, which can allocate IP addresses from IPPools. AntreaIPAM is required by the +# bridging mode and allocates IPs to Pods in bridging mode. It is also required to use Antrea for +# IPAM when configuring secondary network interfaces with Multus. +{{- include "featureGate" (dict "featureGates" .Values.featureGates "name" "AntreaIPAM" "default" false) }} + +# Enable managing external IPs of Services of LoadBalancer type. +{{- include "featureGate" (dict "featureGates" .Values.featureGates "name" "ServiceExternalIP" "default" false) }} + +# The port for the antrea-controller APIServer to serve on. +# Note that if it's set to another value, the `containerPort` of the `api` port of the +# `antrea-controller` container must be set to the same value. +apiPort: {{ .Values.controller.apiPort }} + +# Enable metrics exposure via Prometheus. Initializes Prometheus metrics listener. +enablePrometheusMetrics: {{ .Values.controller.enablePrometheusMetrics }} + +# Indicates whether to use auto-generated self-signed TLS certificate. +# If false, a Secret named "antrea-controller-tls" must be provided with the following keys: +# ca.crt: +# tls.crt: +# tls.key: +selfSignedCert: {{ .Values.controller.selfSignedCert }} + +# Comma-separated list of Cipher Suites. If omitted, the default Go Cipher Suites will be used. +# https://golang.org/pkg/crypto/tls/#pkg-constants +# Note that TLS1.3 Cipher Suites cannot be added to the list. But the apiserver will always +# prefer TLS1.3 Cipher Suites whenever possible. +tlsCipherSuites: {{ .Values.tlsCipherSuites | quote }} + +# TLS min version from: VersionTLS10, VersionTLS11, VersionTLS12, VersionTLS13. +tlsMinVersion: {{ .Values.tlsMinVersion | quote }} + +nodeIPAM: +{{- with .Values.nodeIPAM }} + # Enable the integrated Node IPAM controller within the Antrea controller. + enableNodeIPAM: {{ .enable }} + # CIDR ranges for Pods in cluster. String array containing single CIDR range, or multiple ranges. + # The CIDRs could be either IPv4 or IPv6. At most one CIDR may be specified for each IP family. + # Value ignored when enableNodeIPAM is false. + clusterCIDRs: + {{- with .clusterCIDRs }} + {{- toYaml . | nindent 4 }} + {{- end }} + # CIDR ranges for Services in cluster. It is not necessary to specify it when there is no overlap with clusterCIDRs. + # Value ignored when enableNodeIPAM is false. + serviceCIDR: {{ .serviceCIDR | quote }} + serviceCIDRv6: {{ .serviceCIDRv6 | quote }} + # Mask size for IPv4 Node CIDR in IPv4 or dual-stack cluster. Value ignored when enableNodeIPAM is false + # or when IPv4 Pod CIDR is not configured. Valid range is 16 to 30. + nodeCIDRMaskSizeIPv4: {{ .nodeCIDRMaskSizeIPv4 }} + # Mask size for IPv6 Node CIDR in IPv6 or dual-stack cluster. Value ignored when enableNodeIPAM is false + # or when IPv6 Pod CIDR is not configured. Valid range is 64 to 126. + nodeCIDRMaskSizeIPv6: {{ .nodeCIDRMaskSizeIPv6 }} +{{- end }} diff --git a/build/charts/antrea/templates/NOTES.txt b/build/charts/antrea/templates/NOTES.txt new file mode 100644 index 00000000000..40e0d249333 --- /dev/null +++ b/build/charts/antrea/templates/NOTES.txt @@ -0,0 +1 @@ +The Antrea CNI has been successfully installed. diff --git a/build/charts/antrea/templates/_helpers.tpl b/build/charts/antrea/templates/_helpers.tpl new file mode 100644 index 00000000000..0319db13d43 --- /dev/null +++ b/build/charts/antrea/templates/_helpers.tpl @@ -0,0 +1,9 @@ +{{- define "featureGate" -}} +{{- $name := .name }} +{{- $default := .default }} +{{- if hasKey .featureGates $name }} + {{ $name }}: {{ get .featureGates $name }} +{{- else }} + {{ printf "# %s" $name }}: {{ $default }} +{{- end }} +{{- end -}} diff --git a/build/yamls/base/agent-rbac.yml b/build/charts/antrea/templates/agent/clusterrole.yaml similarity index 87% rename from build/yamls/base/agent-rbac.yml rename to build/charts/antrea/templates/agent/clusterrole.yaml index a75b5fc7b5d..10e847a669b 100644 --- a/build/yamls/base/agent-rbac.yml +++ b/build/charts/antrea/templates/agent/clusterrole.yaml @@ -1,14 +1,9 @@ ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: antrea-agent - namespace: kube-system ---- kind: ClusterRole apiVersion: rbac.authorization.k8s.io/v1 metadata: name: antrea-agent + labels: + app: antrea rules: - apiGroups: - "" @@ -47,13 +42,7 @@ rules: verbs: - get - watch - - list - - apiGroups: - - "" - resources: - - services/status - verbs: - - update + - list - apiGroups: - discovery.k8s.io resources: @@ -172,6 +161,7 @@ rules: resources: - externalippools - ippools + - trafficcontrols verbs: - get - watch @@ -190,16 +180,3 @@ rules: - get - list - watch ---- -kind: ClusterRoleBinding -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: antrea-agent -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: antrea-agent -subjects: - - kind: ServiceAccount - name: antrea-agent - namespace: kube-system diff --git a/build/charts/antrea/templates/agent/clusterrolebinding.yaml b/build/charts/antrea/templates/agent/clusterrolebinding.yaml new file mode 100644 index 00000000000..191035981fb --- /dev/null +++ b/build/charts/antrea/templates/agent/clusterrolebinding.yaml @@ -0,0 +1,14 @@ +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: antrea-agent + labels: + app: antrea +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: antrea-agent +subjects: + - kind: ServiceAccount + name: antrea-agent + namespace: {{ .Release.Namespace }} diff --git a/build/yamls/base/agent.yml b/build/charts/antrea/templates/agent/daemonset.yaml similarity index 52% rename from build/yamls/base/agent.yml rename to build/charts/antrea/templates/agent/daemonset.yaml index 8bc007231d3..3d24e44b45f 100644 --- a/build/yamls/base/agent.yml +++ b/build/charts/antrea/templates/agent/daemonset.yaml @@ -1,48 +1,79 @@ ---- apiVersion: apps/v1 kind: DaemonSet metadata: name: antrea-agent + namespace: {{ .Release.Namespace }} labels: + app: antrea component: antrea-agent spec: selector: matchLabels: + app: antrea component: antrea-agent - updateStrategy: - type: RollingUpdate + {{- with .Values.agent.updateStrategy }} + updateStrategy: {{- toYaml . | nindent 4 }} + {{- end }} template: metadata: annotations: # Starting with v1.21, Kubernetes supports default container annotation. # Using "kubectl logs/exec/attach/cp" doesn't have to specify "-c antrea-agent" when troubleshooting. kubectl.kubernetes.io/default-container: antrea-agent + # Automatically restart Pods with a RollingUpdate if the ConfigMap changes + # See https://helm.sh/docs/howto/charts_tips_and_tricks/#automatically-roll-deployments + checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }} + {{- if eq .Values.trafficEncryptionMode "ipsec" }} + checksum/ipsec-secret: {{ include (print $.Template.BasePath "/agent/ipsec-secret.yaml") . | sha256sum }} + {{- end }} + {{- with .Values.agent.podAnnotations }} + {{- toYaml . | nindent 8 }} + {{- end }} labels: + app: antrea component: antrea-agent + {{- with .Values.agent.podLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} spec: hostNetwork: true - dnsPolicy: ClusterFirstWithHostNet - priorityClassName: system-node-critical - tolerations: - # Mark it as a critical add-on. - - key: CriticalAddonsOnly - operator: Exists - # Make sure it gets scheduled on all nodes. - - effect: NoSchedule - operator: Exists - # Make sure it doesn't get evicted. - - effect: NoExecute - operator: Exists + dnsPolicy: {{ .Values.agent.dnsPolicy }} + priorityClassName: {{ .Values.agent.priorityClassName }} + {{- with .Values.agent.nodeSelector }} nodeSelector: - kubernetes.io/os: linux + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.agent.tolerations }} + tolerations: + {{- toYaml . | trim | nindent 8 }} + {{- end }} + {{- if .Values.testing.simulator.enable }} + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: antrea/instance + operator: NotIn + values: + - simulator + {{- else }} + {{- with .Values.agent.affinity }} + affinity: + {{- toYaml . | trim | nindent 8 }} + {{- end }} + {{- end }} serviceAccountName: antrea-agent initContainers: - name: install-cni - image: antrea - resources: - requests: - cpu: "100m" + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + resources: {{- .Values.agent.installCNI.resources | toYaml | nindent 12 }} + {{- if eq .Values.trafficEncapMode "networkPolicyOnly" }} + command: ["install_cni_chaining"] + {{- else }} command: ["install_cni"] + {{- end }} securityContext: capabilities: add: @@ -52,7 +83,7 @@ spec: # SKIP_CNI_BINARIES takes in values as a comma separated list of # binaries that need to be skipped for installation, e.g. "portmap, bandwidth". - name: SKIP_CNI_BINARIES - value: "" + value: {{ join "," .Values.cni.skipBinaries | quote }} volumeMounts: - name: antrea-config mountPath: /etc/antrea/antrea-cni.conflist @@ -69,15 +100,43 @@ spec: # For changing the default permissions of the run directory. - name: host-var-run-antrea mountPath: /var/run/antrea - containers: - - name: antrea-agent - image: antrea + {{- if .Values.whereabouts.enable }} + - name: install-whereabouts-config + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" resources: requests: - cpu: "200m" + cpu: "100m" + command: ["install_whereabouts_config"] + volumeMounts: + - name: whereabouts-cni-conf + mountPath: /host/etc/cni/net.d/whereabouts.d + - name: whereabouts-secret + mountPath: /var/run/secrets/whereabouts + {{- end }} + containers: + - name: antrea-agent + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + {{- if ((.Values.testing).coverage) }} + command: ["/bin/sh"] + args: ["-c", "sleep 2; antrea-agent-coverage -test.run=TestBincoverRunMain -test.coverprofile=antrea-agent.cov.out -args-file=/agent-arg-file; while true; do sleep 5 & wait $!; done"] + {{- else}} command: ["antrea-agent"] - # Log to both "/var/log/antrea/" and stderr (so "kubectl logs" can work). - args: ["--config", "/etc/antrea/antrea-agent.conf", "--logtostderr=false", "--log_dir=/var/log/antrea", "--alsologtostderr", "--log_file_max_size=100", "--log_file_max_num=4", "--v=0"] + # Log to both "/var/log/antrea/" and stderr (so "kubectl logs" can work).- + args: + - "--config=/etc/antrea/antrea-agent.conf" + - "--logtostderr=false" + - "--log_dir=/var/log/antrea" + - "--alsologtostderr" + - "--log_file_max_size={{ .Values.agent.antreaAgent.logFileMaxSize }}" + - "--log_file_max_num={{ .Values.agent.antreaAgent.logFileMaxNum }}" + {{- if .Values.logVerbosity }} + - "--v={{ .Values.logVerbosity }}" + {{- end }} + {{- with .Values.agent.antreaAgent.extraArgs }} + {{- toYaml . | trim | nindent 12 }} + {{- end }} + {{- end}} env: # Provide pod and node information for clusterinformation CRD. - name: POD_NAME @@ -92,6 +151,19 @@ spec: valueFrom: fieldRef: fieldPath: spec.nodeName + {{- if eq .Values.trafficEncryptionMode "ipsec" }} + # Pre-shared key for IPsec IKE. + - name: ANTREA_IPSEC_PSK + valueFrom: + secretKeyRef: + name: antrea-ipsec + key: psk + {{- end }} + {{- range $k, $v := .Values.agent.antreaAgent.extraEnv }} + - name: {{ $k | quote }} + value: {{ $v | quote }} + {{- end }} + resources: {{- .Values.agent.antreaAgent.resources | toYaml | nindent 12 }} ports: - containerPort: 10350 name: api @@ -155,13 +227,29 @@ spec: mountPropagation: HostToContainer - name: xtables-lock mountPath: /run/xtables.lock + {{- if .Values.whereabouts.enable }} + - name: whereabouts-cni-conf + mountPath: /host/etc/cni/net.d/whereabouts.d + - name: whereabouts-secret + mountPath: /var/run/secrets/whereabouts + {{- end }} + {{- with .Values.agent.antreaAgent.extraVolumeMounts }} + {{- toYaml . | trim | nindent 10 }} + {{- end }} - name: antrea-ovs - image: antrea - resources: - requests: - cpu: "200m" + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + resources: {{- .Values.agent.antreaOVS.resources | toYaml | nindent 12 }} command: ["start_ovs"] - args: ["--log_file_max_size=100", "--log_file_max_num=4"] + args: + - "--log_file_max_size={{ .Values.agent.antreaOVS.logFileMaxSize }}" + - "--log_file_max_num={{ .Values.agent.antreaOVS.logFileMaxNum }}" + {{- if .Values.ovs.hwOffload }} + - "--hw-offload" + {{- end }} + {{- with .Values.agent.antreaOVS.extraArgs }} + {{- toYaml . | trim | nindent 12 }} + {{- end }} securityContext: # capabilities required by OVS daemons capabilities: @@ -189,6 +277,35 @@ spec: - name: host-var-log-antrea mountPath: /var/log/openvswitch subPath: openvswitch + {{- if eq .Values.trafficEncryptionMode "ipsec" }} + - name: antrea-ipsec + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + resources: {{- .Values.agent.antreaIPsec.resources | toYaml | nindent 12 }} + command: ["start_ovs_ipsec"] + livenessProbe: + exec: + command: + - /bin/sh + - -c + - timeout 5 container_liveness_probe ovs-ipsec + initialDelaySeconds: 5 + periodSeconds: 5 + securityContext: + capabilities: + add: + - NET_ADMIN + volumeMounts: + - name: host-var-run-antrea + mountPath: /var/run/openvswitch + subPath: openvswitch + - name: host-var-log-antrea + mountPath: /var/log/openvswitch + subPath: openvswitch + - name: host-var-log-antrea + mountPath: /var/log/strongswan + subPath: strongswan + {{- end }} volumes: - name: antrea-config configMap: @@ -198,7 +315,7 @@ spec: path: /etc/cni/net.d - name: host-cni-bin hostPath: - path: /opt/cni/bin + path: {{ .Values.cni.hostBinPath }} - name: host-proc hostPath: path: /proc @@ -223,3 +340,14 @@ spec: hostPath: path: /run/xtables.lock type: FileOrCreate + {{- with .Values.agent.extraVolumes }} + {{- toYaml . | trim | nindent 8 }} + {{- end }} + {{- if .Values.whereabouts.enable }} + - hostPath: + path: /host/etc/cni/net.d/whereabouts.d + name: whereabouts-cni-conf + - name: whereabouts-secret + secret: + secretName: whereabouts-cni-secret + {{- end }} diff --git a/build/charts/antrea/templates/agent/ipsec-secret.yaml b/build/charts/antrea/templates/agent/ipsec-secret.yaml new file mode 100644 index 00000000000..a49848233aa --- /dev/null +++ b/build/charts/antrea/templates/agent/ipsec-secret.yaml @@ -0,0 +1,13 @@ +{{- if eq .Values.trafficEncryptionMode "ipsec" }} +apiVersion: v1 +kind: Secret +metadata: + name: antrea-ipsec + namespace: {{ .Release.Namespace }} + labels: + app: antrea +type: Opaque +stringData: + # Preshared Key used by IKE for authentication with peers. + psk: {{ .Values.ipsec.psk | quote }} +{{- end }} diff --git a/build/charts/antrea/templates/agent/secret.yaml b/build/charts/antrea/templates/agent/secret.yaml new file mode 100644 index 00000000000..90053e02734 --- /dev/null +++ b/build/charts/antrea/templates/agent/secret.yaml @@ -0,0 +1,8 @@ +apiVersion: v1 +kind: Secret +metadata: + name: antrea-agent-service-account-token + namespace: {{ .Release.Namespace }} + annotations: + kubernetes.io/service-account.name: antrea-agent +type: kubernetes.io/service-account-token diff --git a/build/charts/antrea/templates/agent/serviceaccount.yaml b/build/charts/antrea/templates/agent/serviceaccount.yaml new file mode 100644 index 00000000000..659b91c8c67 --- /dev/null +++ b/build/charts/antrea/templates/agent/serviceaccount.yaml @@ -0,0 +1,7 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: antrea-agent + namespace: {{ .Release.Namespace }} + labels: + app: antrea diff --git a/build/yamls/base/antctl.yml b/build/charts/antrea/templates/antctl/clusterrole.yaml similarity index 73% rename from build/yamls/base/antctl.yml rename to build/charts/antrea/templates/antctl/clusterrole.yaml index 6a3764ae560..4a6a7420b64 100644 --- a/build/yamls/base/antctl.yml +++ b/build/charts/antrea/templates/antctl/clusterrole.yaml @@ -1,14 +1,9 @@ ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: antctl - namespace: kube-system ---- kind: ClusterRole apiVersion: rbac.authorization.k8s.io/v1 metadata: name: antctl + labels: + app: antrea rules: - apiGroups: - controlplane.antrea.io @@ -58,21 +53,6 @@ rules: - /ovstracing - /podinterfaces - /featuregates + - /serviceexternalip verbs: - get ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - labels: - app: antrea - name: antctl - namespace: kube-system -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: antctl -subjects: - - kind: ServiceAccount - name: antctl - namespace: kube-system diff --git a/build/charts/antrea/templates/antctl/clusterrolebinding.yaml b/build/charts/antrea/templates/antctl/clusterrolebinding.yaml new file mode 100644 index 00000000000..3f0a9713920 --- /dev/null +++ b/build/charts/antrea/templates/antctl/clusterrolebinding.yaml @@ -0,0 +1,14 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + labels: + app: antrea + name: antctl +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: antctl +subjects: + - kind: ServiceAccount + name: antctl + namespace: {{ .Release.Namespace }} diff --git a/build/charts/antrea/templates/antctl/secret.yaml b/build/charts/antrea/templates/antctl/secret.yaml new file mode 100644 index 00000000000..c964bc87f59 --- /dev/null +++ b/build/charts/antrea/templates/antctl/secret.yaml @@ -0,0 +1,8 @@ +apiVersion: v1 +kind: Secret +metadata: + name: antctl-service-account-token + namespace: {{ .Release.Namespace }} + annotations: + kubernetes.io/service-account.name: antctl +type: kubernetes.io/service-account-token diff --git a/build/charts/antrea/templates/antctl/serviceaccount.yaml b/build/charts/antrea/templates/antctl/serviceaccount.yaml new file mode 100644 index 00000000000..64e57a4b318 --- /dev/null +++ b/build/charts/antrea/templates/antctl/serviceaccount.yaml @@ -0,0 +1,7 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: antctl + namespace: {{ .Release.Namespace }} + labels: + app: antrea diff --git a/build/yamls/base/cluster-identity-reader.yml b/build/charts/antrea/templates/cluster-identity-reader/clusterrolebinding.yaml similarity index 90% rename from build/yamls/base/cluster-identity-reader.yml rename to build/charts/antrea/templates/cluster-identity-reader/clusterrolebinding.yaml index d2d93f54859..6b0db36d256 100644 --- a/build/yamls/base/cluster-identity-reader.yml +++ b/build/charts/antrea/templates/cluster-identity-reader/clusterrolebinding.yaml @@ -2,6 +2,8 @@ kind: ClusterRole apiVersion: rbac.authorization.k8s.io/v1 metadata: name: antrea-cluster-identity-reader + labels: + app: antrea rules: - apiGroups: - "" diff --git a/build/charts/antrea/templates/configmap.yaml b/build/charts/antrea/templates/configmap.yaml new file mode 100644 index 00000000000..4d749dec75d --- /dev/null +++ b/build/charts/antrea/templates/configmap.yaml @@ -0,0 +1,9 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: antrea-config + namespace: {{ .Release.Namespace }} + labels: + app: antrea +data: +{{ tpl (.Files.Glob "conf/*").AsConfig . | indent 2 | replace " \n" "\n" }} diff --git a/build/charts/antrea/templates/controller/apiservices.yaml b/build/charts/antrea/templates/controller/apiservices.yaml new file mode 100644 index 00000000000..c6b0a531edc --- /dev/null +++ b/build/charts/antrea/templates/controller/apiservices.yaml @@ -0,0 +1,44 @@ +apiVersion: apiregistration.k8s.io/v1 +kind: APIService +metadata: + name: v1beta2.controlplane.antrea.io + labels: + app: antrea +spec: + group: controlplane.antrea.io + groupPriorityMinimum: 100 + version: v1beta2 + versionPriority: 100 + service: + name: antrea + namespace: {{ .Release.Namespace }} +--- +apiVersion: apiregistration.k8s.io/v1 +kind: APIService +metadata: + name: v1beta1.system.antrea.io + labels: + app: antrea +spec: + group: system.antrea.io + groupPriorityMinimum: 100 + version: v1beta1 + versionPriority: 100 + service: + name: antrea + namespace: {{ .Release.Namespace }} +--- +apiVersion: apiregistration.k8s.io/v1 +kind: APIService +metadata: + name: v1alpha1.stats.antrea.io + labels: + app: antrea +spec: + group: stats.antrea.io + groupPriorityMinimum: 100 + version: v1alpha1 + versionPriority: 100 + service: + name: antrea + namespace: {{ .Release.Namespace }} diff --git a/build/yamls/base/controller-rbac.yml b/build/charts/antrea/templates/controller/clusterrole.yaml similarity index 92% rename from build/yamls/base/controller-rbac.yml rename to build/charts/antrea/templates/controller/clusterrole.yaml index 1952ea3bc6d..2a5f043af35 100644 --- a/build/yamls/base/controller-rbac.yml +++ b/build/charts/antrea/templates/controller/clusterrole.yaml @@ -1,14 +1,9 @@ ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: antrea-controller - namespace: kube-system ---- kind: ClusterRole apiVersion: rbac.authorization.k8s.io/v1 metadata: name: antrea-controller + labels: + app: antrea rules: - apiGroups: - "" @@ -124,6 +119,9 @@ rules: - mutatingwebhookconfigurations - validatingwebhookconfigurations resourceNames: + # always give permissions for labelsmutator.antrea.io, even when the + # feature is disabled, to avoid errors in antrea-controller when updating + # the CA cert. - labelsmutator.antrea.io - crdmutator.antrea.io - crdvalidator.antrea.io @@ -244,16 +242,3 @@ rules: - get - list - watch ---- -kind: ClusterRoleBinding -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: antrea-controller -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: antrea-controller -subjects: - - kind: ServiceAccount - name: antrea-controller - namespace: kube-system diff --git a/build/charts/antrea/templates/controller/clusterrolebinding.yaml b/build/charts/antrea/templates/controller/clusterrolebinding.yaml new file mode 100644 index 00000000000..010461d471e --- /dev/null +++ b/build/charts/antrea/templates/controller/clusterrolebinding.yaml @@ -0,0 +1,14 @@ +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: antrea-controller + labels: + app: antrea +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: antrea-controller +subjects: + - kind: ServiceAccount + name: antrea-controller + namespace: {{ .Release.Namespace }} diff --git a/build/charts/antrea/templates/controller/deployment.yaml b/build/charts/antrea/templates/controller/deployment.yaml new file mode 100644 index 00000000000..8f00801da97 --- /dev/null +++ b/build/charts/antrea/templates/controller/deployment.yaml @@ -0,0 +1,156 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: antrea-controller + namespace: {{ .Release.Namespace }} + labels: + app: antrea + component: antrea-controller +spec: + strategy: + # Ensure the existing Pod is stopped before the new one is created. + type: Recreate + selector: + matchLabels: + app: antrea + component: antrea-controller + replicas: 1 + template: + metadata: + annotations: + # Automatically restart Pod if the ConfigMap changes + # See https://helm.sh/docs/howto/charts_tips_and_tricks/#automatically-roll-deployments + checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }} + {{- with .Values.controller.podAnnotations }} + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + app: antrea + component: antrea-controller + {{- with .Values.controller.podLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + {{- with .Values.controller.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + hostNetwork: true + priorityClassName: {{ .Values.controller.priorityClassName }} + {{- with .Values.controller.tolerations }} + tolerations: + {{- toYaml . | trim | nindent 8 }} + {{- end }} + {{- if .Values.testing.simulator.enable }} + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: antrea/instance + operator: NotIn + values: + - simulator + {{- else }} + {{- with .Values.controller.affinity }} + affinity: + {{- toYaml . | trim | nindent 8 }} + {{- end }} + {{- end }} + serviceAccountName: antrea-controller + containers: + - name: antrea-controller + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + resources: {{- .Values.controller.antreaController.resources | toYaml | nindent 12 }} + {{- if ((.Values.testing).coverage) }} + command: ["/bin/sh"] + args: ["-c", "antrea-controller-coverage -test.run=TestBincoverRunMain -test.coverprofile=antrea-controller.cov.out -args-file=/controller-arg-file; while true; do sleep 5 & wait $!; done"] + {{- else }} + command: ["antrea-controller"] + # Log to both "/var/log/antrea/" and stderr (so "kubectl logs" can work). + args: + - "--config=/etc/antrea/antrea-controller.conf" + - "--logtostderr=false" + - "--log_dir=/var/log/antrea" + - "--alsologtostderr" + - "--log_file_max_size={{ .Values.controller.antreaController.logFileMaxSize }}" + - "--log_file_max_num={{ .Values.controller.antreaController.logFileMaxNum }}" + {{- if .Values.logVerbosity }} + - "--v={{ .Values.logVerbosity }}" + {{- end }} + {{- with .Values.controller.antreaController.extraArgs }} + {{- toYaml . | trim | nindent 12 }} + {{- end }} + {{- end }} + env: + # Provide pod and node information for clusterinformation CRD. + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: NODE_NAME + valueFrom: + fieldRef: + fieldPath: spec.nodeName + # Provide ServiceAccount name for validation webhook. + - name: SERVICEACCOUNT_NAME + valueFrom: + fieldRef: + fieldPath: spec.serviceAccountName + - name: ANTREA_CONFIG_MAP_NAME + value: antrea-config + {{- range $k, $v := .Values.controller.antreaController.extraEnv }} + - name: {{ $k | quote }} + value: {{ $v | quote }} + {{- end }} + ports: + - containerPort: 10349 + name: api + protocol: TCP + readinessProbe: + httpGet: + host: localhost + path: /readyz + port: api + scheme: HTTPS + initialDelaySeconds: 5 + timeoutSeconds: 5 + periodSeconds: 10 + failureThreshold: 5 + livenessProbe: + httpGet: + host: localhost + path: /livez + port: api + scheme: HTTPS + timeoutSeconds: 5 + periodSeconds: 10 + failureThreshold: 5 + volumeMounts: + - name: antrea-config + mountPath: /etc/antrea/antrea-controller.conf + subPath: antrea-controller.conf + readOnly: true + - name: antrea-controller-tls + mountPath: /var/run/antrea/antrea-controller-tls + - name: host-var-log-antrea + mountPath: /var/log/antrea + volumes: + - name: antrea-config + configMap: + name: antrea-config + # Make it optional as we only read it when selfSignedCert=false. + - name: antrea-controller-tls + secret: + secretName: antrea-controller-tls + defaultMode: 0400 + optional: true + - name: host-var-log-antrea + hostPath: + path: /var/log/antrea + type: DirectoryOrCreate diff --git a/build/charts/antrea/templates/controller/service.yaml b/build/charts/antrea/templates/controller/service.yaml new file mode 100644 index 00000000000..118f183f488 --- /dev/null +++ b/build/charts/antrea/templates/controller/service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: antrea + namespace: {{ .Release.Namespace }} + labels: + app: antrea +spec: + ports: + - port: 443 + protocol: TCP + targetPort: api + selector: + app: antrea + component: antrea-controller diff --git a/build/charts/antrea/templates/controller/serviceaccount.yaml b/build/charts/antrea/templates/controller/serviceaccount.yaml new file mode 100644 index 00000000000..94046c25030 --- /dev/null +++ b/build/charts/antrea/templates/controller/serviceaccount.yaml @@ -0,0 +1,7 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: antrea-controller + namespace: {{ .Release.Namespace }} + labels: + app: antrea diff --git a/build/yamls/base/crds-rbac.yml b/build/charts/antrea/templates/crds-rbac/clusterroles.yaml similarity index 96% rename from build/yamls/base/crds-rbac.yml rename to build/charts/antrea/templates/crds-rbac/clusterroles.yaml index 3ddc3ac9167..e076228450b 100644 --- a/build/yamls/base/crds-rbac.yml +++ b/build/charts/antrea/templates/crds-rbac/clusterroles.yaml @@ -1,9 +1,9 @@ ---- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: aggregate-antrea-policies-edit labels: + app: antrea # Add these permissions to the "admin" and "edit" default roles. rbac.authorization.k8s.io/aggregate-to-admin: "true" rbac.authorization.k8s.io/aggregate-to-edit: "true" @@ -17,6 +17,7 @@ apiVersion: rbac.authorization.k8s.io/v1 metadata: name: aggregate-antrea-policies-view labels: + app: antrea # Add these permissions to the "view" default role. rbac.authorization.k8s.io/aggregate-to-view: "true" rules: @@ -29,6 +30,7 @@ kind: ClusterRole metadata: name: aggregate-traceflows-edit labels: + app: antrea # Add these permissions to the "admin" and "edit" default roles. rbac.authorization.k8s.io/aggregate-to-admin: "true" rbac.authorization.k8s.io/aggregate-to-edit: "true" @@ -42,6 +44,7 @@ apiVersion: rbac.authorization.k8s.io/v1 metadata: name: aggregate-traceflows-view labels: + app: antrea # Add these permissions to the "view" default role. rbac.authorization.k8s.io/aggregate-to-view: "true" rules: @@ -54,6 +57,7 @@ kind: ClusterRole metadata: name: aggregate-antrea-clustergroups-edit labels: + app: antrea # Add these permissions to the "admin" and "edit" default roles. rbac.authorization.k8s.io/aggregate-to-admin: "true" rbac.authorization.k8s.io/aggregate-to-edit: "true" @@ -67,10 +71,10 @@ apiVersion: rbac.authorization.k8s.io/v1 metadata: name: aggregate-antrea-clustergroups-view labels: + app: antrea # Add these permissions to the "view" default role. rbac.authorization.k8s.io/aggregate-to-view: "true" rules: - apiGroups: ["crd.antrea.io"] resources: ["clustergroups"] verbs: ["get", "list", "watch"] ---- diff --git a/build/charts/antrea/templates/crds/antreaagentinfo.yaml b/build/charts/antrea/templates/crds/antreaagentinfo.yaml new file mode 100644 index 00000000000..e81509d2ce1 --- /dev/null +++ b/build/charts/antrea/templates/crds/antreaagentinfo.yaml @@ -0,0 +1,52 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: antreaagentinfos.crd.antrea.io + labels: + app: antrea +spec: + group: crd.antrea.io + versions: + - name: v1beta1 + served: true + storage: true + schema: + openAPIV3Schema: + type: object + x-kubernetes-preserve-unknown-fields: true + additionalPrinterColumns: + - description: Health status of this Agent + jsonPath: ".agentConditions[?(@.type=='AgentHealthy')].status" + name: Healthy + type: string + - description: Last time the Healthy Condition was updated + jsonPath: ".agentConditions[?(@.type=='AgentHealthy')].lastHeartbeatTime" + name: Last Heartbeat + type: date + - description: Version of this Agent + jsonPath: ".version" + name: Version + type: string + priority: 1 + - description: Node on which this Agent is running + jsonPath: ".nodeRef.name" + name: Node + type: string + priority: 1 + - description: Number of local Pods managed by this Agent + jsonPath: ".localPodNum" + name: Num Pods + type: integer + priority: 2 + - description: Subnets used by this Agent for Pod IPAM + jsonPath: ".nodeSubnets" + name: Subnets + type: string + priority: 2 + scope: Cluster + names: + plural: antreaagentinfos + singular: antreaagentinfo + kind: AntreaAgentInfo + shortNames: + - aai diff --git a/build/charts/antrea/templates/crds/antreacontrollerinfo.yaml b/build/charts/antrea/templates/crds/antreacontrollerinfo.yaml new file mode 100644 index 00000000000..d3cc473c5f2 --- /dev/null +++ b/build/charts/antrea/templates/crds/antreacontrollerinfo.yaml @@ -0,0 +1,52 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: antreacontrollerinfos.crd.antrea.io + labels: + app: antrea +spec: + group: crd.antrea.io + versions: + - name: v1beta1 + served: true + storage: true + schema: + openAPIV3Schema: + type: object + x-kubernetes-preserve-unknown-fields: true + additionalPrinterColumns: + - description: Health status of the Controller + jsonPath: ".controllerConditions[?(@.type=='ControllerHealthy')].status" + name: Healthy + type: string + - description: Last time the Healthy Condition was updated + jsonPath: ".controllerConditions[?(@.type=='ControllerHealthy')].lastHeartbeatTime" + name: Last Heartbeat + type: date + - description: Version of the Controller + jsonPath: ".version" + name: Version + type: string + priority: 1 + - description: Number of Agents connected to the Controller + jsonPath: ".connectedAgentNum" + name: Connected Agents + type: integer + priority: 1 + - description: Node on which the Controller is running + jsonPath: ".nodeRef.name" + name: Node + type: string + priority: 1 + - description: Number of Network Policies computed by Controller + jsonPath: ".networkPolicyControllerInfo.networkPolicyNum" + name: Num Network Policies + type: integer + priority: 2 + scope: Cluster + names: + plural: antreacontrollerinfos + singular: antreacontrollerinfo + kind: AntreaControllerInfo + shortNames: + - aci diff --git a/build/charts/antrea/templates/crds/clustergroup.yaml b/build/charts/antrea/templates/crds/clustergroup.yaml new file mode 100644 index 00000000000..8989b1ce9b0 --- /dev/null +++ b/build/charts/antrea/templates/crds/clustergroup.yaml @@ -0,0 +1,263 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: clustergroups.crd.antrea.io + labels: + app: antrea +spec: + group: crd.antrea.io + versions: + - name: v1alpha2 + served: true + storage: false + schema: + openAPIV3Schema: + type: object + properties: + spec: + type: object + properties: + childGroups: + type: array + items: + type: string + podSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + externalEntitySelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + ipBlock: + type: object + properties: + cidr: + type: string + format: cidr + ipBlocks: + type: array + items: + type: object + properties: + cidr: + type: string + format: cidr + serviceReference: + type: object + properties: + name: + type: string + namespace: + type: string + status: + type: object + properties: + conditions: + type: array + items: + type: object + properties: + type: + type: string + status: + type: string + lastTransitionTime: + type: string + - name: v1alpha3 + served: true + storage: true + schema: + openAPIV3Schema: + type: object + properties: + spec: + type: object + properties: + childGroups: + type: array + items: + type: string + podSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + externalEntitySelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + ipBlocks: + type: array + items: + type: object + properties: + cidr: + type: string + format: cidr + serviceReference: + type: object + properties: + name: + type: string + namespace: + type: string + status: + type: object + properties: + conditions: + type: array + items: + type: object + properties: + type: + type: string + status: + type: string + lastTransitionTime: + type: string + subresources: + status: {} + conversion: + strategy: Webhook + webhook: + conversionReviewVersions: ["v1", "v1beta1"] + clientConfig: + service: + name: "antrea" + namespace: "kube-system" + path: "/convert/clustergroup" + scope: Cluster + names: + plural: clustergroups + singular: clustergroup + kind: ClusterGroup + shortNames: + - cg diff --git a/build/charts/antrea/templates/crds/clusternetworkpolicy.yaml b/build/charts/antrea/templates/crds/clusternetworkpolicy.yaml new file mode 100644 index 00000000000..a2a90da43c9 --- /dev/null +++ b/build/charts/antrea/templates/crds/clusternetworkpolicy.yaml @@ -0,0 +1,579 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: clusternetworkpolicies.crd.antrea.io + labels: + app: antrea +spec: + group: crd.antrea.io + versions: + - name: v1alpha1 + served: true + storage: true + additionalPrinterColumns: + - name: Tier + type: string + description: The Tier to which this ClusterNetworkPolicy belongs to. + jsonPath: .spec.tier + - name: Priority + type: number + format: float + description: The Priority of this ClusterNetworkPolicy relative to other policies. + jsonPath: .spec.priority + - name: Desired Nodes + type: number + format: int32 + description: The total number of Nodes that should realize the NetworkPolicy. + jsonPath: .status.desiredNodesRealized + - name: Current Nodes + type: number + format: int32 + description: The number of Nodes that have realized the NetworkPolicy. + jsonPath: .status.currentNodesRealized + - name: Age + type: date + jsonPath: .metadata.creationTimestamp + schema: + openAPIV3Schema: + type: object + properties: + spec: + # Ensure that Spec.Priority field is set + required: + - priority + type: object + properties: + tier: + type: string + priority: + type: number + format: float + # Ensure that Spec.Priority field is between 1 and 10000 + minimum: 1.0 + maximum: 10000.0 + appliedTo: + type: array + items: + type: object + # Ensure that Spec.AppliedTo does not allow IPBlock field + properties: + podSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + group: + type: string + serviceAccount: + type: object + properties: + name: + type: string + namespace: + type: string + required: + - name + - namespace + ingress: + type: array + items: + type: object + required: + - action + properties: + appliedTo: + type: array + items: + type: object + # Ensure that rule AppliedTo does not allow IPBlock field + properties: + podSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + group: + type: string + serviceAccount: + type: object + properties: + name: + type: string + namespace: + type: string + required: + - name + - namespace + # Ensure that Action field allows only ALLOW, DROP, REJECT and PASS values + action: + type: string + enum: ['Allow', 'Drop', 'Reject', 'Pass'] + ports: + type: array + items: + type: object + properties: + protocol: + type: string + enum: ['TCP', 'UDP', 'SCTP'] + port: + x-kubernetes-int-or-string: true + endPort: + type: integer + protocols: + type: array + items: + type: object + oneOf: + - required: [icmp] + properties: + icmp: + type: object + properties: + icmpType: + type: integer + minimum: 0 + maximum: 255 + icmpCode: + type: integer + minimum: 0 + maximum: 255 + from: + type: array + items: + type: object + properties: + podSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + namespaces: + type: object + properties: + match: + enum: + - Self + type: string + ipBlock: + type: object + properties: + cidr: + type: string + format: cidr + group: + type: string + serviceAccount: + type: object + properties: + name: + type: string + namespace: + type: string + required: + - name + - namespace + nodeSelector: + type: object + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + type: array + type: object + type: array + matchLabels: + x-kubernetes-preserve-unknown-fields: true + name: + type: string + enableLogging: + type: boolean + egress: + type: array + items: + type: object + required: + - action + properties: + appliedTo: + type: array + items: + type: object + # Ensure that rule AppliedTo does not allow IPBlock field + properties: + podSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + group: + type: string + serviceAccount: + type: object + properties: + name: + type: string + namespace: + type: string + required: + - name + - namespace + # Ensure that Action field allows only ALLOW, DROP, REJECT and PASS values + action: + type: string + enum: ['Allow', 'Drop', 'Reject', 'Pass'] + ports: + type: array + items: + type: object + properties: + protocol: + type: string + enum: ['TCP', 'UDP', 'SCTP'] + port: + x-kubernetes-int-or-string: true + endPort: + type: integer + protocols: + type: array + items: + type: object + oneOf: + - required: [icmp] + properties: + icmp: + type: object + properties: + icmpType: + type: integer + minimum: 0 + maximum: 255 + icmpCode: + type: integer + minimum: 0 + maximum: 255 + to: + type: array + items: + type: object + properties: + podSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + namespaces: + type: object + properties: + match: + enum: + - Self + type: string + ipBlock: + type: object + properties: + cidr: + type: string + format: cidr + group: + type: string + fqdn: + type: string + serviceAccount: + type: object + properties: + name: + type: string + namespace: + type: string + required: + - name + - namespace + nodeSelector: + type: object + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + type: array + type: object + type: array + matchLabels: + x-kubernetes-preserve-unknown-fields: true + toServices: + type: array + items: + type: object + required: + - name + - namespace + properties: + name: + type: string + namespace: + type: string + name: + type: string + enableLogging: + type: boolean + status: + type: object + properties: + phase: + type: string + observedGeneration: + type: integer + currentNodesRealized: + type: integer + desiredNodesRealized: + type: integer + subresources: + status: {} + scope: Cluster + names: + plural: clusternetworkpolicies + singular: clusternetworkpolicy + kind: ClusterNetworkPolicy + shortNames: + - acnp diff --git a/build/charts/antrea/templates/crds/egress.yaml b/build/charts/antrea/templates/crds/egress.yaml new file mode 100644 index 00000000000..bcdfea97652 --- /dev/null +++ b/build/charts/antrea/templates/crds/egress.yaml @@ -0,0 +1,112 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: egresses.crd.antrea.io + labels: + app: antrea +spec: + group: crd.antrea.io + versions: + - name: v1alpha2 + served: true + storage: true + schema: + openAPIV3Schema: + type: object + required: + - spec + properties: + spec: + type: object + required: + - appliedTo + anyOf: + - required: + - egressIP + - required: + - externalIPPool + properties: + appliedTo: + type: object + properties: + podSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + egressIP: + type: string + oneOf: + - format: ipv4 + - format: ipv6 + externalIPPool: + type: string + status: + type: object + properties: + egressNode: + type: string + additionalPrinterColumns: + - description: Specifies the SNAT IP address for the selected workloads. + jsonPath: .spec.egressIP + name: EgressIP + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + - description: The Owner Node of egress IP + jsonPath: .status.egressNode + name: Node + type: string + subresources: + status: {} + scope: Cluster + names: + plural: egresses + singular: egress + kind: Egress + shortNames: + - eg diff --git a/build/charts/antrea/templates/crds/externalentity.yaml b/build/charts/antrea/templates/crds/externalentity.yaml new file mode 100644 index 00000000000..bfa251ebe57 --- /dev/null +++ b/build/charts/antrea/templates/crds/externalentity.yaml @@ -0,0 +1,58 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: externalentities.crd.antrea.io + labels: + app: antrea +spec: + group: crd.antrea.io + versions: + - name: v1alpha2 + served: true + storage: true + schema: + openAPIV3Schema: + type: object + properties: + spec: + type: object + properties: + endpoints: + type: array + items: + type: object + properties: + ip: + type: string + oneOf: + - format: ipv4 + - format: ipv6 + name: + type: string + ports: + type: array + items: + type: object + properties: + protocol: + type: string + enum: ['TCP', 'UDP', 'SCTP'] + port: + x-kubernetes-int-or-string: true + name: + type: string + externalNode: + type: string + - name: v1alpha1 + served: false + storage: false + schema: + openAPIV3Schema: + type: object + scope: Namespaced + names: + plural: externalentities + singular: externalentity + kind: ExternalEntity + shortNames: + - ee diff --git a/build/charts/antrea/templates/crds/externalippool.yaml b/build/charts/antrea/templates/crds/externalippool.yaml new file mode 100644 index 00000000000..080c0c620c0 --- /dev/null +++ b/build/charts/antrea/templates/crds/externalippool.yaml @@ -0,0 +1,103 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: externalippools.crd.antrea.io + labels: + app: antrea +spec: + group: crd.antrea.io + versions: + - name: v1alpha2 + served: true + storage: true + schema: + openAPIV3Schema: + type: object + required: + - spec + properties: + spec: + type: object + required: + - ipRanges + - nodeSelector + properties: + ipRanges: + type: array + items: + type: object + oneOf: + - required: + - cidr + - required: + - start + - end + properties: + cidr: + type: string + format: cidr + start: + type: string + oneOf: + - format: ipv4 + - format: ipv6 + end: + type: string + oneOf: + - format: ipv4 + - format: ipv6 + nodeSelector: + type: object + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + type: array + type: object + type: array + matchLabels: + x-kubernetes-preserve-unknown-fields: true + status: + type: object + properties: + usage: + type: object + properties: + total: + type: integer + used: + type: integer + additionalPrinterColumns: + - description: The number of total IPs + jsonPath: .status.usage.total + name: Total + type: integer + - description: The number of allocated IPs + jsonPath: .status.usage.used + name: Used + type: integer + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + subresources: + status: {} + scope: Cluster + names: + plural: externalippools + singular: externalippool + kind: ExternalIPPool + shortNames: + - eip diff --git a/build/charts/antrea/templates/crds/ippool.yaml b/build/charts/antrea/templates/crds/ippool.yaml new file mode 100644 index 00000000000..32529c81e51 --- /dev/null +++ b/build/charts/antrea/templates/crds/ippool.yaml @@ -0,0 +1,109 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: ippools.crd.antrea.io + labels: + app: antrea +spec: + group: crd.antrea.io + versions: + - name: v1alpha2 + served: true + storage: true + schema: + openAPIV3Schema: + type: object + required: + - spec + properties: + spec: + required: + - ipVersion + - ipRanges + type: object + properties: + ipVersion: + type: integer + ipRanges: + items: + oneOf: + - required: + - cidr + - gateway + - prefixLength + - required: + - start + - end + - gateway + - prefixLength + properties: + cidr: + format: cidr + type: string + start: + oneOf: + - format: ipv4 + - format: ipv6 + type: string + end: + oneOf: + - format: ipv4 + - format: ipv6 + type: string + gateway: + oneOf: + - format: ipv4 + - format: ipv6 + type: string + prefixLength: + type: integer + vlan: + type: integer + minimum: 0 + maximum: 4094 + type: object + type: array + status: + properties: + ipAddresses: + items: + properties: + ipAddress: + type: string + owner: + properties: + pod: + properties: + name: + type: string + namespace: + type: string + containerID: + type: string + ifName: + type: string + type: object + statefulSet: + properties: + name: + type: string + namespace: + type: string + index: + type: integer + type: object + type: object + phase: + type: string + type: object + type: array + type: object + subresources: + status: {} + scope: Cluster + names: + plural: ippools + singular: ippool + kind: IPPool + shortNames: + - ipp diff --git a/build/charts/antrea/templates/crds/networkpolicy.yaml b/build/charts/antrea/templates/crds/networkpolicy.yaml new file mode 100644 index 00000000000..7eb31cd2190 --- /dev/null +++ b/build/charts/antrea/templates/crds/networkpolicy.yaml @@ -0,0 +1,480 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: networkpolicies.crd.antrea.io + labels: + app: antrea +spec: + group: crd.antrea.io + versions: + - name: v1alpha1 + served: true + storage: true + additionalPrinterColumns: + - name: Tier + type: string + description: The Tier to which this Antrea NetworkPolicy belongs to. + jsonPath: .spec.tier + - name: Priority + type: number + format: float + description: The Priority of this Antrea NetworkPolicy relative to other policies. + jsonPath: .spec.priority + - name: Desired Nodes + type: number + format: int32 + description: The total number of Nodes that should realize the NetworkPolicy. + jsonPath: .status.desiredNodesRealized + - name: Current Nodes + type: number + format: int32 + description: The number of Nodes that have realized the NetworkPolicy. + jsonPath: .status.currentNodesRealized + - name: Age + type: date + jsonPath: .metadata.creationTimestamp + schema: + openAPIV3Schema: + type: object + properties: + spec: + # Ensure that Spec.Priority field is set + required: + - priority + type: object + properties: + tier: + type: string + priority: + type: number + format: float + # Ensure that Spec.Priority field is between 1 and 10000 + minimum: 1.0 + maximum: 10000.0 + appliedTo: + type: array + items: + type: object + # Ensure that Spec.AppliedTo does not allow NamespaceSelector/IPBlock field + properties: + podSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + ingress: + type: array + items: + type: object + required: + - action + properties: + appliedTo: + type: array + items: + type: object + # Ensure that rule AppliedTo does not allow NamespaceSelector/IPBlock field + properties: + podSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + # Ensure that Action field allows only ALLOW, DROP, REJECT and PASS values + action: + type: string + enum: ['Allow', 'Drop', 'Reject', 'Pass'] + ports: + type: array + items: + type: object + properties: + protocol: + type: string + enum: ['TCP', 'UDP', 'SCTP'] + port: + x-kubernetes-int-or-string: true + endPort: + type: integer + protocols: + type: array + items: + type: object + oneOf: + - required: [icmp] + properties: + icmp: + type: object + properties: + icmpType: + type: integer + minimum: 0 + maximum: 255 + icmpCode: + type: integer + minimum: 0 + maximum: 255 + from: + type: array + items: + type: object + properties: + podSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + externalEntitySelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + ipBlock: + type: object + properties: + cidr: + type: string + format: cidr + nodeSelector: + type: object + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + type: array + type: object + type: array + matchLabels: + x-kubernetes-preserve-unknown-fields: true + name: + type: string + enableLogging: + type: boolean + egress: + type: array + items: + type: object + required: + - action + properties: + appliedTo: + type: array + items: + type: object + # Ensure that rule AppliedTo does not allow NamespaceSelector/IPBlock field + properties: + podSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + # Ensure that Action field allows only ALLOW, DROP, REJECT and PASS values + action: + type: string + enum: ['Allow', 'Drop', 'Reject', 'Pass'] + ports: + type: array + items: + type: object + properties: + protocol: + type: string + enum: ['TCP', 'UDP', 'SCTP'] + port: + x-kubernetes-int-or-string: true + endPort: + type: integer + protocols: + type: array + items: + type: object + oneOf: + - required: [icmp] + properties: + icmp: + type: object + properties: + icmpType: + type: integer + minimum: 0 + maximum: 255 + icmpCode: + type: integer + minimum: 0 + maximum: 255 + to: + type: array + items: + type: object + properties: + podSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + externalEntitySelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + ipBlock: + type: object + properties: + cidr: + type: string + format: cidr + fqdn: + type: string + nodeSelector: + type: object + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + type: array + type: object + type: array + matchLabels: + x-kubernetes-preserve-unknown-fields: true + toServices: + type: array + items: + type: object + required: + - name + properties: + name: + type: string + namespace: + type: string + name: + type: string + enableLogging: + type: boolean + status: + type: object + properties: + phase: + type: string + observedGeneration: + type: integer + currentNodesRealized: + type: integer + desiredNodesRealized: + type: integer + subresources: + status: {} + scope: Namespaced + names: + plural: networkpolicies + singular: networkpolicy + kind: NetworkPolicy + shortNames: + - anp diff --git a/build/charts/antrea/templates/crds/tier.yaml b/build/charts/antrea/templates/crds/tier.yaml new file mode 100644 index 00000000000..1ee1a1ce5fe --- /dev/null +++ b/build/charts/antrea/templates/crds/tier.yaml @@ -0,0 +1,42 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: tiers.crd.antrea.io + labels: + app: antrea +spec: + group: crd.antrea.io + versions: + - name: v1alpha1 + served: true + storage: true + additionalPrinterColumns: + - name: Priority + type: integer + description: The Priority of this Tier relative to other Tiers. + jsonPath: .spec.priority + - name: Age + type: date + jsonPath: .metadata.creationTimestamp + schema: + openAPIV3Schema: + type: object + properties: + spec: + required: + - priority + type: object + properties: + priority: + type: integer + minimum: 0 + maximum: 255 + description: + type: string + scope: Cluster + names: + plural: tiers + singular: tier + kind: Tier + shortNames: + - tr diff --git a/build/charts/antrea/templates/crds/traceflow.yaml b/build/charts/antrea/templates/crds/traceflow.yaml new file mode 100644 index 00000000000..45d00fbb275 --- /dev/null +++ b/build/charts/antrea/templates/crds/traceflow.yaml @@ -0,0 +1,251 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: traceflows.crd.antrea.io + labels: + app: antrea +spec: + group: crd.antrea.io + versions: + - name: v1alpha1 + served: true + storage: true + additionalPrinterColumns: + - jsonPath: .status.phase + description: The phase of the Traceflow. + name: Phase + type: string + - jsonPath: .spec.source.pod + description: The name of the source Pod. + name: Source-Pod + type: string + priority: 10 + - jsonPath: .spec.destination.pod + description: The name of the destination Pod. + name: Destination-Pod + type: string + priority: 10 + - jsonPath: .spec.destination.ip + description: The IP address of the destination. + name: Destination-IP + type: string + priority: 10 + - jsonPath: .spec.liveTraffic + description: Trace live traffic. + name: Live-Traffic + type: boolean + priority: 10 + - jsonPath: .spec.droppedOnly + description: Capture only the dropped packet. + name: Dropped-Only + type: boolean + priority: 10 + - jsonPath: .spec.timeout + description: Timeout in seconds. + name: Timeout + type: integer + priority: 10 + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + schema: + openAPIV3Schema: + type: object + required: + - spec + properties: + spec: + type: object + properties: + source: + type: object + properties: + pod: + type: string + namespace: + type: string + ip: + type: string + oneOf: + - format: ipv4 + - format: ipv6 + destination: + type: object + properties: + pod: + type: string + service: + type: string + namespace: + type: string + ip: + type: string + oneOf: + - format: ipv4 + - format: ipv6 + packet: + type: object + properties: + ipHeader: + type: object + properties: + srcIP: + type: string + oneOf: + - format: ipv4 + - format: ipv6 + protocol: + type: integer + ttl: + type: integer + flags: + type: integer + ipv6Header: + type: object + properties: + srcIP: + type: string + format: ipv6 + nextHeader: + type: integer + hopLimit: + type: integer + transportHeader: + type: object + properties: + icmp: + type: object + properties: + id: + type: integer + sequence: + type: integer + udp: + type: object + properties: + srcPort: + type: integer + dstPort: + type: integer + tcp: + type: object + properties: + srcPort: + type: integer + dstPort: + type: integer + flags: + type: integer + liveTraffic: + type: boolean + droppedOnly: + type: boolean + timeout: + type: integer + status: + type: object + properties: + reason: + type: string + dataplaneTag: + type: integer + phase: + type: string + startTime: + type: string + results: + type: array + items: + type: object + properties: + node: + type: string + role: + type: string + timestamp: + type: integer + observations: + type: array + items: + type: object + properties: + component: + type: string + componentInfo: + type: string + action: + type: string + pod: + type: string + dstMAC: + type: string + networkPolicy: + type: string + ttl: + type: integer + translatedSrcIP: + type: string + translatedDstIP: + type: string + tunnelDstIP: + type: string + capturedPacket: + properties: + srcIP: + type: string + dstIP: + type: string + length: + type: integer + ipHeader: + properties: + flags: + type: integer + protocol: + type: integer + ttl: + type: integer + type: object + ipv6Header: + properties: + hopLimit: + type: integer + nextHeader: + type: integer + type: object + transportHeader: + properties: + tcp: + properties: + dstPort: + type: integer + srcPort: + type: integer + flags: + type: integer + type: object + udp: + properties: + dstPort: + type: integer + srcPort: + type: integer + type: object + icmp: + properties: + id: + type: integer + sequence: + type: integer + type: object + type: object + type: object + subresources: + status: {} + scope: Cluster + names: + plural: traceflows + singular: traceflow + kind: Traceflow + shortNames: + - tf diff --git a/build/charts/antrea/templates/crds/trafficcontrol.yaml b/build/charts/antrea/templates/crds/trafficcontrol.yaml new file mode 100644 index 00000000000..0f2ffdb457c --- /dev/null +++ b/build/charts/antrea/templates/crds/trafficcontrol.yaml @@ -0,0 +1,283 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: trafficcontrols.crd.antrea.io +spec: + group: crd.antrea.io + versions: + - name: v1alpha2 + served: true + storage: true + schema: + openAPIV3Schema: + type: object + required: + - spec + properties: + spec: + type: object + required: + - appliedTo + - direction + - action + - targetPort + properties: + appliedTo: + type: object + properties: + podSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + direction: + type: string + enum: + - Ingress + - Egress + - Both + action: + type: string + enum: + - Mirror + - Redirect + targetPort: + type: object + oneOf: + - required: [ovsInternal] + - required: [device] + - required: [geneve] + - required: [vxlan] + - required: [gre] + - required: [erspan] + properties: + ovsInternal: + type: object + required: + - name + properties: + name: + type: string + device: + type: object + required: + - name + properties: + name: + type: string + geneve: + type: object + required: + - remoteIP + properties: + remoteIP: + type: string + oneOf: + - format: ipv4 + - format: ipv6 + vni: + type: integer + minimum: 0 + maximum: 16777215 + destinationPort: + type: integer + minimum: 1 + maximum: 65535 + vxlan: + type: object + required: + - remoteIP + properties: + remoteIP: + type: string + oneOf: + - format: ipv4 + - format: ipv6 + vni: + type: integer + minimum: 0 + maximum: 16777215 + destinationPort: + type: integer + minimum: 1 + maximum: 65535 + gre: + type: object + required: + - remoteIP + properties: + remoteIP: + type: string + oneOf: + - format: ipv4 + - format: ipv6 + key: + type: integer + minimum: 0 + maximum: 4294967295 + erspan: + type: object + required: + - remoteIP + - version + properties: + remoteIP: + type: string + oneOf: + - format: ipv4 + - format: ipv6 + sessionID: + type: integer + minimum: 0 + maximum: 1023 + version: + type: integer + enum: + - 1 + - 2 + index: + type: integer + dir: + type: integer + enum: + - 0 + - 1 + hardwareID: + type: integer + returnPort: + type: object + oneOf: + - required: [ovsInternal] + - required: [device] + - required: [geneve] + - required: [vxlan] + - required: [gre] + properties: + ovsInternal: + type: object + required: + - name + properties: + name: + type: string + device: + type: object + required: + - name + properties: + name: + type: string + geneve: + type: object + required: + - remoteIP + properties: + remoteIP: + type: string + oneOf: + - format: ipv4 + - format: ipv6 + vni: + type: integer + minimum: 0 + maximum: 16777215 + destinationPort: + type: integer + minimum: 1 + maximum: 65535 + vxlan: + type: object + required: + - remoteIP + properties: + remoteIP: + type: string + oneOf: + - format: ipv4 + - format: ipv6 + vni: + type: integer + minimum: 0 + maximum: 16777215 + destinationPort: + type: integer + minimum: 1 + maximum: 65535 + gre: + type: object + required: + - remoteIP + properties: + remoteIP: + type: string + oneOf: + - format: ipv4 + - format: ipv6 + key: + type: integer + minimum: 0 + maximum: 4294967295 + additionalPrinterColumns: + - description: Specifies the direction of traffic that should be matched. + jsonPath: .spec.direction + name: Direction + type: string + - description: Specifies the action that should be taken for the traffic. + jsonPath: .spec.action + name: Action + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + subresources: + status: {} + scope: Cluster + names: + plural: trafficcontrols + singular: trafficcontrol + kind: TrafficControl + shortNames: + - tc diff --git a/build/charts/antrea/templates/simulator/configmap.yaml b/build/charts/antrea/templates/simulator/configmap.yaml new file mode 100644 index 00000000000..b4f4010ea83 --- /dev/null +++ b/build/charts/antrea/templates/simulator/configmap.yaml @@ -0,0 +1,11 @@ +{{- if .Values.testing.simulator.enable }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: node-configmap + namespace: {{ .Release.Namespace }} + labels: + app: antrea +data: + content.type: test-cluster +{{- end }} diff --git a/build/yamls/patches/simulator/antrea-agent-simulator.yml b/build/charts/antrea/templates/simulator/statefulset.yaml similarity index 96% rename from build/yamls/patches/simulator/antrea-agent-simulator.yml rename to build/charts/antrea/templates/simulator/statefulset.yaml index d66b83f904c..3b88accb1bb 100644 --- a/build/yamls/patches/simulator/antrea-agent-simulator.yml +++ b/build/charts/antrea/templates/simulator/statefulset.yaml @@ -1,17 +1,11 @@ ---- -apiVersion: v1 -data: - content.type: test-cluster -kind: ConfigMap -metadata: - name: node-configmap - namespace: kube-system ---- +{{- if .Values.testing.simulator.enable }} apiVersion: apps/v1 kind: StatefulSet metadata: name: antrea-agent-simulator - namespace: kube-system + namespace: {{ .Release.Namespace }} + labels: + app: antrea spec: podManagementPolicy: Parallel replicas: 1 @@ -151,3 +145,4 @@ spec: - effect: NoExecute key: node.kubernetes.io/not-ready operator: Exists +{{- end }} diff --git a/build/charts/antrea/templates/webhooks/mutating/crdmutator.yaml b/build/charts/antrea/templates/webhooks/mutating/crdmutator.yaml new file mode 100644 index 00000000000..f87e33111de --- /dev/null +++ b/build/charts/antrea/templates/webhooks/mutating/crdmutator.yaml @@ -0,0 +1,37 @@ +apiVersion: admissionregistration.k8s.io/v1 +kind: MutatingWebhookConfiguration +metadata: + name: "crdmutator.antrea.io" + labels: + app: antrea +webhooks: + - name: "acnpmutator.antrea.io" + clientConfig: + service: + name: "antrea" + namespace: {{ .Release.Namespace }} + path: "/mutate/acnp" + rules: + - operations: ["CREATE", "UPDATE"] + apiGroups: ["crd.antrea.io"] + apiVersions: ["v1alpha1"] + resources: ["clusternetworkpolicies"] + scope: "Cluster" + admissionReviewVersions: ["v1", "v1beta1"] + sideEffects: None + timeoutSeconds: 5 + - name: "anpmutator.antrea.io" + clientConfig: + service: + name: "antrea" + namespace: {{ .Release.Namespace }} + path: "/mutate/anp" + rules: + - operations: ["CREATE", "UPDATE"] + apiGroups: ["crd.antrea.io"] + apiVersions: ["v1alpha1"] + resources: ["networkpolicies"] + scope: "Namespaced" + admissionReviewVersions: ["v1", "v1beta1"] + sideEffects: None + timeoutSeconds: 5 diff --git a/build/yamls/patches/admissioncontroller/webhook.yml b/build/charts/antrea/templates/webhooks/mutating/labelsmutator.yaml similarity index 86% rename from build/yamls/patches/admissioncontroller/webhook.yml rename to build/charts/antrea/templates/webhooks/mutating/labelsmutator.yaml index b36ac0edeb1..f87a49e30db 100644 --- a/build/yamls/patches/admissioncontroller/webhook.yml +++ b/build/charts/antrea/templates/webhooks/mutating/labelsmutator.yaml @@ -1,7 +1,10 @@ +{{- if .Values.webhooks.labelsMutator.enable }} apiVersion: admissionregistration.k8s.io/v1 kind: MutatingWebhookConfiguration metadata: name: "labelsmutator.antrea.io" + labels: + app: antrea webhooks: - name: "namelabelmutator.antrea.io" clientConfig: @@ -18,3 +21,4 @@ webhooks: admissionReviewVersions: ["v1", "v1beta1"] sideEffects: None timeoutSeconds: 5 +{{- end }} diff --git a/build/charts/antrea/templates/webhooks/validating/crdvalidator.yaml b/build/charts/antrea/templates/webhooks/validating/crdvalidator.yaml new file mode 100644 index 00000000000..6cd661c3eeb --- /dev/null +++ b/build/charts/antrea/templates/webhooks/validating/crdvalidator.yaml @@ -0,0 +1,112 @@ +apiVersion: admissionregistration.k8s.io/v1 +kind: ValidatingWebhookConfiguration +metadata: + name: "crdvalidator.antrea.io" + labels: + app: antrea +webhooks: + - name: "tiervalidator.antrea.io" + clientConfig: + service: + name: "antrea" + namespace: {{ .Release.Namespace }} + path: "/validate/tier" + rules: + - operations: ["CREATE", "UPDATE", "DELETE"] + apiGroups: ["crd.antrea.io"] + apiVersions: ["v1alpha1"] + resources: ["tiers"] + scope: "Cluster" + admissionReviewVersions: ["v1", "v1beta1"] + sideEffects: None + timeoutSeconds: 5 + - name: "acnpvalidator.antrea.io" + clientConfig: + service: + name: "antrea" + namespace: {{ .Release.Namespace }} + path: "/validate/acnp" + rules: + - operations: ["CREATE", "UPDATE"] + apiGroups: ["crd.antrea.io"] + apiVersions: ["v1alpha1"] + resources: ["clusternetworkpolicies"] + scope: "Cluster" + admissionReviewVersions: ["v1", "v1beta1"] + sideEffects: None + timeoutSeconds: 5 + - name: "anpvalidator.antrea.io" + clientConfig: + service: + name: "antrea" + namespace: {{ .Release.Namespace }} + path: "/validate/anp" + rules: + - operations: ["CREATE", "UPDATE"] + apiGroups: ["crd.antrea.io"] + apiVersions: ["v1alpha1"] + resources: ["networkpolicies"] + scope: "Namespaced" + admissionReviewVersions: ["v1", "v1beta1"] + sideEffects: None + timeoutSeconds: 5 + - name: "clustergroupvalidator.antrea.io" + clientConfig: + service: + name: "antrea" + namespace: {{ .Release.Namespace }} + path: "/validate/clustergroup" + rules: + - operations: ["CREATE", "UPDATE"] + apiGroups: ["crd.antrea.io"] + apiVersions: ["v1alpha3", "v1alpha2"] + resources: ["clustergroups"] + scope: "Cluster" + admissionReviewVersions: ["v1", "v1beta1"] + sideEffects: None + timeoutSeconds: 5 + - name: "externalippoolvalidator.antrea.io" + clientConfig: + service: + name: "antrea" + namespace: {{ .Release.Namespace }} + path: "/validate/externalippool" + rules: + - operations: ["UPDATE"] + apiGroups: ["crd.antrea.io"] + apiVersions: ["v1alpha2"] + resources: ["externalippools"] + scope: "Cluster" + admissionReviewVersions: ["v1", "v1beta1"] + sideEffects: None + timeoutSeconds: 5 + - name: "egressvalidator.antrea.io" + clientConfig: + service: + name: "antrea" + namespace: {{ .Release.Namespace }} + path: "/validate/egress" + rules: + - operations: ["CREATE", "UPDATE"] + apiGroups: ["crd.antrea.io"] + apiVersions: ["v1alpha2"] + resources: ["egresses"] + scope: "Cluster" + admissionReviewVersions: ["v1", "v1beta1"] + sideEffects: None + timeoutSeconds: 5 + - name: "ippoolvalidator.antrea.io" + clientConfig: + service: + name: "antrea" + namespace: {{ .Release.Namespace }} + path: "/validate/ippool" + rules: + - operations: ["CREATE", "UPDATE", "DELETE"] + apiGroups: ["crd.antrea.io"] + apiVersions: ["v1alpha2"] + resources: ["ippools"] + scope: "Cluster" + admissionReviewVersions: ["v1", "v1beta1"] + sideEffects: None + timeoutSeconds: 5 diff --git a/build/charts/antrea/templates/whereabouts/clusterrole.yaml b/build/charts/antrea/templates/whereabouts/clusterrole.yaml new file mode 100644 index 00000000000..c7af5821866 --- /dev/null +++ b/build/charts/antrea/templates/whereabouts/clusterrole.yaml @@ -0,0 +1,22 @@ +{{- if .Values.whereabouts.enable }} +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: antrea-agent-whereabouts + labels: + app: antrea +rules: + - apiGroups: + - whereabouts.cni.cncf.io + resources: + - ippools + verbs: + - get + - put + - watch + - list + - update + - patch + - create + - delete +{{- end }} diff --git a/build/charts/antrea/templates/whereabouts/clusterrolebinding.yaml b/build/charts/antrea/templates/whereabouts/clusterrolebinding.yaml new file mode 100644 index 00000000000..5961902f8ff --- /dev/null +++ b/build/charts/antrea/templates/whereabouts/clusterrolebinding.yaml @@ -0,0 +1,16 @@ +{{- if .Values.whereabouts.enable }} +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: antrea-agent-whereabouts + labels: + app: antrea +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: antrea-agent-whereabouts +subjects: + - kind: ServiceAccount + name: antrea-agent-whereabouts + namespace: {{ .Release.Namespace }} +{{- end }} diff --git a/build/charts/antrea/templates/whereabouts/secret.yaml b/build/charts/antrea/templates/whereabouts/secret.yaml new file mode 100644 index 00000000000..fba1efd9058 --- /dev/null +++ b/build/charts/antrea/templates/whereabouts/secret.yaml @@ -0,0 +1,12 @@ +{{- if .Values.whereabouts.enable }} +apiVersion: v1 +kind: Secret +metadata: + name: whereabouts-cni-secret + namespace: {{ .Release.Namespace }} + annotations: + kubernetes.io/service-account.name: antrea-agent-whereabouts + labels: + app: antrea +type: kubernetes.io/service-account-token +{{- end }} diff --git a/build/charts/antrea/templates/whereabouts/serviceaccount.yaml b/build/charts/antrea/templates/whereabouts/serviceaccount.yaml new file mode 100644 index 00000000000..9129cf25470 --- /dev/null +++ b/build/charts/antrea/templates/whereabouts/serviceaccount.yaml @@ -0,0 +1,9 @@ +{{- if .Values.whereabouts.enable }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: antrea-agent-whereabouts + namespace: {{ .Release.Namespace }} + labels: + app: antrea +{{- end }} diff --git a/build/charts/antrea/values.yaml b/build/charts/antrea/values.yaml new file mode 100644 index 00000000000..f7212eb3289 --- /dev/null +++ b/build/charts/antrea/values.yaml @@ -0,0 +1,280 @@ +# -- Container image to use for Antrea components. +image: + repository: "projects.registry.vmware.com/antrea/antrea-ubuntu" + pullPolicy: "IfNotPresent" + tag: "latest" + +# -- Determines how traffic is encapsulated. It must be one of "encap", +# "noEncap", "hybrid", or "networkPolicyOnly". +trafficEncapMode: "encap" +# -- Tunnel protocol used for encapsulating traffic across Nodes. It must be one +# of "geneve", "vxlan", "gre", "stt". +tunnelType: "geneve" +# -- Determines how tunnel traffic is encrypted. Currently encryption only works +# with encap mode.It must be one of "none", "ipsec", "wireGuard". +trafficEncryptionMode: "none" +# -- Enable bridging mode of Pod network on Nodes, in which the Node's transport +# interface is connected to the OVS bridge. +enableBridgingMode: false +# -- Disable TX checksum offloading for container network interfaces. It's +# supposed to be set to true when the datapath doesn't support TX checksum +# offloading, which causes packets to be dropped due to bad checksum. It affects +# Pods running on Linux Nodes only. +disableTXChecksumOffload: false +# -- Whether or not to SNAT (using the Node IP) the egress traffic from a Pod to +# the external network. +noSNAT: false +# -- Name of the interface antrea-agent will create and use for host <-> Pod +# communication. +hostGateway: "antrea-gw0" +# -- Name of the interface on Node which is used for tunneling or routing the +# traffic across Nodes. +transportInterface: "" +# -- Network CIDRs of the interface on Node which is used for tunneling or +# routing the traffic across Nodes. +transportInterfaceCIDRs: [] + +multicast: + # -- Names of the interfaces on Nodes that are used to forward multicast traffic. + multicastInterfaces: [] + # -- The interval at which the antrea-agent sends IGMP queries to Pods. + # Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". + igmpQueryInterval: "125s" + +# -- Default MTU to use for the host gateway interface and the network interface +# of each Pod. By default, antrea-agent will discover the MTU of the Node's +# primary interface and adjust it to accommodate for tunnel encapsulation +# overhead if applicable. +defaultMTU: 0 + +ovs: + # -- Name of the OVS bridge antrea-agent will create and use. + bridgeName: "br-int" + # -- Enable hardware offload for the OVS bridge (required additional + # configuration). + hwOffload: false + +wireGuard: + # -- Port for WireGuard to send and receive traffic. + port: 51820 + +ipsec: + # -- Preshared Key (PSK) for IKE authentication. It will be stored in a secret + # and passed to antrea-agent as an environment variable. + psk: "changeme" + +egress: + # -- CIDR ranges to which outbound Pod traffic will not be SNAT'd by Egresses. + exceptCIDRs: [] + +nodePortLocal: + # -- Enable the NodePortLocal feature. + enable: false + # -- Port range used by NodePortLocal when creating Pod port mappings. + portRange: "61000-62000" + +antreaProxy: + # -- Proxy all Service traffic, for all Service types, regardless of where it + # comes from. + proxyAll: false + # -- String array of values which specifies the host IPv4/IPv6 addresses for + # NodePort. By default, all host addresses are used. + nodePortAddresses: [] + ## -- List of Services which should be ignored by AntreaProxy. + skipServices: [] + # -- When set to false, AntreaProxy no longer load-balances traffic destined + # to the External IPs of LoadBalancer Services. + proxyLoadBalancerIPs: true + +nodeIPAM: + # -- Enable Node IPAM in Antrea + enable: false + # -- CIDR ranges to use when allocating Pod IP addresses. + clusterCIDRs: [] + # -- IPv4 CIDR ranges reserved for Services. + serviceCIDR: "" + # -- IPv6 CIDR ranges reserved for Services. + serviceCIDRv6: "" + # -- Mask size for IPv4 Node CIDR in IPv4 or dual-stack cluster. + nodeCIDRMaskSizeIPv4: 24 + # -- Mask size for IPv6 Node CIDR in IPv6 or dual-stack cluster. + nodeCIDRMaskSizeIPv6: 64 + +# -- Address of Kubernetes apiserver, to override any value provided in +# kubeconfig or InClusterConfig. +kubeAPIServerOverride: "" +# -- IPv4 CIDR range used for Services. Required when AntreaProxy is disabled. +serviceCIDR: "" +# -- IPv6 CIDR range used for Services. Required when AntreaProxy is disabled. +serviceCIDRv6: "" + +# -- Comma-separated list of cipher suites that will be used by the Antrea +# APIservers. If empty, the default Go Cipher Suites will be used. See +# https://golang.org/pkg/crypto/tls/#pkg-constants. +tlsCipherSuites: "" +# -- TLS min version from: VersionTLS10, VersionTLS11, VersionTLS12, +# VersionTLS13. +tlsMinVersion: "" + +# -- To explicitly enable or disable a FeatureGate and bypass the Antrea +# defaults, add an entry to the dictionary with the FeatureGate's name as the +# key and a boolean as the value. +featureGates: {} + +agent: + # -- Port for the antrea-agent APIServer to serve on. + apiPort: 10350 + # -- Enable metrics exposure via Prometheus. + enablePrometheusMetrics: true + # -- Annotations to be added to antrea-agent Pods. + podAnnotations: {} + # -- Labels to be added to antrea-agent Pods. + podLabels: {} + # -- Tolerations for the antrea-agent Pods. + tolerations: + # Mark it as a critical add-on. + - key: CriticalAddonsOnly + operator: Exists + # Make sure it gets scheduled on all Nodes. + - effect: NoSchedule + operator: Exists + # Make sure it doesn't get evicted. + - effect: NoExecute + operator: Exists + # -- Node selector for the antrea-agent Pods. + nodeSelector: + kubernetes.io/os: linux + # -- Prority class to use for the antrea-agent Pods. + priorityClassName: "system-node-critical" + # -- Affinity for the antrea-agent Pods. + affinity: {} + # -- DNS Policy for the antrea-agent Pods. + dnsPolicy: "ClusterFirstWithHostNet" + # -- Update strategy for the antrea-agent DaemonSet. + updateStrategy: + type: RollingUpdate + # -- Additional volumes for antrea-agent Pods. + extraVolumes: [] + installCNI: + # -- Resource requests and limits for the install-cni initContainer. + resources: + requests: + cpu: "100m" + antreaAgent: + # -- Extra environment variables to be injected into antrea-agent. + extraEnv: {} + # -- Max size in MBs of any single log file. + logFileMaxSize: 100 + # -- Max number of log files. + logFileMaxNum: 4 + # -- Extra command-line arguments for antrea-agent. + extraArgs: [] + # -- Additional volumeMounts for the antrea-agent container. + extraVolumeMounts: [] + # -- Resource requests and limits for the antrea-agent container. + resources: + requests: + cpu: "200m" + antreaOVS: + # -- Max size in MBs of any single log file. + logFileMaxSize: 100 + # -- Max number of log files. + logFileMaxNum: 4 + # -- Extra command-line arguments for antrea-ovs. + extraArgs: [] + # -- Resource requests and limits for the antrea-ovs container. + resources: + requests: + cpu: "200m" + antreaIPsec: + # -- Resource requests and limits for the antrea-ipsec container (when IPsec + # is enabled). + resources: + requests: + cpu: "50m" + +controller: + # -- Port for the antrea-controller APIServer to serve on. + apiPort: 10349 + # -- Enable metrics exposure via Prometheus. + enablePrometheusMetrics: true + # -- Annotations to be added to antrea-controller Pod. + podAnnotations: {} + # -- Labels to be added to antrea-controller Pod. + podLabels: {} + # -- Indicates whether to use auto-generated self-signed TLS certificates. If + # false, a Secret named "antrea-controller-tls" must be provided with the + # following keys: ca.crt, tls.crt, tls.key. + selfSignedCert: true + # -- Tolerations for the antrea-controller Pod. + tolerations: + # Mark it as a critical add-on. + - key: CriticalAddonsOnly + operator: Exists + # Allow it to schedule onto master nodes. + - key: node-role.kubernetes.io/master + effect: NoSchedule + # Control-plane taint for Kubernetes >= 1.24. + - key: node-role.kubernetes.io/control-plane + effect: NoSchedule + # -- Node selector for the antrea-controller Pod. + nodeSelector: + kubernetes.io/os: linux + # -- Prority class to use for the antrea-controller Pod. + priorityClassName: "system-cluster-critical" + # -- Affinity for the antrea-controller Pod. + affinity: {} + antreaController: + # -- Extra environment variables to be injected into antrea-controller. + extraEnv: {} + # -- Max size in MBs of any single log file. + logFileMaxSize: 100 + # -- Max number of log files. + logFileMaxNum: 4 + # -- Extra command-line arguments for antrea-controller. + extraArgs: [] + # -- Resource requests and limits for the antrea-controller container. + resources: + requests: + cpu: "200m" + +flowCollector: + # -- IPFIX collector address as a string with format :[][:]. + collectorAddr: "flow-aggregator.flow-aggregator.svc:4739:tls" + # -- Determines how often the flow exporter polls for new connections. + flowPollInterval: "5s" + # -- timeout after which a flow record is sent to the collector for active + # flows. + activeFlowExportTimeout: "5s" + # -- timeout after which a flow record is sent to the collector for idle + # flows. + idleFlowExportTimeout: "15s" + +cni: + # -- Chained plugins to use alongside antrea-cni. + plugins: + portmap: true + bandwidth: true + # -- Installation path of CNI binaries on the host. + hostBinPath: "/opt/cni/bin" + # -- CNI binaries shipped with Antrea for which installation should be + # skipped. + skipBinaries: [] + +webhooks: + labelsMutator: + ## -- Mutate all namespaces to add the "antrea.io/metadata.name" label. + enable: false + +## -- Global log verbosity switch for all Antrea components. +logVerbosity: 0 + +## -- Install and configure Whereabouts, for use by the antrea-agent. +whereabouts: + enable: false + +testing: + ## -- enable code coverage measurement (used when testing Antrea only). + coverage: false + simulator: + enable: false diff --git a/build/images/codegen/Dockerfile b/build/images/codegen/Dockerfile index 810a8a513ed..c472be6de24 100644 --- a/build/images/codegen/Dockerfile +++ b/build/images/codegen/Dockerfile @@ -18,9 +18,11 @@ LABEL description="A Docker image based on the golang image, which includes code ENV GO111MODULE=on -ARG K8S_VERSION=1.21.0 +ARG K8S_VERSION=1.24.0 # The k8s.io/kube-openapi repo does not have tag, using a workable commit hash. -ARG KUBEOPENAPI_VERSION=v0.0.0-20210305164622-f622666832c1 +# We use the version that is referenced in the Kubernetes go.mod (for the +# correct K8s version). +ARG KUBEOPENAPI_VERSION=v0.0.0-20220328201542-3ee0da9b0b42 RUN go get k8s.io/code-generator/cmd/client-gen@kubernetes-$K8S_VERSION && \ go get k8s.io/code-generator/cmd/deepcopy-gen@kubernetes-$K8S_VERSION && \ diff --git a/build/images/codegen/README.md b/build/images/codegen/README.md index cfe9b380910..8bf29fd3002 100644 --- a/build/images/codegen/README.md +++ b/build/images/codegen/README.md @@ -20,6 +20,7 @@ Here is the table of codegen images that have been uploaded: | Tag | Change | | :----------------------------- | --------------------------------------- | +| kubernetes-1.24.0 | Upgraded K8s libraries to v1.24.0 | | kubernetes-1.21.0-build.1 | Upgraded protoc-gen-go to v1.5.2 | | kubernetes-1.21.0-build.0 | Upgraded Go to v1.17 | | kubernetes-1.21.0 | Upgraded K8s libraries to v1.21.0 | diff --git a/build/images/deps/ovs-version b/build/images/deps/ovs-version index 3b1fc7950fa..d76bd2ba3ef 100644 --- a/build/images/deps/ovs-version +++ b/build/images/deps/ovs-version @@ -1 +1 @@ -2.15.1 +2.17.0 diff --git a/build/images/ovs/apply-patches.sh b/build/images/ovs/apply-patches.sh index 67fdd4faaca..3d3bead5078 100755 --- a/build/images/ovs/apply-patches.sh +++ b/build/images/ovs/apply-patches.sh @@ -35,8 +35,15 @@ function version_let() { test "$(printf '%s\n' "$@" | sort -V | head -n 1)" == " # greater than or equal to function version_get() { test "$(printf '%s\n' "$@" | sort -rV | head -n 1)" == "$1"; } -if version_lt "$OVS_VERSION" "2.13.0" || version_gt "$OVS_VERSION" "2.15.1"; then - echoerr "OVS_VERSION $OVS_VERSION is not supported (must be >= 2.13.0 and <= 2.15.1)" +function apply_patch() { + commit_sha="$1" + shift + curl -s "https://github.com/openvswitch/ovs/commit/$commit_sha.patch" | \ + git apply "$@" +} + +if version_lt "$OVS_VERSION" "2.13.0" || version_gt "$OVS_VERSION" "2.17.0"; then + echoerr "OVS_VERSION $OVS_VERSION is not supported (must be >= 2.13.0 and <= 2.17.0)" exit 1 fi @@ -46,8 +53,7 @@ fi # This patch (post 2.13.0) ensures that ct_nw_src/ct_nw_dst supports IP Mask. if version_let "$OVS_VERSION" "2.13.0"; then - curl https://github.com/openvswitch/ovs/commit/1740aaf49dad6f533705dc3dce8d955a1840052a.patch | \ - git apply + apply_patch "1740aaf49dad6f533705dc3dce8d955a1840052a" fi if version_get "$OVS_VERSION" "2.13.0" && version_lt "$OVS_VERSION" "2.14.0" ; then @@ -55,43 +61,43 @@ if version_get "$OVS_VERSION" "2.13.0" && version_lt "$OVS_VERSION" "2.14.0" ; t # ovs-vswitchd exit by default. Antrea relies on this to support hitless upgrade # of the Agent DaemonSet. # The second patch depends on the first one. - curl https://github.com/openvswitch/ovs/commit/586cd3101e7fda54d14fb5bf12d847f35d968627.patch | \ - git apply + apply_patch "586cd3101e7fda54d14fb5bf12d847f35d968627" # We exclude 2 files which are likely to cause conflicts. - curl https://github.com/openvswitch/ovs/commit/79eadafeb1b47a3871cb792aa972f6e4d89d1a0b.patch | \ - git apply --exclude NEWS --exclude vswitchd/ovs-vswitchd.8.in + apply_patch "586cd3101e7fda54d14fb5bf12d847f35d968627" "--exclude NEWS" "--exclude vswitchd/ovs-vswitchd.8.in" # This patch (post 2.13.x) ensures that ovs-vswitchd does not delete datapath # ports on exit. - curl https://github.com/openvswitch/ovs/commit/7cc77b301f80a63cd4893198d82be0eef303f731.patch | \ - git apply + apply_patch "7cc77b301f80a63cd4893198d82be0eef303f731" # These patches (post 2.13.x) are needed to fix the debian build on Ubuntu 20.04. - curl https://github.com/openvswitch/ovs/commit/c101cd4171cfe04e214f858b4bbe089e56f13f9b.patch | \ - git apply - curl https://github.com/openvswitch/ovs/commit/3c18bb0fe9f23308061217f72e2245f0e311b20b.patch | \ - git apply - curl https://github.com/openvswitch/ovs/commit/fe175ac17352ceb2dbc9958112b4b1bc114d82f0.patch | \ - git apply + apply_patch "c101cd4171cfe04e214f858b4bbe089e56f13f9b" + apply_patch "3c18bb0fe9f23308061217f72e2245f0e311b20b" + apply_patch "fe175ac17352ceb2dbc9958112b4b1bc114d82f0" # The OVS ovs-monitor-ipsec script has a Python3 shebang but still includes some Python2-specific code. # Until the patch which fixes the script is merged upstream, we apply it here, or Antrea IPsec support will be broken. - curl https://github.com/openvswitch/ovs/commit/8a09c2590ef2ea0edc250ec46e3d41bd5874b4ab.patch | \ - git apply + apply_patch "8a09c2590ef2ea0edc250ec46e3d41bd5874b4ab" fi # Starting from version 5.7.0, strongSwan no longer supports specifying a configuration parameter # with the path delimited by dots in a configuration file. This patch fixes the strongSwan # configuration parameters that ovs-monitor-ipsec writes, to comply with the new strongSwan format. if version_lt "$OVS_VERSION" "2.14.1" ; then - curl https://github.com/openvswitch/ovs/commit/b424becaac58d8cb08fb19ea839be6807d3ed57f.patch | \ - git apply + apply_patch "b424becaac58d8cb08fb19ea839be6807d3ed57f" fi # This patch is necessary to ensure that ovs-monitor-ipsec generates a correct IPsec configuration # for strongSwan when using IPv6. -curl https://github.com/openvswitch/ovs/commit/e59194b606078d90b73f86092f9b76385afa73f0.patch | \ - git apply +if version_lt "$OVS_VERSION" "2.15.4" || (version_get "$OVS_VERSION" "2.16.0" && version_lt "$OVS_VERSION" "2.16.3") ; then + apply_patch "e59194b606078d90b73f86092f9b76385afa73f0" +fi + +# This patch fixes a log file leak in OVS. +# See https://github.com/antrea-io/antrea/issues/2003 +# It is fixed in the OVS master branch and will be included starting with OVS 2.18. +if version_lt "$OVS_VERSION" "2.18.0" ; then + apply_patch "78ff3961ca9fb012eaaca3d3af1e8186fe1827e7" +fi # OVS hardcodes the installation path to /usr/lib/python3.7/dist-packages/ but this location # does not seem to be in the Python path in Ubuntu 20.04. There may be a better way to do this, diff --git a/build/images/scripts/Install-WindowsCNI.ps1 b/build/images/scripts/Install-WindowsCNI.ps1 index e85ba3b2bab..282f5e3975c 100644 --- a/build/images/scripts/Install-WindowsCNI.ps1 +++ b/build/images/scripts/Install-WindowsCNI.ps1 @@ -3,7 +3,6 @@ $ErrorActionPreference = "Stop"; mkdir -force /host/var/run/secrets/kubernetes.io/serviceaccount cp -force /var/run/secrets/kubernetes.io/serviceaccount/* /host/var/run/secrets/kubernetes.io/serviceaccount/ mkdir -force /host/k/antrea/etc/ -mkdir -force /host/k/antrea/logs/ cp /k/antrea/cni/* /host/opt/cni/bin/ cp /etc/antrea/antrea-agent.conf /host/k/antrea/etc/ diff --git a/build/images/scripts/install_cni b/build/images/scripts/install_cni index 62bac9aed8f..0c6d2a54492 100755 --- a/build/images/scripts/install_cni +++ b/build/images/scripts/install_cni @@ -3,7 +3,7 @@ set -euo pipefail # Fetching the list of the binaries that user wants to skip installing. -IFS=',' read -r -a binaries <<< "$SKIP_CNI_BINARIES" +IFS=',' read -r -a binaries <<< "${SKIP_CNI_BINARIES:-}" # Todo: check version and continue installation only for a newer version # Install Antrea binary file diff --git a/build/yamls/antrea-aks.yml b/build/yamls/antrea-aks.yml index eee762e7e45..d29d3f36159 100644 --- a/build/yamls/antrea-aks.yml +++ b/build/yamls/antrea-aks.yml @@ -1,2740 +1,59 @@ -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition +--- +# Source: antrea/templates/agent/serviceaccount.yaml +apiVersion: v1 +kind: ServiceAccount metadata: + name: antrea-agent + namespace: kube-system labels: app: antrea - name: antreaagentinfos.crd.antrea.io -spec: - group: crd.antrea.io - names: - kind: AntreaAgentInfo - plural: antreaagentinfos - shortNames: - - aai - singular: antreaagentinfo - scope: Cluster - versions: - - additionalPrinterColumns: - - description: Health status of this Agent - jsonPath: .agentConditions[?(@.type=='AgentHealthy')].status - name: Healthy - type: string - - description: Last time the Healthy Condition was updated - jsonPath: .agentConditions[?(@.type=='AgentHealthy')].lastHeartbeatTime - name: Last Heartbeat - type: date - - description: Version of this Agent - jsonPath: .version - name: Version - priority: 1 - type: string - - description: Node on which this Agent is running - jsonPath: .nodeRef.name - name: Node - priority: 1 - type: string - - description: Number of local Pods managed by this Agent - jsonPath: .localPodNum - name: Num Pods - priority: 2 - type: integer - - description: Subnets used by this Agent for Pod IPAM - jsonPath: .nodeSubnets - name: Subnets - priority: 2 - type: string - name: v1beta1 - schema: - openAPIV3Schema: - type: object - x-kubernetes-preserve-unknown-fields: true - served: true - storage: true --- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition +# Source: antrea/templates/antctl/serviceaccount.yaml +apiVersion: v1 +kind: ServiceAccount metadata: + name: antctl + namespace: kube-system labels: app: antrea - name: antreacontrollerinfos.crd.antrea.io -spec: - group: crd.antrea.io - names: - kind: AntreaControllerInfo - plural: antreacontrollerinfos - shortNames: - - aci - singular: antreacontrollerinfo - scope: Cluster - versions: - - additionalPrinterColumns: - - description: Health status of the Controller - jsonPath: .controllerConditions[?(@.type=='ControllerHealthy')].status - name: Healthy - type: string - - description: Last time the Healthy Condition was updated - jsonPath: .controllerConditions[?(@.type=='ControllerHealthy')].lastHeartbeatTime - name: Last Heartbeat - type: date - - description: Version of the Controller - jsonPath: .version - name: Version - priority: 1 - type: string - - description: Number of Agents connected to the Controller - jsonPath: .connectedAgentNum - name: Connected Agents - priority: 1 - type: integer - - description: Node on which the Controller is running - jsonPath: .nodeRef.name - name: Node - priority: 1 - type: string - - description: Number of Network Policies computed by Controller - jsonPath: .networkPolicyControllerInfo.networkPolicyNum - name: Num Network Policies - priority: 2 - type: integer - name: v1beta1 - schema: - openAPIV3Schema: - type: object - x-kubernetes-preserve-unknown-fields: true - served: true - storage: true --- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition +# Source: antrea/templates/controller/serviceaccount.yaml +apiVersion: v1 +kind: ServiceAccount metadata: + name: antrea-controller + namespace: kube-system labels: app: antrea - name: clustergroups.crd.antrea.io -spec: - conversion: - strategy: Webhook - webhook: - clientConfig: - service: - name: antrea - namespace: kube-system - path: /convert/clustergroup - conversionReviewVersions: - - v1 - - v1beta1 - group: crd.antrea.io - names: - kind: ClusterGroup - plural: clustergroups - shortNames: - - cg - singular: clustergroup - scope: Cluster - versions: - - name: v1alpha2 - schema: - openAPIV3Schema: - properties: - spec: - properties: - childGroups: - items: - type: string - type: array - externalEntitySelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - ipBlock: - properties: - cidr: - format: cidr - type: string - type: object - ipBlocks: - items: - properties: - cidr: - format: cidr - type: string - type: object - type: array - namespaceSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - podSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - serviceReference: - properties: - name: - type: string - namespace: - type: string - type: object - type: object - status: - properties: - conditions: - items: - properties: - lastTransitionTime: - type: string - status: - type: string - type: - type: string - type: object - type: array - type: object - type: object - served: true - storage: false - - name: v1alpha3 - schema: - openAPIV3Schema: - properties: - spec: - properties: - childGroups: - items: - type: string - type: array - externalEntitySelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - ipBlocks: - items: - properties: - cidr: - format: cidr - type: string - type: object - type: array - namespaceSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - podSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - serviceReference: - properties: - name: - type: string - namespace: - type: string - type: object - type: object - status: - properties: - conditions: - items: - properties: - lastTransitionTime: - type: string - status: - type: string - type: - type: string - type: object - type: array - type: object - type: object - served: true - storage: true - subresources: - status: {} --- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition +# Source: antrea/templates/agent/secret.yaml +apiVersion: v1 +kind: Secret +metadata: + name: antrea-agent-service-account-token + namespace: kube-system + annotations: + kubernetes.io/service-account.name: antrea-agent +type: kubernetes.io/service-account-token +--- +# Source: antrea/templates/antctl/secret.yaml +apiVersion: v1 +kind: Secret +metadata: + name: antctl-service-account-token + namespace: kube-system + annotations: + kubernetes.io/service-account.name: antctl +type: kubernetes.io/service-account-token +--- +# Source: antrea/templates/configmap.yaml +apiVersion: v1 +kind: ConfigMap metadata: + name: antrea-config + namespace: kube-system labels: app: antrea - name: clusternetworkpolicies.crd.antrea.io -spec: - group: crd.antrea.io - names: - kind: ClusterNetworkPolicy - plural: clusternetworkpolicies - shortNames: - - acnp - singular: clusternetworkpolicy - scope: Cluster - versions: - - additionalPrinterColumns: - - description: The Tier to which this ClusterNetworkPolicy belongs to. - jsonPath: .spec.tier - name: Tier - type: string - - description: The Priority of this ClusterNetworkPolicy relative to other policies. - format: float - jsonPath: .spec.priority - name: Priority - type: number - - description: The total number of Nodes that should realize the NetworkPolicy. - format: int32 - jsonPath: .status.desiredNodesRealized - name: Desired Nodes - type: number - - description: The number of Nodes that have realized the NetworkPolicy. - format: int32 - jsonPath: .status.currentNodesRealized - name: Current Nodes - type: number - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha1 - schema: - openAPIV3Schema: - properties: - spec: - properties: - appliedTo: - items: - properties: - group: - type: string - namespaceSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - podSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - serviceAccount: - properties: - name: - type: string - namespace: - type: string - required: - - name - - namespace - type: object - type: object - type: array - egress: - items: - properties: - action: - enum: - - Allow - - Drop - - Reject - - Pass - type: string - appliedTo: - items: - properties: - group: - type: string - namespaceSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - podSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - serviceAccount: - properties: - name: - type: string - namespace: - type: string - required: - - name - - namespace - type: object - type: object - type: array - enableLogging: - type: boolean - name: - type: string - ports: - items: - properties: - endPort: - type: integer - port: - x-kubernetes-int-or-string: true - protocol: - enum: - - TCP - - UDP - - SCTP - type: string - type: object - type: array - to: - items: - properties: - fqdn: - type: string - group: - type: string - ipBlock: - properties: - cidr: - format: cidr - type: string - type: object - namespaceSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - namespaces: - properties: - match: - type: string - type: object - nodeSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - podSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - serviceAccount: - properties: - name: - type: string - namespace: - type: string - required: - - name - - namespace - type: object - type: object - type: array - toServices: - items: - properties: - name: - type: string - namespace: - type: string - required: - - name - - namespace - type: object - type: array - required: - - action - type: object - type: array - ingress: - items: - properties: - action: - enum: - - Allow - - Drop - - Reject - - Pass - type: string - appliedTo: - items: - properties: - group: - type: string - namespaceSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - podSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - serviceAccount: - properties: - name: - type: string - namespace: - type: string - required: - - name - - namespace - type: object - type: object - type: array - enableLogging: - type: boolean - from: - items: - properties: - group: - type: string - ipBlock: - properties: - cidr: - format: cidr - type: string - type: object - namespaceSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - namespaces: - properties: - match: - enum: - - Self - type: string - type: object - nodeSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - podSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - serviceAccount: - properties: - name: - type: string - namespace: - type: string - required: - - name - - namespace - type: object - type: object - type: array - name: - type: string - ports: - items: - properties: - endPort: - type: integer - port: - x-kubernetes-int-or-string: true - protocol: - enum: - - TCP - - UDP - - SCTP - type: string - type: object - type: array - required: - - action - type: object - type: array - priority: - format: float - maximum: 10000 - minimum: 1 - type: number - tier: - type: string - required: - - priority - type: object - status: - properties: - currentNodesRealized: - type: integer - desiredNodesRealized: - type: integer - observedGeneration: - type: integer - phase: - type: string - type: object - type: object - served: true - storage: true - subresources: - status: {} ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - labels: - app: antrea - name: egresses.crd.antrea.io -spec: - group: crd.antrea.io - names: - kind: Egress - plural: egresses - shortNames: - - eg - singular: egress - scope: Cluster - versions: - - additionalPrinterColumns: - - description: Specifies the SNAT IP address for the selected workloads. - jsonPath: .spec.egressIP - name: EgressIP - type: string - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - - description: The Owner Node of egress IP - jsonPath: .status.egressNode - name: Node - type: string - name: v1alpha2 - schema: - openAPIV3Schema: - properties: - spec: - anyOf: - - required: - - egressIP - - required: - - externalIPPool - properties: - appliedTo: - properties: - namespaceSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - podSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - type: object - egressIP: - oneOf: - - format: ipv4 - - format: ipv6 - type: string - externalIPPool: - type: string - required: - - appliedTo - type: object - status: - properties: - egressNode: - type: string - type: object - required: - - spec - type: object - served: true - storage: true - subresources: - status: {} ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - labels: - app: antrea - name: externalentities.crd.antrea.io -spec: - group: crd.antrea.io - names: - kind: ExternalEntity - plural: externalentities - shortNames: - - ee - singular: externalentity - scope: Namespaced - versions: - - name: v1alpha2 - schema: - openAPIV3Schema: - properties: - spec: - properties: - endpoints: - items: - properties: - ip: - oneOf: - - format: ipv4 - - format: ipv6 - type: string - name: - type: string - type: object - type: array - externalNode: - type: string - ports: - items: - properties: - name: - type: string - port: - x-kubernetes-int-or-string: true - protocol: - enum: - - TCP - - UDP - - SCTP - type: string - type: object - type: array - type: object - type: object - served: true - storage: true - - name: v1alpha1 - schema: - openAPIV3Schema: - type: object - served: false - storage: false ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - labels: - app: antrea - name: externalippools.crd.antrea.io -spec: - group: crd.antrea.io - names: - kind: ExternalIPPool - plural: externalippools - shortNames: - - eip - singular: externalippool - scope: Cluster - versions: - - additionalPrinterColumns: - - description: The number of total IPs - jsonPath: .status.usage.total - name: Total - type: integer - - description: The number of allocated IPs - jsonPath: .status.usage.used - name: Used - type: integer - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha2 - schema: - openAPIV3Schema: - properties: - spec: - properties: - ipRanges: - items: - oneOf: - - required: - - cidr - - required: - - start - - end - properties: - cidr: - format: cidr - type: string - end: - oneOf: - - format: ipv4 - - format: ipv6 - type: string - start: - oneOf: - - format: ipv4 - - format: ipv6 - type: string - type: object - type: array - nodeSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - required: - - ipRanges - - nodeSelector - type: object - status: - properties: - usage: - properties: - total: - type: integer - used: - type: integer - type: object - type: object - required: - - spec - type: object - served: true - storage: true - subresources: - status: {} ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - labels: - app: antrea - name: ippools.crd.antrea.io -spec: - group: crd.antrea.io - names: - kind: IPPool - plural: ippools - shortNames: - - ipp - singular: ippool - scope: Cluster - versions: - - name: v1alpha2 - schema: - openAPIV3Schema: - properties: - spec: - properties: - ipRanges: - items: - oneOf: - - required: - - cidr - - gateway - - prefixLength - - required: - - start - - end - - gateway - - prefixLength - properties: - cidr: - format: cidr - type: string - end: - oneOf: - - format: ipv4 - - format: ipv6 - type: string - gateway: - oneOf: - - format: ipv4 - - format: ipv6 - type: string - prefixLength: - type: integer - start: - oneOf: - - format: ipv4 - - format: ipv6 - type: string - vlan: - maximum: 4094 - minimum: 0 - type: integer - type: object - type: array - ipVersion: - type: integer - required: - - ipVersion - - ipRanges - type: object - status: - properties: - ipAddresses: - items: - properties: - ipAddress: - type: string - owner: - properties: - pod: - properties: - containerID: - type: string - name: - type: string - namespace: - type: string - type: object - statefulSet: - properties: - index: - type: integer - name: - type: string - namespace: - type: string - type: object - type: object - phase: - type: string - type: object - type: array - type: object - required: - - spec - type: object - served: true - storage: true - subresources: - status: {} ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - labels: - app: antrea - name: networkpolicies.crd.antrea.io -spec: - group: crd.antrea.io - names: - kind: NetworkPolicy - plural: networkpolicies - shortNames: - - anp - singular: networkpolicy - scope: Namespaced - versions: - - additionalPrinterColumns: - - description: The Tier to which this Antrea NetworkPolicy belongs to. - jsonPath: .spec.tier - name: Tier - type: string - - description: The Priority of this Antrea NetworkPolicy relative to other policies. - format: float - jsonPath: .spec.priority - name: Priority - type: number - - description: The total number of Nodes that should realize the NetworkPolicy. - format: int32 - jsonPath: .status.desiredNodesRealized - name: Desired Nodes - type: number - - description: The number of Nodes that have realized the NetworkPolicy. - format: int32 - jsonPath: .status.currentNodesRealized - name: Current Nodes - type: number - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha1 - schema: - openAPIV3Schema: - properties: - spec: - properties: - appliedTo: - items: - properties: - podSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - type: object - type: array - egress: - items: - properties: - action: - enum: - - Allow - - Drop - - Reject - - Pass - type: string - appliedTo: - items: - properties: - podSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - type: object - type: array - enableLogging: - type: boolean - name: - type: string - ports: - items: - properties: - endPort: - type: integer - port: - x-kubernetes-int-or-string: true - protocol: - enum: - - TCP - - UDP - - SCTP - type: string - type: object - type: array - to: - items: - properties: - externalEntitySelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - fqdn: - type: string - ipBlock: - properties: - cidr: - format: cidr - type: string - type: object - namespaceSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - nodeSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - podSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - type: object - type: array - toServices: - items: - properties: - name: - type: string - namespace: - type: string - required: - - name - type: object - type: array - required: - - action - type: object - type: array - ingress: - items: - properties: - action: - enum: - - Allow - - Drop - - Reject - - Pass - type: string - appliedTo: - items: - properties: - podSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - type: object - type: array - enableLogging: - type: boolean - from: - items: - properties: - externalEntitySelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - ipBlock: - properties: - cidr: - format: cidr - type: string - type: object - namespaceSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - nodeSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - podSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - type: object - type: array - name: - type: string - ports: - items: - properties: - endPort: - type: integer - port: - x-kubernetes-int-or-string: true - protocol: - enum: - - TCP - - UDP - - SCTP - type: string - type: object - type: array - required: - - action - type: object - type: array - priority: - format: float - maximum: 10000 - minimum: 1 - type: number - tier: - type: string - required: - - priority - type: object - status: - properties: - currentNodesRealized: - type: integer - desiredNodesRealized: - type: integer - observedGeneration: - type: integer - phase: - type: string - type: object - type: object - served: true - storage: true - subresources: - status: {} ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - labels: - app: antrea - name: tiers.crd.antrea.io -spec: - group: crd.antrea.io - names: - kind: Tier - plural: tiers - shortNames: - - tr - singular: tier - scope: Cluster - versions: - - additionalPrinterColumns: - - description: The Priority of this Tier relative to other Tiers. - jsonPath: .spec.priority - name: Priority - type: integer - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha1 - schema: - openAPIV3Schema: - properties: - spec: - properties: - description: - type: string - priority: - maximum: 255 - minimum: 0 - type: integer - required: - - priority - type: object - type: object - served: true - storage: true ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - labels: - app: antrea - name: traceflows.crd.antrea.io -spec: - group: crd.antrea.io - names: - kind: Traceflow - plural: traceflows - shortNames: - - tf - singular: traceflow - scope: Cluster - versions: - - additionalPrinterColumns: - - description: The phase of the Traceflow. - jsonPath: .status.phase - name: Phase - type: string - - description: The name of the source Pod. - jsonPath: .spec.source.pod - name: Source-Pod - priority: 10 - type: string - - description: The name of the destination Pod. - jsonPath: .spec.destination.pod - name: Destination-Pod - priority: 10 - type: string - - description: The IP address of the destination. - jsonPath: .spec.destination.ip - name: Destination-IP - priority: 10 - type: string - - description: Trace live traffic. - jsonPath: .spec.liveTraffic - name: Live-Traffic - priority: 10 - type: boolean - - description: Capture only the dropped packet. - jsonPath: .spec.droppedOnly - name: Dropped-Only - priority: 10 - type: boolean - - description: Timeout in seconds. - jsonPath: .spec.timeout - name: Timeout - priority: 10 - type: integer - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha1 - schema: - openAPIV3Schema: - properties: - spec: - properties: - destination: - properties: - ip: - oneOf: - - format: ipv4 - - format: ipv6 - type: string - namespace: - type: string - pod: - type: string - service: - type: string - type: object - droppedOnly: - type: boolean - liveTraffic: - type: boolean - packet: - properties: - ipHeader: - properties: - flags: - type: integer - protocol: - type: integer - srcIP: - oneOf: - - format: ipv4 - - format: ipv6 - type: string - ttl: - type: integer - type: object - ipv6Header: - properties: - hopLimit: - type: integer - nextHeader: - type: integer - srcIP: - format: ipv6 - type: string - type: object - transportHeader: - properties: - icmp: - properties: - id: - type: integer - sequence: - type: integer - type: object - tcp: - properties: - dstPort: - type: integer - flags: - type: integer - srcPort: - type: integer - type: object - udp: - properties: - dstPort: - type: integer - srcPort: - type: integer - type: object - type: object - type: object - source: - properties: - ip: - oneOf: - - format: ipv4 - - format: ipv6 - type: string - namespace: - type: string - pod: - type: string - type: object - timeout: - type: integer - type: object - status: - properties: - capturedPacket: - properties: - dstIP: - type: string - ipHeader: - properties: - flags: - type: integer - protocol: - type: integer - ttl: - type: integer - type: object - ipv6Header: - properties: - hopLimit: - type: integer - nextHeader: - type: integer - type: object - length: - type: integer - srcIP: - type: string - transportHeader: - properties: - icmp: - properties: - id: - type: integer - sequence: - type: integer - type: object - tcp: - properties: - dstPort: - type: integer - flags: - type: integer - srcPort: - type: integer - type: object - udp: - properties: - dstPort: - type: integer - srcPort: - type: integer - type: object - type: object - type: object - dataplaneTag: - type: integer - phase: - type: string - reason: - type: string - results: - items: - properties: - node: - type: string - observations: - items: - properties: - action: - type: string - component: - type: string - componentInfo: - type: string - dstMAC: - type: string - networkPolicy: - type: string - pod: - type: string - translatedDstIP: - type: string - translatedSrcIP: - type: string - ttl: - type: integer - tunnelDstIP: - type: string - type: object - type: array - role: - type: string - timestamp: - type: integer - type: object - type: array - startTime: - type: string - type: object - required: - - spec - type: object - served: true - storage: true - subresources: - status: {} ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - labels: - app: antrea - name: antctl - namespace: kube-system ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - labels: - app: antrea - name: antrea-agent - namespace: kube-system ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - labels: - app: antrea - name: antrea-controller - namespace: kube-system ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - labels: - app: antrea - rbac.authorization.k8s.io/aggregate-to-admin: "true" - rbac.authorization.k8s.io/aggregate-to-edit: "true" - name: aggregate-antrea-clustergroups-edit -rules: -- apiGroups: - - crd.antrea.io - resources: - - clustergroups - verbs: - - get - - list - - watch - - create - - update - - patch - - delete ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - labels: - app: antrea - rbac.authorization.k8s.io/aggregate-to-view: "true" - name: aggregate-antrea-clustergroups-view -rules: -- apiGroups: - - crd.antrea.io - resources: - - clustergroups - verbs: - - get - - list - - watch ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - labels: - app: antrea - rbac.authorization.k8s.io/aggregate-to-admin: "true" - rbac.authorization.k8s.io/aggregate-to-edit: "true" - name: aggregate-antrea-policies-edit -rules: -- apiGroups: - - crd.antrea.io - resources: - - clusternetworkpolicies - - networkpolicies - verbs: - - get - - list - - watch - - create - - update - - patch - - delete ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - labels: - app: antrea - rbac.authorization.k8s.io/aggregate-to-view: "true" - name: aggregate-antrea-policies-view -rules: -- apiGroups: - - crd.antrea.io - resources: - - clusternetworkpolicies - - networkpolicies - verbs: - - get - - list - - watch ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - labels: - app: antrea - rbac.authorization.k8s.io/aggregate-to-admin: "true" - rbac.authorization.k8s.io/aggregate-to-edit: "true" - name: aggregate-traceflows-edit -rules: -- apiGroups: - - crd.antrea.io - resources: - - traceflows - verbs: - - get - - list - - watch - - create - - update - - patch - - delete ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - labels: - app: antrea - rbac.authorization.k8s.io/aggregate-to-view: "true" - name: aggregate-traceflows-view -rules: -- apiGroups: - - crd.antrea.io - resources: - - traceflows - verbs: - - get - - list - - watch ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - labels: - app: antrea - name: antctl -rules: -- apiGroups: - - controlplane.antrea.io - resources: - - networkpolicies - - appliedtogroups - - addressgroups - verbs: - - get - - list -- apiGroups: - - stats.antrea.io - resources: - - networkpolicystats - - antreaclusternetworkpolicystats - - antreanetworkpolicystats - verbs: - - get - - list -- apiGroups: - - system.antrea.io - resources: - - controllerinfos - - agentinfos - verbs: - - get -- apiGroups: - - system.antrea.io - resources: - - supportbundles - verbs: - - get - - post -- apiGroups: - - system.antrea.io - resources: - - supportbundles/download - verbs: - - get -- nonResourceURLs: - - /agentinfo - - /addressgroups - - /appliedtogroups - - /loglevel - - /networkpolicies - - /ovsflows - - /ovstracing - - /podinterfaces - - /featuregates - verbs: - - get ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - labels: - app: antrea - name: antrea-agent -rules: -- apiGroups: - - "" - resources: - - nodes - verbs: - - get - - watch - - list -- apiGroups: - - "" - resources: - - nodes/status - verbs: - - patch -- apiGroups: - - "" - resources: - - pods - verbs: - - get - - watch - - list -- apiGroups: - - "" - resources: - - pods/status - verbs: - - patch -- apiGroups: - - "" - resources: - - endpoints - - services - - namespaces - verbs: - - get - - watch - - list -- apiGroups: - - "" - resources: - - services/status - verbs: - - update -- apiGroups: - - discovery.k8s.io - resources: - - endpointslices - verbs: - - get - - watch - - list -- apiGroups: - - crd.antrea.io - resources: - - antreaagentinfos - verbs: - - get - - create - - update - - delete -- apiGroups: - - controlplane.antrea.io - resources: - - networkpolicies - - appliedtogroups - - addressgroups - verbs: - - get - - watch - - list -- apiGroups: - - controlplane.antrea.io - resources: - - egressgroups - verbs: - - get - - watch - - list -- apiGroups: - - controlplane.antrea.io - resources: - - nodestatssummaries - verbs: - - create -- apiGroups: - - controlplane.antrea.io - resources: - - networkpolicies/status - verbs: - - create - - get -- apiGroups: - - authentication.k8s.io - resources: - - tokenreviews - verbs: - - create -- apiGroups: - - authorization.k8s.io - resources: - - subjectaccessreviews - verbs: - - create -- apiGroups: - - "" - resourceNames: - - extension-apiserver-authentication - resources: - - configmaps - verbs: - - get - - list - - watch -- apiGroups: - - "" - resourceNames: - - antrea-ca - resources: - - configmaps - verbs: - - get - - watch - - list -- apiGroups: - - crd.antrea.io - resources: - - traceflows - - traceflows/status - verbs: - - get - - watch - - list - - update - - patch - - create - - delete -- apiGroups: - - crd.antrea.io - resources: - - egresses - verbs: - - get - - watch - - list -- apiGroups: - - crd.antrea.io - resources: - - egresses/status - verbs: - - update -- apiGroups: - - crd.antrea.io - resources: - - externalippools - - ippools - verbs: - - get - - watch - - list -- apiGroups: - - crd.antrea.io - resources: - - ippools/status - verbs: - - update -- apiGroups: - - k8s.cni.cncf.io - resources: - - network-attachment-definitions - verbs: - - get - - list - - watch ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - labels: - app: antrea - name: antrea-cluster-identity-reader -rules: -- apiGroups: - - "" - resourceNames: - - antrea-cluster-identity - resources: - - configmaps - verbs: - - get ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - labels: - app: antrea - name: antrea-controller -rules: -- apiGroups: - - "" - resources: - - pods - - services - - namespaces - - configmaps - verbs: - - get - - watch - - list -- apiGroups: - - "" - resources: - - nodes - verbs: - - get - - watch - - list - - patch -- apiGroups: - - "" - resources: - - services/status - verbs: - - update -- apiGroups: - - networking.k8s.io - resources: - - networkpolicies - verbs: - - get - - watch - - list -- apiGroups: - - authentication.k8s.io - resources: - - tokenreviews - verbs: - - create -- apiGroups: - - authorization.k8s.io - resources: - - subjectaccessreviews - verbs: - - create -- apiGroups: - - apiextensions.k8s.io - resources: - - customresourcedefinitions - verbs: - - get - - update -- apiGroups: - - "" - resourceNames: - - extension-apiserver-authentication - resources: - - configmaps - verbs: - - get - - list - - watch -- apiGroups: - - "" - resourceNames: - - antrea-ca - - antrea-cluster-identity - resources: - - configmaps - verbs: - - get - - update -- apiGroups: - - "" - resources: - - configmaps - verbs: - - create -- apiGroups: - - apiregistration.k8s.io - resourceNames: - - v1alpha1.stats.antrea.io - - v1beta1.system.antrea.io - - v1beta2.controlplane.antrea.io - resources: - - apiservices - verbs: - - get - - update -- apiGroups: - - apiregistration.k8s.io - resourceNames: - - v1beta1.networking.antrea.tanzu.vmware.com - - v1beta1.controlplane.antrea.tanzu.vmware.com - - v1alpha1.stats.antrea.tanzu.vmware.com - - v1beta1.system.antrea.tanzu.vmware.com - - v1beta2.controlplane.antrea.tanzu.vmware.com - resources: - - apiservices - verbs: - - delete -- apiGroups: - - admissionregistration.k8s.io - resourceNames: - - labelsmutator.antrea.io - - crdmutator.antrea.io - - crdvalidator.antrea.io - resources: - - mutatingwebhookconfigurations - - validatingwebhookconfigurations - verbs: - - get - - update -- apiGroups: - - crd.antrea.io - resources: - - antreacontrollerinfos - verbs: - - get - - create - - update - - delete -- apiGroups: - - crd.antrea.io - resources: - - antreaagentinfos - verbs: - - list - - delete -- apiGroups: - - crd.antrea.io - resources: - - clusternetworkpolicies - - networkpolicies - verbs: - - get - - watch - - list - - update - - patch - - create - - delete -- apiGroups: - - crd.antrea.io - resources: - - clusternetworkpolicies/status - - networkpolicies/status - verbs: - - update -- apiGroups: - - crd.antrea.io - resources: - - tiers - verbs: - - get - - watch - - list - - update - - patch - - create - - delete -- apiGroups: - - crd.antrea.io - resources: - - traceflows - - traceflows/status - verbs: - - get - - watch - - list - - update - - patch - - create - - delete -- apiGroups: - - crd.antrea.io - resources: - - externalentities - - clustergroups - verbs: - - get - - watch - - list - - update - - patch - - create - - delete -- apiGroups: - - crd.antrea.io - resources: - - clustergroups/status - verbs: - - update -- apiGroups: - - crd.antrea.io - resources: - - egresses - verbs: - - get - - watch - - list - - update - - patch -- apiGroups: - - crd.antrea.io - resources: - - externalippools - - ippools - verbs: - - get - - watch - - list -- apiGroups: - - crd.antrea.io - resources: - - externalippools/status - - ippools/status - verbs: - - update -- apiGroups: - - apps - resources: - - statefulsets - verbs: - - get - - list - - watch ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - labels: - app: antrea - name: antctl - namespace: kube-system -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: antctl -subjects: -- kind: ServiceAccount - name: antctl - namespace: kube-system ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - labels: - app: antrea - name: antrea-agent -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: antrea-agent -subjects: -- kind: ServiceAccount - name: antrea-agent - namespace: kube-system ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - labels: - app: antrea - name: antrea-controller -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: antrea-controller -subjects: -- kind: ServiceAccount - name: antrea-controller - namespace: kube-system ---- -apiVersion: v1 data: antrea-agent.conf: | # FeatureGates is a map of feature names to bools that enable or disable experimental features. @@ -2771,7 +90,8 @@ data: # Egress: true # Enable AntreaIPAM, which can allocate IP addresses from IPPools. AntreaIPAM is required by the - # bridging mode and allocates IPs to Pods in bridging mode. + # bridging mode and allocates IPs to Pods in bridging mode. It is also required to use Antrea for + # IPAM when configuring secondary network interfaces with Multus. # AntreaIPAM: false # Enable multicast traffic. This feature is supported only with noEncap mode. @@ -2785,21 +105,23 @@ data: # Enable managing external IPs of Services of LoadBalancer type. # ServiceExternalIP: false + # Enable mirroring or redirecting the traffic Pods send or receive. + # TrafficControl: false + # Name of the OpenVSwitch bridge antrea-agent will create and use. # Make sure it doesn't conflict with your existing OpenVSwitch bridges. - #ovsBridge: br-int + ovsBridge: "br-int" # Datapath type to use for the OpenVSwitch bridge created by Antrea. Supported values are: # - system # - netdev # 'system' is the default value and corresponds to the kernel datapath. Use 'netdev' to run - # OVS in userspace mode (not fully supported yet). Userspace mode requires the tun device driver to - # be available. + # OVS in userspace mode. Userspace mode requires the tun device driver to be available. #ovsDatapathType: system # Name of the interface antrea-agent will create and use for host <--> pod communication. # Make sure it doesn't conflict with your existing interfaces. - #hostGateway: antrea-gw0 + hostGateway: "antrea-gw0" # Determines how traffic is encapsulated. It has the following options: # encap(default): Inter-node Pod traffic is always encapsulated and Pod to external network @@ -2811,14 +133,14 @@ data: # networkPolicyOnly: Antrea enforces NetworkPolicy only, and utilizes CNI chaining and delegates Pod # IPAM and connectivity to the primary CNI. # - trafficEncapMode: networkPolicyOnly + trafficEncapMode: "networkPolicyOnly" # Whether or not to SNAT (using the Node IP) the egress traffic from a Pod to the external network. # This option is for the noEncap traffic mode only, and the default value is false. In the noEncap # mode, if the cluster's Pod CIDR is reachable from the external network, then the Pod traffic to # the external network needs not be SNAT'd. In the networkPolicyOnly mode, antrea-agent never # performs SNAT and this option will be ignored; for other modes it must be set to false. - #noSNAT: false + noSNAT: false # Tunnel protocols used for encapsulating traffic across Nodes. If WireGuard is enabled in trafficEncryptionMode, # this option will not take effect. Supported values: @@ -2827,7 +149,7 @@ data: # - gre # - stt # Note that "gre" is not supported for IPv6 clusters (IPv6-only or dual-stack clusters). - #tunnelType: geneve + tunnelType: "geneve" # Determines how tunnel traffic is encrypted. Currently encryption only works with encap mode. # It has the following options: @@ -2837,44 +159,54 @@ data: # the PSK value must be passed to Antrea Agent through an environment # variable: ANTREA_IPSEC_PSK. # - wireGuard: Enable WireGuard for tunnel traffic encryption. - #trafficEncryptionMode: none + trafficEncryptionMode: "none" # Enable bridging mode of Pod network on Nodes, in which the Node's transport interface is connected - # to the OVS bridge, and cross-Node/VLAN traffic from AntreaIPAM Pods (Pods whose IP addresses are - # allocated by AntreaIPAM from IPPools) is sent to the underlay network via the uplink, and - # forwarded/routed by the underlay network. + # to the OVS bridge, and cross-Node/VLAN traffic of AntreaIPAM Pods (Pods whose IP addresses are + # allocated by AntreaIPAM from IPPools) is sent to the underlay network, and forwarded/routed by the + # underlay network. # This option requires the `AntreaIPAM` feature gate to be enabled. At this moment, it supports only # IPv4 and Linux Nodes, and can be enabled only when `ovsDatapathType` is `system`, # `trafficEncapMode` is `noEncap`, and `noSNAT` is true. - #enableBridgingMode: false + enableBridgingMode: false + + # Disable TX checksum offloading for container network interfaces. It's supposed to be set to true when the + # datapath doesn't support TX checksum offloading, which causes packets to be dropped due to bad checksum. + # It affects Pods running on Linux Nodes only. + disableTXChecksumOffload: false # Default MTU to use for the host gateway interface and the network interface of each Pod. # If omitted, antrea-agent will discover the MTU of the Node's primary interface and # also adjust MTU to accommodate for tunnel encapsulation overhead (if applicable). - #defaultMTU: 0 + defaultMTU: 0 # wireGuard specifies WireGuard related configurations. wireGuard: - # The port for WireGuard to receive traffic. - # port: 51820 + # The port for WireGuard to receive traffic. + port: 51820 egress: - # exceptCIDRs is the CIDR ranges to which outbound Pod traffic will not be SNAT'd by Egresses. - # exceptCIDRs: [] + # exceptCIDRs is the CIDR ranges to which outbound Pod traffic will not be SNAT'd by Egresses. + exceptCIDRs: + + # ClusterIP CIDR range for Services. It's required when AntreaProxy is not enabled, and should be + # set to the same value as the one specified by --service-cluster-ip-range for kube-apiserver. When + # AntreaProxy is enabled, this parameter is not needed and will be ignored if provided. + serviceCIDR: "" # ClusterIP CIDR range for IPv6 Services. It's required when using kube-proxy to provide IPv6 Service in a Dual-Stack # cluster or an IPv6 only cluster. The value should be the same as the configuration for kube-apiserver specified by # --service-cluster-ip-range. When AntreaProxy is enabled, this parameter is not needed. # No default value for this field. - #serviceCIDRv6: + serviceCIDRv6: "" # The port for the antrea-agent APIServer to serve on. # Note that if it's set to another value, the `containerPort` of the `api` port of the # `antrea-agent` container must be set to the same value. - #apiPort: 10350 + apiPort: 10350 # Enable metrics exposure via Prometheus. Initializes Prometheus metrics listener. - #enablePrometheusMetrics: true + enablePrometheusMetrics: true # Provide the IPFIX collector address as a string with format :[][:]. # HOST can either be the DNS name or the IP of the Flow Collector. For example, @@ -2885,50 +217,50 @@ data: # If no PROTO is given, we consider "tls" as default. We support "tls", "tcp" and # "udp" protocols. "tls" is used for securing communication between flow exporter and # flow aggregator. - #flowCollectorAddr: "flow-aggregator.flow-aggregator.svc:4739:tls" + flowCollectorAddr: "flow-aggregator.flow-aggregator.svc:4739:tls" # Provide flow poll interval as a duration string. This determines how often the # flow exporter dumps connections from the conntrack module. Flow poll interval # should be greater than or equal to 1s (one second). # Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". - #flowPollInterval: "5s" + flowPollInterval: "5s" # Provide the active flow export timeout, which is the timeout after which a flow # record is sent to the collector for active flows. Thus, for flows with a continuous # stream of packets, a flow record will be exported to the collector once the elapsed # time since the last export event is equal to the value of this timeout. # Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". - #activeFlowExportTimeout: "30s" + activeFlowExportTimeout: "5s" # Provide the idle flow export timeout, which is the timeout after which a flow # record is sent to the collector for idle flows. A flow is considered idle if no # packet matching this flow has been observed since the last export event. # Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". - #idleFlowExportTimeout: "15s" + idleFlowExportTimeout: "15s" nodePortLocal: # Enable NodePortLocal, a feature used to make Pods reachable using port forwarding on the host. To # enable this feature, you need to set "enable" to true, and ensure that the NodePortLocal feature # gate is also enabled (which is the default). - # enable: false + enable: false # Provide the port range used by NodePortLocal. When the NodePortLocal feature is enabled, a port # from that range will be assigned whenever a Pod's container defines a specific port to be exposed # (each container can define a list of ports as pod.spec.containers[].ports), and all Node traffic # directed to that port will be forwarded to the Pod. - # portRange: 61000-62000 + portRange: "61000-62000" # Provide the address of Kubernetes apiserver, to override any value provided in kubeconfig or InClusterConfig. # Defaults to "". It must be a host string, a host:port pair, or a URL to the base of the apiserver. - #kubeAPIServerOverride: "" + kubeAPIServerOverride: "" # Comma-separated list of Cipher Suites. If omitted, the default Go Cipher Suites will be used. # https://golang.org/pkg/crypto/tls/#pkg-constants # Note that TLS1.3 Cipher Suites cannot be added to the list. But the apiserver will always # prefer TLS1.3 Cipher Suites whenever possible. - #tlsCipherSuites: + tlsCipherSuites: "" # TLS min version from: VersionTLS10, VersionTLS11, VersionTLS12, VersionTLS13. - #tlsMinVersion: + tlsMinVersion: "" # The name of the interface on Node which is used for tunneling or routing the traffic across Nodes. # If there are multiple IP addresses configured on the interface, the first one is used. The IP @@ -2937,11 +269,16 @@ data: # 1. transportInterface # 2. transportInterfaceCIDRs # 3. The Node IP - #transportInterface: + transportInterface: "" + multicast: # The names of the interfaces on Nodes that are used to forward multicast traffic. # Defaults to transport interface if not set. - #multicastInterfaces: [] + multicastInterfaces: + + # The interval at which the antrea-agent sends IGMP queries to Pods. + # Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". + igmpQueryInterval: "125s" # The network CIDRs of the interface on Node which is used for tunneling or routing the traffic across # Nodes. If there are multiple interfaces configured the same network CIDR, the first one is used. The @@ -2950,7 +287,7 @@ data: # 1. transportInterface # 2. transportInterfaceCIDRs # 3. The Node IP - #transportInterfaceCIDRs: [,] + transportInterfaceCIDRs: # Option antreaProxy contains AntreaProxy related configuration options. antreaProxy: @@ -2959,22 +296,22 @@ data: # feature to be enabled. # Note that this option is experimental. If kube-proxy is removed, option kubeAPIServerOverride must be used to access # apiserver directly. - #proxyAll: false + proxyAll: false # A string array of values which specifies the host IPv4/IPv6 addresses for NodePort. Values can be valid IP blocks. # (e.g. 1.2.3.0/24, 1.2.3.4/32). An empty string slice is meant to select all host IPv4/IPv6 addresses. # Note that the option is only valid when proxyAll is true. - #nodePortAddresses: [] + nodePortAddresses: # An array of string values to specify a list of Services which should be ignored by AntreaProxy (traffic to these # Services will not be load-balanced). Values can be a valid ClusterIP (e.g. 10.11.1.2) or a Service name # with Namespace (e.g. kube-system/kube-dns) - #skipServices: [] + skipServices: # When ProxyLoadBalancerIPs is set to false, AntreaProxy no longer load-balances traffic destined to the # External IPs of LoadBalancer Services. This is useful when the external LoadBalancer provides additional # capabilities (e.g. TLS termination) and it is desirable for Pod-to-ExternalIP traffic to be sent to the # external LoadBalancer instead of being load-balanced to an Endpoint directly by AntreaProxy. # Note that setting ProxyLoadBalancerIPs to false usually only makes sense when ProxyAll is set to true and # kube-proxy is removed from the cluser, otherwise kube-proxy will still load-balance this traffic. - #proxyLoadBalancerIPs: true + proxyLoadBalancerIPs: true antrea-cni.conflist: | { "cniVersion":"0.3.0", @@ -2985,11 +322,13 @@ data: "ipam": { "type": "host-local" } - }, + } + , { "type": "portmap", "capabilities": {"portMappings": true} - }, + } + , { "type": "bandwidth", "capabilities": {"bandwidth": true} @@ -3016,8 +355,9 @@ data: # Run Kubernetes NodeIPAMController with Antrea. # NodeIPAM: false - # Enable flexible IPAM mode for Antrea. This mode allows to assign IP Ranges to Namespaces, - # Deployments and StatefulSets via IP Pool annotation. + # Enable AntreaIPAM, which can allocate IP addresses from IPPools. AntreaIPAM is required by the + # bridging mode and allocates IPs to Pods in bridging mode. It is also required to use Antrea for + # IPAM when configuring secondary network interfaces with Multus. # AntreaIPAM: false # Enable managing external IPs of Services of LoadBalancer type. @@ -3026,659 +366,3674 @@ data: # The port for the antrea-controller APIServer to serve on. # Note that if it's set to another value, the `containerPort` of the `api` port of the # `antrea-controller` container must be set to the same value. - #apiPort: 10349 + apiPort: 10349 # Enable metrics exposure via Prometheus. Initializes Prometheus metrics listener. - #enablePrometheusMetrics: true + enablePrometheusMetrics: true # Indicates whether to use auto-generated self-signed TLS certificate. - # If false, A Secret named "antrea-controller-tls" must be provided with the following keys: + # If false, a Secret named "antrea-controller-tls" must be provided with the following keys: # ca.crt: # tls.crt: # tls.key: - # And the Secret must be mounted to directory "/var/run/antrea/antrea-controller-tls" of the - # antrea-controller container. - #selfSignedCert: true + selfSignedCert: true # Comma-separated list of Cipher Suites. If omitted, the default Go Cipher Suites will be used. # https://golang.org/pkg/crypto/tls/#pkg-constants # Note that TLS1.3 Cipher Suites cannot be added to the list. But the apiserver will always # prefer TLS1.3 Cipher Suites whenever possible. - #tlsCipherSuites: + tlsCipherSuites: "" # TLS min version from: VersionTLS10, VersionTLS11, VersionTLS12, VersionTLS13. - #tlsMinVersion: + tlsMinVersion: "" nodeIPAM: - # Enable the integrated Node IPAM controller within the Antrea controller. - # enableNodeIPAM: false - - # CIDR ranges for Pods in cluster. String array containing single CIDR range, or multiple ranges. - # The CIDRs could be either IPv4 or IPv6. At most one CIDR may be specified for each IP family. - # Value ignored when enableNodeIPAM is false. - # clusterCIDRs: [] - - # CIDR ranges for Services in cluster. It is not necessary to specify it when there is no overlap with clusterCIDRs. - # Value ignored when enableNodeIPAM is false. - # serviceCIDR: - # serviceCIDRv6: - - # Mask size for IPv4 Node CIDR in IPv4 or dual-stack cluster. Value ignored when enableNodeIPAM is false - # or when IPv4 Pod CIDR is not configured. Valid range is 16 to 30. - # nodeCIDRMaskSizeIPv4: 24 - - # Mask size for IPv6 Node CIDR in IPv6 or dual-stack cluster. Value ignored when enableNodeIPAM is false - # or when IPv6 Pod CIDR is not configured. Valid range is 64 to 126. - # nodeCIDRMaskSizeIPv6: 64 -kind: ConfigMap + # Enable the integrated Node IPAM controller within the Antrea controller. + enableNodeIPAM: false + # CIDR ranges for Pods in cluster. String array containing single CIDR range, or multiple ranges. + # The CIDRs could be either IPv4 or IPv6. At most one CIDR may be specified for each IP family. + # Value ignored when enableNodeIPAM is false. + clusterCIDRs: + # CIDR ranges for Services in cluster. It is not necessary to specify it when there is no overlap with clusterCIDRs. + # Value ignored when enableNodeIPAM is false. + serviceCIDR: "" + serviceCIDRv6: "" + # Mask size for IPv4 Node CIDR in IPv4 or dual-stack cluster. Value ignored when enableNodeIPAM is false + # or when IPv4 Pod CIDR is not configured. Valid range is 16 to 30. + nodeCIDRMaskSizeIPv4: 24 + # Mask size for IPv6 Node CIDR in IPv6 or dual-stack cluster. Value ignored when enableNodeIPAM is false + # or when IPv6 Pod CIDR is not configured. Valid range is 64 to 126. + nodeCIDRMaskSizeIPv6: 64 +--- +# Source: antrea/templates/crds/antreaagentinfo.yaml +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: antreaagentinfos.crd.antrea.io + labels: + app: antrea +spec: + group: crd.antrea.io + versions: + - name: v1beta1 + served: true + storage: true + schema: + openAPIV3Schema: + type: object + x-kubernetes-preserve-unknown-fields: true + additionalPrinterColumns: + - description: Health status of this Agent + jsonPath: ".agentConditions[?(@.type=='AgentHealthy')].status" + name: Healthy + type: string + - description: Last time the Healthy Condition was updated + jsonPath: ".agentConditions[?(@.type=='AgentHealthy')].lastHeartbeatTime" + name: Last Heartbeat + type: date + - description: Version of this Agent + jsonPath: ".version" + name: Version + type: string + priority: 1 + - description: Node on which this Agent is running + jsonPath: ".nodeRef.name" + name: Node + type: string + priority: 1 + - description: Number of local Pods managed by this Agent + jsonPath: ".localPodNum" + name: Num Pods + type: integer + priority: 2 + - description: Subnets used by this Agent for Pod IPAM + jsonPath: ".nodeSubnets" + name: Subnets + type: string + priority: 2 + scope: Cluster + names: + plural: antreaagentinfos + singular: antreaagentinfo + kind: AntreaAgentInfo + shortNames: + - aai +--- +# Source: antrea/templates/crds/antreacontrollerinfo.yaml +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: antreacontrollerinfos.crd.antrea.io + labels: + app: antrea +spec: + group: crd.antrea.io + versions: + - name: v1beta1 + served: true + storage: true + schema: + openAPIV3Schema: + type: object + x-kubernetes-preserve-unknown-fields: true + additionalPrinterColumns: + - description: Health status of the Controller + jsonPath: ".controllerConditions[?(@.type=='ControllerHealthy')].status" + name: Healthy + type: string + - description: Last time the Healthy Condition was updated + jsonPath: ".controllerConditions[?(@.type=='ControllerHealthy')].lastHeartbeatTime" + name: Last Heartbeat + type: date + - description: Version of the Controller + jsonPath: ".version" + name: Version + type: string + priority: 1 + - description: Number of Agents connected to the Controller + jsonPath: ".connectedAgentNum" + name: Connected Agents + type: integer + priority: 1 + - description: Node on which the Controller is running + jsonPath: ".nodeRef.name" + name: Node + type: string + priority: 1 + - description: Number of Network Policies computed by Controller + jsonPath: ".networkPolicyControllerInfo.networkPolicyNum" + name: Num Network Policies + type: integer + priority: 2 + scope: Cluster + names: + plural: antreacontrollerinfos + singular: antreacontrollerinfo + kind: AntreaControllerInfo + shortNames: + - aci +--- +# Source: antrea/templates/crds/clustergroup.yaml +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: clustergroups.crd.antrea.io + labels: + app: antrea +spec: + group: crd.antrea.io + versions: + - name: v1alpha2 + served: true + storage: false + schema: + openAPIV3Schema: + type: object + properties: + spec: + type: object + properties: + childGroups: + type: array + items: + type: string + podSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + externalEntitySelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + ipBlock: + type: object + properties: + cidr: + type: string + format: cidr + ipBlocks: + type: array + items: + type: object + properties: + cidr: + type: string + format: cidr + serviceReference: + type: object + properties: + name: + type: string + namespace: + type: string + status: + type: object + properties: + conditions: + type: array + items: + type: object + properties: + type: + type: string + status: + type: string + lastTransitionTime: + type: string + - name: v1alpha3 + served: true + storage: true + schema: + openAPIV3Schema: + type: object + properties: + spec: + type: object + properties: + childGroups: + type: array + items: + type: string + podSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + externalEntitySelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + ipBlocks: + type: array + items: + type: object + properties: + cidr: + type: string + format: cidr + serviceReference: + type: object + properties: + name: + type: string + namespace: + type: string + status: + type: object + properties: + conditions: + type: array + items: + type: object + properties: + type: + type: string + status: + type: string + lastTransitionTime: + type: string + subresources: + status: {} + conversion: + strategy: Webhook + webhook: + conversionReviewVersions: ["v1", "v1beta1"] + clientConfig: + service: + name: "antrea" + namespace: "kube-system" + path: "/convert/clustergroup" + scope: Cluster + names: + plural: clustergroups + singular: clustergroup + kind: ClusterGroup + shortNames: + - cg +--- +# Source: antrea/templates/crds/clusternetworkpolicy.yaml +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: clusternetworkpolicies.crd.antrea.io + labels: + app: antrea +spec: + group: crd.antrea.io + versions: + - name: v1alpha1 + served: true + storage: true + additionalPrinterColumns: + - name: Tier + type: string + description: The Tier to which this ClusterNetworkPolicy belongs to. + jsonPath: .spec.tier + - name: Priority + type: number + format: float + description: The Priority of this ClusterNetworkPolicy relative to other policies. + jsonPath: .spec.priority + - name: Desired Nodes + type: number + format: int32 + description: The total number of Nodes that should realize the NetworkPolicy. + jsonPath: .status.desiredNodesRealized + - name: Current Nodes + type: number + format: int32 + description: The number of Nodes that have realized the NetworkPolicy. + jsonPath: .status.currentNodesRealized + - name: Age + type: date + jsonPath: .metadata.creationTimestamp + schema: + openAPIV3Schema: + type: object + properties: + spec: + # Ensure that Spec.Priority field is set + required: + - priority + type: object + properties: + tier: + type: string + priority: + type: number + format: float + # Ensure that Spec.Priority field is between 1 and 10000 + minimum: 1.0 + maximum: 10000.0 + appliedTo: + type: array + items: + type: object + # Ensure that Spec.AppliedTo does not allow IPBlock field + properties: + podSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + group: + type: string + serviceAccount: + type: object + properties: + name: + type: string + namespace: + type: string + required: + - name + - namespace + ingress: + type: array + items: + type: object + required: + - action + properties: + appliedTo: + type: array + items: + type: object + # Ensure that rule AppliedTo does not allow IPBlock field + properties: + podSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + group: + type: string + serviceAccount: + type: object + properties: + name: + type: string + namespace: + type: string + required: + - name + - namespace + # Ensure that Action field allows only ALLOW, DROP, REJECT and PASS values + action: + type: string + enum: ['Allow', 'Drop', 'Reject', 'Pass'] + ports: + type: array + items: + type: object + properties: + protocol: + type: string + enum: ['TCP', 'UDP', 'SCTP'] + port: + x-kubernetes-int-or-string: true + endPort: + type: integer + protocols: + type: array + items: + type: object + oneOf: + - required: [icmp] + properties: + icmp: + type: object + properties: + icmpType: + type: integer + minimum: 0 + maximum: 255 + icmpCode: + type: integer + minimum: 0 + maximum: 255 + from: + type: array + items: + type: object + properties: + podSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + namespaces: + type: object + properties: + match: + enum: + - Self + type: string + ipBlock: + type: object + properties: + cidr: + type: string + format: cidr + group: + type: string + serviceAccount: + type: object + properties: + name: + type: string + namespace: + type: string + required: + - name + - namespace + nodeSelector: + type: object + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + type: array + type: object + type: array + matchLabels: + x-kubernetes-preserve-unknown-fields: true + name: + type: string + enableLogging: + type: boolean + egress: + type: array + items: + type: object + required: + - action + properties: + appliedTo: + type: array + items: + type: object + # Ensure that rule AppliedTo does not allow IPBlock field + properties: + podSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + group: + type: string + serviceAccount: + type: object + properties: + name: + type: string + namespace: + type: string + required: + - name + - namespace + # Ensure that Action field allows only ALLOW, DROP, REJECT and PASS values + action: + type: string + enum: ['Allow', 'Drop', 'Reject', 'Pass'] + ports: + type: array + items: + type: object + properties: + protocol: + type: string + enum: ['TCP', 'UDP', 'SCTP'] + port: + x-kubernetes-int-or-string: true + endPort: + type: integer + protocols: + type: array + items: + type: object + oneOf: + - required: [icmp] + properties: + icmp: + type: object + properties: + icmpType: + type: integer + minimum: 0 + maximum: 255 + icmpCode: + type: integer + minimum: 0 + maximum: 255 + to: + type: array + items: + type: object + properties: + podSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + namespaces: + type: object + properties: + match: + enum: + - Self + type: string + ipBlock: + type: object + properties: + cidr: + type: string + format: cidr + group: + type: string + fqdn: + type: string + serviceAccount: + type: object + properties: + name: + type: string + namespace: + type: string + required: + - name + - namespace + nodeSelector: + type: object + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + type: array + type: object + type: array + matchLabels: + x-kubernetes-preserve-unknown-fields: true + toServices: + type: array + items: + type: object + required: + - name + - namespace + properties: + name: + type: string + namespace: + type: string + name: + type: string + enableLogging: + type: boolean + status: + type: object + properties: + phase: + type: string + observedGeneration: + type: integer + currentNodesRealized: + type: integer + desiredNodesRealized: + type: integer + subresources: + status: {} + scope: Cluster + names: + plural: clusternetworkpolicies + singular: clusternetworkpolicy + kind: ClusterNetworkPolicy + shortNames: + - acnp +--- +# Source: antrea/templates/crds/egress.yaml +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: egresses.crd.antrea.io + labels: + app: antrea +spec: + group: crd.antrea.io + versions: + - name: v1alpha2 + served: true + storage: true + schema: + openAPIV3Schema: + type: object + required: + - spec + properties: + spec: + type: object + required: + - appliedTo + anyOf: + - required: + - egressIP + - required: + - externalIPPool + properties: + appliedTo: + type: object + properties: + podSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + egressIP: + type: string + oneOf: + - format: ipv4 + - format: ipv6 + externalIPPool: + type: string + status: + type: object + properties: + egressNode: + type: string + additionalPrinterColumns: + - description: Specifies the SNAT IP address for the selected workloads. + jsonPath: .spec.egressIP + name: EgressIP + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + - description: The Owner Node of egress IP + jsonPath: .status.egressNode + name: Node + type: string + subresources: + status: {} + scope: Cluster + names: + plural: egresses + singular: egress + kind: Egress + shortNames: + - eg +--- +# Source: antrea/templates/crds/externalentity.yaml +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: externalentities.crd.antrea.io + labels: + app: antrea +spec: + group: crd.antrea.io + versions: + - name: v1alpha2 + served: true + storage: true + schema: + openAPIV3Schema: + type: object + properties: + spec: + type: object + properties: + endpoints: + type: array + items: + type: object + properties: + ip: + type: string + oneOf: + - format: ipv4 + - format: ipv6 + name: + type: string + ports: + type: array + items: + type: object + properties: + protocol: + type: string + enum: ['TCP', 'UDP', 'SCTP'] + port: + x-kubernetes-int-or-string: true + name: + type: string + externalNode: + type: string + - name: v1alpha1 + served: false + storage: false + schema: + openAPIV3Schema: + type: object + scope: Namespaced + names: + plural: externalentities + singular: externalentity + kind: ExternalEntity + shortNames: + - ee +--- +# Source: antrea/templates/crds/externalippool.yaml +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: externalippools.crd.antrea.io + labels: + app: antrea +spec: + group: crd.antrea.io + versions: + - name: v1alpha2 + served: true + storage: true + schema: + openAPIV3Schema: + type: object + required: + - spec + properties: + spec: + type: object + required: + - ipRanges + - nodeSelector + properties: + ipRanges: + type: array + items: + type: object + oneOf: + - required: + - cidr + - required: + - start + - end + properties: + cidr: + type: string + format: cidr + start: + type: string + oneOf: + - format: ipv4 + - format: ipv6 + end: + type: string + oneOf: + - format: ipv4 + - format: ipv6 + nodeSelector: + type: object + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + type: array + type: object + type: array + matchLabels: + x-kubernetes-preserve-unknown-fields: true + status: + type: object + properties: + usage: + type: object + properties: + total: + type: integer + used: + type: integer + additionalPrinterColumns: + - description: The number of total IPs + jsonPath: .status.usage.total + name: Total + type: integer + - description: The number of allocated IPs + jsonPath: .status.usage.used + name: Used + type: integer + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + subresources: + status: {} + scope: Cluster + names: + plural: externalippools + singular: externalippool + kind: ExternalIPPool + shortNames: + - eip +--- +# Source: antrea/templates/crds/ippool.yaml +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: ippools.crd.antrea.io + labels: + app: antrea +spec: + group: crd.antrea.io + versions: + - name: v1alpha2 + served: true + storage: true + schema: + openAPIV3Schema: + type: object + required: + - spec + properties: + spec: + required: + - ipVersion + - ipRanges + type: object + properties: + ipVersion: + type: integer + ipRanges: + items: + oneOf: + - required: + - cidr + - gateway + - prefixLength + - required: + - start + - end + - gateway + - prefixLength + properties: + cidr: + format: cidr + type: string + start: + oneOf: + - format: ipv4 + - format: ipv6 + type: string + end: + oneOf: + - format: ipv4 + - format: ipv6 + type: string + gateway: + oneOf: + - format: ipv4 + - format: ipv6 + type: string + prefixLength: + type: integer + vlan: + type: integer + minimum: 0 + maximum: 4094 + type: object + type: array + status: + properties: + ipAddresses: + items: + properties: + ipAddress: + type: string + owner: + properties: + pod: + properties: + name: + type: string + namespace: + type: string + containerID: + type: string + ifName: + type: string + type: object + statefulSet: + properties: + name: + type: string + namespace: + type: string + index: + type: integer + type: object + type: object + phase: + type: string + type: object + type: array + type: object + subresources: + status: {} + scope: Cluster + names: + plural: ippools + singular: ippool + kind: IPPool + shortNames: + - ipp +--- +# Source: antrea/templates/crds/networkpolicy.yaml +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: networkpolicies.crd.antrea.io + labels: + app: antrea +spec: + group: crd.antrea.io + versions: + - name: v1alpha1 + served: true + storage: true + additionalPrinterColumns: + - name: Tier + type: string + description: The Tier to which this Antrea NetworkPolicy belongs to. + jsonPath: .spec.tier + - name: Priority + type: number + format: float + description: The Priority of this Antrea NetworkPolicy relative to other policies. + jsonPath: .spec.priority + - name: Desired Nodes + type: number + format: int32 + description: The total number of Nodes that should realize the NetworkPolicy. + jsonPath: .status.desiredNodesRealized + - name: Current Nodes + type: number + format: int32 + description: The number of Nodes that have realized the NetworkPolicy. + jsonPath: .status.currentNodesRealized + - name: Age + type: date + jsonPath: .metadata.creationTimestamp + schema: + openAPIV3Schema: + type: object + properties: + spec: + # Ensure that Spec.Priority field is set + required: + - priority + type: object + properties: + tier: + type: string + priority: + type: number + format: float + # Ensure that Spec.Priority field is between 1 and 10000 + minimum: 1.0 + maximum: 10000.0 + appliedTo: + type: array + items: + type: object + # Ensure that Spec.AppliedTo does not allow NamespaceSelector/IPBlock field + properties: + podSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + ingress: + type: array + items: + type: object + required: + - action + properties: + appliedTo: + type: array + items: + type: object + # Ensure that rule AppliedTo does not allow NamespaceSelector/IPBlock field + properties: + podSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + # Ensure that Action field allows only ALLOW, DROP, REJECT and PASS values + action: + type: string + enum: ['Allow', 'Drop', 'Reject', 'Pass'] + ports: + type: array + items: + type: object + properties: + protocol: + type: string + enum: ['TCP', 'UDP', 'SCTP'] + port: + x-kubernetes-int-or-string: true + endPort: + type: integer + protocols: + type: array + items: + type: object + oneOf: + - required: [icmp] + properties: + icmp: + type: object + properties: + icmpType: + type: integer + minimum: 0 + maximum: 255 + icmpCode: + type: integer + minimum: 0 + maximum: 255 + from: + type: array + items: + type: object + properties: + podSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + externalEntitySelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + ipBlock: + type: object + properties: + cidr: + type: string + format: cidr + nodeSelector: + type: object + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + type: array + type: object + type: array + matchLabels: + x-kubernetes-preserve-unknown-fields: true + name: + type: string + enableLogging: + type: boolean + egress: + type: array + items: + type: object + required: + - action + properties: + appliedTo: + type: array + items: + type: object + # Ensure that rule AppliedTo does not allow NamespaceSelector/IPBlock field + properties: + podSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + # Ensure that Action field allows only ALLOW, DROP, REJECT and PASS values + action: + type: string + enum: ['Allow', 'Drop', 'Reject', 'Pass'] + ports: + type: array + items: + type: object + properties: + protocol: + type: string + enum: ['TCP', 'UDP', 'SCTP'] + port: + x-kubernetes-int-or-string: true + endPort: + type: integer + protocols: + type: array + items: + type: object + oneOf: + - required: [icmp] + properties: + icmp: + type: object + properties: + icmpType: + type: integer + minimum: 0 + maximum: 255 + icmpCode: + type: integer + minimum: 0 + maximum: 255 + to: + type: array + items: + type: object + properties: + podSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + externalEntitySelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + ipBlock: + type: object + properties: + cidr: + type: string + format: cidr + fqdn: + type: string + nodeSelector: + type: object + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + type: array + type: object + type: array + matchLabels: + x-kubernetes-preserve-unknown-fields: true + toServices: + type: array + items: + type: object + required: + - name + properties: + name: + type: string + namespace: + type: string + name: + type: string + enableLogging: + type: boolean + status: + type: object + properties: + phase: + type: string + observedGeneration: + type: integer + currentNodesRealized: + type: integer + desiredNodesRealized: + type: integer + subresources: + status: {} + scope: Namespaced + names: + plural: networkpolicies + singular: networkpolicy + kind: NetworkPolicy + shortNames: + - anp +--- +# Source: antrea/templates/crds/tier.yaml +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: tiers.crd.antrea.io + labels: + app: antrea +spec: + group: crd.antrea.io + versions: + - name: v1alpha1 + served: true + storage: true + additionalPrinterColumns: + - name: Priority + type: integer + description: The Priority of this Tier relative to other Tiers. + jsonPath: .spec.priority + - name: Age + type: date + jsonPath: .metadata.creationTimestamp + schema: + openAPIV3Schema: + type: object + properties: + spec: + required: + - priority + type: object + properties: + priority: + type: integer + minimum: 0 + maximum: 255 + description: + type: string + scope: Cluster + names: + plural: tiers + singular: tier + kind: Tier + shortNames: + - tr +--- +# Source: antrea/templates/crds/traceflow.yaml +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: traceflows.crd.antrea.io + labels: + app: antrea +spec: + group: crd.antrea.io + versions: + - name: v1alpha1 + served: true + storage: true + additionalPrinterColumns: + - jsonPath: .status.phase + description: The phase of the Traceflow. + name: Phase + type: string + - jsonPath: .spec.source.pod + description: The name of the source Pod. + name: Source-Pod + type: string + priority: 10 + - jsonPath: .spec.destination.pod + description: The name of the destination Pod. + name: Destination-Pod + type: string + priority: 10 + - jsonPath: .spec.destination.ip + description: The IP address of the destination. + name: Destination-IP + type: string + priority: 10 + - jsonPath: .spec.liveTraffic + description: Trace live traffic. + name: Live-Traffic + type: boolean + priority: 10 + - jsonPath: .spec.droppedOnly + description: Capture only the dropped packet. + name: Dropped-Only + type: boolean + priority: 10 + - jsonPath: .spec.timeout + description: Timeout in seconds. + name: Timeout + type: integer + priority: 10 + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + schema: + openAPIV3Schema: + type: object + required: + - spec + properties: + spec: + type: object + properties: + source: + type: object + properties: + pod: + type: string + namespace: + type: string + ip: + type: string + oneOf: + - format: ipv4 + - format: ipv6 + destination: + type: object + properties: + pod: + type: string + service: + type: string + namespace: + type: string + ip: + type: string + oneOf: + - format: ipv4 + - format: ipv6 + packet: + type: object + properties: + ipHeader: + type: object + properties: + srcIP: + type: string + oneOf: + - format: ipv4 + - format: ipv6 + protocol: + type: integer + ttl: + type: integer + flags: + type: integer + ipv6Header: + type: object + properties: + srcIP: + type: string + format: ipv6 + nextHeader: + type: integer + hopLimit: + type: integer + transportHeader: + type: object + properties: + icmp: + type: object + properties: + id: + type: integer + sequence: + type: integer + udp: + type: object + properties: + srcPort: + type: integer + dstPort: + type: integer + tcp: + type: object + properties: + srcPort: + type: integer + dstPort: + type: integer + flags: + type: integer + liveTraffic: + type: boolean + droppedOnly: + type: boolean + timeout: + type: integer + status: + type: object + properties: + reason: + type: string + dataplaneTag: + type: integer + phase: + type: string + startTime: + type: string + results: + type: array + items: + type: object + properties: + node: + type: string + role: + type: string + timestamp: + type: integer + observations: + type: array + items: + type: object + properties: + component: + type: string + componentInfo: + type: string + action: + type: string + pod: + type: string + dstMAC: + type: string + networkPolicy: + type: string + ttl: + type: integer + translatedSrcIP: + type: string + translatedDstIP: + type: string + tunnelDstIP: + type: string + capturedPacket: + properties: + srcIP: + type: string + dstIP: + type: string + length: + type: integer + ipHeader: + properties: + flags: + type: integer + protocol: + type: integer + ttl: + type: integer + type: object + ipv6Header: + properties: + hopLimit: + type: integer + nextHeader: + type: integer + type: object + transportHeader: + properties: + tcp: + properties: + dstPort: + type: integer + srcPort: + type: integer + flags: + type: integer + type: object + udp: + properties: + dstPort: + type: integer + srcPort: + type: integer + type: object + icmp: + properties: + id: + type: integer + sequence: + type: integer + type: object + type: object + type: object + subresources: + status: {} + scope: Cluster + names: + plural: traceflows + singular: traceflow + kind: Traceflow + shortNames: + - tf +--- +# Source: antrea/templates/crds/trafficcontrol.yaml +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: trafficcontrols.crd.antrea.io +spec: + group: crd.antrea.io + versions: + - name: v1alpha2 + served: true + storage: true + schema: + openAPIV3Schema: + type: object + required: + - spec + properties: + spec: + type: object + required: + - appliedTo + - direction + - action + - targetPort + properties: + appliedTo: + type: object + properties: + podSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + direction: + type: string + enum: + - Ingress + - Egress + - Both + action: + type: string + enum: + - Mirror + - Redirect + targetPort: + type: object + oneOf: + - required: [ovsInternal] + - required: [device] + - required: [geneve] + - required: [vxlan] + - required: [gre] + - required: [erspan] + properties: + ovsInternal: + type: object + required: + - name + properties: + name: + type: string + device: + type: object + required: + - name + properties: + name: + type: string + geneve: + type: object + required: + - remoteIP + properties: + remoteIP: + type: string + oneOf: + - format: ipv4 + - format: ipv6 + vni: + type: integer + minimum: 0 + maximum: 16777215 + destinationPort: + type: integer + minimum: 1 + maximum: 65535 + vxlan: + type: object + required: + - remoteIP + properties: + remoteIP: + type: string + oneOf: + - format: ipv4 + - format: ipv6 + vni: + type: integer + minimum: 0 + maximum: 16777215 + destinationPort: + type: integer + minimum: 1 + maximum: 65535 + gre: + type: object + required: + - remoteIP + properties: + remoteIP: + type: string + oneOf: + - format: ipv4 + - format: ipv6 + key: + type: integer + minimum: 0 + maximum: 4294967295 + erspan: + type: object + required: + - remoteIP + - version + properties: + remoteIP: + type: string + oneOf: + - format: ipv4 + - format: ipv6 + sessionID: + type: integer + minimum: 0 + maximum: 1023 + version: + type: integer + enum: + - 1 + - 2 + index: + type: integer + dir: + type: integer + enum: + - 0 + - 1 + hardwareID: + type: integer + returnPort: + type: object + oneOf: + - required: [ovsInternal] + - required: [device] + - required: [geneve] + - required: [vxlan] + - required: [gre] + properties: + ovsInternal: + type: object + required: + - name + properties: + name: + type: string + device: + type: object + required: + - name + properties: + name: + type: string + geneve: + type: object + required: + - remoteIP + properties: + remoteIP: + type: string + oneOf: + - format: ipv4 + - format: ipv6 + vni: + type: integer + minimum: 0 + maximum: 16777215 + destinationPort: + type: integer + minimum: 1 + maximum: 65535 + vxlan: + type: object + required: + - remoteIP + properties: + remoteIP: + type: string + oneOf: + - format: ipv4 + - format: ipv6 + vni: + type: integer + minimum: 0 + maximum: 16777215 + destinationPort: + type: integer + minimum: 1 + maximum: 65535 + gre: + type: object + required: + - remoteIP + properties: + remoteIP: + type: string + oneOf: + - format: ipv4 + - format: ipv6 + key: + type: integer + minimum: 0 + maximum: 4294967295 + additionalPrinterColumns: + - description: Specifies the direction of traffic that should be matched. + jsonPath: .spec.direction + name: Direction + type: string + - description: Specifies the action that should be taken for the traffic. + jsonPath: .spec.action + name: Action + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + subresources: + status: {} + scope: Cluster + names: + plural: trafficcontrols + singular: trafficcontrol + kind: TrafficControl + shortNames: + - tc +--- +# Source: antrea/templates/agent/clusterrole.yaml +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: antrea-agent + labels: + app: antrea +rules: + - apiGroups: + - "" + resources: + - nodes + verbs: + - get + - watch + - list + - apiGroups: + - "" + resources: + - nodes/status + verbs: + - patch + - apiGroups: + - "" + resources: + - pods + verbs: + - get + - watch + - list + - apiGroups: + - "" + resources: + - pods/status + verbs: + - patch + - apiGroups: + - "" + resources: + - endpoints + - services + - namespaces + verbs: + - get + - watch + - list + - apiGroups: + - discovery.k8s.io + resources: + - endpointslices + verbs: + - get + - watch + - list + - apiGroups: + - crd.antrea.io + resources: + - antreaagentinfos + verbs: + - get + - create + - update + - delete + - apiGroups: + - controlplane.antrea.io + resources: + - networkpolicies + - appliedtogroups + - addressgroups + verbs: + - get + - watch + - list + - apiGroups: + - controlplane.antrea.io + resources: + - egressgroups + verbs: + - get + - watch + - list + - apiGroups: + - controlplane.antrea.io + resources: + - nodestatssummaries + verbs: + - create + - apiGroups: + - controlplane.antrea.io + resources: + - networkpolicies/status + verbs: + - create + - get + - apiGroups: + - authentication.k8s.io + resources: + - tokenreviews + verbs: + - create + - apiGroups: + - authorization.k8s.io + resources: + - subjectaccessreviews + verbs: + - create + # This is the content of built-in role kube-system/extension-apiserver-authentication-reader. + # But it doesn't have list/watch permission before K8s v1.17.0 so the extension apiserver (antrea-agent) will + # have permission issue after bumping up apiserver library to a version that supports dynamic authentication. + # See https://github.com/kubernetes/kubernetes/pull/85375 + # To support K8s clusters older than v1.17.0, we grant the required permissions directly instead of relying on + # the extension-apiserver-authentication role. + - apiGroups: + - "" + resourceNames: + - extension-apiserver-authentication + resources: + - configmaps + verbs: + - get + - list + - watch + - apiGroups: + - "" + resources: + - configmaps + resourceNames: + - antrea-ca + verbs: + - get + - watch + - list + - apiGroups: + - crd.antrea.io + resources: + - traceflows + - traceflows/status + verbs: + - get + - watch + - list + - update + - patch + - create + - delete + - apiGroups: + - crd.antrea.io + resources: + - egresses + verbs: + - get + - watch + - list + - apiGroups: + - crd.antrea.io + resources: + - egresses/status + verbs: + - update + - apiGroups: + - crd.antrea.io + resources: + - externalippools + - ippools + - trafficcontrols + verbs: + - get + - watch + - list + - apiGroups: + - crd.antrea.io + resources: + - ippools/status + verbs: + - update + - apiGroups: + - k8s.cni.cncf.io + resources: + - network-attachment-definitions + verbs: + - get + - list + - watch +--- +# Source: antrea/templates/antctl/clusterrole.yaml +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: antctl + labels: + app: antrea +rules: + - apiGroups: + - controlplane.antrea.io + resources: + - networkpolicies + - appliedtogroups + - addressgroups + verbs: + - get + - list + - apiGroups: + - stats.antrea.io + resources: + - networkpolicystats + - antreaclusternetworkpolicystats + - antreanetworkpolicystats + verbs: + - get + - list + - apiGroups: + - system.antrea.io + resources: + - controllerinfos + - agentinfos + verbs: + - get + - apiGroups: + - system.antrea.io + resources: + - supportbundles + verbs: + - get + - post + - apiGroups: + - system.antrea.io + resources: + - supportbundles/download + verbs: + - get + - nonResourceURLs: + - /agentinfo + - /addressgroups + - /appliedtogroups + - /loglevel + - /networkpolicies + - /ovsflows + - /ovstracing + - /podinterfaces + - /featuregates + - /serviceexternalip + verbs: + - get +--- +# Source: antrea/templates/cluster-identity-reader/clusterrolebinding.yaml +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: antrea-cluster-identity-reader + labels: + app: antrea +rules: + - apiGroups: + - "" + resources: + - configmaps + resourceNames: + - antrea-cluster-identity + verbs: + - get +--- +# Source: antrea/templates/controller/clusterrole.yaml +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: antrea-controller + labels: + app: antrea +rules: + - apiGroups: + - "" + resources: + - pods + - services + - namespaces + - configmaps + verbs: + - get + - watch + - list + - apiGroups: + - "" + resources: + - nodes + verbs: + - get + - watch + - list + - patch + - apiGroups: + - "" + resources: + - services/status + verbs: + - update + - apiGroups: + - networking.k8s.io + resources: + - networkpolicies + verbs: + - get + - watch + - list + - apiGroups: + - authentication.k8s.io + resources: + - tokenreviews + verbs: + - create + - apiGroups: + - authorization.k8s.io + resources: + - subjectaccessreviews + verbs: + - create + - apiGroups: + - apiextensions.k8s.io + resources: + - customresourcedefinitions + verbs: + - get + - update + # This is the content of built-in role kube-system/extension-apiserver-authentication-reader. + # But it doesn't have list/watch permission before K8s v1.17.0 so the extension apiserver (antrea-controller) will + # have permission issue after bumping up apiserver library to a version that supports dynamic authentication. + # See https://github.com/kubernetes/kubernetes/pull/85375 + # To support K8s clusters older than v1.17.0, we grant the required permissions directly instead of relying on + # the extension-apiserver-authentication role. + - apiGroups: + - "" + resourceNames: + - extension-apiserver-authentication + resources: + - configmaps + verbs: + - get + - list + - watch + - apiGroups: + - "" + resources: + - configmaps + resourceNames: + - antrea-ca + - antrea-cluster-identity + verbs: + - get + - update + - apiGroups: + - "" + resources: + - configmaps + verbs: + - create + - apiGroups: + - apiregistration.k8s.io + resources: + - apiservices + resourceNames: + - v1alpha1.stats.antrea.io + - v1beta1.system.antrea.io + - v1beta2.controlplane.antrea.io + verbs: + - get + - update + - apiGroups: + - apiregistration.k8s.io + resources: + - apiservices + resourceNames: + - v1beta1.networking.antrea.tanzu.vmware.com + - v1beta1.controlplane.antrea.tanzu.vmware.com + - v1alpha1.stats.antrea.tanzu.vmware.com + - v1beta1.system.antrea.tanzu.vmware.com + - v1beta2.controlplane.antrea.tanzu.vmware.com + verbs: + - delete + - apiGroups: + - admissionregistration.k8s.io + resources: + - mutatingwebhookconfigurations + - validatingwebhookconfigurations + resourceNames: + # always give permissions for labelsmutator.antrea.io, even when the + # feature is disabled, to avoid errors in antrea-controller when updating + # the CA cert. + - labelsmutator.antrea.io + - crdmutator.antrea.io + - crdvalidator.antrea.io + verbs: + - get + - update + - apiGroups: + - crd.antrea.io + resources: + - antreacontrollerinfos + verbs: + - get + - create + - update + - delete + - apiGroups: + - crd.antrea.io + resources: + - antreaagentinfos + verbs: + - list + - delete + - apiGroups: + - crd.antrea.io + resources: + - clusternetworkpolicies + - networkpolicies + verbs: + - get + - watch + - list + - update + - patch + - create + - delete + - apiGroups: + - crd.antrea.io + resources: + - clusternetworkpolicies/status + - networkpolicies/status + verbs: + - update + - apiGroups: + - crd.antrea.io + resources: + - tiers + verbs: + - get + - watch + - list + - update + - patch + - create + - delete + - apiGroups: + - crd.antrea.io + resources: + - traceflows + - traceflows/status + verbs: + - get + - watch + - list + - update + - patch + - create + - delete + - apiGroups: + - crd.antrea.io + resources: + - externalentities + - clustergroups + verbs: + - get + - watch + - list + - update + - patch + - create + - delete + - apiGroups: + - crd.antrea.io + resources: + - clustergroups/status + verbs: + - update + - apiGroups: + - crd.antrea.io + resources: + - egresses + verbs: + - get + - watch + - list + - update + - patch + - apiGroups: + - crd.antrea.io + resources: + - externalippools + - ippools + verbs: + - get + - watch + - list + - apiGroups: + - crd.antrea.io + resources: + - externalippools/status + - ippools/status + verbs: + - update + - apiGroups: + - apps + resources: + - statefulsets + verbs: + - get + - list + - watch +--- +# Source: antrea/templates/crds-rbac/clusterroles.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole metadata: + name: aggregate-antrea-policies-edit labels: app: antrea - name: antrea-config-82h2mk24gg - namespace: kube-system + # Add these permissions to the "admin" and "edit" default roles. + rbac.authorization.k8s.io/aggregate-to-admin: "true" + rbac.authorization.k8s.io/aggregate-to-edit: "true" +rules: +- apiGroups: ["crd.antrea.io"] + resources: ["clusternetworkpolicies", "networkpolicies"] + verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] --- -apiVersion: v1 -kind: Service +# Source: antrea/templates/crds-rbac/clusterroles.yaml +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: aggregate-antrea-policies-view + labels: + app: antrea + # Add these permissions to the "view" default role. + rbac.authorization.k8s.io/aggregate-to-view: "true" +rules: +- apiGroups: ["crd.antrea.io"] + resources: ["clusternetworkpolicies", "networkpolicies"] + verbs: ["get", "list", "watch"] +--- +# Source: antrea/templates/crds-rbac/clusterroles.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: aggregate-traceflows-edit + labels: + app: antrea + # Add these permissions to the "admin" and "edit" default roles. + rbac.authorization.k8s.io/aggregate-to-admin: "true" + rbac.authorization.k8s.io/aggregate-to-edit: "true" +rules: +- apiGroups: ["crd.antrea.io"] + resources: ["traceflows"] + verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] +--- +# Source: antrea/templates/crds-rbac/clusterroles.yaml +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: aggregate-traceflows-view + labels: + app: antrea + # Add these permissions to the "view" default role. + rbac.authorization.k8s.io/aggregate-to-view: "true" +rules: +- apiGroups: ["crd.antrea.io"] + resources: ["traceflows"] + verbs: ["get", "list", "watch"] +--- +# Source: antrea/templates/crds-rbac/clusterroles.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: aggregate-antrea-clustergroups-edit + labels: + app: antrea + # Add these permissions to the "admin" and "edit" default roles. + rbac.authorization.k8s.io/aggregate-to-admin: "true" + rbac.authorization.k8s.io/aggregate-to-edit: "true" +rules: +- apiGroups: ["crd.antrea.io"] + resources: ["clustergroups"] + verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] +--- +# Source: antrea/templates/crds-rbac/clusterroles.yaml +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: aggregate-antrea-clustergroups-view + labels: + app: antrea + # Add these permissions to the "view" default role. + rbac.authorization.k8s.io/aggregate-to-view: "true" +rules: +- apiGroups: ["crd.antrea.io"] + resources: ["clustergroups"] + verbs: ["get", "list", "watch"] +--- +# Source: antrea/templates/agent/clusterrolebinding.yaml +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: antrea-agent + labels: + app: antrea +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: antrea-agent +subjects: + - kind: ServiceAccount + name: antrea-agent + namespace: kube-system +--- +# Source: antrea/templates/antctl/clusterrolebinding.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + labels: + app: antrea + name: antctl +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: antctl +subjects: + - kind: ServiceAccount + name: antctl + namespace: kube-system +--- +# Source: antrea/templates/controller/clusterrolebinding.yaml +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 metadata: + name: antrea-controller labels: app: antrea +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: antrea-controller +subjects: + - kind: ServiceAccount + name: antrea-controller + namespace: kube-system +--- +# Source: antrea/templates/controller/service.yaml +apiVersion: v1 +kind: Service +metadata: name: antrea namespace: kube-system + labels: + app: antrea spec: ports: - - port: 443 - protocol: TCP - targetPort: api + - port: 443 + protocol: TCP + targetPort: api selector: app: antrea component: antrea-controller --- +# Source: antrea/templates/agent/daemonset.yaml apiVersion: apps/v1 -kind: Deployment +kind: DaemonSet metadata: + name: antrea-agent + namespace: kube-system labels: app: antrea - component: antrea-controller + component: antrea-agent +spec: + selector: + matchLabels: + app: antrea + component: antrea-agent + updateStrategy: + type: RollingUpdate + template: + metadata: + annotations: + # Starting with v1.21, Kubernetes supports default container annotation. + # Using "kubectl logs/exec/attach/cp" doesn't have to specify "-c antrea-agent" when troubleshooting. + kubectl.kubernetes.io/default-container: antrea-agent + # Automatically restart Pods with a RollingUpdate if the ConfigMap changes + # See https://helm.sh/docs/howto/charts_tips_and_tricks/#automatically-roll-deployments + checksum/config: fd449f30e949fff2d22ed79bca0a040535429c5b605b7b93dfdbfd3b359115ae + labels: + app: antrea + component: antrea-agent + spec: + hostNetwork: true + dnsPolicy: ClusterFirst + priorityClassName: system-node-critical + nodeSelector: + kubernetes.io/os: linux + tolerations: + - key: CriticalAddonsOnly + operator: Exists + - effect: NoSchedule + operator: Exists + - effect: NoExecute + operator: Exists + serviceAccountName: antrea-agent + initContainers: + - name: install-cni + image: "projects.registry.vmware.com/antrea/antrea-ubuntu:latest" + imagePullPolicy: IfNotPresent + resources: + requests: + cpu: 100m + command: ["install_cni_chaining"] + securityContext: + capabilities: + add: + # SYS_MODULE is required to load the OVS kernel module. + - SYS_MODULE + env: + # SKIP_CNI_BINARIES takes in values as a comma separated list of + # binaries that need to be skipped for installation, e.g. "portmap, bandwidth". + - name: SKIP_CNI_BINARIES + value: "" + volumeMounts: + - name: antrea-config + mountPath: /etc/antrea/antrea-cni.conflist + subPath: antrea-cni.conflist + readOnly: true + - name: host-cni-conf + mountPath: /host/etc/cni/net.d + - name: host-cni-bin + mountPath: /host/opt/cni/bin + # For loading the OVS kernel module. + - name: host-lib-modules + mountPath: /lib/modules + readOnly: true + # For changing the default permissions of the run directory. + - name: host-var-run-antrea + mountPath: /var/run/antrea + containers: + - name: antrea-agent + image: "projects.registry.vmware.com/antrea/antrea-ubuntu:latest" + imagePullPolicy: IfNotPresent + command: ["antrea-agent"] + # Log to both "/var/log/antrea/" and stderr (so "kubectl logs" can work).- + args: + - "--config=/etc/antrea/antrea-agent.conf" + - "--logtostderr=false" + - "--log_dir=/var/log/antrea" + - "--alsologtostderr" + - "--log_file_max_size=100" + - "--log_file_max_num=4" + env: + # Provide pod and node information for clusterinformation CRD. + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: NODE_NAME + valueFrom: + fieldRef: + fieldPath: spec.nodeName + resources: + requests: + cpu: 200m + ports: + - containerPort: 10350 + name: api + protocol: TCP + livenessProbe: + exec: + command: + - /bin/sh + - -c + - container_liveness_probe agent + initialDelaySeconds: 5 + timeoutSeconds: 5 + periodSeconds: 10 + failureThreshold: 5 + readinessProbe: + httpGet: + host: localhost + path: /readyz + port: api + scheme: HTTPS + initialDelaySeconds: 5 + timeoutSeconds: 5 + periodSeconds: 10 + # In large-scale clusters, it may take up to 40~50 seconds for the antrea-agent to reconnect to the antrea + # Service after the antrea-controller restarts. The antrea-agent shouldn't be reported as NotReady in this + # scenario, otherwise the DaemonSet controller would restart all agents at once, as opposed to performing a + # rolling update. Set failureThreshold to 8 so it can tolerate 70s of disconnection. + failureThreshold: 8 + securityContext: + # antrea-agent needs to perform sysctl configuration. + privileged: true + volumeMounts: + - name: antrea-config + mountPath: /etc/antrea/antrea-agent.conf + subPath: antrea-agent.conf + readOnly: true + - name: host-var-run-antrea + mountPath: /var/run/antrea + - name: host-var-run-antrea + mountPath: /var/run/openvswitch + subPath: openvswitch + # host-local IPAM stores allocated IP addresses as files in /var/lib/cni/networks/$NETWORK_NAME. + # Mount a sub-directory of host-var-run-antrea to it for persistence of IP allocation. + - name: host-var-run-antrea + mountPath: /var/lib/cni + subPath: cni + # We need to mount both the /proc directory and the /var/run/netns directory so that + # antrea-agent can open the network namespace path when setting up Pod + # networking. Different container runtimes may use /proc or /var/run/netns when invoking + # the CNI commands. Docker uses /proc and containerd uses /var/run/netns. + - name: host-var-log-antrea + mountPath: /var/log/antrea + - name: host-proc + mountPath: /host/proc + readOnly: true + - name: host-var-run-netns + mountPath: /host/var/run/netns + readOnly: true + # When a container is created, a mount point for the network namespace is added under + # /var/run/netns on the host, which needs to be propagated to the antrea-agent container. + mountPropagation: HostToContainer + - name: xtables-lock + mountPath: /run/xtables.lock + - name: antrea-ovs + image: "projects.registry.vmware.com/antrea/antrea-ubuntu:latest" + imagePullPolicy: IfNotPresent + resources: + requests: + cpu: 200m + command: ["start_ovs"] + args: + - "--log_file_max_size=100" + - "--log_file_max_num=4" + securityContext: + # capabilities required by OVS daemons + capabilities: + add: + - SYS_NICE + - NET_ADMIN + - SYS_ADMIN + - IPC_LOCK + livenessProbe: + exec: + # docker CRI doesn't honor timeoutSeconds, add "timeout" to the command as a workaround. + # https://github.com/kubernetes/kubernetes/issues/51901 + command: + - /bin/sh + - -c + - timeout 10 container_liveness_probe ovs + initialDelaySeconds: 5 + timeoutSeconds: 10 + periodSeconds: 10 + failureThreshold: 5 + volumeMounts: + - name: host-var-run-antrea + mountPath: /var/run/openvswitch + subPath: openvswitch + - name: host-var-log-antrea + mountPath: /var/log/openvswitch + subPath: openvswitch + volumes: + - name: antrea-config + configMap: + name: antrea-config + - name: host-cni-conf + hostPath: + path: /etc/cni/net.d + - name: host-cni-bin + hostPath: + path: /opt/cni/bin + - name: host-proc + hostPath: + path: /proc + - name: host-var-run-netns + hostPath: + path: /var/run/netns + - name: host-var-run-antrea + hostPath: + path: /var/run/antrea + # we use subPath to create run subdirectories for different component (e.g. OVS) and + # subPath requires the base volume to exist + type: DirectoryOrCreate + - name: host-var-log-antrea + hostPath: + path: /var/log/antrea + # we use subPath to create logging subdirectories for different component (e.g. OVS) + type: DirectoryOrCreate + - name: host-lib-modules + hostPath: + path: /lib/modules + - name: xtables-lock + hostPath: + path: /run/xtables.lock + type: FileOrCreate +--- +# Source: antrea/templates/controller/deployment.yaml +apiVersion: apps/v1 +kind: Deployment +metadata: name: antrea-controller namespace: kube-system + labels: + app: antrea + component: antrea-controller spec: - replicas: 1 + strategy: + # Ensure the existing Pod is stopped before the new one is created. + type: Recreate selector: matchLabels: app: antrea component: antrea-controller - strategy: - type: Recreate + replicas: 1 template: metadata: + annotations: + # Automatically restart Pod if the ConfigMap changes + # See https://helm.sh/docs/howto/charts_tips_and_tricks/#automatically-roll-deployments + checksum/config: fd449f30e949fff2d22ed79bca0a040535429c5b605b7b93dfdbfd3b359115ae labels: app: antrea component: antrea-controller spec: - containers: - - args: - - --config - - /etc/antrea/antrea-controller.conf - - --logtostderr=false - - --log_dir=/var/log/antrea - - --alsologtostderr - - --log_file_max_size=100 - - --log_file_max_num=4 - - --v=0 - command: - - antrea-controller - env: - - name: POD_NAME - valueFrom: - fieldRef: - fieldPath: metadata.name - - name: POD_NAMESPACE - valueFrom: - fieldRef: - fieldPath: metadata.namespace - - name: NODE_NAME - valueFrom: - fieldRef: - fieldPath: spec.nodeName - - name: SERVICEACCOUNT_NAME - valueFrom: - fieldRef: - fieldPath: spec.serviceAccountName - - name: ANTREA_CONFIG_MAP_NAME - value: antrea-config-82h2mk24gg - image: projects.registry.vmware.com/antrea/antrea-ubuntu:latest - imagePullPolicy: IfNotPresent - livenessProbe: - failureThreshold: 5 - httpGet: - host: localhost - path: /livez - port: api - scheme: HTTPS - periodSeconds: 10 - timeoutSeconds: 5 - name: antrea-controller - ports: - - containerPort: 10349 - name: api - protocol: TCP - readinessProbe: - failureThreshold: 5 - httpGet: - host: localhost - path: /readyz - port: api - scheme: HTTPS - initialDelaySeconds: 5 - periodSeconds: 10 - timeoutSeconds: 5 - resources: - requests: - cpu: 200m - volumeMounts: - - mountPath: /etc/antrea/antrea-controller.conf - name: antrea-config - readOnly: true - subPath: antrea-controller.conf - - mountPath: /var/run/antrea/antrea-controller-tls - name: antrea-controller-tls - - mountPath: /var/log/antrea - name: host-var-log-antrea - hostNetwork: true nodeSelector: kubernetes.io/os: linux + hostNetwork: true priorityClassName: system-cluster-critical - serviceAccountName: antrea-controller tolerations: - - key: CriticalAddonsOnly - operator: Exists - - effect: NoSchedule - key: node-role.kubernetes.io/master + - key: CriticalAddonsOnly + operator: Exists + - effect: NoSchedule + key: node-role.kubernetes.io/master + - effect: NoSchedule + key: node-role.kubernetes.io/control-plane + serviceAccountName: antrea-controller + containers: + - name: antrea-controller + image: "projects.registry.vmware.com/antrea/antrea-ubuntu:latest" + imagePullPolicy: IfNotPresent + resources: + requests: + cpu: 200m + command: ["antrea-controller"] + # Log to both "/var/log/antrea/" and stderr (so "kubectl logs" can work). + args: + - "--config=/etc/antrea/antrea-controller.conf" + - "--logtostderr=false" + - "--log_dir=/var/log/antrea" + - "--alsologtostderr" + - "--log_file_max_size=100" + - "--log_file_max_num=4" + env: + # Provide pod and node information for clusterinformation CRD. + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: NODE_NAME + valueFrom: + fieldRef: + fieldPath: spec.nodeName + # Provide ServiceAccount name for validation webhook. + - name: SERVICEACCOUNT_NAME + valueFrom: + fieldRef: + fieldPath: spec.serviceAccountName + - name: ANTREA_CONFIG_MAP_NAME + value: antrea-config + ports: + - containerPort: 10349 + name: api + protocol: TCP + readinessProbe: + httpGet: + host: localhost + path: /readyz + port: api + scheme: HTTPS + initialDelaySeconds: 5 + timeoutSeconds: 5 + periodSeconds: 10 + failureThreshold: 5 + livenessProbe: + httpGet: + host: localhost + path: /livez + port: api + scheme: HTTPS + timeoutSeconds: 5 + periodSeconds: 10 + failureThreshold: 5 + volumeMounts: + - name: antrea-config + mountPath: /etc/antrea/antrea-controller.conf + subPath: antrea-controller.conf + readOnly: true + - name: antrea-controller-tls + mountPath: /var/run/antrea/antrea-controller-tls + - name: host-var-log-antrea + mountPath: /var/log/antrea volumes: - - configMap: - name: antrea-config-82h2mk24gg - name: antrea-config - - name: antrea-controller-tls - secret: - defaultMode: 256 - optional: true - secretName: antrea-controller-tls - - hostPath: - path: /var/log/antrea - type: DirectoryOrCreate - name: host-var-log-antrea + - name: antrea-config + configMap: + name: antrea-config + # Make it optional as we only read it when selfSignedCert=false. + - name: antrea-controller-tls + secret: + secretName: antrea-controller-tls + defaultMode: 0400 + optional: true + - name: host-var-log-antrea + hostPath: + path: /var/log/antrea + type: DirectoryOrCreate --- +# Source: antrea/templates/controller/apiservices.yaml apiVersion: apiregistration.k8s.io/v1 kind: APIService metadata: + name: v1beta2.controlplane.antrea.io labels: app: antrea - name: v1alpha1.stats.antrea.io spec: - group: stats.antrea.io + group: controlplane.antrea.io groupPriorityMinimum: 100 + version: v1beta2 + versionPriority: 100 service: name: antrea namespace: kube-system - version: v1alpha1 - versionPriority: 100 --- +# Source: antrea/templates/controller/apiservices.yaml apiVersion: apiregistration.k8s.io/v1 kind: APIService metadata: + name: v1beta1.system.antrea.io labels: app: antrea - name: v1beta1.system.antrea.io spec: group: system.antrea.io groupPriorityMinimum: 100 + version: v1beta1 + versionPriority: 100 service: name: antrea namespace: kube-system - version: v1beta1 - versionPriority: 100 --- +# Source: antrea/templates/controller/apiservices.yaml apiVersion: apiregistration.k8s.io/v1 kind: APIService metadata: + name: v1alpha1.stats.antrea.io labels: app: antrea - name: v1beta2.controlplane.antrea.io spec: - group: controlplane.antrea.io + group: stats.antrea.io groupPriorityMinimum: 100 + version: v1alpha1 + versionPriority: 100 service: name: antrea namespace: kube-system - version: v1beta2 - versionPriority: 100 ---- -apiVersion: apps/v1 -kind: DaemonSet -metadata: - labels: - app: antrea - component: antrea-agent - name: antrea-agent - namespace: kube-system -spec: - selector: - matchLabels: - app: antrea - component: antrea-agent - template: - metadata: - annotations: - kubectl.kubernetes.io/default-container: antrea-agent - labels: - app: antrea - component: antrea-agent - spec: - containers: - - args: - - --config - - /etc/antrea/antrea-agent.conf - - --logtostderr=false - - --log_dir=/var/log/antrea - - --alsologtostderr - - --log_file_max_size=100 - - --log_file_max_num=4 - - --v=0 - command: - - antrea-agent - env: - - name: POD_NAME - valueFrom: - fieldRef: - fieldPath: metadata.name - - name: POD_NAMESPACE - valueFrom: - fieldRef: - fieldPath: metadata.namespace - - name: NODE_NAME - valueFrom: - fieldRef: - fieldPath: spec.nodeName - image: projects.registry.vmware.com/antrea/antrea-ubuntu:latest - imagePullPolicy: IfNotPresent - livenessProbe: - exec: - command: - - /bin/sh - - -c - - container_liveness_probe agent - failureThreshold: 5 - initialDelaySeconds: 5 - periodSeconds: 10 - timeoutSeconds: 5 - name: antrea-agent - ports: - - containerPort: 10350 - name: api - protocol: TCP - readinessProbe: - failureThreshold: 8 - httpGet: - host: localhost - path: /readyz - port: api - scheme: HTTPS - initialDelaySeconds: 5 - periodSeconds: 10 - timeoutSeconds: 5 - resources: - requests: - cpu: 200m - securityContext: - privileged: true - volumeMounts: - - mountPath: /etc/antrea/antrea-agent.conf - name: antrea-config - readOnly: true - subPath: antrea-agent.conf - - mountPath: /var/run/antrea - name: host-var-run-antrea - - mountPath: /var/run/openvswitch - name: host-var-run-antrea - subPath: openvswitch - - mountPath: /var/lib/cni - name: host-var-run-antrea - subPath: cni - - mountPath: /var/log/antrea - name: host-var-log-antrea - - mountPath: /host/proc - name: host-proc - readOnly: true - - mountPath: /host/var/run/netns - mountPropagation: HostToContainer - name: host-var-run-netns - readOnly: true - - mountPath: /run/xtables.lock - name: xtables-lock - - args: - - --log_file_max_size=100 - - --log_file_max_num=4 - command: - - start_ovs - image: projects.registry.vmware.com/antrea/antrea-ubuntu:latest - imagePullPolicy: IfNotPresent - livenessProbe: - exec: - command: - - /bin/sh - - -c - - timeout 10 container_liveness_probe ovs - failureThreshold: 5 - initialDelaySeconds: 5 - periodSeconds: 10 - timeoutSeconds: 10 - name: antrea-ovs - resources: - requests: - cpu: 200m - securityContext: - capabilities: - add: - - SYS_NICE - - NET_ADMIN - - SYS_ADMIN - - IPC_LOCK - volumeMounts: - - mountPath: /var/run/openvswitch - name: host-var-run-antrea - subPath: openvswitch - - mountPath: /var/log/openvswitch - name: host-var-log-antrea - subPath: openvswitch - dnsPolicy: ClusterFirstWithHostNet - hostNetwork: true - initContainers: - - command: - - install_cni_chaining - env: - - name: SKIP_CNI_BINARIES - value: "" - image: projects.registry.vmware.com/antrea/antrea-ubuntu:latest - imagePullPolicy: IfNotPresent - name: install-cni - resources: - requests: - cpu: 100m - securityContext: - capabilities: - add: - - SYS_MODULE - volumeMounts: - - mountPath: /etc/antrea/antrea-cni.conflist - name: antrea-config - readOnly: true - subPath: antrea-cni.conflist - - mountPath: /host/etc/cni/net.d - name: host-cni-conf - - mountPath: /host/opt/cni/bin - name: host-cni-bin - - mountPath: /lib/modules - name: host-lib-modules - readOnly: true - - mountPath: /var/run/antrea - name: host-var-run-antrea - nodeSelector: - kubernetes.io/os: linux - priorityClassName: system-node-critical - serviceAccountName: antrea-agent - tolerations: - - key: CriticalAddonsOnly - operator: Exists - - effect: NoSchedule - operator: Exists - - effect: NoExecute - operator: Exists - volumes: - - configMap: - name: antrea-config-82h2mk24gg - name: antrea-config - - hostPath: - path: /etc/cni/net.d - name: host-cni-conf - - hostPath: - path: /opt/cni/bin - name: host-cni-bin - - hostPath: - path: /proc - name: host-proc - - hostPath: - path: /var/run/netns - name: host-var-run-netns - - hostPath: - path: /var/run/antrea - type: DirectoryOrCreate - name: host-var-run-antrea - - hostPath: - path: /var/log/antrea - type: DirectoryOrCreate - name: host-var-log-antrea - - hostPath: - path: /lib/modules - name: host-lib-modules - - hostPath: - path: /run/xtables.lock - type: FileOrCreate - name: xtables-lock - updateStrategy: - type: RollingUpdate --- +# Source: antrea/templates/webhooks/mutating/crdmutator.yaml apiVersion: admissionregistration.k8s.io/v1 kind: MutatingWebhookConfiguration metadata: + name: "crdmutator.antrea.io" labels: app: antrea - name: crdmutator.antrea.io webhooks: -- admissionReviewVersions: - - v1 - - v1beta1 - clientConfig: - service: - name: antrea - namespace: kube-system - path: /mutate/acnp - name: acnpmutator.antrea.io - rules: - - apiGroups: - - crd.antrea.io - apiVersions: - - v1alpha1 - operations: - - CREATE - - UPDATE - resources: - - clusternetworkpolicies - scope: Cluster - sideEffects: None - timeoutSeconds: 5 -- admissionReviewVersions: - - v1 - - v1beta1 - clientConfig: - service: - name: antrea - namespace: kube-system - path: /mutate/anp - name: anpmutator.antrea.io - rules: - - apiGroups: - - crd.antrea.io - apiVersions: - - v1alpha1 - operations: - - CREATE - - UPDATE - resources: - - networkpolicies - scope: Namespaced - sideEffects: None - timeoutSeconds: 5 + - name: "acnpmutator.antrea.io" + clientConfig: + service: + name: "antrea" + namespace: kube-system + path: "/mutate/acnp" + rules: + - operations: ["CREATE", "UPDATE"] + apiGroups: ["crd.antrea.io"] + apiVersions: ["v1alpha1"] + resources: ["clusternetworkpolicies"] + scope: "Cluster" + admissionReviewVersions: ["v1", "v1beta1"] + sideEffects: None + timeoutSeconds: 5 + - name: "anpmutator.antrea.io" + clientConfig: + service: + name: "antrea" + namespace: kube-system + path: "/mutate/anp" + rules: + - operations: ["CREATE", "UPDATE"] + apiGroups: ["crd.antrea.io"] + apiVersions: ["v1alpha1"] + resources: ["networkpolicies"] + scope: "Namespaced" + admissionReviewVersions: ["v1", "v1beta1"] + sideEffects: None + timeoutSeconds: 5 --- +# Source: antrea/templates/webhooks/validating/crdvalidator.yaml apiVersion: admissionregistration.k8s.io/v1 kind: ValidatingWebhookConfiguration metadata: + name: "crdvalidator.antrea.io" labels: app: antrea - name: crdvalidator.antrea.io webhooks: -- admissionReviewVersions: - - v1 - - v1beta1 - clientConfig: - service: - name: antrea - namespace: kube-system - path: /validate/tier - name: tiervalidator.antrea.io - rules: - - apiGroups: - - crd.antrea.io - apiVersions: - - v1alpha1 - operations: - - CREATE - - UPDATE - - DELETE - resources: - - tiers - scope: Cluster - sideEffects: None - timeoutSeconds: 5 -- admissionReviewVersions: - - v1 - - v1beta1 - clientConfig: - service: - name: antrea - namespace: kube-system - path: /validate/acnp - name: acnpvalidator.antrea.io - rules: - - apiGroups: - - crd.antrea.io - apiVersions: - - v1alpha1 - operations: - - CREATE - - UPDATE - resources: - - clusternetworkpolicies - scope: Cluster - sideEffects: None - timeoutSeconds: 5 -- admissionReviewVersions: - - v1 - - v1beta1 - clientConfig: - service: - name: antrea - namespace: kube-system - path: /validate/anp - name: anpvalidator.antrea.io - rules: - - apiGroups: - - crd.antrea.io - apiVersions: - - v1alpha1 - operations: - - CREATE - - UPDATE - resources: - - networkpolicies - scope: Namespaced - sideEffects: None - timeoutSeconds: 5 -- admissionReviewVersions: - - v1 - - v1beta1 - clientConfig: - service: - name: antrea - namespace: kube-system - path: /validate/clustergroup - name: clustergroupvalidator.antrea.io - rules: - - apiGroups: - - crd.antrea.io - apiVersions: - - v1alpha3 - - v1alpha2 - operations: - - CREATE - - UPDATE - resources: - - clustergroups - scope: Cluster - sideEffects: None - timeoutSeconds: 5 -- admissionReviewVersions: - - v1 - - v1beta1 - clientConfig: - service: - name: antrea - namespace: kube-system - path: /validate/externalippool - name: externalippoolvalidator.antrea.io - rules: - - apiGroups: - - crd.antrea.io - apiVersions: - - v1alpha2 - operations: - - UPDATE - resources: - - externalippools - scope: Cluster - sideEffects: None - timeoutSeconds: 5 -- admissionReviewVersions: - - v1 - - v1beta1 - clientConfig: - service: - name: antrea - namespace: kube-system - path: /validate/egress - name: egressvalidator.antrea.io - rules: - - apiGroups: - - crd.antrea.io - apiVersions: - - v1alpha2 - operations: - - CREATE - - UPDATE - resources: - - egresses - scope: Cluster - sideEffects: None - timeoutSeconds: 5 -- admissionReviewVersions: - - v1 - - v1beta1 - clientConfig: - service: - name: antrea - namespace: kube-system - path: /validate/ippool - name: ippoolvalidator.antrea.io - rules: - - apiGroups: - - crd.antrea.io - apiVersions: - - v1alpha2 - operations: - - CREATE - - UPDATE - - DELETE - resources: - - ippools - scope: Cluster - sideEffects: None - timeoutSeconds: 5 + - name: "tiervalidator.antrea.io" + clientConfig: + service: + name: "antrea" + namespace: kube-system + path: "/validate/tier" + rules: + - operations: ["CREATE", "UPDATE", "DELETE"] + apiGroups: ["crd.antrea.io"] + apiVersions: ["v1alpha1"] + resources: ["tiers"] + scope: "Cluster" + admissionReviewVersions: ["v1", "v1beta1"] + sideEffects: None + timeoutSeconds: 5 + - name: "acnpvalidator.antrea.io" + clientConfig: + service: + name: "antrea" + namespace: kube-system + path: "/validate/acnp" + rules: + - operations: ["CREATE", "UPDATE"] + apiGroups: ["crd.antrea.io"] + apiVersions: ["v1alpha1"] + resources: ["clusternetworkpolicies"] + scope: "Cluster" + admissionReviewVersions: ["v1", "v1beta1"] + sideEffects: None + timeoutSeconds: 5 + - name: "anpvalidator.antrea.io" + clientConfig: + service: + name: "antrea" + namespace: kube-system + path: "/validate/anp" + rules: + - operations: ["CREATE", "UPDATE"] + apiGroups: ["crd.antrea.io"] + apiVersions: ["v1alpha1"] + resources: ["networkpolicies"] + scope: "Namespaced" + admissionReviewVersions: ["v1", "v1beta1"] + sideEffects: None + timeoutSeconds: 5 + - name: "clustergroupvalidator.antrea.io" + clientConfig: + service: + name: "antrea" + namespace: kube-system + path: "/validate/clustergroup" + rules: + - operations: ["CREATE", "UPDATE"] + apiGroups: ["crd.antrea.io"] + apiVersions: ["v1alpha3", "v1alpha2"] + resources: ["clustergroups"] + scope: "Cluster" + admissionReviewVersions: ["v1", "v1beta1"] + sideEffects: None + timeoutSeconds: 5 + - name: "externalippoolvalidator.antrea.io" + clientConfig: + service: + name: "antrea" + namespace: kube-system + path: "/validate/externalippool" + rules: + - operations: ["UPDATE"] + apiGroups: ["crd.antrea.io"] + apiVersions: ["v1alpha2"] + resources: ["externalippools"] + scope: "Cluster" + admissionReviewVersions: ["v1", "v1beta1"] + sideEffects: None + timeoutSeconds: 5 + - name: "egressvalidator.antrea.io" + clientConfig: + service: + name: "antrea" + namespace: kube-system + path: "/validate/egress" + rules: + - operations: ["CREATE", "UPDATE"] + apiGroups: ["crd.antrea.io"] + apiVersions: ["v1alpha2"] + resources: ["egresses"] + scope: "Cluster" + admissionReviewVersions: ["v1", "v1beta1"] + sideEffects: None + timeoutSeconds: 5 + - name: "ippoolvalidator.antrea.io" + clientConfig: + service: + name: "antrea" + namespace: kube-system + path: "/validate/ippool" + rules: + - operations: ["CREATE", "UPDATE", "DELETE"] + apiGroups: ["crd.antrea.io"] + apiVersions: ["v1alpha2"] + resources: ["ippools"] + scope: "Cluster" + admissionReviewVersions: ["v1", "v1beta1"] + sideEffects: None + timeoutSeconds: 5 diff --git a/build/yamls/antrea-eks.yml b/build/yamls/antrea-eks.yml index 53a6ef8c0a3..7587cc5d41e 100644 --- a/build/yamls/antrea-eks.yml +++ b/build/yamls/antrea-eks.yml @@ -1,2740 +1,59 @@ -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition +--- +# Source: antrea/templates/agent/serviceaccount.yaml +apiVersion: v1 +kind: ServiceAccount metadata: + name: antrea-agent + namespace: kube-system labels: app: antrea - name: antreaagentinfos.crd.antrea.io -spec: - group: crd.antrea.io - names: - kind: AntreaAgentInfo - plural: antreaagentinfos - shortNames: - - aai - singular: antreaagentinfo - scope: Cluster - versions: - - additionalPrinterColumns: - - description: Health status of this Agent - jsonPath: .agentConditions[?(@.type=='AgentHealthy')].status - name: Healthy - type: string - - description: Last time the Healthy Condition was updated - jsonPath: .agentConditions[?(@.type=='AgentHealthy')].lastHeartbeatTime - name: Last Heartbeat - type: date - - description: Version of this Agent - jsonPath: .version - name: Version - priority: 1 - type: string - - description: Node on which this Agent is running - jsonPath: .nodeRef.name - name: Node - priority: 1 - type: string - - description: Number of local Pods managed by this Agent - jsonPath: .localPodNum - name: Num Pods - priority: 2 - type: integer - - description: Subnets used by this Agent for Pod IPAM - jsonPath: .nodeSubnets - name: Subnets - priority: 2 - type: string - name: v1beta1 - schema: - openAPIV3Schema: - type: object - x-kubernetes-preserve-unknown-fields: true - served: true - storage: true --- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition +# Source: antrea/templates/antctl/serviceaccount.yaml +apiVersion: v1 +kind: ServiceAccount metadata: + name: antctl + namespace: kube-system labels: app: antrea - name: antreacontrollerinfos.crd.antrea.io -spec: - group: crd.antrea.io - names: - kind: AntreaControllerInfo - plural: antreacontrollerinfos - shortNames: - - aci - singular: antreacontrollerinfo - scope: Cluster - versions: - - additionalPrinterColumns: - - description: Health status of the Controller - jsonPath: .controllerConditions[?(@.type=='ControllerHealthy')].status - name: Healthy - type: string - - description: Last time the Healthy Condition was updated - jsonPath: .controllerConditions[?(@.type=='ControllerHealthy')].lastHeartbeatTime - name: Last Heartbeat - type: date - - description: Version of the Controller - jsonPath: .version - name: Version - priority: 1 - type: string - - description: Number of Agents connected to the Controller - jsonPath: .connectedAgentNum - name: Connected Agents - priority: 1 - type: integer - - description: Node on which the Controller is running - jsonPath: .nodeRef.name - name: Node - priority: 1 - type: string - - description: Number of Network Policies computed by Controller - jsonPath: .networkPolicyControllerInfo.networkPolicyNum - name: Num Network Policies - priority: 2 - type: integer - name: v1beta1 - schema: - openAPIV3Schema: - type: object - x-kubernetes-preserve-unknown-fields: true - served: true - storage: true --- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition +# Source: antrea/templates/controller/serviceaccount.yaml +apiVersion: v1 +kind: ServiceAccount metadata: + name: antrea-controller + namespace: kube-system labels: app: antrea - name: clustergroups.crd.antrea.io -spec: - conversion: - strategy: Webhook - webhook: - clientConfig: - service: - name: antrea - namespace: kube-system - path: /convert/clustergroup - conversionReviewVersions: - - v1 - - v1beta1 - group: crd.antrea.io - names: - kind: ClusterGroup - plural: clustergroups - shortNames: - - cg - singular: clustergroup - scope: Cluster - versions: - - name: v1alpha2 - schema: - openAPIV3Schema: - properties: - spec: - properties: - childGroups: - items: - type: string - type: array - externalEntitySelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - ipBlock: - properties: - cidr: - format: cidr - type: string - type: object - ipBlocks: - items: - properties: - cidr: - format: cidr - type: string - type: object - type: array - namespaceSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - podSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - serviceReference: - properties: - name: - type: string - namespace: - type: string - type: object - type: object - status: - properties: - conditions: - items: - properties: - lastTransitionTime: - type: string - status: - type: string - type: - type: string - type: object - type: array - type: object - type: object - served: true - storage: false - - name: v1alpha3 - schema: - openAPIV3Schema: - properties: - spec: - properties: - childGroups: - items: - type: string - type: array - externalEntitySelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - ipBlocks: - items: - properties: - cidr: - format: cidr - type: string - type: object - type: array - namespaceSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - podSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - serviceReference: - properties: - name: - type: string - namespace: - type: string - type: object - type: object - status: - properties: - conditions: - items: - properties: - lastTransitionTime: - type: string - status: - type: string - type: - type: string - type: object - type: array - type: object - type: object - served: true - storage: true - subresources: - status: {} --- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition +# Source: antrea/templates/agent/secret.yaml +apiVersion: v1 +kind: Secret +metadata: + name: antrea-agent-service-account-token + namespace: kube-system + annotations: + kubernetes.io/service-account.name: antrea-agent +type: kubernetes.io/service-account-token +--- +# Source: antrea/templates/antctl/secret.yaml +apiVersion: v1 +kind: Secret +metadata: + name: antctl-service-account-token + namespace: kube-system + annotations: + kubernetes.io/service-account.name: antctl +type: kubernetes.io/service-account-token +--- +# Source: antrea/templates/configmap.yaml +apiVersion: v1 +kind: ConfigMap metadata: + name: antrea-config + namespace: kube-system labels: app: antrea - name: clusternetworkpolicies.crd.antrea.io -spec: - group: crd.antrea.io - names: - kind: ClusterNetworkPolicy - plural: clusternetworkpolicies - shortNames: - - acnp - singular: clusternetworkpolicy - scope: Cluster - versions: - - additionalPrinterColumns: - - description: The Tier to which this ClusterNetworkPolicy belongs to. - jsonPath: .spec.tier - name: Tier - type: string - - description: The Priority of this ClusterNetworkPolicy relative to other policies. - format: float - jsonPath: .spec.priority - name: Priority - type: number - - description: The total number of Nodes that should realize the NetworkPolicy. - format: int32 - jsonPath: .status.desiredNodesRealized - name: Desired Nodes - type: number - - description: The number of Nodes that have realized the NetworkPolicy. - format: int32 - jsonPath: .status.currentNodesRealized - name: Current Nodes - type: number - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha1 - schema: - openAPIV3Schema: - properties: - spec: - properties: - appliedTo: - items: - properties: - group: - type: string - namespaceSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - podSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - serviceAccount: - properties: - name: - type: string - namespace: - type: string - required: - - name - - namespace - type: object - type: object - type: array - egress: - items: - properties: - action: - enum: - - Allow - - Drop - - Reject - - Pass - type: string - appliedTo: - items: - properties: - group: - type: string - namespaceSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - podSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - serviceAccount: - properties: - name: - type: string - namespace: - type: string - required: - - name - - namespace - type: object - type: object - type: array - enableLogging: - type: boolean - name: - type: string - ports: - items: - properties: - endPort: - type: integer - port: - x-kubernetes-int-or-string: true - protocol: - enum: - - TCP - - UDP - - SCTP - type: string - type: object - type: array - to: - items: - properties: - fqdn: - type: string - group: - type: string - ipBlock: - properties: - cidr: - format: cidr - type: string - type: object - namespaceSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - namespaces: - properties: - match: - type: string - type: object - nodeSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - podSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - serviceAccount: - properties: - name: - type: string - namespace: - type: string - required: - - name - - namespace - type: object - type: object - type: array - toServices: - items: - properties: - name: - type: string - namespace: - type: string - required: - - name - - namespace - type: object - type: array - required: - - action - type: object - type: array - ingress: - items: - properties: - action: - enum: - - Allow - - Drop - - Reject - - Pass - type: string - appliedTo: - items: - properties: - group: - type: string - namespaceSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - podSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - serviceAccount: - properties: - name: - type: string - namespace: - type: string - required: - - name - - namespace - type: object - type: object - type: array - enableLogging: - type: boolean - from: - items: - properties: - group: - type: string - ipBlock: - properties: - cidr: - format: cidr - type: string - type: object - namespaceSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - namespaces: - properties: - match: - enum: - - Self - type: string - type: object - nodeSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - podSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - serviceAccount: - properties: - name: - type: string - namespace: - type: string - required: - - name - - namespace - type: object - type: object - type: array - name: - type: string - ports: - items: - properties: - endPort: - type: integer - port: - x-kubernetes-int-or-string: true - protocol: - enum: - - TCP - - UDP - - SCTP - type: string - type: object - type: array - required: - - action - type: object - type: array - priority: - format: float - maximum: 10000 - minimum: 1 - type: number - tier: - type: string - required: - - priority - type: object - status: - properties: - currentNodesRealized: - type: integer - desiredNodesRealized: - type: integer - observedGeneration: - type: integer - phase: - type: string - type: object - type: object - served: true - storage: true - subresources: - status: {} ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - labels: - app: antrea - name: egresses.crd.antrea.io -spec: - group: crd.antrea.io - names: - kind: Egress - plural: egresses - shortNames: - - eg - singular: egress - scope: Cluster - versions: - - additionalPrinterColumns: - - description: Specifies the SNAT IP address for the selected workloads. - jsonPath: .spec.egressIP - name: EgressIP - type: string - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - - description: The Owner Node of egress IP - jsonPath: .status.egressNode - name: Node - type: string - name: v1alpha2 - schema: - openAPIV3Schema: - properties: - spec: - anyOf: - - required: - - egressIP - - required: - - externalIPPool - properties: - appliedTo: - properties: - namespaceSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - podSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - type: object - egressIP: - oneOf: - - format: ipv4 - - format: ipv6 - type: string - externalIPPool: - type: string - required: - - appliedTo - type: object - status: - properties: - egressNode: - type: string - type: object - required: - - spec - type: object - served: true - storage: true - subresources: - status: {} ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - labels: - app: antrea - name: externalentities.crd.antrea.io -spec: - group: crd.antrea.io - names: - kind: ExternalEntity - plural: externalentities - shortNames: - - ee - singular: externalentity - scope: Namespaced - versions: - - name: v1alpha2 - schema: - openAPIV3Schema: - properties: - spec: - properties: - endpoints: - items: - properties: - ip: - oneOf: - - format: ipv4 - - format: ipv6 - type: string - name: - type: string - type: object - type: array - externalNode: - type: string - ports: - items: - properties: - name: - type: string - port: - x-kubernetes-int-or-string: true - protocol: - enum: - - TCP - - UDP - - SCTP - type: string - type: object - type: array - type: object - type: object - served: true - storage: true - - name: v1alpha1 - schema: - openAPIV3Schema: - type: object - served: false - storage: false ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - labels: - app: antrea - name: externalippools.crd.antrea.io -spec: - group: crd.antrea.io - names: - kind: ExternalIPPool - plural: externalippools - shortNames: - - eip - singular: externalippool - scope: Cluster - versions: - - additionalPrinterColumns: - - description: The number of total IPs - jsonPath: .status.usage.total - name: Total - type: integer - - description: The number of allocated IPs - jsonPath: .status.usage.used - name: Used - type: integer - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha2 - schema: - openAPIV3Schema: - properties: - spec: - properties: - ipRanges: - items: - oneOf: - - required: - - cidr - - required: - - start - - end - properties: - cidr: - format: cidr - type: string - end: - oneOf: - - format: ipv4 - - format: ipv6 - type: string - start: - oneOf: - - format: ipv4 - - format: ipv6 - type: string - type: object - type: array - nodeSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - required: - - ipRanges - - nodeSelector - type: object - status: - properties: - usage: - properties: - total: - type: integer - used: - type: integer - type: object - type: object - required: - - spec - type: object - served: true - storage: true - subresources: - status: {} ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - labels: - app: antrea - name: ippools.crd.antrea.io -spec: - group: crd.antrea.io - names: - kind: IPPool - plural: ippools - shortNames: - - ipp - singular: ippool - scope: Cluster - versions: - - name: v1alpha2 - schema: - openAPIV3Schema: - properties: - spec: - properties: - ipRanges: - items: - oneOf: - - required: - - cidr - - gateway - - prefixLength - - required: - - start - - end - - gateway - - prefixLength - properties: - cidr: - format: cidr - type: string - end: - oneOf: - - format: ipv4 - - format: ipv6 - type: string - gateway: - oneOf: - - format: ipv4 - - format: ipv6 - type: string - prefixLength: - type: integer - start: - oneOf: - - format: ipv4 - - format: ipv6 - type: string - vlan: - maximum: 4094 - minimum: 0 - type: integer - type: object - type: array - ipVersion: - type: integer - required: - - ipVersion - - ipRanges - type: object - status: - properties: - ipAddresses: - items: - properties: - ipAddress: - type: string - owner: - properties: - pod: - properties: - containerID: - type: string - name: - type: string - namespace: - type: string - type: object - statefulSet: - properties: - index: - type: integer - name: - type: string - namespace: - type: string - type: object - type: object - phase: - type: string - type: object - type: array - type: object - required: - - spec - type: object - served: true - storage: true - subresources: - status: {} ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - labels: - app: antrea - name: networkpolicies.crd.antrea.io -spec: - group: crd.antrea.io - names: - kind: NetworkPolicy - plural: networkpolicies - shortNames: - - anp - singular: networkpolicy - scope: Namespaced - versions: - - additionalPrinterColumns: - - description: The Tier to which this Antrea NetworkPolicy belongs to. - jsonPath: .spec.tier - name: Tier - type: string - - description: The Priority of this Antrea NetworkPolicy relative to other policies. - format: float - jsonPath: .spec.priority - name: Priority - type: number - - description: The total number of Nodes that should realize the NetworkPolicy. - format: int32 - jsonPath: .status.desiredNodesRealized - name: Desired Nodes - type: number - - description: The number of Nodes that have realized the NetworkPolicy. - format: int32 - jsonPath: .status.currentNodesRealized - name: Current Nodes - type: number - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha1 - schema: - openAPIV3Schema: - properties: - spec: - properties: - appliedTo: - items: - properties: - podSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - type: object - type: array - egress: - items: - properties: - action: - enum: - - Allow - - Drop - - Reject - - Pass - type: string - appliedTo: - items: - properties: - podSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - type: object - type: array - enableLogging: - type: boolean - name: - type: string - ports: - items: - properties: - endPort: - type: integer - port: - x-kubernetes-int-or-string: true - protocol: - enum: - - TCP - - UDP - - SCTP - type: string - type: object - type: array - to: - items: - properties: - externalEntitySelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - fqdn: - type: string - ipBlock: - properties: - cidr: - format: cidr - type: string - type: object - namespaceSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - nodeSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - podSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - type: object - type: array - toServices: - items: - properties: - name: - type: string - namespace: - type: string - required: - - name - type: object - type: array - required: - - action - type: object - type: array - ingress: - items: - properties: - action: - enum: - - Allow - - Drop - - Reject - - Pass - type: string - appliedTo: - items: - properties: - podSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - type: object - type: array - enableLogging: - type: boolean - from: - items: - properties: - externalEntitySelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - ipBlock: - properties: - cidr: - format: cidr - type: string - type: object - namespaceSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - nodeSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - podSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - type: object - type: array - name: - type: string - ports: - items: - properties: - endPort: - type: integer - port: - x-kubernetes-int-or-string: true - protocol: - enum: - - TCP - - UDP - - SCTP - type: string - type: object - type: array - required: - - action - type: object - type: array - priority: - format: float - maximum: 10000 - minimum: 1 - type: number - tier: - type: string - required: - - priority - type: object - status: - properties: - currentNodesRealized: - type: integer - desiredNodesRealized: - type: integer - observedGeneration: - type: integer - phase: - type: string - type: object - type: object - served: true - storage: true - subresources: - status: {} ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - labels: - app: antrea - name: tiers.crd.antrea.io -spec: - group: crd.antrea.io - names: - kind: Tier - plural: tiers - shortNames: - - tr - singular: tier - scope: Cluster - versions: - - additionalPrinterColumns: - - description: The Priority of this Tier relative to other Tiers. - jsonPath: .spec.priority - name: Priority - type: integer - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha1 - schema: - openAPIV3Schema: - properties: - spec: - properties: - description: - type: string - priority: - maximum: 255 - minimum: 0 - type: integer - required: - - priority - type: object - type: object - served: true - storage: true ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - labels: - app: antrea - name: traceflows.crd.antrea.io -spec: - group: crd.antrea.io - names: - kind: Traceflow - plural: traceflows - shortNames: - - tf - singular: traceflow - scope: Cluster - versions: - - additionalPrinterColumns: - - description: The phase of the Traceflow. - jsonPath: .status.phase - name: Phase - type: string - - description: The name of the source Pod. - jsonPath: .spec.source.pod - name: Source-Pod - priority: 10 - type: string - - description: The name of the destination Pod. - jsonPath: .spec.destination.pod - name: Destination-Pod - priority: 10 - type: string - - description: The IP address of the destination. - jsonPath: .spec.destination.ip - name: Destination-IP - priority: 10 - type: string - - description: Trace live traffic. - jsonPath: .spec.liveTraffic - name: Live-Traffic - priority: 10 - type: boolean - - description: Capture only the dropped packet. - jsonPath: .spec.droppedOnly - name: Dropped-Only - priority: 10 - type: boolean - - description: Timeout in seconds. - jsonPath: .spec.timeout - name: Timeout - priority: 10 - type: integer - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha1 - schema: - openAPIV3Schema: - properties: - spec: - properties: - destination: - properties: - ip: - oneOf: - - format: ipv4 - - format: ipv6 - type: string - namespace: - type: string - pod: - type: string - service: - type: string - type: object - droppedOnly: - type: boolean - liveTraffic: - type: boolean - packet: - properties: - ipHeader: - properties: - flags: - type: integer - protocol: - type: integer - srcIP: - oneOf: - - format: ipv4 - - format: ipv6 - type: string - ttl: - type: integer - type: object - ipv6Header: - properties: - hopLimit: - type: integer - nextHeader: - type: integer - srcIP: - format: ipv6 - type: string - type: object - transportHeader: - properties: - icmp: - properties: - id: - type: integer - sequence: - type: integer - type: object - tcp: - properties: - dstPort: - type: integer - flags: - type: integer - srcPort: - type: integer - type: object - udp: - properties: - dstPort: - type: integer - srcPort: - type: integer - type: object - type: object - type: object - source: - properties: - ip: - oneOf: - - format: ipv4 - - format: ipv6 - type: string - namespace: - type: string - pod: - type: string - type: object - timeout: - type: integer - type: object - status: - properties: - capturedPacket: - properties: - dstIP: - type: string - ipHeader: - properties: - flags: - type: integer - protocol: - type: integer - ttl: - type: integer - type: object - ipv6Header: - properties: - hopLimit: - type: integer - nextHeader: - type: integer - type: object - length: - type: integer - srcIP: - type: string - transportHeader: - properties: - icmp: - properties: - id: - type: integer - sequence: - type: integer - type: object - tcp: - properties: - dstPort: - type: integer - flags: - type: integer - srcPort: - type: integer - type: object - udp: - properties: - dstPort: - type: integer - srcPort: - type: integer - type: object - type: object - type: object - dataplaneTag: - type: integer - phase: - type: string - reason: - type: string - results: - items: - properties: - node: - type: string - observations: - items: - properties: - action: - type: string - component: - type: string - componentInfo: - type: string - dstMAC: - type: string - networkPolicy: - type: string - pod: - type: string - translatedDstIP: - type: string - translatedSrcIP: - type: string - ttl: - type: integer - tunnelDstIP: - type: string - type: object - type: array - role: - type: string - timestamp: - type: integer - type: object - type: array - startTime: - type: string - type: object - required: - - spec - type: object - served: true - storage: true - subresources: - status: {} ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - labels: - app: antrea - name: antctl - namespace: kube-system ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - labels: - app: antrea - name: antrea-agent - namespace: kube-system ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - labels: - app: antrea - name: antrea-controller - namespace: kube-system ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - labels: - app: antrea - rbac.authorization.k8s.io/aggregate-to-admin: "true" - rbac.authorization.k8s.io/aggregate-to-edit: "true" - name: aggregate-antrea-clustergroups-edit -rules: -- apiGroups: - - crd.antrea.io - resources: - - clustergroups - verbs: - - get - - list - - watch - - create - - update - - patch - - delete ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - labels: - app: antrea - rbac.authorization.k8s.io/aggregate-to-view: "true" - name: aggregate-antrea-clustergroups-view -rules: -- apiGroups: - - crd.antrea.io - resources: - - clustergroups - verbs: - - get - - list - - watch ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - labels: - app: antrea - rbac.authorization.k8s.io/aggregate-to-admin: "true" - rbac.authorization.k8s.io/aggregate-to-edit: "true" - name: aggregate-antrea-policies-edit -rules: -- apiGroups: - - crd.antrea.io - resources: - - clusternetworkpolicies - - networkpolicies - verbs: - - get - - list - - watch - - create - - update - - patch - - delete ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - labels: - app: antrea - rbac.authorization.k8s.io/aggregate-to-view: "true" - name: aggregate-antrea-policies-view -rules: -- apiGroups: - - crd.antrea.io - resources: - - clusternetworkpolicies - - networkpolicies - verbs: - - get - - list - - watch ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - labels: - app: antrea - rbac.authorization.k8s.io/aggregate-to-admin: "true" - rbac.authorization.k8s.io/aggregate-to-edit: "true" - name: aggregate-traceflows-edit -rules: -- apiGroups: - - crd.antrea.io - resources: - - traceflows - verbs: - - get - - list - - watch - - create - - update - - patch - - delete ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - labels: - app: antrea - rbac.authorization.k8s.io/aggregate-to-view: "true" - name: aggregate-traceflows-view -rules: -- apiGroups: - - crd.antrea.io - resources: - - traceflows - verbs: - - get - - list - - watch ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - labels: - app: antrea - name: antctl -rules: -- apiGroups: - - controlplane.antrea.io - resources: - - networkpolicies - - appliedtogroups - - addressgroups - verbs: - - get - - list -- apiGroups: - - stats.antrea.io - resources: - - networkpolicystats - - antreaclusternetworkpolicystats - - antreanetworkpolicystats - verbs: - - get - - list -- apiGroups: - - system.antrea.io - resources: - - controllerinfos - - agentinfos - verbs: - - get -- apiGroups: - - system.antrea.io - resources: - - supportbundles - verbs: - - get - - post -- apiGroups: - - system.antrea.io - resources: - - supportbundles/download - verbs: - - get -- nonResourceURLs: - - /agentinfo - - /addressgroups - - /appliedtogroups - - /loglevel - - /networkpolicies - - /ovsflows - - /ovstracing - - /podinterfaces - - /featuregates - verbs: - - get ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - labels: - app: antrea - name: antrea-agent -rules: -- apiGroups: - - "" - resources: - - nodes - verbs: - - get - - watch - - list -- apiGroups: - - "" - resources: - - nodes/status - verbs: - - patch -- apiGroups: - - "" - resources: - - pods - verbs: - - get - - watch - - list -- apiGroups: - - "" - resources: - - pods/status - verbs: - - patch -- apiGroups: - - "" - resources: - - endpoints - - services - - namespaces - verbs: - - get - - watch - - list -- apiGroups: - - "" - resources: - - services/status - verbs: - - update -- apiGroups: - - discovery.k8s.io - resources: - - endpointslices - verbs: - - get - - watch - - list -- apiGroups: - - crd.antrea.io - resources: - - antreaagentinfos - verbs: - - get - - create - - update - - delete -- apiGroups: - - controlplane.antrea.io - resources: - - networkpolicies - - appliedtogroups - - addressgroups - verbs: - - get - - watch - - list -- apiGroups: - - controlplane.antrea.io - resources: - - egressgroups - verbs: - - get - - watch - - list -- apiGroups: - - controlplane.antrea.io - resources: - - nodestatssummaries - verbs: - - create -- apiGroups: - - controlplane.antrea.io - resources: - - networkpolicies/status - verbs: - - create - - get -- apiGroups: - - authentication.k8s.io - resources: - - tokenreviews - verbs: - - create -- apiGroups: - - authorization.k8s.io - resources: - - subjectaccessreviews - verbs: - - create -- apiGroups: - - "" - resourceNames: - - extension-apiserver-authentication - resources: - - configmaps - verbs: - - get - - list - - watch -- apiGroups: - - "" - resourceNames: - - antrea-ca - resources: - - configmaps - verbs: - - get - - watch - - list -- apiGroups: - - crd.antrea.io - resources: - - traceflows - - traceflows/status - verbs: - - get - - watch - - list - - update - - patch - - create - - delete -- apiGroups: - - crd.antrea.io - resources: - - egresses - verbs: - - get - - watch - - list -- apiGroups: - - crd.antrea.io - resources: - - egresses/status - verbs: - - update -- apiGroups: - - crd.antrea.io - resources: - - externalippools - - ippools - verbs: - - get - - watch - - list -- apiGroups: - - crd.antrea.io - resources: - - ippools/status - verbs: - - update -- apiGroups: - - k8s.cni.cncf.io - resources: - - network-attachment-definitions - verbs: - - get - - list - - watch ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - labels: - app: antrea - name: antrea-cluster-identity-reader -rules: -- apiGroups: - - "" - resourceNames: - - antrea-cluster-identity - resources: - - configmaps - verbs: - - get ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - labels: - app: antrea - name: antrea-controller -rules: -- apiGroups: - - "" - resources: - - pods - - services - - namespaces - - configmaps - verbs: - - get - - watch - - list -- apiGroups: - - "" - resources: - - nodes - verbs: - - get - - watch - - list - - patch -- apiGroups: - - "" - resources: - - services/status - verbs: - - update -- apiGroups: - - networking.k8s.io - resources: - - networkpolicies - verbs: - - get - - watch - - list -- apiGroups: - - authentication.k8s.io - resources: - - tokenreviews - verbs: - - create -- apiGroups: - - authorization.k8s.io - resources: - - subjectaccessreviews - verbs: - - create -- apiGroups: - - apiextensions.k8s.io - resources: - - customresourcedefinitions - verbs: - - get - - update -- apiGroups: - - "" - resourceNames: - - extension-apiserver-authentication - resources: - - configmaps - verbs: - - get - - list - - watch -- apiGroups: - - "" - resourceNames: - - antrea-ca - - antrea-cluster-identity - resources: - - configmaps - verbs: - - get - - update -- apiGroups: - - "" - resources: - - configmaps - verbs: - - create -- apiGroups: - - apiregistration.k8s.io - resourceNames: - - v1alpha1.stats.antrea.io - - v1beta1.system.antrea.io - - v1beta2.controlplane.antrea.io - resources: - - apiservices - verbs: - - get - - update -- apiGroups: - - apiregistration.k8s.io - resourceNames: - - v1beta1.networking.antrea.tanzu.vmware.com - - v1beta1.controlplane.antrea.tanzu.vmware.com - - v1alpha1.stats.antrea.tanzu.vmware.com - - v1beta1.system.antrea.tanzu.vmware.com - - v1beta2.controlplane.antrea.tanzu.vmware.com - resources: - - apiservices - verbs: - - delete -- apiGroups: - - admissionregistration.k8s.io - resourceNames: - - labelsmutator.antrea.io - - crdmutator.antrea.io - - crdvalidator.antrea.io - resources: - - mutatingwebhookconfigurations - - validatingwebhookconfigurations - verbs: - - get - - update -- apiGroups: - - crd.antrea.io - resources: - - antreacontrollerinfos - verbs: - - get - - create - - update - - delete -- apiGroups: - - crd.antrea.io - resources: - - antreaagentinfos - verbs: - - list - - delete -- apiGroups: - - crd.antrea.io - resources: - - clusternetworkpolicies - - networkpolicies - verbs: - - get - - watch - - list - - update - - patch - - create - - delete -- apiGroups: - - crd.antrea.io - resources: - - clusternetworkpolicies/status - - networkpolicies/status - verbs: - - update -- apiGroups: - - crd.antrea.io - resources: - - tiers - verbs: - - get - - watch - - list - - update - - patch - - create - - delete -- apiGroups: - - crd.antrea.io - resources: - - traceflows - - traceflows/status - verbs: - - get - - watch - - list - - update - - patch - - create - - delete -- apiGroups: - - crd.antrea.io - resources: - - externalentities - - clustergroups - verbs: - - get - - watch - - list - - update - - patch - - create - - delete -- apiGroups: - - crd.antrea.io - resources: - - clustergroups/status - verbs: - - update -- apiGroups: - - crd.antrea.io - resources: - - egresses - verbs: - - get - - watch - - list - - update - - patch -- apiGroups: - - crd.antrea.io - resources: - - externalippools - - ippools - verbs: - - get - - watch - - list -- apiGroups: - - crd.antrea.io - resources: - - externalippools/status - - ippools/status - verbs: - - update -- apiGroups: - - apps - resources: - - statefulsets - verbs: - - get - - list - - watch ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - labels: - app: antrea - name: antctl - namespace: kube-system -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: antctl -subjects: -- kind: ServiceAccount - name: antctl - namespace: kube-system ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - labels: - app: antrea - name: antrea-agent -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: antrea-agent -subjects: -- kind: ServiceAccount - name: antrea-agent - namespace: kube-system ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - labels: - app: antrea - name: antrea-controller -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: antrea-controller -subjects: -- kind: ServiceAccount - name: antrea-controller - namespace: kube-system ---- -apiVersion: v1 data: antrea-agent.conf: | # FeatureGates is a map of feature names to bools that enable or disable experimental features. @@ -2771,7 +90,8 @@ data: # Egress: true # Enable AntreaIPAM, which can allocate IP addresses from IPPools. AntreaIPAM is required by the - # bridging mode and allocates IPs to Pods in bridging mode. + # bridging mode and allocates IPs to Pods in bridging mode. It is also required to use Antrea for + # IPAM when configuring secondary network interfaces with Multus. # AntreaIPAM: false # Enable multicast traffic. This feature is supported only with noEncap mode. @@ -2785,21 +105,23 @@ data: # Enable managing external IPs of Services of LoadBalancer type. # ServiceExternalIP: false + # Enable mirroring or redirecting the traffic Pods send or receive. + # TrafficControl: false + # Name of the OpenVSwitch bridge antrea-agent will create and use. # Make sure it doesn't conflict with your existing OpenVSwitch bridges. - #ovsBridge: br-int + ovsBridge: "br-int" # Datapath type to use for the OpenVSwitch bridge created by Antrea. Supported values are: # - system # - netdev # 'system' is the default value and corresponds to the kernel datapath. Use 'netdev' to run - # OVS in userspace mode (not fully supported yet). Userspace mode requires the tun device driver to - # be available. + # OVS in userspace mode. Userspace mode requires the tun device driver to be available. #ovsDatapathType: system # Name of the interface antrea-agent will create and use for host <--> pod communication. # Make sure it doesn't conflict with your existing interfaces. - #hostGateway: antrea-gw0 + hostGateway: "antrea-gw0" # Determines how traffic is encapsulated. It has the following options: # encap(default): Inter-node Pod traffic is always encapsulated and Pod to external network @@ -2811,14 +133,14 @@ data: # networkPolicyOnly: Antrea enforces NetworkPolicy only, and utilizes CNI chaining and delegates Pod # IPAM and connectivity to the primary CNI. # - trafficEncapMode: networkPolicyOnly + trafficEncapMode: "networkPolicyOnly" # Whether or not to SNAT (using the Node IP) the egress traffic from a Pod to the external network. # This option is for the noEncap traffic mode only, and the default value is false. In the noEncap # mode, if the cluster's Pod CIDR is reachable from the external network, then the Pod traffic to # the external network needs not be SNAT'd. In the networkPolicyOnly mode, antrea-agent never # performs SNAT and this option will be ignored; for other modes it must be set to false. - #noSNAT: false + noSNAT: false # Tunnel protocols used for encapsulating traffic across Nodes. If WireGuard is enabled in trafficEncryptionMode, # this option will not take effect. Supported values: @@ -2827,7 +149,7 @@ data: # - gre # - stt # Note that "gre" is not supported for IPv6 clusters (IPv6-only or dual-stack clusters). - #tunnelType: geneve + tunnelType: "geneve" # Determines how tunnel traffic is encrypted. Currently encryption only works with encap mode. # It has the following options: @@ -2837,44 +159,54 @@ data: # the PSK value must be passed to Antrea Agent through an environment # variable: ANTREA_IPSEC_PSK. # - wireGuard: Enable WireGuard for tunnel traffic encryption. - #trafficEncryptionMode: none + trafficEncryptionMode: "none" # Enable bridging mode of Pod network on Nodes, in which the Node's transport interface is connected - # to the OVS bridge, and cross-Node/VLAN traffic from AntreaIPAM Pods (Pods whose IP addresses are - # allocated by AntreaIPAM from IPPools) is sent to the underlay network via the uplink, and - # forwarded/routed by the underlay network. + # to the OVS bridge, and cross-Node/VLAN traffic of AntreaIPAM Pods (Pods whose IP addresses are + # allocated by AntreaIPAM from IPPools) is sent to the underlay network, and forwarded/routed by the + # underlay network. # This option requires the `AntreaIPAM` feature gate to be enabled. At this moment, it supports only # IPv4 and Linux Nodes, and can be enabled only when `ovsDatapathType` is `system`, # `trafficEncapMode` is `noEncap`, and `noSNAT` is true. - #enableBridgingMode: false + enableBridgingMode: false + + # Disable TX checksum offloading for container network interfaces. It's supposed to be set to true when the + # datapath doesn't support TX checksum offloading, which causes packets to be dropped due to bad checksum. + # It affects Pods running on Linux Nodes only. + disableTXChecksumOffload: false # Default MTU to use for the host gateway interface and the network interface of each Pod. # If omitted, antrea-agent will discover the MTU of the Node's primary interface and # also adjust MTU to accommodate for tunnel encapsulation overhead (if applicable). - #defaultMTU: 0 + defaultMTU: 0 # wireGuard specifies WireGuard related configurations. wireGuard: - # The port for WireGuard to receive traffic. - # port: 51820 + # The port for WireGuard to receive traffic. + port: 51820 egress: - # exceptCIDRs is the CIDR ranges to which outbound Pod traffic will not be SNAT'd by Egresses. - # exceptCIDRs: [] + # exceptCIDRs is the CIDR ranges to which outbound Pod traffic will not be SNAT'd by Egresses. + exceptCIDRs: + + # ClusterIP CIDR range for Services. It's required when AntreaProxy is not enabled, and should be + # set to the same value as the one specified by --service-cluster-ip-range for kube-apiserver. When + # AntreaProxy is enabled, this parameter is not needed and will be ignored if provided. + serviceCIDR: "" # ClusterIP CIDR range for IPv6 Services. It's required when using kube-proxy to provide IPv6 Service in a Dual-Stack # cluster or an IPv6 only cluster. The value should be the same as the configuration for kube-apiserver specified by # --service-cluster-ip-range. When AntreaProxy is enabled, this parameter is not needed. # No default value for this field. - #serviceCIDRv6: + serviceCIDRv6: "" # The port for the antrea-agent APIServer to serve on. # Note that if it's set to another value, the `containerPort` of the `api` port of the # `antrea-agent` container must be set to the same value. - #apiPort: 10350 + apiPort: 10350 # Enable metrics exposure via Prometheus. Initializes Prometheus metrics listener. - #enablePrometheusMetrics: true + enablePrometheusMetrics: true # Provide the IPFIX collector address as a string with format :[][:]. # HOST can either be the DNS name or the IP of the Flow Collector. For example, @@ -2885,50 +217,50 @@ data: # If no PROTO is given, we consider "tls" as default. We support "tls", "tcp" and # "udp" protocols. "tls" is used for securing communication between flow exporter and # flow aggregator. - #flowCollectorAddr: "flow-aggregator.flow-aggregator.svc:4739:tls" + flowCollectorAddr: "flow-aggregator.flow-aggregator.svc:4739:tls" # Provide flow poll interval as a duration string. This determines how often the # flow exporter dumps connections from the conntrack module. Flow poll interval # should be greater than or equal to 1s (one second). # Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". - #flowPollInterval: "5s" + flowPollInterval: "5s" # Provide the active flow export timeout, which is the timeout after which a flow # record is sent to the collector for active flows. Thus, for flows with a continuous # stream of packets, a flow record will be exported to the collector once the elapsed # time since the last export event is equal to the value of this timeout. # Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". - #activeFlowExportTimeout: "30s" + activeFlowExportTimeout: "5s" # Provide the idle flow export timeout, which is the timeout after which a flow # record is sent to the collector for idle flows. A flow is considered idle if no # packet matching this flow has been observed since the last export event. # Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". - #idleFlowExportTimeout: "15s" + idleFlowExportTimeout: "15s" nodePortLocal: # Enable NodePortLocal, a feature used to make Pods reachable using port forwarding on the host. To # enable this feature, you need to set "enable" to true, and ensure that the NodePortLocal feature # gate is also enabled (which is the default). - # enable: false + enable: false # Provide the port range used by NodePortLocal. When the NodePortLocal feature is enabled, a port # from that range will be assigned whenever a Pod's container defines a specific port to be exposed # (each container can define a list of ports as pod.spec.containers[].ports), and all Node traffic # directed to that port will be forwarded to the Pod. - # portRange: 61000-62000 + portRange: "61000-62000" # Provide the address of Kubernetes apiserver, to override any value provided in kubeconfig or InClusterConfig. # Defaults to "". It must be a host string, a host:port pair, or a URL to the base of the apiserver. - #kubeAPIServerOverride: "" + kubeAPIServerOverride: "" # Comma-separated list of Cipher Suites. If omitted, the default Go Cipher Suites will be used. # https://golang.org/pkg/crypto/tls/#pkg-constants # Note that TLS1.3 Cipher Suites cannot be added to the list. But the apiserver will always # prefer TLS1.3 Cipher Suites whenever possible. - #tlsCipherSuites: + tlsCipherSuites: "" # TLS min version from: VersionTLS10, VersionTLS11, VersionTLS12, VersionTLS13. - #tlsMinVersion: + tlsMinVersion: "" # The name of the interface on Node which is used for tunneling or routing the traffic across Nodes. # If there are multiple IP addresses configured on the interface, the first one is used. The IP @@ -2937,11 +269,16 @@ data: # 1. transportInterface # 2. transportInterfaceCIDRs # 3. The Node IP - #transportInterface: + transportInterface: "" + multicast: # The names of the interfaces on Nodes that are used to forward multicast traffic. # Defaults to transport interface if not set. - #multicastInterfaces: [] + multicastInterfaces: + + # The interval at which the antrea-agent sends IGMP queries to Pods. + # Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". + igmpQueryInterval: "125s" # The network CIDRs of the interface on Node which is used for tunneling or routing the traffic across # Nodes. If there are multiple interfaces configured the same network CIDR, the first one is used. The @@ -2950,7 +287,7 @@ data: # 1. transportInterface # 2. transportInterfaceCIDRs # 3. The Node IP - #transportInterfaceCIDRs: [,] + transportInterfaceCIDRs: # Option antreaProxy contains AntreaProxy related configuration options. antreaProxy: @@ -2959,22 +296,22 @@ data: # feature to be enabled. # Note that this option is experimental. If kube-proxy is removed, option kubeAPIServerOverride must be used to access # apiserver directly. - #proxyAll: false + proxyAll: false # A string array of values which specifies the host IPv4/IPv6 addresses for NodePort. Values can be valid IP blocks. # (e.g. 1.2.3.0/24, 1.2.3.4/32). An empty string slice is meant to select all host IPv4/IPv6 addresses. # Note that the option is only valid when proxyAll is true. - #nodePortAddresses: [] + nodePortAddresses: # An array of string values to specify a list of Services which should be ignored by AntreaProxy (traffic to these # Services will not be load-balanced). Values can be a valid ClusterIP (e.g. 10.11.1.2) or a Service name # with Namespace (e.g. kube-system/kube-dns) - #skipServices: [] + skipServices: # When ProxyLoadBalancerIPs is set to false, AntreaProxy no longer load-balances traffic destined to the # External IPs of LoadBalancer Services. This is useful when the external LoadBalancer provides additional # capabilities (e.g. TLS termination) and it is desirable for Pod-to-ExternalIP traffic to be sent to the # external LoadBalancer instead of being load-balanced to an Endpoint directly by AntreaProxy. # Note that setting ProxyLoadBalancerIPs to false usually only makes sense when ProxyAll is set to true and # kube-proxy is removed from the cluser, otherwise kube-proxy will still load-balance this traffic. - #proxyLoadBalancerIPs: true + proxyLoadBalancerIPs: true antrea-cni.conflist: | { "cniVersion":"0.3.0", @@ -2985,11 +322,13 @@ data: "ipam": { "type": "host-local" } - }, + } + , { "type": "portmap", "capabilities": {"portMappings": true} - }, + } + , { "type": "bandwidth", "capabilities": {"bandwidth": true} @@ -3016,8 +355,9 @@ data: # Run Kubernetes NodeIPAMController with Antrea. # NodeIPAM: false - # Enable flexible IPAM mode for Antrea. This mode allows to assign IP Ranges to Namespaces, - # Deployments and StatefulSets via IP Pool annotation. + # Enable AntreaIPAM, which can allocate IP addresses from IPPools. AntreaIPAM is required by the + # bridging mode and allocates IPs to Pods in bridging mode. It is also required to use Antrea for + # IPAM when configuring secondary network interfaces with Multus. # AntreaIPAM: false # Enable managing external IPs of Services of LoadBalancer type. @@ -3026,661 +366,3676 @@ data: # The port for the antrea-controller APIServer to serve on. # Note that if it's set to another value, the `containerPort` of the `api` port of the # `antrea-controller` container must be set to the same value. - #apiPort: 10349 + apiPort: 10349 # Enable metrics exposure via Prometheus. Initializes Prometheus metrics listener. - #enablePrometheusMetrics: true + enablePrometheusMetrics: true # Indicates whether to use auto-generated self-signed TLS certificate. - # If false, A Secret named "antrea-controller-tls" must be provided with the following keys: + # If false, a Secret named "antrea-controller-tls" must be provided with the following keys: # ca.crt: # tls.crt: # tls.key: - # And the Secret must be mounted to directory "/var/run/antrea/antrea-controller-tls" of the - # antrea-controller container. - #selfSignedCert: true + selfSignedCert: true # Comma-separated list of Cipher Suites. If omitted, the default Go Cipher Suites will be used. # https://golang.org/pkg/crypto/tls/#pkg-constants # Note that TLS1.3 Cipher Suites cannot be added to the list. But the apiserver will always # prefer TLS1.3 Cipher Suites whenever possible. - #tlsCipherSuites: + tlsCipherSuites: "" # TLS min version from: VersionTLS10, VersionTLS11, VersionTLS12, VersionTLS13. - #tlsMinVersion: + tlsMinVersion: "" nodeIPAM: - # Enable the integrated Node IPAM controller within the Antrea controller. - # enableNodeIPAM: false - - # CIDR ranges for Pods in cluster. String array containing single CIDR range, or multiple ranges. - # The CIDRs could be either IPv4 or IPv6. At most one CIDR may be specified for each IP family. - # Value ignored when enableNodeIPAM is false. - # clusterCIDRs: [] - - # CIDR ranges for Services in cluster. It is not necessary to specify it when there is no overlap with clusterCIDRs. - # Value ignored when enableNodeIPAM is false. - # serviceCIDR: - # serviceCIDRv6: - - # Mask size for IPv4 Node CIDR in IPv4 or dual-stack cluster. Value ignored when enableNodeIPAM is false - # or when IPv4 Pod CIDR is not configured. Valid range is 16 to 30. - # nodeCIDRMaskSizeIPv4: 24 - - # Mask size for IPv6 Node CIDR in IPv6 or dual-stack cluster. Value ignored when enableNodeIPAM is false - # or when IPv6 Pod CIDR is not configured. Valid range is 64 to 126. - # nodeCIDRMaskSizeIPv6: 64 -kind: ConfigMap + # Enable the integrated Node IPAM controller within the Antrea controller. + enableNodeIPAM: false + # CIDR ranges for Pods in cluster. String array containing single CIDR range, or multiple ranges. + # The CIDRs could be either IPv4 or IPv6. At most one CIDR may be specified for each IP family. + # Value ignored when enableNodeIPAM is false. + clusterCIDRs: + # CIDR ranges for Services in cluster. It is not necessary to specify it when there is no overlap with clusterCIDRs. + # Value ignored when enableNodeIPAM is false. + serviceCIDR: "" + serviceCIDRv6: "" + # Mask size for IPv4 Node CIDR in IPv4 or dual-stack cluster. Value ignored when enableNodeIPAM is false + # or when IPv4 Pod CIDR is not configured. Valid range is 16 to 30. + nodeCIDRMaskSizeIPv4: 24 + # Mask size for IPv6 Node CIDR in IPv6 or dual-stack cluster. Value ignored when enableNodeIPAM is false + # or when IPv6 Pod CIDR is not configured. Valid range is 64 to 126. + nodeCIDRMaskSizeIPv6: 64 +--- +# Source: antrea/templates/crds/antreaagentinfo.yaml +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: antreaagentinfos.crd.antrea.io + labels: + app: antrea +spec: + group: crd.antrea.io + versions: + - name: v1beta1 + served: true + storage: true + schema: + openAPIV3Schema: + type: object + x-kubernetes-preserve-unknown-fields: true + additionalPrinterColumns: + - description: Health status of this Agent + jsonPath: ".agentConditions[?(@.type=='AgentHealthy')].status" + name: Healthy + type: string + - description: Last time the Healthy Condition was updated + jsonPath: ".agentConditions[?(@.type=='AgentHealthy')].lastHeartbeatTime" + name: Last Heartbeat + type: date + - description: Version of this Agent + jsonPath: ".version" + name: Version + type: string + priority: 1 + - description: Node on which this Agent is running + jsonPath: ".nodeRef.name" + name: Node + type: string + priority: 1 + - description: Number of local Pods managed by this Agent + jsonPath: ".localPodNum" + name: Num Pods + type: integer + priority: 2 + - description: Subnets used by this Agent for Pod IPAM + jsonPath: ".nodeSubnets" + name: Subnets + type: string + priority: 2 + scope: Cluster + names: + plural: antreaagentinfos + singular: antreaagentinfo + kind: AntreaAgentInfo + shortNames: + - aai +--- +# Source: antrea/templates/crds/antreacontrollerinfo.yaml +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: antreacontrollerinfos.crd.antrea.io + labels: + app: antrea +spec: + group: crd.antrea.io + versions: + - name: v1beta1 + served: true + storage: true + schema: + openAPIV3Schema: + type: object + x-kubernetes-preserve-unknown-fields: true + additionalPrinterColumns: + - description: Health status of the Controller + jsonPath: ".controllerConditions[?(@.type=='ControllerHealthy')].status" + name: Healthy + type: string + - description: Last time the Healthy Condition was updated + jsonPath: ".controllerConditions[?(@.type=='ControllerHealthy')].lastHeartbeatTime" + name: Last Heartbeat + type: date + - description: Version of the Controller + jsonPath: ".version" + name: Version + type: string + priority: 1 + - description: Number of Agents connected to the Controller + jsonPath: ".connectedAgentNum" + name: Connected Agents + type: integer + priority: 1 + - description: Node on which the Controller is running + jsonPath: ".nodeRef.name" + name: Node + type: string + priority: 1 + - description: Number of Network Policies computed by Controller + jsonPath: ".networkPolicyControllerInfo.networkPolicyNum" + name: Num Network Policies + type: integer + priority: 2 + scope: Cluster + names: + plural: antreacontrollerinfos + singular: antreacontrollerinfo + kind: AntreaControllerInfo + shortNames: + - aci +--- +# Source: antrea/templates/crds/clustergroup.yaml +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: clustergroups.crd.antrea.io + labels: + app: antrea +spec: + group: crd.antrea.io + versions: + - name: v1alpha2 + served: true + storage: false + schema: + openAPIV3Schema: + type: object + properties: + spec: + type: object + properties: + childGroups: + type: array + items: + type: string + podSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + externalEntitySelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + ipBlock: + type: object + properties: + cidr: + type: string + format: cidr + ipBlocks: + type: array + items: + type: object + properties: + cidr: + type: string + format: cidr + serviceReference: + type: object + properties: + name: + type: string + namespace: + type: string + status: + type: object + properties: + conditions: + type: array + items: + type: object + properties: + type: + type: string + status: + type: string + lastTransitionTime: + type: string + - name: v1alpha3 + served: true + storage: true + schema: + openAPIV3Schema: + type: object + properties: + spec: + type: object + properties: + childGroups: + type: array + items: + type: string + podSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + externalEntitySelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + ipBlocks: + type: array + items: + type: object + properties: + cidr: + type: string + format: cidr + serviceReference: + type: object + properties: + name: + type: string + namespace: + type: string + status: + type: object + properties: + conditions: + type: array + items: + type: object + properties: + type: + type: string + status: + type: string + lastTransitionTime: + type: string + subresources: + status: {} + conversion: + strategy: Webhook + webhook: + conversionReviewVersions: ["v1", "v1beta1"] + clientConfig: + service: + name: "antrea" + namespace: "kube-system" + path: "/convert/clustergroup" + scope: Cluster + names: + plural: clustergroups + singular: clustergroup + kind: ClusterGroup + shortNames: + - cg +--- +# Source: antrea/templates/crds/clusternetworkpolicy.yaml +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: clusternetworkpolicies.crd.antrea.io + labels: + app: antrea +spec: + group: crd.antrea.io + versions: + - name: v1alpha1 + served: true + storage: true + additionalPrinterColumns: + - name: Tier + type: string + description: The Tier to which this ClusterNetworkPolicy belongs to. + jsonPath: .spec.tier + - name: Priority + type: number + format: float + description: The Priority of this ClusterNetworkPolicy relative to other policies. + jsonPath: .spec.priority + - name: Desired Nodes + type: number + format: int32 + description: The total number of Nodes that should realize the NetworkPolicy. + jsonPath: .status.desiredNodesRealized + - name: Current Nodes + type: number + format: int32 + description: The number of Nodes that have realized the NetworkPolicy. + jsonPath: .status.currentNodesRealized + - name: Age + type: date + jsonPath: .metadata.creationTimestamp + schema: + openAPIV3Schema: + type: object + properties: + spec: + # Ensure that Spec.Priority field is set + required: + - priority + type: object + properties: + tier: + type: string + priority: + type: number + format: float + # Ensure that Spec.Priority field is between 1 and 10000 + minimum: 1.0 + maximum: 10000.0 + appliedTo: + type: array + items: + type: object + # Ensure that Spec.AppliedTo does not allow IPBlock field + properties: + podSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + group: + type: string + serviceAccount: + type: object + properties: + name: + type: string + namespace: + type: string + required: + - name + - namespace + ingress: + type: array + items: + type: object + required: + - action + properties: + appliedTo: + type: array + items: + type: object + # Ensure that rule AppliedTo does not allow IPBlock field + properties: + podSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + group: + type: string + serviceAccount: + type: object + properties: + name: + type: string + namespace: + type: string + required: + - name + - namespace + # Ensure that Action field allows only ALLOW, DROP, REJECT and PASS values + action: + type: string + enum: ['Allow', 'Drop', 'Reject', 'Pass'] + ports: + type: array + items: + type: object + properties: + protocol: + type: string + enum: ['TCP', 'UDP', 'SCTP'] + port: + x-kubernetes-int-or-string: true + endPort: + type: integer + protocols: + type: array + items: + type: object + oneOf: + - required: [icmp] + properties: + icmp: + type: object + properties: + icmpType: + type: integer + minimum: 0 + maximum: 255 + icmpCode: + type: integer + minimum: 0 + maximum: 255 + from: + type: array + items: + type: object + properties: + podSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + namespaces: + type: object + properties: + match: + enum: + - Self + type: string + ipBlock: + type: object + properties: + cidr: + type: string + format: cidr + group: + type: string + serviceAccount: + type: object + properties: + name: + type: string + namespace: + type: string + required: + - name + - namespace + nodeSelector: + type: object + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + type: array + type: object + type: array + matchLabels: + x-kubernetes-preserve-unknown-fields: true + name: + type: string + enableLogging: + type: boolean + egress: + type: array + items: + type: object + required: + - action + properties: + appliedTo: + type: array + items: + type: object + # Ensure that rule AppliedTo does not allow IPBlock field + properties: + podSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + group: + type: string + serviceAccount: + type: object + properties: + name: + type: string + namespace: + type: string + required: + - name + - namespace + # Ensure that Action field allows only ALLOW, DROP, REJECT and PASS values + action: + type: string + enum: ['Allow', 'Drop', 'Reject', 'Pass'] + ports: + type: array + items: + type: object + properties: + protocol: + type: string + enum: ['TCP', 'UDP', 'SCTP'] + port: + x-kubernetes-int-or-string: true + endPort: + type: integer + protocols: + type: array + items: + type: object + oneOf: + - required: [icmp] + properties: + icmp: + type: object + properties: + icmpType: + type: integer + minimum: 0 + maximum: 255 + icmpCode: + type: integer + minimum: 0 + maximum: 255 + to: + type: array + items: + type: object + properties: + podSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + namespaces: + type: object + properties: + match: + enum: + - Self + type: string + ipBlock: + type: object + properties: + cidr: + type: string + format: cidr + group: + type: string + fqdn: + type: string + serviceAccount: + type: object + properties: + name: + type: string + namespace: + type: string + required: + - name + - namespace + nodeSelector: + type: object + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + type: array + type: object + type: array + matchLabels: + x-kubernetes-preserve-unknown-fields: true + toServices: + type: array + items: + type: object + required: + - name + - namespace + properties: + name: + type: string + namespace: + type: string + name: + type: string + enableLogging: + type: boolean + status: + type: object + properties: + phase: + type: string + observedGeneration: + type: integer + currentNodesRealized: + type: integer + desiredNodesRealized: + type: integer + subresources: + status: {} + scope: Cluster + names: + plural: clusternetworkpolicies + singular: clusternetworkpolicy + kind: ClusterNetworkPolicy + shortNames: + - acnp +--- +# Source: antrea/templates/crds/egress.yaml +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: egresses.crd.antrea.io + labels: + app: antrea +spec: + group: crd.antrea.io + versions: + - name: v1alpha2 + served: true + storage: true + schema: + openAPIV3Schema: + type: object + required: + - spec + properties: + spec: + type: object + required: + - appliedTo + anyOf: + - required: + - egressIP + - required: + - externalIPPool + properties: + appliedTo: + type: object + properties: + podSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + egressIP: + type: string + oneOf: + - format: ipv4 + - format: ipv6 + externalIPPool: + type: string + status: + type: object + properties: + egressNode: + type: string + additionalPrinterColumns: + - description: Specifies the SNAT IP address for the selected workloads. + jsonPath: .spec.egressIP + name: EgressIP + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + - description: The Owner Node of egress IP + jsonPath: .status.egressNode + name: Node + type: string + subresources: + status: {} + scope: Cluster + names: + plural: egresses + singular: egress + kind: Egress + shortNames: + - eg +--- +# Source: antrea/templates/crds/externalentity.yaml +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: externalentities.crd.antrea.io + labels: + app: antrea +spec: + group: crd.antrea.io + versions: + - name: v1alpha2 + served: true + storage: true + schema: + openAPIV3Schema: + type: object + properties: + spec: + type: object + properties: + endpoints: + type: array + items: + type: object + properties: + ip: + type: string + oneOf: + - format: ipv4 + - format: ipv6 + name: + type: string + ports: + type: array + items: + type: object + properties: + protocol: + type: string + enum: ['TCP', 'UDP', 'SCTP'] + port: + x-kubernetes-int-or-string: true + name: + type: string + externalNode: + type: string + - name: v1alpha1 + served: false + storage: false + schema: + openAPIV3Schema: + type: object + scope: Namespaced + names: + plural: externalentities + singular: externalentity + kind: ExternalEntity + shortNames: + - ee +--- +# Source: antrea/templates/crds/externalippool.yaml +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: externalippools.crd.antrea.io + labels: + app: antrea +spec: + group: crd.antrea.io + versions: + - name: v1alpha2 + served: true + storage: true + schema: + openAPIV3Schema: + type: object + required: + - spec + properties: + spec: + type: object + required: + - ipRanges + - nodeSelector + properties: + ipRanges: + type: array + items: + type: object + oneOf: + - required: + - cidr + - required: + - start + - end + properties: + cidr: + type: string + format: cidr + start: + type: string + oneOf: + - format: ipv4 + - format: ipv6 + end: + type: string + oneOf: + - format: ipv4 + - format: ipv6 + nodeSelector: + type: object + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + type: array + type: object + type: array + matchLabels: + x-kubernetes-preserve-unknown-fields: true + status: + type: object + properties: + usage: + type: object + properties: + total: + type: integer + used: + type: integer + additionalPrinterColumns: + - description: The number of total IPs + jsonPath: .status.usage.total + name: Total + type: integer + - description: The number of allocated IPs + jsonPath: .status.usage.used + name: Used + type: integer + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + subresources: + status: {} + scope: Cluster + names: + plural: externalippools + singular: externalippool + kind: ExternalIPPool + shortNames: + - eip +--- +# Source: antrea/templates/crds/ippool.yaml +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: ippools.crd.antrea.io + labels: + app: antrea +spec: + group: crd.antrea.io + versions: + - name: v1alpha2 + served: true + storage: true + schema: + openAPIV3Schema: + type: object + required: + - spec + properties: + spec: + required: + - ipVersion + - ipRanges + type: object + properties: + ipVersion: + type: integer + ipRanges: + items: + oneOf: + - required: + - cidr + - gateway + - prefixLength + - required: + - start + - end + - gateway + - prefixLength + properties: + cidr: + format: cidr + type: string + start: + oneOf: + - format: ipv4 + - format: ipv6 + type: string + end: + oneOf: + - format: ipv4 + - format: ipv6 + type: string + gateway: + oneOf: + - format: ipv4 + - format: ipv6 + type: string + prefixLength: + type: integer + vlan: + type: integer + minimum: 0 + maximum: 4094 + type: object + type: array + status: + properties: + ipAddresses: + items: + properties: + ipAddress: + type: string + owner: + properties: + pod: + properties: + name: + type: string + namespace: + type: string + containerID: + type: string + ifName: + type: string + type: object + statefulSet: + properties: + name: + type: string + namespace: + type: string + index: + type: integer + type: object + type: object + phase: + type: string + type: object + type: array + type: object + subresources: + status: {} + scope: Cluster + names: + plural: ippools + singular: ippool + kind: IPPool + shortNames: + - ipp +--- +# Source: antrea/templates/crds/networkpolicy.yaml +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: networkpolicies.crd.antrea.io + labels: + app: antrea +spec: + group: crd.antrea.io + versions: + - name: v1alpha1 + served: true + storage: true + additionalPrinterColumns: + - name: Tier + type: string + description: The Tier to which this Antrea NetworkPolicy belongs to. + jsonPath: .spec.tier + - name: Priority + type: number + format: float + description: The Priority of this Antrea NetworkPolicy relative to other policies. + jsonPath: .spec.priority + - name: Desired Nodes + type: number + format: int32 + description: The total number of Nodes that should realize the NetworkPolicy. + jsonPath: .status.desiredNodesRealized + - name: Current Nodes + type: number + format: int32 + description: The number of Nodes that have realized the NetworkPolicy. + jsonPath: .status.currentNodesRealized + - name: Age + type: date + jsonPath: .metadata.creationTimestamp + schema: + openAPIV3Schema: + type: object + properties: + spec: + # Ensure that Spec.Priority field is set + required: + - priority + type: object + properties: + tier: + type: string + priority: + type: number + format: float + # Ensure that Spec.Priority field is between 1 and 10000 + minimum: 1.0 + maximum: 10000.0 + appliedTo: + type: array + items: + type: object + # Ensure that Spec.AppliedTo does not allow NamespaceSelector/IPBlock field + properties: + podSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + ingress: + type: array + items: + type: object + required: + - action + properties: + appliedTo: + type: array + items: + type: object + # Ensure that rule AppliedTo does not allow NamespaceSelector/IPBlock field + properties: + podSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + # Ensure that Action field allows only ALLOW, DROP, REJECT and PASS values + action: + type: string + enum: ['Allow', 'Drop', 'Reject', 'Pass'] + ports: + type: array + items: + type: object + properties: + protocol: + type: string + enum: ['TCP', 'UDP', 'SCTP'] + port: + x-kubernetes-int-or-string: true + endPort: + type: integer + protocols: + type: array + items: + type: object + oneOf: + - required: [icmp] + properties: + icmp: + type: object + properties: + icmpType: + type: integer + minimum: 0 + maximum: 255 + icmpCode: + type: integer + minimum: 0 + maximum: 255 + from: + type: array + items: + type: object + properties: + podSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + externalEntitySelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + ipBlock: + type: object + properties: + cidr: + type: string + format: cidr + nodeSelector: + type: object + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + type: array + type: object + type: array + matchLabels: + x-kubernetes-preserve-unknown-fields: true + name: + type: string + enableLogging: + type: boolean + egress: + type: array + items: + type: object + required: + - action + properties: + appliedTo: + type: array + items: + type: object + # Ensure that rule AppliedTo does not allow NamespaceSelector/IPBlock field + properties: + podSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + # Ensure that Action field allows only ALLOW, DROP, REJECT and PASS values + action: + type: string + enum: ['Allow', 'Drop', 'Reject', 'Pass'] + ports: + type: array + items: + type: object + properties: + protocol: + type: string + enum: ['TCP', 'UDP', 'SCTP'] + port: + x-kubernetes-int-or-string: true + endPort: + type: integer + protocols: + type: array + items: + type: object + oneOf: + - required: [icmp] + properties: + icmp: + type: object + properties: + icmpType: + type: integer + minimum: 0 + maximum: 255 + icmpCode: + type: integer + minimum: 0 + maximum: 255 + to: + type: array + items: + type: object + properties: + podSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + externalEntitySelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + ipBlock: + type: object + properties: + cidr: + type: string + format: cidr + fqdn: + type: string + nodeSelector: + type: object + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + type: array + type: object + type: array + matchLabels: + x-kubernetes-preserve-unknown-fields: true + toServices: + type: array + items: + type: object + required: + - name + properties: + name: + type: string + namespace: + type: string + name: + type: string + enableLogging: + type: boolean + status: + type: object + properties: + phase: + type: string + observedGeneration: + type: integer + currentNodesRealized: + type: integer + desiredNodesRealized: + type: integer + subresources: + status: {} + scope: Namespaced + names: + plural: networkpolicies + singular: networkpolicy + kind: NetworkPolicy + shortNames: + - anp +--- +# Source: antrea/templates/crds/tier.yaml +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: tiers.crd.antrea.io + labels: + app: antrea +spec: + group: crd.antrea.io + versions: + - name: v1alpha1 + served: true + storage: true + additionalPrinterColumns: + - name: Priority + type: integer + description: The Priority of this Tier relative to other Tiers. + jsonPath: .spec.priority + - name: Age + type: date + jsonPath: .metadata.creationTimestamp + schema: + openAPIV3Schema: + type: object + properties: + spec: + required: + - priority + type: object + properties: + priority: + type: integer + minimum: 0 + maximum: 255 + description: + type: string + scope: Cluster + names: + plural: tiers + singular: tier + kind: Tier + shortNames: + - tr +--- +# Source: antrea/templates/crds/traceflow.yaml +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: traceflows.crd.antrea.io + labels: + app: antrea +spec: + group: crd.antrea.io + versions: + - name: v1alpha1 + served: true + storage: true + additionalPrinterColumns: + - jsonPath: .status.phase + description: The phase of the Traceflow. + name: Phase + type: string + - jsonPath: .spec.source.pod + description: The name of the source Pod. + name: Source-Pod + type: string + priority: 10 + - jsonPath: .spec.destination.pod + description: The name of the destination Pod. + name: Destination-Pod + type: string + priority: 10 + - jsonPath: .spec.destination.ip + description: The IP address of the destination. + name: Destination-IP + type: string + priority: 10 + - jsonPath: .spec.liveTraffic + description: Trace live traffic. + name: Live-Traffic + type: boolean + priority: 10 + - jsonPath: .spec.droppedOnly + description: Capture only the dropped packet. + name: Dropped-Only + type: boolean + priority: 10 + - jsonPath: .spec.timeout + description: Timeout in seconds. + name: Timeout + type: integer + priority: 10 + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + schema: + openAPIV3Schema: + type: object + required: + - spec + properties: + spec: + type: object + properties: + source: + type: object + properties: + pod: + type: string + namespace: + type: string + ip: + type: string + oneOf: + - format: ipv4 + - format: ipv6 + destination: + type: object + properties: + pod: + type: string + service: + type: string + namespace: + type: string + ip: + type: string + oneOf: + - format: ipv4 + - format: ipv6 + packet: + type: object + properties: + ipHeader: + type: object + properties: + srcIP: + type: string + oneOf: + - format: ipv4 + - format: ipv6 + protocol: + type: integer + ttl: + type: integer + flags: + type: integer + ipv6Header: + type: object + properties: + srcIP: + type: string + format: ipv6 + nextHeader: + type: integer + hopLimit: + type: integer + transportHeader: + type: object + properties: + icmp: + type: object + properties: + id: + type: integer + sequence: + type: integer + udp: + type: object + properties: + srcPort: + type: integer + dstPort: + type: integer + tcp: + type: object + properties: + srcPort: + type: integer + dstPort: + type: integer + flags: + type: integer + liveTraffic: + type: boolean + droppedOnly: + type: boolean + timeout: + type: integer + status: + type: object + properties: + reason: + type: string + dataplaneTag: + type: integer + phase: + type: string + startTime: + type: string + results: + type: array + items: + type: object + properties: + node: + type: string + role: + type: string + timestamp: + type: integer + observations: + type: array + items: + type: object + properties: + component: + type: string + componentInfo: + type: string + action: + type: string + pod: + type: string + dstMAC: + type: string + networkPolicy: + type: string + ttl: + type: integer + translatedSrcIP: + type: string + translatedDstIP: + type: string + tunnelDstIP: + type: string + capturedPacket: + properties: + srcIP: + type: string + dstIP: + type: string + length: + type: integer + ipHeader: + properties: + flags: + type: integer + protocol: + type: integer + ttl: + type: integer + type: object + ipv6Header: + properties: + hopLimit: + type: integer + nextHeader: + type: integer + type: object + transportHeader: + properties: + tcp: + properties: + dstPort: + type: integer + srcPort: + type: integer + flags: + type: integer + type: object + udp: + properties: + dstPort: + type: integer + srcPort: + type: integer + type: object + icmp: + properties: + id: + type: integer + sequence: + type: integer + type: object + type: object + type: object + subresources: + status: {} + scope: Cluster + names: + plural: traceflows + singular: traceflow + kind: Traceflow + shortNames: + - tf +--- +# Source: antrea/templates/crds/trafficcontrol.yaml +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: trafficcontrols.crd.antrea.io +spec: + group: crd.antrea.io + versions: + - name: v1alpha2 + served: true + storage: true + schema: + openAPIV3Schema: + type: object + required: + - spec + properties: + spec: + type: object + required: + - appliedTo + - direction + - action + - targetPort + properties: + appliedTo: + type: object + properties: + podSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + direction: + type: string + enum: + - Ingress + - Egress + - Both + action: + type: string + enum: + - Mirror + - Redirect + targetPort: + type: object + oneOf: + - required: [ovsInternal] + - required: [device] + - required: [geneve] + - required: [vxlan] + - required: [gre] + - required: [erspan] + properties: + ovsInternal: + type: object + required: + - name + properties: + name: + type: string + device: + type: object + required: + - name + properties: + name: + type: string + geneve: + type: object + required: + - remoteIP + properties: + remoteIP: + type: string + oneOf: + - format: ipv4 + - format: ipv6 + vni: + type: integer + minimum: 0 + maximum: 16777215 + destinationPort: + type: integer + minimum: 1 + maximum: 65535 + vxlan: + type: object + required: + - remoteIP + properties: + remoteIP: + type: string + oneOf: + - format: ipv4 + - format: ipv6 + vni: + type: integer + minimum: 0 + maximum: 16777215 + destinationPort: + type: integer + minimum: 1 + maximum: 65535 + gre: + type: object + required: + - remoteIP + properties: + remoteIP: + type: string + oneOf: + - format: ipv4 + - format: ipv6 + key: + type: integer + minimum: 0 + maximum: 4294967295 + erspan: + type: object + required: + - remoteIP + - version + properties: + remoteIP: + type: string + oneOf: + - format: ipv4 + - format: ipv6 + sessionID: + type: integer + minimum: 0 + maximum: 1023 + version: + type: integer + enum: + - 1 + - 2 + index: + type: integer + dir: + type: integer + enum: + - 0 + - 1 + hardwareID: + type: integer + returnPort: + type: object + oneOf: + - required: [ovsInternal] + - required: [device] + - required: [geneve] + - required: [vxlan] + - required: [gre] + properties: + ovsInternal: + type: object + required: + - name + properties: + name: + type: string + device: + type: object + required: + - name + properties: + name: + type: string + geneve: + type: object + required: + - remoteIP + properties: + remoteIP: + type: string + oneOf: + - format: ipv4 + - format: ipv6 + vni: + type: integer + minimum: 0 + maximum: 16777215 + destinationPort: + type: integer + minimum: 1 + maximum: 65535 + vxlan: + type: object + required: + - remoteIP + properties: + remoteIP: + type: string + oneOf: + - format: ipv4 + - format: ipv6 + vni: + type: integer + minimum: 0 + maximum: 16777215 + destinationPort: + type: integer + minimum: 1 + maximum: 65535 + gre: + type: object + required: + - remoteIP + properties: + remoteIP: + type: string + oneOf: + - format: ipv4 + - format: ipv6 + key: + type: integer + minimum: 0 + maximum: 4294967295 + additionalPrinterColumns: + - description: Specifies the direction of traffic that should be matched. + jsonPath: .spec.direction + name: Direction + type: string + - description: Specifies the action that should be taken for the traffic. + jsonPath: .spec.action + name: Action + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + subresources: + status: {} + scope: Cluster + names: + plural: trafficcontrols + singular: trafficcontrol + kind: TrafficControl + shortNames: + - tc +--- +# Source: antrea/templates/agent/clusterrole.yaml +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: antrea-agent + labels: + app: antrea +rules: + - apiGroups: + - "" + resources: + - nodes + verbs: + - get + - watch + - list + - apiGroups: + - "" + resources: + - nodes/status + verbs: + - patch + - apiGroups: + - "" + resources: + - pods + verbs: + - get + - watch + - list + - apiGroups: + - "" + resources: + - pods/status + verbs: + - patch + - apiGroups: + - "" + resources: + - endpoints + - services + - namespaces + verbs: + - get + - watch + - list + - apiGroups: + - discovery.k8s.io + resources: + - endpointslices + verbs: + - get + - watch + - list + - apiGroups: + - crd.antrea.io + resources: + - antreaagentinfos + verbs: + - get + - create + - update + - delete + - apiGroups: + - controlplane.antrea.io + resources: + - networkpolicies + - appliedtogroups + - addressgroups + verbs: + - get + - watch + - list + - apiGroups: + - controlplane.antrea.io + resources: + - egressgroups + verbs: + - get + - watch + - list + - apiGroups: + - controlplane.antrea.io + resources: + - nodestatssummaries + verbs: + - create + - apiGroups: + - controlplane.antrea.io + resources: + - networkpolicies/status + verbs: + - create + - get + - apiGroups: + - authentication.k8s.io + resources: + - tokenreviews + verbs: + - create + - apiGroups: + - authorization.k8s.io + resources: + - subjectaccessreviews + verbs: + - create + # This is the content of built-in role kube-system/extension-apiserver-authentication-reader. + # But it doesn't have list/watch permission before K8s v1.17.0 so the extension apiserver (antrea-agent) will + # have permission issue after bumping up apiserver library to a version that supports dynamic authentication. + # See https://github.com/kubernetes/kubernetes/pull/85375 + # To support K8s clusters older than v1.17.0, we grant the required permissions directly instead of relying on + # the extension-apiserver-authentication role. + - apiGroups: + - "" + resourceNames: + - extension-apiserver-authentication + resources: + - configmaps + verbs: + - get + - list + - watch + - apiGroups: + - "" + resources: + - configmaps + resourceNames: + - antrea-ca + verbs: + - get + - watch + - list + - apiGroups: + - crd.antrea.io + resources: + - traceflows + - traceflows/status + verbs: + - get + - watch + - list + - update + - patch + - create + - delete + - apiGroups: + - crd.antrea.io + resources: + - egresses + verbs: + - get + - watch + - list + - apiGroups: + - crd.antrea.io + resources: + - egresses/status + verbs: + - update + - apiGroups: + - crd.antrea.io + resources: + - externalippools + - ippools + - trafficcontrols + verbs: + - get + - watch + - list + - apiGroups: + - crd.antrea.io + resources: + - ippools/status + verbs: + - update + - apiGroups: + - k8s.cni.cncf.io + resources: + - network-attachment-definitions + verbs: + - get + - list + - watch +--- +# Source: antrea/templates/antctl/clusterrole.yaml +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: antctl + labels: + app: antrea +rules: + - apiGroups: + - controlplane.antrea.io + resources: + - networkpolicies + - appliedtogroups + - addressgroups + verbs: + - get + - list + - apiGroups: + - stats.antrea.io + resources: + - networkpolicystats + - antreaclusternetworkpolicystats + - antreanetworkpolicystats + verbs: + - get + - list + - apiGroups: + - system.antrea.io + resources: + - controllerinfos + - agentinfos + verbs: + - get + - apiGroups: + - system.antrea.io + resources: + - supportbundles + verbs: + - get + - post + - apiGroups: + - system.antrea.io + resources: + - supportbundles/download + verbs: + - get + - nonResourceURLs: + - /agentinfo + - /addressgroups + - /appliedtogroups + - /loglevel + - /networkpolicies + - /ovsflows + - /ovstracing + - /podinterfaces + - /featuregates + - /serviceexternalip + verbs: + - get +--- +# Source: antrea/templates/cluster-identity-reader/clusterrolebinding.yaml +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: antrea-cluster-identity-reader + labels: + app: antrea +rules: + - apiGroups: + - "" + resources: + - configmaps + resourceNames: + - antrea-cluster-identity + verbs: + - get +--- +# Source: antrea/templates/controller/clusterrole.yaml +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: antrea-controller + labels: + app: antrea +rules: + - apiGroups: + - "" + resources: + - pods + - services + - namespaces + - configmaps + verbs: + - get + - watch + - list + - apiGroups: + - "" + resources: + - nodes + verbs: + - get + - watch + - list + - patch + - apiGroups: + - "" + resources: + - services/status + verbs: + - update + - apiGroups: + - networking.k8s.io + resources: + - networkpolicies + verbs: + - get + - watch + - list + - apiGroups: + - authentication.k8s.io + resources: + - tokenreviews + verbs: + - create + - apiGroups: + - authorization.k8s.io + resources: + - subjectaccessreviews + verbs: + - create + - apiGroups: + - apiextensions.k8s.io + resources: + - customresourcedefinitions + verbs: + - get + - update + # This is the content of built-in role kube-system/extension-apiserver-authentication-reader. + # But it doesn't have list/watch permission before K8s v1.17.0 so the extension apiserver (antrea-controller) will + # have permission issue after bumping up apiserver library to a version that supports dynamic authentication. + # See https://github.com/kubernetes/kubernetes/pull/85375 + # To support K8s clusters older than v1.17.0, we grant the required permissions directly instead of relying on + # the extension-apiserver-authentication role. + - apiGroups: + - "" + resourceNames: + - extension-apiserver-authentication + resources: + - configmaps + verbs: + - get + - list + - watch + - apiGroups: + - "" + resources: + - configmaps + resourceNames: + - antrea-ca + - antrea-cluster-identity + verbs: + - get + - update + - apiGroups: + - "" + resources: + - configmaps + verbs: + - create + - apiGroups: + - apiregistration.k8s.io + resources: + - apiservices + resourceNames: + - v1alpha1.stats.antrea.io + - v1beta1.system.antrea.io + - v1beta2.controlplane.antrea.io + verbs: + - get + - update + - apiGroups: + - apiregistration.k8s.io + resources: + - apiservices + resourceNames: + - v1beta1.networking.antrea.tanzu.vmware.com + - v1beta1.controlplane.antrea.tanzu.vmware.com + - v1alpha1.stats.antrea.tanzu.vmware.com + - v1beta1.system.antrea.tanzu.vmware.com + - v1beta2.controlplane.antrea.tanzu.vmware.com + verbs: + - delete + - apiGroups: + - admissionregistration.k8s.io + resources: + - mutatingwebhookconfigurations + - validatingwebhookconfigurations + resourceNames: + # always give permissions for labelsmutator.antrea.io, even when the + # feature is disabled, to avoid errors in antrea-controller when updating + # the CA cert. + - labelsmutator.antrea.io + - crdmutator.antrea.io + - crdvalidator.antrea.io + verbs: + - get + - update + - apiGroups: + - crd.antrea.io + resources: + - antreacontrollerinfos + verbs: + - get + - create + - update + - delete + - apiGroups: + - crd.antrea.io + resources: + - antreaagentinfos + verbs: + - list + - delete + - apiGroups: + - crd.antrea.io + resources: + - clusternetworkpolicies + - networkpolicies + verbs: + - get + - watch + - list + - update + - patch + - create + - delete + - apiGroups: + - crd.antrea.io + resources: + - clusternetworkpolicies/status + - networkpolicies/status + verbs: + - update + - apiGroups: + - crd.antrea.io + resources: + - tiers + verbs: + - get + - watch + - list + - update + - patch + - create + - delete + - apiGroups: + - crd.antrea.io + resources: + - traceflows + - traceflows/status + verbs: + - get + - watch + - list + - update + - patch + - create + - delete + - apiGroups: + - crd.antrea.io + resources: + - externalentities + - clustergroups + verbs: + - get + - watch + - list + - update + - patch + - create + - delete + - apiGroups: + - crd.antrea.io + resources: + - clustergroups/status + verbs: + - update + - apiGroups: + - crd.antrea.io + resources: + - egresses + verbs: + - get + - watch + - list + - update + - patch + - apiGroups: + - crd.antrea.io + resources: + - externalippools + - ippools + verbs: + - get + - watch + - list + - apiGroups: + - crd.antrea.io + resources: + - externalippools/status + - ippools/status + verbs: + - update + - apiGroups: + - apps + resources: + - statefulsets + verbs: + - get + - list + - watch +--- +# Source: antrea/templates/crds-rbac/clusterroles.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole metadata: + name: aggregate-antrea-policies-edit labels: app: antrea - name: antrea-config-82h2mk24gg - namespace: kube-system + # Add these permissions to the "admin" and "edit" default roles. + rbac.authorization.k8s.io/aggregate-to-admin: "true" + rbac.authorization.k8s.io/aggregate-to-edit: "true" +rules: +- apiGroups: ["crd.antrea.io"] + resources: ["clusternetworkpolicies", "networkpolicies"] + verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] --- -apiVersion: v1 -kind: Service +# Source: antrea/templates/crds-rbac/clusterroles.yaml +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: aggregate-antrea-policies-view + labels: + app: antrea + # Add these permissions to the "view" default role. + rbac.authorization.k8s.io/aggregate-to-view: "true" +rules: +- apiGroups: ["crd.antrea.io"] + resources: ["clusternetworkpolicies", "networkpolicies"] + verbs: ["get", "list", "watch"] +--- +# Source: antrea/templates/crds-rbac/clusterroles.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: aggregate-traceflows-edit + labels: + app: antrea + # Add these permissions to the "admin" and "edit" default roles. + rbac.authorization.k8s.io/aggregate-to-admin: "true" + rbac.authorization.k8s.io/aggregate-to-edit: "true" +rules: +- apiGroups: ["crd.antrea.io"] + resources: ["traceflows"] + verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] +--- +# Source: antrea/templates/crds-rbac/clusterroles.yaml +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 metadata: + name: aggregate-traceflows-view + labels: + app: antrea + # Add these permissions to the "view" default role. + rbac.authorization.k8s.io/aggregate-to-view: "true" +rules: +- apiGroups: ["crd.antrea.io"] + resources: ["traceflows"] + verbs: ["get", "list", "watch"] +--- +# Source: antrea/templates/crds-rbac/clusterroles.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: aggregate-antrea-clustergroups-edit + labels: + app: antrea + # Add these permissions to the "admin" and "edit" default roles. + rbac.authorization.k8s.io/aggregate-to-admin: "true" + rbac.authorization.k8s.io/aggregate-to-edit: "true" +rules: +- apiGroups: ["crd.antrea.io"] + resources: ["clustergroups"] + verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] +--- +# Source: antrea/templates/crds-rbac/clusterroles.yaml +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: aggregate-antrea-clustergroups-view + labels: + app: antrea + # Add these permissions to the "view" default role. + rbac.authorization.k8s.io/aggregate-to-view: "true" +rules: +- apiGroups: ["crd.antrea.io"] + resources: ["clustergroups"] + verbs: ["get", "list", "watch"] +--- +# Source: antrea/templates/agent/clusterrolebinding.yaml +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: antrea-agent + labels: + app: antrea +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: antrea-agent +subjects: + - kind: ServiceAccount + name: antrea-agent + namespace: kube-system +--- +# Source: antrea/templates/antctl/clusterrolebinding.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + labels: + app: antrea + name: antctl +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: antctl +subjects: + - kind: ServiceAccount + name: antctl + namespace: kube-system +--- +# Source: antrea/templates/controller/clusterrolebinding.yaml +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: antrea-controller labels: app: antrea +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: antrea-controller +subjects: + - kind: ServiceAccount + name: antrea-controller + namespace: kube-system +--- +# Source: antrea/templates/controller/service.yaml +apiVersion: v1 +kind: Service +metadata: name: antrea namespace: kube-system + labels: + app: antrea spec: ports: - - port: 443 - protocol: TCP - targetPort: api + - port: 443 + protocol: TCP + targetPort: api selector: app: antrea component: antrea-controller --- +# Source: antrea/templates/agent/daemonset.yaml apiVersion: apps/v1 -kind: Deployment +kind: DaemonSet metadata: + name: antrea-agent + namespace: kube-system labels: app: antrea - component: antrea-controller + component: antrea-agent +spec: + selector: + matchLabels: + app: antrea + component: antrea-agent + updateStrategy: + type: RollingUpdate + template: + metadata: + annotations: + # Starting with v1.21, Kubernetes supports default container annotation. + # Using "kubectl logs/exec/attach/cp" doesn't have to specify "-c antrea-agent" when troubleshooting. + kubectl.kubernetes.io/default-container: antrea-agent + # Automatically restart Pods with a RollingUpdate if the ConfigMap changes + # See https://helm.sh/docs/howto/charts_tips_and_tricks/#automatically-roll-deployments + checksum/config: fd449f30e949fff2d22ed79bca0a040535429c5b605b7b93dfdbfd3b359115ae + labels: + app: antrea + component: antrea-agent + spec: + hostNetwork: true + dnsPolicy: ClusterFirstWithHostNet + priorityClassName: system-node-critical + nodeSelector: + kubernetes.io/os: linux + tolerations: + - key: CriticalAddonsOnly + operator: Exists + - effect: NoSchedule + operator: Exists + - effect: NoExecute + operator: Exists + serviceAccountName: antrea-agent + initContainers: + - name: install-cni + image: "projects.registry.vmware.com/antrea/antrea-ubuntu:latest" + imagePullPolicy: IfNotPresent + resources: + requests: + cpu: 100m + command: ["install_cni_chaining"] + securityContext: + capabilities: + add: + # SYS_MODULE is required to load the OVS kernel module. + - SYS_MODULE + env: + # SKIP_CNI_BINARIES takes in values as a comma separated list of + # binaries that need to be skipped for installation, e.g. "portmap, bandwidth". + - name: SKIP_CNI_BINARIES + value: "" + volumeMounts: + - name: antrea-config + mountPath: /etc/antrea/antrea-cni.conflist + subPath: antrea-cni.conflist + readOnly: true + - name: host-cni-conf + mountPath: /host/etc/cni/net.d + - name: host-cni-bin + mountPath: /host/opt/cni/bin + # For loading the OVS kernel module. + - name: host-lib-modules + mountPath: /lib/modules + readOnly: true + # For changing the default permissions of the run directory. + - name: host-var-run-antrea + mountPath: /var/run/antrea + containers: + - name: antrea-agent + image: "projects.registry.vmware.com/antrea/antrea-ubuntu:latest" + imagePullPolicy: IfNotPresent + command: ["antrea-agent"] + # Log to both "/var/log/antrea/" and stderr (so "kubectl logs" can work).- + args: + - "--config=/etc/antrea/antrea-agent.conf" + - "--logtostderr=false" + - "--log_dir=/var/log/antrea" + - "--alsologtostderr" + - "--log_file_max_size=100" + - "--log_file_max_num=4" + env: + # Provide pod and node information for clusterinformation CRD. + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: NODE_NAME + valueFrom: + fieldRef: + fieldPath: spec.nodeName + - name: "ANTREA_CLOUD_EKS" + value: "true" + resources: + requests: + cpu: 200m + ports: + - containerPort: 10350 + name: api + protocol: TCP + livenessProbe: + exec: + command: + - /bin/sh + - -c + - container_liveness_probe agent + initialDelaySeconds: 5 + timeoutSeconds: 5 + periodSeconds: 10 + failureThreshold: 5 + readinessProbe: + httpGet: + host: localhost + path: /readyz + port: api + scheme: HTTPS + initialDelaySeconds: 5 + timeoutSeconds: 5 + periodSeconds: 10 + # In large-scale clusters, it may take up to 40~50 seconds for the antrea-agent to reconnect to the antrea + # Service after the antrea-controller restarts. The antrea-agent shouldn't be reported as NotReady in this + # scenario, otherwise the DaemonSet controller would restart all agents at once, as opposed to performing a + # rolling update. Set failureThreshold to 8 so it can tolerate 70s of disconnection. + failureThreshold: 8 + securityContext: + # antrea-agent needs to perform sysctl configuration. + privileged: true + volumeMounts: + - name: antrea-config + mountPath: /etc/antrea/antrea-agent.conf + subPath: antrea-agent.conf + readOnly: true + - name: host-var-run-antrea + mountPath: /var/run/antrea + - name: host-var-run-antrea + mountPath: /var/run/openvswitch + subPath: openvswitch + # host-local IPAM stores allocated IP addresses as files in /var/lib/cni/networks/$NETWORK_NAME. + # Mount a sub-directory of host-var-run-antrea to it for persistence of IP allocation. + - name: host-var-run-antrea + mountPath: /var/lib/cni + subPath: cni + # We need to mount both the /proc directory and the /var/run/netns directory so that + # antrea-agent can open the network namespace path when setting up Pod + # networking. Different container runtimes may use /proc or /var/run/netns when invoking + # the CNI commands. Docker uses /proc and containerd uses /var/run/netns. + - name: host-var-log-antrea + mountPath: /var/log/antrea + - name: host-proc + mountPath: /host/proc + readOnly: true + - name: host-var-run-netns + mountPath: /host/var/run/netns + readOnly: true + # When a container is created, a mount point for the network namespace is added under + # /var/run/netns on the host, which needs to be propagated to the antrea-agent container. + mountPropagation: HostToContainer + - name: xtables-lock + mountPath: /run/xtables.lock + - name: antrea-ovs + image: "projects.registry.vmware.com/antrea/antrea-ubuntu:latest" + imagePullPolicy: IfNotPresent + resources: + requests: + cpu: 200m + command: ["start_ovs"] + args: + - "--log_file_max_size=100" + - "--log_file_max_num=4" + securityContext: + # capabilities required by OVS daemons + capabilities: + add: + - SYS_NICE + - NET_ADMIN + - SYS_ADMIN + - IPC_LOCK + livenessProbe: + exec: + # docker CRI doesn't honor timeoutSeconds, add "timeout" to the command as a workaround. + # https://github.com/kubernetes/kubernetes/issues/51901 + command: + - /bin/sh + - -c + - timeout 10 container_liveness_probe ovs + initialDelaySeconds: 5 + timeoutSeconds: 10 + periodSeconds: 10 + failureThreshold: 5 + volumeMounts: + - name: host-var-run-antrea + mountPath: /var/run/openvswitch + subPath: openvswitch + - name: host-var-log-antrea + mountPath: /var/log/openvswitch + subPath: openvswitch + volumes: + - name: antrea-config + configMap: + name: antrea-config + - name: host-cni-conf + hostPath: + path: /etc/cni/net.d + - name: host-cni-bin + hostPath: + path: /opt/cni/bin + - name: host-proc + hostPath: + path: /proc + - name: host-var-run-netns + hostPath: + path: /var/run/netns + - name: host-var-run-antrea + hostPath: + path: /var/run/antrea + # we use subPath to create run subdirectories for different component (e.g. OVS) and + # subPath requires the base volume to exist + type: DirectoryOrCreate + - name: host-var-log-antrea + hostPath: + path: /var/log/antrea + # we use subPath to create logging subdirectories for different component (e.g. OVS) + type: DirectoryOrCreate + - name: host-lib-modules + hostPath: + path: /lib/modules + - name: xtables-lock + hostPath: + path: /run/xtables.lock + type: FileOrCreate +--- +# Source: antrea/templates/controller/deployment.yaml +apiVersion: apps/v1 +kind: Deployment +metadata: name: antrea-controller namespace: kube-system + labels: + app: antrea + component: antrea-controller spec: - replicas: 1 + strategy: + # Ensure the existing Pod is stopped before the new one is created. + type: Recreate selector: matchLabels: app: antrea component: antrea-controller - strategy: - type: Recreate + replicas: 1 template: metadata: + annotations: + # Automatically restart Pod if the ConfigMap changes + # See https://helm.sh/docs/howto/charts_tips_and_tricks/#automatically-roll-deployments + checksum/config: fd449f30e949fff2d22ed79bca0a040535429c5b605b7b93dfdbfd3b359115ae labels: app: antrea component: antrea-controller spec: - containers: - - args: - - --config - - /etc/antrea/antrea-controller.conf - - --logtostderr=false - - --log_dir=/var/log/antrea - - --alsologtostderr - - --log_file_max_size=100 - - --log_file_max_num=4 - - --v=0 - command: - - antrea-controller - env: - - name: POD_NAME - valueFrom: - fieldRef: - fieldPath: metadata.name - - name: POD_NAMESPACE - valueFrom: - fieldRef: - fieldPath: metadata.namespace - - name: NODE_NAME - valueFrom: - fieldRef: - fieldPath: spec.nodeName - - name: SERVICEACCOUNT_NAME - valueFrom: - fieldRef: - fieldPath: spec.serviceAccountName - - name: ANTREA_CONFIG_MAP_NAME - value: antrea-config-82h2mk24gg - image: projects.registry.vmware.com/antrea/antrea-ubuntu:latest - imagePullPolicy: IfNotPresent - livenessProbe: - failureThreshold: 5 - httpGet: - host: localhost - path: /livez - port: api - scheme: HTTPS - periodSeconds: 10 - timeoutSeconds: 5 - name: antrea-controller - ports: - - containerPort: 10349 - name: api - protocol: TCP - readinessProbe: - failureThreshold: 5 - httpGet: - host: localhost - path: /readyz - port: api - scheme: HTTPS - initialDelaySeconds: 5 - periodSeconds: 10 - timeoutSeconds: 5 - resources: - requests: - cpu: 200m - volumeMounts: - - mountPath: /etc/antrea/antrea-controller.conf - name: antrea-config - readOnly: true - subPath: antrea-controller.conf - - mountPath: /var/run/antrea/antrea-controller-tls - name: antrea-controller-tls - - mountPath: /var/log/antrea - name: host-var-log-antrea - hostNetwork: true nodeSelector: kubernetes.io/os: linux + hostNetwork: true priorityClassName: system-cluster-critical - serviceAccountName: antrea-controller tolerations: - - key: CriticalAddonsOnly - operator: Exists - - effect: NoSchedule - key: node-role.kubernetes.io/master + - key: CriticalAddonsOnly + operator: Exists + - effect: NoSchedule + key: node-role.kubernetes.io/master + - effect: NoSchedule + key: node-role.kubernetes.io/control-plane + serviceAccountName: antrea-controller + containers: + - name: antrea-controller + image: "projects.registry.vmware.com/antrea/antrea-ubuntu:latest" + imagePullPolicy: IfNotPresent + resources: + requests: + cpu: 200m + command: ["antrea-controller"] + # Log to both "/var/log/antrea/" and stderr (so "kubectl logs" can work). + args: + - "--config=/etc/antrea/antrea-controller.conf" + - "--logtostderr=false" + - "--log_dir=/var/log/antrea" + - "--alsologtostderr" + - "--log_file_max_size=100" + - "--log_file_max_num=4" + env: + # Provide pod and node information for clusterinformation CRD. + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: NODE_NAME + valueFrom: + fieldRef: + fieldPath: spec.nodeName + # Provide ServiceAccount name for validation webhook. + - name: SERVICEACCOUNT_NAME + valueFrom: + fieldRef: + fieldPath: spec.serviceAccountName + - name: ANTREA_CONFIG_MAP_NAME + value: antrea-config + ports: + - containerPort: 10349 + name: api + protocol: TCP + readinessProbe: + httpGet: + host: localhost + path: /readyz + port: api + scheme: HTTPS + initialDelaySeconds: 5 + timeoutSeconds: 5 + periodSeconds: 10 + failureThreshold: 5 + livenessProbe: + httpGet: + host: localhost + path: /livez + port: api + scheme: HTTPS + timeoutSeconds: 5 + periodSeconds: 10 + failureThreshold: 5 + volumeMounts: + - name: antrea-config + mountPath: /etc/antrea/antrea-controller.conf + subPath: antrea-controller.conf + readOnly: true + - name: antrea-controller-tls + mountPath: /var/run/antrea/antrea-controller-tls + - name: host-var-log-antrea + mountPath: /var/log/antrea volumes: - - configMap: - name: antrea-config-82h2mk24gg - name: antrea-config - - name: antrea-controller-tls - secret: - defaultMode: 256 - optional: true - secretName: antrea-controller-tls - - hostPath: - path: /var/log/antrea - type: DirectoryOrCreate - name: host-var-log-antrea + - name: antrea-config + configMap: + name: antrea-config + # Make it optional as we only read it when selfSignedCert=false. + - name: antrea-controller-tls + secret: + secretName: antrea-controller-tls + defaultMode: 0400 + optional: true + - name: host-var-log-antrea + hostPath: + path: /var/log/antrea + type: DirectoryOrCreate --- +# Source: antrea/templates/controller/apiservices.yaml apiVersion: apiregistration.k8s.io/v1 kind: APIService metadata: + name: v1beta2.controlplane.antrea.io labels: app: antrea - name: v1alpha1.stats.antrea.io spec: - group: stats.antrea.io + group: controlplane.antrea.io groupPriorityMinimum: 100 + version: v1beta2 + versionPriority: 100 service: name: antrea namespace: kube-system - version: v1alpha1 - versionPriority: 100 --- +# Source: antrea/templates/controller/apiservices.yaml apiVersion: apiregistration.k8s.io/v1 kind: APIService metadata: + name: v1beta1.system.antrea.io labels: app: antrea - name: v1beta1.system.antrea.io spec: group: system.antrea.io groupPriorityMinimum: 100 + version: v1beta1 + versionPriority: 100 service: name: antrea namespace: kube-system - version: v1beta1 - versionPriority: 100 --- +# Source: antrea/templates/controller/apiservices.yaml apiVersion: apiregistration.k8s.io/v1 kind: APIService metadata: + name: v1alpha1.stats.antrea.io labels: app: antrea - name: v1beta2.controlplane.antrea.io spec: - group: controlplane.antrea.io + group: stats.antrea.io groupPriorityMinimum: 100 + version: v1alpha1 + versionPriority: 100 service: name: antrea namespace: kube-system - version: v1beta2 - versionPriority: 100 ---- -apiVersion: apps/v1 -kind: DaemonSet -metadata: - labels: - app: antrea - component: antrea-agent - name: antrea-agent - namespace: kube-system -spec: - selector: - matchLabels: - app: antrea - component: antrea-agent - template: - metadata: - annotations: - kubectl.kubernetes.io/default-container: antrea-agent - labels: - app: antrea - component: antrea-agent - spec: - containers: - - args: - - --config - - /etc/antrea/antrea-agent.conf - - --logtostderr=false - - --log_dir=/var/log/antrea - - --alsologtostderr - - --log_file_max_size=100 - - --log_file_max_num=4 - - --v=0 - command: - - antrea-agent - env: - - name: ANTREA_CLOUD_EKS - value: "true" - - name: POD_NAME - valueFrom: - fieldRef: - fieldPath: metadata.name - - name: POD_NAMESPACE - valueFrom: - fieldRef: - fieldPath: metadata.namespace - - name: NODE_NAME - valueFrom: - fieldRef: - fieldPath: spec.nodeName - image: projects.registry.vmware.com/antrea/antrea-ubuntu:latest - imagePullPolicy: IfNotPresent - livenessProbe: - exec: - command: - - /bin/sh - - -c - - container_liveness_probe agent - failureThreshold: 5 - initialDelaySeconds: 5 - periodSeconds: 10 - timeoutSeconds: 5 - name: antrea-agent - ports: - - containerPort: 10350 - name: api - protocol: TCP - readinessProbe: - failureThreshold: 8 - httpGet: - host: localhost - path: /readyz - port: api - scheme: HTTPS - initialDelaySeconds: 5 - periodSeconds: 10 - timeoutSeconds: 5 - resources: - requests: - cpu: 200m - securityContext: - privileged: true - volumeMounts: - - mountPath: /etc/antrea/antrea-agent.conf - name: antrea-config - readOnly: true - subPath: antrea-agent.conf - - mountPath: /var/run/antrea - name: host-var-run-antrea - - mountPath: /var/run/openvswitch - name: host-var-run-antrea - subPath: openvswitch - - mountPath: /var/lib/cni - name: host-var-run-antrea - subPath: cni - - mountPath: /var/log/antrea - name: host-var-log-antrea - - mountPath: /host/proc - name: host-proc - readOnly: true - - mountPath: /host/var/run/netns - mountPropagation: HostToContainer - name: host-var-run-netns - readOnly: true - - mountPath: /run/xtables.lock - name: xtables-lock - - args: - - --log_file_max_size=100 - - --log_file_max_num=4 - command: - - start_ovs - image: projects.registry.vmware.com/antrea/antrea-ubuntu:latest - imagePullPolicy: IfNotPresent - livenessProbe: - exec: - command: - - /bin/sh - - -c - - timeout 10 container_liveness_probe ovs - failureThreshold: 5 - initialDelaySeconds: 5 - periodSeconds: 10 - timeoutSeconds: 10 - name: antrea-ovs - resources: - requests: - cpu: 200m - securityContext: - capabilities: - add: - - SYS_NICE - - NET_ADMIN - - SYS_ADMIN - - IPC_LOCK - volumeMounts: - - mountPath: /var/run/openvswitch - name: host-var-run-antrea - subPath: openvswitch - - mountPath: /var/log/openvswitch - name: host-var-log-antrea - subPath: openvswitch - dnsPolicy: ClusterFirstWithHostNet - hostNetwork: true - initContainers: - - command: - - install_cni_chaining - env: - - name: SKIP_CNI_BINARIES - value: "" - image: projects.registry.vmware.com/antrea/antrea-ubuntu:latest - imagePullPolicy: IfNotPresent - name: install-cni - resources: - requests: - cpu: 100m - securityContext: - capabilities: - add: - - SYS_MODULE - volumeMounts: - - mountPath: /etc/antrea/antrea-cni.conflist - name: antrea-config - readOnly: true - subPath: antrea-cni.conflist - - mountPath: /host/etc/cni/net.d - name: host-cni-conf - - mountPath: /host/opt/cni/bin - name: host-cni-bin - - mountPath: /lib/modules - name: host-lib-modules - readOnly: true - - mountPath: /var/run/antrea - name: host-var-run-antrea - nodeSelector: - kubernetes.io/os: linux - priorityClassName: system-node-critical - serviceAccountName: antrea-agent - tolerations: - - key: CriticalAddonsOnly - operator: Exists - - effect: NoSchedule - operator: Exists - - effect: NoExecute - operator: Exists - volumes: - - configMap: - name: antrea-config-82h2mk24gg - name: antrea-config - - hostPath: - path: /etc/cni/net.d - name: host-cni-conf - - hostPath: - path: /opt/cni/bin - name: host-cni-bin - - hostPath: - path: /proc - name: host-proc - - hostPath: - path: /var/run/netns - name: host-var-run-netns - - hostPath: - path: /var/run/antrea - type: DirectoryOrCreate - name: host-var-run-antrea - - hostPath: - path: /var/log/antrea - type: DirectoryOrCreate - name: host-var-log-antrea - - hostPath: - path: /lib/modules - name: host-lib-modules - - hostPath: - path: /run/xtables.lock - type: FileOrCreate - name: xtables-lock - updateStrategy: - type: RollingUpdate --- +# Source: antrea/templates/webhooks/mutating/crdmutator.yaml apiVersion: admissionregistration.k8s.io/v1 kind: MutatingWebhookConfiguration metadata: + name: "crdmutator.antrea.io" labels: app: antrea - name: crdmutator.antrea.io webhooks: -- admissionReviewVersions: - - v1 - - v1beta1 - clientConfig: - service: - name: antrea - namespace: kube-system - path: /mutate/acnp - name: acnpmutator.antrea.io - rules: - - apiGroups: - - crd.antrea.io - apiVersions: - - v1alpha1 - operations: - - CREATE - - UPDATE - resources: - - clusternetworkpolicies - scope: Cluster - sideEffects: None - timeoutSeconds: 5 -- admissionReviewVersions: - - v1 - - v1beta1 - clientConfig: - service: - name: antrea - namespace: kube-system - path: /mutate/anp - name: anpmutator.antrea.io - rules: - - apiGroups: - - crd.antrea.io - apiVersions: - - v1alpha1 - operations: - - CREATE - - UPDATE - resources: - - networkpolicies - scope: Namespaced - sideEffects: None - timeoutSeconds: 5 + - name: "acnpmutator.antrea.io" + clientConfig: + service: + name: "antrea" + namespace: kube-system + path: "/mutate/acnp" + rules: + - operations: ["CREATE", "UPDATE"] + apiGroups: ["crd.antrea.io"] + apiVersions: ["v1alpha1"] + resources: ["clusternetworkpolicies"] + scope: "Cluster" + admissionReviewVersions: ["v1", "v1beta1"] + sideEffects: None + timeoutSeconds: 5 + - name: "anpmutator.antrea.io" + clientConfig: + service: + name: "antrea" + namespace: kube-system + path: "/mutate/anp" + rules: + - operations: ["CREATE", "UPDATE"] + apiGroups: ["crd.antrea.io"] + apiVersions: ["v1alpha1"] + resources: ["networkpolicies"] + scope: "Namespaced" + admissionReviewVersions: ["v1", "v1beta1"] + sideEffects: None + timeoutSeconds: 5 --- +# Source: antrea/templates/webhooks/validating/crdvalidator.yaml apiVersion: admissionregistration.k8s.io/v1 kind: ValidatingWebhookConfiguration metadata: + name: "crdvalidator.antrea.io" labels: app: antrea - name: crdvalidator.antrea.io webhooks: -- admissionReviewVersions: - - v1 - - v1beta1 - clientConfig: - service: - name: antrea - namespace: kube-system - path: /validate/tier - name: tiervalidator.antrea.io - rules: - - apiGroups: - - crd.antrea.io - apiVersions: - - v1alpha1 - operations: - - CREATE - - UPDATE - - DELETE - resources: - - tiers - scope: Cluster - sideEffects: None - timeoutSeconds: 5 -- admissionReviewVersions: - - v1 - - v1beta1 - clientConfig: - service: - name: antrea - namespace: kube-system - path: /validate/acnp - name: acnpvalidator.antrea.io - rules: - - apiGroups: - - crd.antrea.io - apiVersions: - - v1alpha1 - operations: - - CREATE - - UPDATE - resources: - - clusternetworkpolicies - scope: Cluster - sideEffects: None - timeoutSeconds: 5 -- admissionReviewVersions: - - v1 - - v1beta1 - clientConfig: - service: - name: antrea - namespace: kube-system - path: /validate/anp - name: anpvalidator.antrea.io - rules: - - apiGroups: - - crd.antrea.io - apiVersions: - - v1alpha1 - operations: - - CREATE - - UPDATE - resources: - - networkpolicies - scope: Namespaced - sideEffects: None - timeoutSeconds: 5 -- admissionReviewVersions: - - v1 - - v1beta1 - clientConfig: - service: - name: antrea - namespace: kube-system - path: /validate/clustergroup - name: clustergroupvalidator.antrea.io - rules: - - apiGroups: - - crd.antrea.io - apiVersions: - - v1alpha3 - - v1alpha2 - operations: - - CREATE - - UPDATE - resources: - - clustergroups - scope: Cluster - sideEffects: None - timeoutSeconds: 5 -- admissionReviewVersions: - - v1 - - v1beta1 - clientConfig: - service: - name: antrea - namespace: kube-system - path: /validate/externalippool - name: externalippoolvalidator.antrea.io - rules: - - apiGroups: - - crd.antrea.io - apiVersions: - - v1alpha2 - operations: - - UPDATE - resources: - - externalippools - scope: Cluster - sideEffects: None - timeoutSeconds: 5 -- admissionReviewVersions: - - v1 - - v1beta1 - clientConfig: - service: - name: antrea - namespace: kube-system - path: /validate/egress - name: egressvalidator.antrea.io - rules: - - apiGroups: - - crd.antrea.io - apiVersions: - - v1alpha2 - operations: - - CREATE - - UPDATE - resources: - - egresses - scope: Cluster - sideEffects: None - timeoutSeconds: 5 -- admissionReviewVersions: - - v1 - - v1beta1 - clientConfig: - service: - name: antrea - namespace: kube-system - path: /validate/ippool - name: ippoolvalidator.antrea.io - rules: - - apiGroups: - - crd.antrea.io - apiVersions: - - v1alpha2 - operations: - - CREATE - - UPDATE - - DELETE - resources: - - ippools - scope: Cluster - sideEffects: None - timeoutSeconds: 5 + - name: "tiervalidator.antrea.io" + clientConfig: + service: + name: "antrea" + namespace: kube-system + path: "/validate/tier" + rules: + - operations: ["CREATE", "UPDATE", "DELETE"] + apiGroups: ["crd.antrea.io"] + apiVersions: ["v1alpha1"] + resources: ["tiers"] + scope: "Cluster" + admissionReviewVersions: ["v1", "v1beta1"] + sideEffects: None + timeoutSeconds: 5 + - name: "acnpvalidator.antrea.io" + clientConfig: + service: + name: "antrea" + namespace: kube-system + path: "/validate/acnp" + rules: + - operations: ["CREATE", "UPDATE"] + apiGroups: ["crd.antrea.io"] + apiVersions: ["v1alpha1"] + resources: ["clusternetworkpolicies"] + scope: "Cluster" + admissionReviewVersions: ["v1", "v1beta1"] + sideEffects: None + timeoutSeconds: 5 + - name: "anpvalidator.antrea.io" + clientConfig: + service: + name: "antrea" + namespace: kube-system + path: "/validate/anp" + rules: + - operations: ["CREATE", "UPDATE"] + apiGroups: ["crd.antrea.io"] + apiVersions: ["v1alpha1"] + resources: ["networkpolicies"] + scope: "Namespaced" + admissionReviewVersions: ["v1", "v1beta1"] + sideEffects: None + timeoutSeconds: 5 + - name: "clustergroupvalidator.antrea.io" + clientConfig: + service: + name: "antrea" + namespace: kube-system + path: "/validate/clustergroup" + rules: + - operations: ["CREATE", "UPDATE"] + apiGroups: ["crd.antrea.io"] + apiVersions: ["v1alpha3", "v1alpha2"] + resources: ["clustergroups"] + scope: "Cluster" + admissionReviewVersions: ["v1", "v1beta1"] + sideEffects: None + timeoutSeconds: 5 + - name: "externalippoolvalidator.antrea.io" + clientConfig: + service: + name: "antrea" + namespace: kube-system + path: "/validate/externalippool" + rules: + - operations: ["UPDATE"] + apiGroups: ["crd.antrea.io"] + apiVersions: ["v1alpha2"] + resources: ["externalippools"] + scope: "Cluster" + admissionReviewVersions: ["v1", "v1beta1"] + sideEffects: None + timeoutSeconds: 5 + - name: "egressvalidator.antrea.io" + clientConfig: + service: + name: "antrea" + namespace: kube-system + path: "/validate/egress" + rules: + - operations: ["CREATE", "UPDATE"] + apiGroups: ["crd.antrea.io"] + apiVersions: ["v1alpha2"] + resources: ["egresses"] + scope: "Cluster" + admissionReviewVersions: ["v1", "v1beta1"] + sideEffects: None + timeoutSeconds: 5 + - name: "ippoolvalidator.antrea.io" + clientConfig: + service: + name: "antrea" + namespace: kube-system + path: "/validate/ippool" + rules: + - operations: ["CREATE", "UPDATE", "DELETE"] + apiGroups: ["crd.antrea.io"] + apiVersions: ["v1alpha2"] + resources: ["ippools"] + scope: "Cluster" + admissionReviewVersions: ["v1", "v1beta1"] + sideEffects: None + timeoutSeconds: 5 diff --git a/build/yamls/antrea-gke.yml b/build/yamls/antrea-gke.yml index 78552174cbd..7294819af5f 100644 --- a/build/yamls/antrea-gke.yml +++ b/build/yamls/antrea-gke.yml @@ -1,2740 +1,59 @@ -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition +--- +# Source: antrea/templates/agent/serviceaccount.yaml +apiVersion: v1 +kind: ServiceAccount metadata: + name: antrea-agent + namespace: kube-system labels: app: antrea - name: antreaagentinfos.crd.antrea.io -spec: - group: crd.antrea.io - names: - kind: AntreaAgentInfo - plural: antreaagentinfos - shortNames: - - aai - singular: antreaagentinfo - scope: Cluster - versions: - - additionalPrinterColumns: - - description: Health status of this Agent - jsonPath: .agentConditions[?(@.type=='AgentHealthy')].status - name: Healthy - type: string - - description: Last time the Healthy Condition was updated - jsonPath: .agentConditions[?(@.type=='AgentHealthy')].lastHeartbeatTime - name: Last Heartbeat - type: date - - description: Version of this Agent - jsonPath: .version - name: Version - priority: 1 - type: string - - description: Node on which this Agent is running - jsonPath: .nodeRef.name - name: Node - priority: 1 - type: string - - description: Number of local Pods managed by this Agent - jsonPath: .localPodNum - name: Num Pods - priority: 2 - type: integer - - description: Subnets used by this Agent for Pod IPAM - jsonPath: .nodeSubnets - name: Subnets - priority: 2 - type: string - name: v1beta1 - schema: - openAPIV3Schema: - type: object - x-kubernetes-preserve-unknown-fields: true - served: true - storage: true --- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition +# Source: antrea/templates/antctl/serviceaccount.yaml +apiVersion: v1 +kind: ServiceAccount metadata: + name: antctl + namespace: kube-system labels: app: antrea - name: antreacontrollerinfos.crd.antrea.io -spec: - group: crd.antrea.io - names: - kind: AntreaControllerInfo - plural: antreacontrollerinfos - shortNames: - - aci - singular: antreacontrollerinfo - scope: Cluster - versions: - - additionalPrinterColumns: - - description: Health status of the Controller - jsonPath: .controllerConditions[?(@.type=='ControllerHealthy')].status - name: Healthy - type: string - - description: Last time the Healthy Condition was updated - jsonPath: .controllerConditions[?(@.type=='ControllerHealthy')].lastHeartbeatTime - name: Last Heartbeat - type: date - - description: Version of the Controller - jsonPath: .version - name: Version - priority: 1 - type: string - - description: Number of Agents connected to the Controller - jsonPath: .connectedAgentNum - name: Connected Agents - priority: 1 - type: integer - - description: Node on which the Controller is running - jsonPath: .nodeRef.name - name: Node - priority: 1 - type: string - - description: Number of Network Policies computed by Controller - jsonPath: .networkPolicyControllerInfo.networkPolicyNum - name: Num Network Policies - priority: 2 - type: integer - name: v1beta1 - schema: - openAPIV3Schema: - type: object - x-kubernetes-preserve-unknown-fields: true - served: true - storage: true --- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition +# Source: antrea/templates/controller/serviceaccount.yaml +apiVersion: v1 +kind: ServiceAccount metadata: + name: antrea-controller + namespace: kube-system labels: app: antrea - name: clustergroups.crd.antrea.io -spec: - conversion: - strategy: Webhook - webhook: - clientConfig: - service: - name: antrea - namespace: kube-system - path: /convert/clustergroup - conversionReviewVersions: - - v1 - - v1beta1 - group: crd.antrea.io - names: - kind: ClusterGroup - plural: clustergroups - shortNames: - - cg - singular: clustergroup - scope: Cluster - versions: - - name: v1alpha2 - schema: - openAPIV3Schema: - properties: - spec: - properties: - childGroups: - items: - type: string - type: array - externalEntitySelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - ipBlock: - properties: - cidr: - format: cidr - type: string - type: object - ipBlocks: - items: - properties: - cidr: - format: cidr - type: string - type: object - type: array - namespaceSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - podSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - serviceReference: - properties: - name: - type: string - namespace: - type: string - type: object - type: object - status: - properties: - conditions: - items: - properties: - lastTransitionTime: - type: string - status: - type: string - type: - type: string - type: object - type: array - type: object - type: object - served: true - storage: false - - name: v1alpha3 - schema: - openAPIV3Schema: - properties: - spec: - properties: - childGroups: - items: - type: string - type: array - externalEntitySelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - ipBlocks: - items: - properties: - cidr: - format: cidr - type: string - type: object - type: array - namespaceSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - podSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - serviceReference: - properties: - name: - type: string - namespace: - type: string - type: object - type: object - status: - properties: - conditions: - items: - properties: - lastTransitionTime: - type: string - status: - type: string - type: - type: string - type: object - type: array - type: object - type: object - served: true - storage: true - subresources: - status: {} --- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition +# Source: antrea/templates/agent/secret.yaml +apiVersion: v1 +kind: Secret +metadata: + name: antrea-agent-service-account-token + namespace: kube-system + annotations: + kubernetes.io/service-account.name: antrea-agent +type: kubernetes.io/service-account-token +--- +# Source: antrea/templates/antctl/secret.yaml +apiVersion: v1 +kind: Secret +metadata: + name: antctl-service-account-token + namespace: kube-system + annotations: + kubernetes.io/service-account.name: antctl +type: kubernetes.io/service-account-token +--- +# Source: antrea/templates/configmap.yaml +apiVersion: v1 +kind: ConfigMap metadata: + name: antrea-config + namespace: kube-system labels: app: antrea - name: clusternetworkpolicies.crd.antrea.io -spec: - group: crd.antrea.io - names: - kind: ClusterNetworkPolicy - plural: clusternetworkpolicies - shortNames: - - acnp - singular: clusternetworkpolicy - scope: Cluster - versions: - - additionalPrinterColumns: - - description: The Tier to which this ClusterNetworkPolicy belongs to. - jsonPath: .spec.tier - name: Tier - type: string - - description: The Priority of this ClusterNetworkPolicy relative to other policies. - format: float - jsonPath: .spec.priority - name: Priority - type: number - - description: The total number of Nodes that should realize the NetworkPolicy. - format: int32 - jsonPath: .status.desiredNodesRealized - name: Desired Nodes - type: number - - description: The number of Nodes that have realized the NetworkPolicy. - format: int32 - jsonPath: .status.currentNodesRealized - name: Current Nodes - type: number - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha1 - schema: - openAPIV3Schema: - properties: - spec: - properties: - appliedTo: - items: - properties: - group: - type: string - namespaceSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - podSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - serviceAccount: - properties: - name: - type: string - namespace: - type: string - required: - - name - - namespace - type: object - type: object - type: array - egress: - items: - properties: - action: - enum: - - Allow - - Drop - - Reject - - Pass - type: string - appliedTo: - items: - properties: - group: - type: string - namespaceSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - podSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - serviceAccount: - properties: - name: - type: string - namespace: - type: string - required: - - name - - namespace - type: object - type: object - type: array - enableLogging: - type: boolean - name: - type: string - ports: - items: - properties: - endPort: - type: integer - port: - x-kubernetes-int-or-string: true - protocol: - enum: - - TCP - - UDP - - SCTP - type: string - type: object - type: array - to: - items: - properties: - fqdn: - type: string - group: - type: string - ipBlock: - properties: - cidr: - format: cidr - type: string - type: object - namespaceSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - namespaces: - properties: - match: - type: string - type: object - nodeSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - podSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - serviceAccount: - properties: - name: - type: string - namespace: - type: string - required: - - name - - namespace - type: object - type: object - type: array - toServices: - items: - properties: - name: - type: string - namespace: - type: string - required: - - name - - namespace - type: object - type: array - required: - - action - type: object - type: array - ingress: - items: - properties: - action: - enum: - - Allow - - Drop - - Reject - - Pass - type: string - appliedTo: - items: - properties: - group: - type: string - namespaceSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - podSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - serviceAccount: - properties: - name: - type: string - namespace: - type: string - required: - - name - - namespace - type: object - type: object - type: array - enableLogging: - type: boolean - from: - items: - properties: - group: - type: string - ipBlock: - properties: - cidr: - format: cidr - type: string - type: object - namespaceSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - namespaces: - properties: - match: - enum: - - Self - type: string - type: object - nodeSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - podSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - serviceAccount: - properties: - name: - type: string - namespace: - type: string - required: - - name - - namespace - type: object - type: object - type: array - name: - type: string - ports: - items: - properties: - endPort: - type: integer - port: - x-kubernetes-int-or-string: true - protocol: - enum: - - TCP - - UDP - - SCTP - type: string - type: object - type: array - required: - - action - type: object - type: array - priority: - format: float - maximum: 10000 - minimum: 1 - type: number - tier: - type: string - required: - - priority - type: object - status: - properties: - currentNodesRealized: - type: integer - desiredNodesRealized: - type: integer - observedGeneration: - type: integer - phase: - type: string - type: object - type: object - served: true - storage: true - subresources: - status: {} ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - labels: - app: antrea - name: egresses.crd.antrea.io -spec: - group: crd.antrea.io - names: - kind: Egress - plural: egresses - shortNames: - - eg - singular: egress - scope: Cluster - versions: - - additionalPrinterColumns: - - description: Specifies the SNAT IP address for the selected workloads. - jsonPath: .spec.egressIP - name: EgressIP - type: string - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - - description: The Owner Node of egress IP - jsonPath: .status.egressNode - name: Node - type: string - name: v1alpha2 - schema: - openAPIV3Schema: - properties: - spec: - anyOf: - - required: - - egressIP - - required: - - externalIPPool - properties: - appliedTo: - properties: - namespaceSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - podSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - type: object - egressIP: - oneOf: - - format: ipv4 - - format: ipv6 - type: string - externalIPPool: - type: string - required: - - appliedTo - type: object - status: - properties: - egressNode: - type: string - type: object - required: - - spec - type: object - served: true - storage: true - subresources: - status: {} ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - labels: - app: antrea - name: externalentities.crd.antrea.io -spec: - group: crd.antrea.io - names: - kind: ExternalEntity - plural: externalentities - shortNames: - - ee - singular: externalentity - scope: Namespaced - versions: - - name: v1alpha2 - schema: - openAPIV3Schema: - properties: - spec: - properties: - endpoints: - items: - properties: - ip: - oneOf: - - format: ipv4 - - format: ipv6 - type: string - name: - type: string - type: object - type: array - externalNode: - type: string - ports: - items: - properties: - name: - type: string - port: - x-kubernetes-int-or-string: true - protocol: - enum: - - TCP - - UDP - - SCTP - type: string - type: object - type: array - type: object - type: object - served: true - storage: true - - name: v1alpha1 - schema: - openAPIV3Schema: - type: object - served: false - storage: false ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - labels: - app: antrea - name: externalippools.crd.antrea.io -spec: - group: crd.antrea.io - names: - kind: ExternalIPPool - plural: externalippools - shortNames: - - eip - singular: externalippool - scope: Cluster - versions: - - additionalPrinterColumns: - - description: The number of total IPs - jsonPath: .status.usage.total - name: Total - type: integer - - description: The number of allocated IPs - jsonPath: .status.usage.used - name: Used - type: integer - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha2 - schema: - openAPIV3Schema: - properties: - spec: - properties: - ipRanges: - items: - oneOf: - - required: - - cidr - - required: - - start - - end - properties: - cidr: - format: cidr - type: string - end: - oneOf: - - format: ipv4 - - format: ipv6 - type: string - start: - oneOf: - - format: ipv4 - - format: ipv6 - type: string - type: object - type: array - nodeSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - required: - - ipRanges - - nodeSelector - type: object - status: - properties: - usage: - properties: - total: - type: integer - used: - type: integer - type: object - type: object - required: - - spec - type: object - served: true - storage: true - subresources: - status: {} ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - labels: - app: antrea - name: ippools.crd.antrea.io -spec: - group: crd.antrea.io - names: - kind: IPPool - plural: ippools - shortNames: - - ipp - singular: ippool - scope: Cluster - versions: - - name: v1alpha2 - schema: - openAPIV3Schema: - properties: - spec: - properties: - ipRanges: - items: - oneOf: - - required: - - cidr - - gateway - - prefixLength - - required: - - start - - end - - gateway - - prefixLength - properties: - cidr: - format: cidr - type: string - end: - oneOf: - - format: ipv4 - - format: ipv6 - type: string - gateway: - oneOf: - - format: ipv4 - - format: ipv6 - type: string - prefixLength: - type: integer - start: - oneOf: - - format: ipv4 - - format: ipv6 - type: string - vlan: - maximum: 4094 - minimum: 0 - type: integer - type: object - type: array - ipVersion: - type: integer - required: - - ipVersion - - ipRanges - type: object - status: - properties: - ipAddresses: - items: - properties: - ipAddress: - type: string - owner: - properties: - pod: - properties: - containerID: - type: string - name: - type: string - namespace: - type: string - type: object - statefulSet: - properties: - index: - type: integer - name: - type: string - namespace: - type: string - type: object - type: object - phase: - type: string - type: object - type: array - type: object - required: - - spec - type: object - served: true - storage: true - subresources: - status: {} ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - labels: - app: antrea - name: networkpolicies.crd.antrea.io -spec: - group: crd.antrea.io - names: - kind: NetworkPolicy - plural: networkpolicies - shortNames: - - anp - singular: networkpolicy - scope: Namespaced - versions: - - additionalPrinterColumns: - - description: The Tier to which this Antrea NetworkPolicy belongs to. - jsonPath: .spec.tier - name: Tier - type: string - - description: The Priority of this Antrea NetworkPolicy relative to other policies. - format: float - jsonPath: .spec.priority - name: Priority - type: number - - description: The total number of Nodes that should realize the NetworkPolicy. - format: int32 - jsonPath: .status.desiredNodesRealized - name: Desired Nodes - type: number - - description: The number of Nodes that have realized the NetworkPolicy. - format: int32 - jsonPath: .status.currentNodesRealized - name: Current Nodes - type: number - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha1 - schema: - openAPIV3Schema: - properties: - spec: - properties: - appliedTo: - items: - properties: - podSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - type: object - type: array - egress: - items: - properties: - action: - enum: - - Allow - - Drop - - Reject - - Pass - type: string - appliedTo: - items: - properties: - podSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - type: object - type: array - enableLogging: - type: boolean - name: - type: string - ports: - items: - properties: - endPort: - type: integer - port: - x-kubernetes-int-or-string: true - protocol: - enum: - - TCP - - UDP - - SCTP - type: string - type: object - type: array - to: - items: - properties: - externalEntitySelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - fqdn: - type: string - ipBlock: - properties: - cidr: - format: cidr - type: string - type: object - namespaceSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - nodeSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - podSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - type: object - type: array - toServices: - items: - properties: - name: - type: string - namespace: - type: string - required: - - name - type: object - type: array - required: - - action - type: object - type: array - ingress: - items: - properties: - action: - enum: - - Allow - - Drop - - Reject - - Pass - type: string - appliedTo: - items: - properties: - podSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - type: object - type: array - enableLogging: - type: boolean - from: - items: - properties: - externalEntitySelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - ipBlock: - properties: - cidr: - format: cidr - type: string - type: object - namespaceSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - nodeSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - podSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - type: object - type: array - name: - type: string - ports: - items: - properties: - endPort: - type: integer - port: - x-kubernetes-int-or-string: true - protocol: - enum: - - TCP - - UDP - - SCTP - type: string - type: object - type: array - required: - - action - type: object - type: array - priority: - format: float - maximum: 10000 - minimum: 1 - type: number - tier: - type: string - required: - - priority - type: object - status: - properties: - currentNodesRealized: - type: integer - desiredNodesRealized: - type: integer - observedGeneration: - type: integer - phase: - type: string - type: object - type: object - served: true - storage: true - subresources: - status: {} ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - labels: - app: antrea - name: tiers.crd.antrea.io -spec: - group: crd.antrea.io - names: - kind: Tier - plural: tiers - shortNames: - - tr - singular: tier - scope: Cluster - versions: - - additionalPrinterColumns: - - description: The Priority of this Tier relative to other Tiers. - jsonPath: .spec.priority - name: Priority - type: integer - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha1 - schema: - openAPIV3Schema: - properties: - spec: - properties: - description: - type: string - priority: - maximum: 255 - minimum: 0 - type: integer - required: - - priority - type: object - type: object - served: true - storage: true ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - labels: - app: antrea - name: traceflows.crd.antrea.io -spec: - group: crd.antrea.io - names: - kind: Traceflow - plural: traceflows - shortNames: - - tf - singular: traceflow - scope: Cluster - versions: - - additionalPrinterColumns: - - description: The phase of the Traceflow. - jsonPath: .status.phase - name: Phase - type: string - - description: The name of the source Pod. - jsonPath: .spec.source.pod - name: Source-Pod - priority: 10 - type: string - - description: The name of the destination Pod. - jsonPath: .spec.destination.pod - name: Destination-Pod - priority: 10 - type: string - - description: The IP address of the destination. - jsonPath: .spec.destination.ip - name: Destination-IP - priority: 10 - type: string - - description: Trace live traffic. - jsonPath: .spec.liveTraffic - name: Live-Traffic - priority: 10 - type: boolean - - description: Capture only the dropped packet. - jsonPath: .spec.droppedOnly - name: Dropped-Only - priority: 10 - type: boolean - - description: Timeout in seconds. - jsonPath: .spec.timeout - name: Timeout - priority: 10 - type: integer - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha1 - schema: - openAPIV3Schema: - properties: - spec: - properties: - destination: - properties: - ip: - oneOf: - - format: ipv4 - - format: ipv6 - type: string - namespace: - type: string - pod: - type: string - service: - type: string - type: object - droppedOnly: - type: boolean - liveTraffic: - type: boolean - packet: - properties: - ipHeader: - properties: - flags: - type: integer - protocol: - type: integer - srcIP: - oneOf: - - format: ipv4 - - format: ipv6 - type: string - ttl: - type: integer - type: object - ipv6Header: - properties: - hopLimit: - type: integer - nextHeader: - type: integer - srcIP: - format: ipv6 - type: string - type: object - transportHeader: - properties: - icmp: - properties: - id: - type: integer - sequence: - type: integer - type: object - tcp: - properties: - dstPort: - type: integer - flags: - type: integer - srcPort: - type: integer - type: object - udp: - properties: - dstPort: - type: integer - srcPort: - type: integer - type: object - type: object - type: object - source: - properties: - ip: - oneOf: - - format: ipv4 - - format: ipv6 - type: string - namespace: - type: string - pod: - type: string - type: object - timeout: - type: integer - type: object - status: - properties: - capturedPacket: - properties: - dstIP: - type: string - ipHeader: - properties: - flags: - type: integer - protocol: - type: integer - ttl: - type: integer - type: object - ipv6Header: - properties: - hopLimit: - type: integer - nextHeader: - type: integer - type: object - length: - type: integer - srcIP: - type: string - transportHeader: - properties: - icmp: - properties: - id: - type: integer - sequence: - type: integer - type: object - tcp: - properties: - dstPort: - type: integer - flags: - type: integer - srcPort: - type: integer - type: object - udp: - properties: - dstPort: - type: integer - srcPort: - type: integer - type: object - type: object - type: object - dataplaneTag: - type: integer - phase: - type: string - reason: - type: string - results: - items: - properties: - node: - type: string - observations: - items: - properties: - action: - type: string - component: - type: string - componentInfo: - type: string - dstMAC: - type: string - networkPolicy: - type: string - pod: - type: string - translatedDstIP: - type: string - translatedSrcIP: - type: string - ttl: - type: integer - tunnelDstIP: - type: string - type: object - type: array - role: - type: string - timestamp: - type: integer - type: object - type: array - startTime: - type: string - type: object - required: - - spec - type: object - served: true - storage: true - subresources: - status: {} ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - labels: - app: antrea - name: antctl - namespace: kube-system ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - labels: - app: antrea - name: antrea-agent - namespace: kube-system ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - labels: - app: antrea - name: antrea-controller - namespace: kube-system ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - labels: - app: antrea - rbac.authorization.k8s.io/aggregate-to-admin: "true" - rbac.authorization.k8s.io/aggregate-to-edit: "true" - name: aggregate-antrea-clustergroups-edit -rules: -- apiGroups: - - crd.antrea.io - resources: - - clustergroups - verbs: - - get - - list - - watch - - create - - update - - patch - - delete ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - labels: - app: antrea - rbac.authorization.k8s.io/aggregate-to-view: "true" - name: aggregate-antrea-clustergroups-view -rules: -- apiGroups: - - crd.antrea.io - resources: - - clustergroups - verbs: - - get - - list - - watch ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - labels: - app: antrea - rbac.authorization.k8s.io/aggregate-to-admin: "true" - rbac.authorization.k8s.io/aggregate-to-edit: "true" - name: aggregate-antrea-policies-edit -rules: -- apiGroups: - - crd.antrea.io - resources: - - clusternetworkpolicies - - networkpolicies - verbs: - - get - - list - - watch - - create - - update - - patch - - delete ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - labels: - app: antrea - rbac.authorization.k8s.io/aggregate-to-view: "true" - name: aggregate-antrea-policies-view -rules: -- apiGroups: - - crd.antrea.io - resources: - - clusternetworkpolicies - - networkpolicies - verbs: - - get - - list - - watch ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - labels: - app: antrea - rbac.authorization.k8s.io/aggregate-to-admin: "true" - rbac.authorization.k8s.io/aggregate-to-edit: "true" - name: aggregate-traceflows-edit -rules: -- apiGroups: - - crd.antrea.io - resources: - - traceflows - verbs: - - get - - list - - watch - - create - - update - - patch - - delete ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - labels: - app: antrea - rbac.authorization.k8s.io/aggregate-to-view: "true" - name: aggregate-traceflows-view -rules: -- apiGroups: - - crd.antrea.io - resources: - - traceflows - verbs: - - get - - list - - watch ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - labels: - app: antrea - name: antctl -rules: -- apiGroups: - - controlplane.antrea.io - resources: - - networkpolicies - - appliedtogroups - - addressgroups - verbs: - - get - - list -- apiGroups: - - stats.antrea.io - resources: - - networkpolicystats - - antreaclusternetworkpolicystats - - antreanetworkpolicystats - verbs: - - get - - list -- apiGroups: - - system.antrea.io - resources: - - controllerinfos - - agentinfos - verbs: - - get -- apiGroups: - - system.antrea.io - resources: - - supportbundles - verbs: - - get - - post -- apiGroups: - - system.antrea.io - resources: - - supportbundles/download - verbs: - - get -- nonResourceURLs: - - /agentinfo - - /addressgroups - - /appliedtogroups - - /loglevel - - /networkpolicies - - /ovsflows - - /ovstracing - - /podinterfaces - - /featuregates - verbs: - - get ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - labels: - app: antrea - name: antrea-agent -rules: -- apiGroups: - - "" - resources: - - nodes - verbs: - - get - - watch - - list -- apiGroups: - - "" - resources: - - nodes/status - verbs: - - patch -- apiGroups: - - "" - resources: - - pods - verbs: - - get - - watch - - list -- apiGroups: - - "" - resources: - - pods/status - verbs: - - patch -- apiGroups: - - "" - resources: - - endpoints - - services - - namespaces - verbs: - - get - - watch - - list -- apiGroups: - - "" - resources: - - services/status - verbs: - - update -- apiGroups: - - discovery.k8s.io - resources: - - endpointslices - verbs: - - get - - watch - - list -- apiGroups: - - crd.antrea.io - resources: - - antreaagentinfos - verbs: - - get - - create - - update - - delete -- apiGroups: - - controlplane.antrea.io - resources: - - networkpolicies - - appliedtogroups - - addressgroups - verbs: - - get - - watch - - list -- apiGroups: - - controlplane.antrea.io - resources: - - egressgroups - verbs: - - get - - watch - - list -- apiGroups: - - controlplane.antrea.io - resources: - - nodestatssummaries - verbs: - - create -- apiGroups: - - controlplane.antrea.io - resources: - - networkpolicies/status - verbs: - - create - - get -- apiGroups: - - authentication.k8s.io - resources: - - tokenreviews - verbs: - - create -- apiGroups: - - authorization.k8s.io - resources: - - subjectaccessreviews - verbs: - - create -- apiGroups: - - "" - resourceNames: - - extension-apiserver-authentication - resources: - - configmaps - verbs: - - get - - list - - watch -- apiGroups: - - "" - resourceNames: - - antrea-ca - resources: - - configmaps - verbs: - - get - - watch - - list -- apiGroups: - - crd.antrea.io - resources: - - traceflows - - traceflows/status - verbs: - - get - - watch - - list - - update - - patch - - create - - delete -- apiGroups: - - crd.antrea.io - resources: - - egresses - verbs: - - get - - watch - - list -- apiGroups: - - crd.antrea.io - resources: - - egresses/status - verbs: - - update -- apiGroups: - - crd.antrea.io - resources: - - externalippools - - ippools - verbs: - - get - - watch - - list -- apiGroups: - - crd.antrea.io - resources: - - ippools/status - verbs: - - update -- apiGroups: - - k8s.cni.cncf.io - resources: - - network-attachment-definitions - verbs: - - get - - list - - watch ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - labels: - app: antrea - name: antrea-cluster-identity-reader -rules: -- apiGroups: - - "" - resourceNames: - - antrea-cluster-identity - resources: - - configmaps - verbs: - - get ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - labels: - app: antrea - name: antrea-controller -rules: -- apiGroups: - - "" - resources: - - pods - - services - - namespaces - - configmaps - verbs: - - get - - watch - - list -- apiGroups: - - "" - resources: - - nodes - verbs: - - get - - watch - - list - - patch -- apiGroups: - - "" - resources: - - services/status - verbs: - - update -- apiGroups: - - networking.k8s.io - resources: - - networkpolicies - verbs: - - get - - watch - - list -- apiGroups: - - authentication.k8s.io - resources: - - tokenreviews - verbs: - - create -- apiGroups: - - authorization.k8s.io - resources: - - subjectaccessreviews - verbs: - - create -- apiGroups: - - apiextensions.k8s.io - resources: - - customresourcedefinitions - verbs: - - get - - update -- apiGroups: - - "" - resourceNames: - - extension-apiserver-authentication - resources: - - configmaps - verbs: - - get - - list - - watch -- apiGroups: - - "" - resourceNames: - - antrea-ca - - antrea-cluster-identity - resources: - - configmaps - verbs: - - get - - update -- apiGroups: - - "" - resources: - - configmaps - verbs: - - create -- apiGroups: - - apiregistration.k8s.io - resourceNames: - - v1alpha1.stats.antrea.io - - v1beta1.system.antrea.io - - v1beta2.controlplane.antrea.io - resources: - - apiservices - verbs: - - get - - update -- apiGroups: - - apiregistration.k8s.io - resourceNames: - - v1beta1.networking.antrea.tanzu.vmware.com - - v1beta1.controlplane.antrea.tanzu.vmware.com - - v1alpha1.stats.antrea.tanzu.vmware.com - - v1beta1.system.antrea.tanzu.vmware.com - - v1beta2.controlplane.antrea.tanzu.vmware.com - resources: - - apiservices - verbs: - - delete -- apiGroups: - - admissionregistration.k8s.io - resourceNames: - - labelsmutator.antrea.io - - crdmutator.antrea.io - - crdvalidator.antrea.io - resources: - - mutatingwebhookconfigurations - - validatingwebhookconfigurations - verbs: - - get - - update -- apiGroups: - - crd.antrea.io - resources: - - antreacontrollerinfos - verbs: - - get - - create - - update - - delete -- apiGroups: - - crd.antrea.io - resources: - - antreaagentinfos - verbs: - - list - - delete -- apiGroups: - - crd.antrea.io - resources: - - clusternetworkpolicies - - networkpolicies - verbs: - - get - - watch - - list - - update - - patch - - create - - delete -- apiGroups: - - crd.antrea.io - resources: - - clusternetworkpolicies/status - - networkpolicies/status - verbs: - - update -- apiGroups: - - crd.antrea.io - resources: - - tiers - verbs: - - get - - watch - - list - - update - - patch - - create - - delete -- apiGroups: - - crd.antrea.io - resources: - - traceflows - - traceflows/status - verbs: - - get - - watch - - list - - update - - patch - - create - - delete -- apiGroups: - - crd.antrea.io - resources: - - externalentities - - clustergroups - verbs: - - get - - watch - - list - - update - - patch - - create - - delete -- apiGroups: - - crd.antrea.io - resources: - - clustergroups/status - verbs: - - update -- apiGroups: - - crd.antrea.io - resources: - - egresses - verbs: - - get - - watch - - list - - update - - patch -- apiGroups: - - crd.antrea.io - resources: - - externalippools - - ippools - verbs: - - get - - watch - - list -- apiGroups: - - crd.antrea.io - resources: - - externalippools/status - - ippools/status - verbs: - - update -- apiGroups: - - apps - resources: - - statefulsets - verbs: - - get - - list - - watch ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - labels: - app: antrea - name: antctl - namespace: kube-system -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: antctl -subjects: -- kind: ServiceAccount - name: antctl - namespace: kube-system ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - labels: - app: antrea - name: antrea-agent -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: antrea-agent -subjects: -- kind: ServiceAccount - name: antrea-agent - namespace: kube-system ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - labels: - app: antrea - name: antrea-controller -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: antrea-controller -subjects: -- kind: ServiceAccount - name: antrea-controller - namespace: kube-system ---- -apiVersion: v1 data: antrea-agent.conf: | # FeatureGates is a map of feature names to bools that enable or disable experimental features. @@ -2771,7 +90,8 @@ data: # Egress: true # Enable AntreaIPAM, which can allocate IP addresses from IPPools. AntreaIPAM is required by the - # bridging mode and allocates IPs to Pods in bridging mode. + # bridging mode and allocates IPs to Pods in bridging mode. It is also required to use Antrea for + # IPAM when configuring secondary network interfaces with Multus. # AntreaIPAM: false # Enable multicast traffic. This feature is supported only with noEncap mode. @@ -2785,21 +105,23 @@ data: # Enable managing external IPs of Services of LoadBalancer type. # ServiceExternalIP: false + # Enable mirroring or redirecting the traffic Pods send or receive. + # TrafficControl: false + # Name of the OpenVSwitch bridge antrea-agent will create and use. # Make sure it doesn't conflict with your existing OpenVSwitch bridges. - #ovsBridge: br-int + ovsBridge: "br-int" # Datapath type to use for the OpenVSwitch bridge created by Antrea. Supported values are: # - system # - netdev # 'system' is the default value and corresponds to the kernel datapath. Use 'netdev' to run - # OVS in userspace mode (not fully supported yet). Userspace mode requires the tun device driver to - # be available. + # OVS in userspace mode. Userspace mode requires the tun device driver to be available. #ovsDatapathType: system # Name of the interface antrea-agent will create and use for host <--> pod communication. # Make sure it doesn't conflict with your existing interfaces. - #hostGateway: antrea-gw0 + hostGateway: "antrea-gw0" # Determines how traffic is encapsulated. It has the following options: # encap(default): Inter-node Pod traffic is always encapsulated and Pod to external network @@ -2811,14 +133,14 @@ data: # networkPolicyOnly: Antrea enforces NetworkPolicy only, and utilizes CNI chaining and delegates Pod # IPAM and connectivity to the primary CNI. # - trafficEncapMode: noEncap + trafficEncapMode: "noEncap" # Whether or not to SNAT (using the Node IP) the egress traffic from a Pod to the external network. # This option is for the noEncap traffic mode only, and the default value is false. In the noEncap # mode, if the cluster's Pod CIDR is reachable from the external network, then the Pod traffic to # the external network needs not be SNAT'd. In the networkPolicyOnly mode, antrea-agent never # performs SNAT and this option will be ignored; for other modes it must be set to false. - #noSNAT: false + noSNAT: false # Tunnel protocols used for encapsulating traffic across Nodes. If WireGuard is enabled in trafficEncryptionMode, # this option will not take effect. Supported values: @@ -2827,7 +149,7 @@ data: # - gre # - stt # Note that "gre" is not supported for IPv6 clusters (IPv6-only or dual-stack clusters). - #tunnelType: geneve + tunnelType: "geneve" # Determines how tunnel traffic is encrypted. Currently encryption only works with encap mode. # It has the following options: @@ -2837,44 +159,54 @@ data: # the PSK value must be passed to Antrea Agent through an environment # variable: ANTREA_IPSEC_PSK. # - wireGuard: Enable WireGuard for tunnel traffic encryption. - #trafficEncryptionMode: none + trafficEncryptionMode: "none" # Enable bridging mode of Pod network on Nodes, in which the Node's transport interface is connected - # to the OVS bridge, and cross-Node/VLAN traffic from AntreaIPAM Pods (Pods whose IP addresses are - # allocated by AntreaIPAM from IPPools) is sent to the underlay network via the uplink, and - # forwarded/routed by the underlay network. + # to the OVS bridge, and cross-Node/VLAN traffic of AntreaIPAM Pods (Pods whose IP addresses are + # allocated by AntreaIPAM from IPPools) is sent to the underlay network, and forwarded/routed by the + # underlay network. # This option requires the `AntreaIPAM` feature gate to be enabled. At this moment, it supports only # IPv4 and Linux Nodes, and can be enabled only when `ovsDatapathType` is `system`, # `trafficEncapMode` is `noEncap`, and `noSNAT` is true. - #enableBridgingMode: false + enableBridgingMode: false + + # Disable TX checksum offloading for container network interfaces. It's supposed to be set to true when the + # datapath doesn't support TX checksum offloading, which causes packets to be dropped due to bad checksum. + # It affects Pods running on Linux Nodes only. + disableTXChecksumOffload: false # Default MTU to use for the host gateway interface and the network interface of each Pod. # If omitted, antrea-agent will discover the MTU of the Node's primary interface and # also adjust MTU to accommodate for tunnel encapsulation overhead (if applicable). - #defaultMTU: 0 + defaultMTU: 0 # wireGuard specifies WireGuard related configurations. wireGuard: - # The port for WireGuard to receive traffic. - # port: 51820 + # The port for WireGuard to receive traffic. + port: 51820 egress: - # exceptCIDRs is the CIDR ranges to which outbound Pod traffic will not be SNAT'd by Egresses. - # exceptCIDRs: [] + # exceptCIDRs is the CIDR ranges to which outbound Pod traffic will not be SNAT'd by Egresses. + exceptCIDRs: + + # ClusterIP CIDR range for Services. It's required when AntreaProxy is not enabled, and should be + # set to the same value as the one specified by --service-cluster-ip-range for kube-apiserver. When + # AntreaProxy is enabled, this parameter is not needed and will be ignored if provided. + serviceCIDR: "" # ClusterIP CIDR range for IPv6 Services. It's required when using kube-proxy to provide IPv6 Service in a Dual-Stack # cluster or an IPv6 only cluster. The value should be the same as the configuration for kube-apiserver specified by # --service-cluster-ip-range. When AntreaProxy is enabled, this parameter is not needed. # No default value for this field. - #serviceCIDRv6: + serviceCIDRv6: "" # The port for the antrea-agent APIServer to serve on. # Note that if it's set to another value, the `containerPort` of the `api` port of the # `antrea-agent` container must be set to the same value. - #apiPort: 10350 + apiPort: 10350 # Enable metrics exposure via Prometheus. Initializes Prometheus metrics listener. - #enablePrometheusMetrics: true + enablePrometheusMetrics: true # Provide the IPFIX collector address as a string with format :[][:]. # HOST can either be the DNS name or the IP of the Flow Collector. For example, @@ -2885,50 +217,50 @@ data: # If no PROTO is given, we consider "tls" as default. We support "tls", "tcp" and # "udp" protocols. "tls" is used for securing communication between flow exporter and # flow aggregator. - #flowCollectorAddr: "flow-aggregator.flow-aggregator.svc:4739:tls" + flowCollectorAddr: "flow-aggregator.flow-aggregator.svc:4739:tls" # Provide flow poll interval as a duration string. This determines how often the # flow exporter dumps connections from the conntrack module. Flow poll interval # should be greater than or equal to 1s (one second). # Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". - #flowPollInterval: "5s" + flowPollInterval: "5s" # Provide the active flow export timeout, which is the timeout after which a flow # record is sent to the collector for active flows. Thus, for flows with a continuous # stream of packets, a flow record will be exported to the collector once the elapsed # time since the last export event is equal to the value of this timeout. # Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". - #activeFlowExportTimeout: "30s" + activeFlowExportTimeout: "5s" # Provide the idle flow export timeout, which is the timeout after which a flow # record is sent to the collector for idle flows. A flow is considered idle if no # packet matching this flow has been observed since the last export event. # Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". - #idleFlowExportTimeout: "15s" + idleFlowExportTimeout: "15s" nodePortLocal: # Enable NodePortLocal, a feature used to make Pods reachable using port forwarding on the host. To # enable this feature, you need to set "enable" to true, and ensure that the NodePortLocal feature # gate is also enabled (which is the default). - # enable: false + enable: false # Provide the port range used by NodePortLocal. When the NodePortLocal feature is enabled, a port # from that range will be assigned whenever a Pod's container defines a specific port to be exposed # (each container can define a list of ports as pod.spec.containers[].ports), and all Node traffic # directed to that port will be forwarded to the Pod. - # portRange: 61000-62000 + portRange: "61000-62000" # Provide the address of Kubernetes apiserver, to override any value provided in kubeconfig or InClusterConfig. # Defaults to "". It must be a host string, a host:port pair, or a URL to the base of the apiserver. - #kubeAPIServerOverride: "" + kubeAPIServerOverride: "" # Comma-separated list of Cipher Suites. If omitted, the default Go Cipher Suites will be used. # https://golang.org/pkg/crypto/tls/#pkg-constants # Note that TLS1.3 Cipher Suites cannot be added to the list. But the apiserver will always # prefer TLS1.3 Cipher Suites whenever possible. - #tlsCipherSuites: + tlsCipherSuites: "" # TLS min version from: VersionTLS10, VersionTLS11, VersionTLS12, VersionTLS13. - #tlsMinVersion: + tlsMinVersion: "" # The name of the interface on Node which is used for tunneling or routing the traffic across Nodes. # If there are multiple IP addresses configured on the interface, the first one is used. The IP @@ -2937,11 +269,16 @@ data: # 1. transportInterface # 2. transportInterfaceCIDRs # 3. The Node IP - #transportInterface: + transportInterface: "" + multicast: # The names of the interfaces on Nodes that are used to forward multicast traffic. # Defaults to transport interface if not set. - #multicastInterfaces: [] + multicastInterfaces: + + # The interval at which the antrea-agent sends IGMP queries to Pods. + # Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". + igmpQueryInterval: "125s" # The network CIDRs of the interface on Node which is used for tunneling or routing the traffic across # Nodes. If there are multiple interfaces configured the same network CIDR, the first one is used. The @@ -2950,7 +287,7 @@ data: # 1. transportInterface # 2. transportInterfaceCIDRs # 3. The Node IP - #transportInterfaceCIDRs: [,] + transportInterfaceCIDRs: # Option antreaProxy contains AntreaProxy related configuration options. antreaProxy: @@ -2959,22 +296,22 @@ data: # feature to be enabled. # Note that this option is experimental. If kube-proxy is removed, option kubeAPIServerOverride must be used to access # apiserver directly. - #proxyAll: false + proxyAll: false # A string array of values which specifies the host IPv4/IPv6 addresses for NodePort. Values can be valid IP blocks. # (e.g. 1.2.3.0/24, 1.2.3.4/32). An empty string slice is meant to select all host IPv4/IPv6 addresses. # Note that the option is only valid when proxyAll is true. - #nodePortAddresses: [] + nodePortAddresses: # An array of string values to specify a list of Services which should be ignored by AntreaProxy (traffic to these # Services will not be load-balanced). Values can be a valid ClusterIP (e.g. 10.11.1.2) or a Service name # with Namespace (e.g. kube-system/kube-dns) - #skipServices: [] + skipServices: # When ProxyLoadBalancerIPs is set to false, AntreaProxy no longer load-balances traffic destined to the # External IPs of LoadBalancer Services. This is useful when the external LoadBalancer provides additional # capabilities (e.g. TLS termination) and it is desirable for Pod-to-ExternalIP traffic to be sent to the # external LoadBalancer instead of being load-balanced to an Endpoint directly by AntreaProxy. # Note that setting ProxyLoadBalancerIPs to false usually only makes sense when ProxyAll is set to true and # kube-proxy is removed from the cluser, otherwise kube-proxy will still load-balance this traffic. - #proxyLoadBalancerIPs: true + proxyLoadBalancerIPs: true antrea-cni.conflist: | { "cniVersion":"0.3.0", @@ -2985,11 +322,13 @@ data: "ipam": { "type": "host-local" } - }, + } + , { "type": "portmap", "capabilities": {"portMappings": true} - }, + } + , { "type": "bandwidth", "capabilities": {"bandwidth": true} @@ -3016,8 +355,9 @@ data: # Run Kubernetes NodeIPAMController with Antrea. # NodeIPAM: false - # Enable flexible IPAM mode for Antrea. This mode allows to assign IP Ranges to Namespaces, - # Deployments and StatefulSets via IP Pool annotation. + # Enable AntreaIPAM, which can allocate IP addresses from IPPools. AntreaIPAM is required by the + # bridging mode and allocates IPs to Pods in bridging mode. It is also required to use Antrea for + # IPAM when configuring secondary network interfaces with Multus. # AntreaIPAM: false # Enable managing external IPs of Services of LoadBalancer type. @@ -3026,659 +366,3674 @@ data: # The port for the antrea-controller APIServer to serve on. # Note that if it's set to another value, the `containerPort` of the `api` port of the # `antrea-controller` container must be set to the same value. - #apiPort: 10349 + apiPort: 10349 # Enable metrics exposure via Prometheus. Initializes Prometheus metrics listener. - #enablePrometheusMetrics: true + enablePrometheusMetrics: true # Indicates whether to use auto-generated self-signed TLS certificate. - # If false, A Secret named "antrea-controller-tls" must be provided with the following keys: + # If false, a Secret named "antrea-controller-tls" must be provided with the following keys: # ca.crt: # tls.crt: # tls.key: - # And the Secret must be mounted to directory "/var/run/antrea/antrea-controller-tls" of the - # antrea-controller container. - #selfSignedCert: true + selfSignedCert: true # Comma-separated list of Cipher Suites. If omitted, the default Go Cipher Suites will be used. # https://golang.org/pkg/crypto/tls/#pkg-constants # Note that TLS1.3 Cipher Suites cannot be added to the list. But the apiserver will always # prefer TLS1.3 Cipher Suites whenever possible. - #tlsCipherSuites: + tlsCipherSuites: "" # TLS min version from: VersionTLS10, VersionTLS11, VersionTLS12, VersionTLS13. - #tlsMinVersion: + tlsMinVersion: "" nodeIPAM: - # Enable the integrated Node IPAM controller within the Antrea controller. - # enableNodeIPAM: false - - # CIDR ranges for Pods in cluster. String array containing single CIDR range, or multiple ranges. - # The CIDRs could be either IPv4 or IPv6. At most one CIDR may be specified for each IP family. - # Value ignored when enableNodeIPAM is false. - # clusterCIDRs: [] - - # CIDR ranges for Services in cluster. It is not necessary to specify it when there is no overlap with clusterCIDRs. - # Value ignored when enableNodeIPAM is false. - # serviceCIDR: - # serviceCIDRv6: - - # Mask size for IPv4 Node CIDR in IPv4 or dual-stack cluster. Value ignored when enableNodeIPAM is false - # or when IPv4 Pod CIDR is not configured. Valid range is 16 to 30. - # nodeCIDRMaskSizeIPv4: 24 - - # Mask size for IPv6 Node CIDR in IPv6 or dual-stack cluster. Value ignored when enableNodeIPAM is false - # or when IPv6 Pod CIDR is not configured. Valid range is 64 to 126. - # nodeCIDRMaskSizeIPv6: 64 -kind: ConfigMap + # Enable the integrated Node IPAM controller within the Antrea controller. + enableNodeIPAM: false + # CIDR ranges for Pods in cluster. String array containing single CIDR range, or multiple ranges. + # The CIDRs could be either IPv4 or IPv6. At most one CIDR may be specified for each IP family. + # Value ignored when enableNodeIPAM is false. + clusterCIDRs: + # CIDR ranges for Services in cluster. It is not necessary to specify it when there is no overlap with clusterCIDRs. + # Value ignored when enableNodeIPAM is false. + serviceCIDR: "" + serviceCIDRv6: "" + # Mask size for IPv4 Node CIDR in IPv4 or dual-stack cluster. Value ignored when enableNodeIPAM is false + # or when IPv4 Pod CIDR is not configured. Valid range is 16 to 30. + nodeCIDRMaskSizeIPv4: 24 + # Mask size for IPv6 Node CIDR in IPv6 or dual-stack cluster. Value ignored when enableNodeIPAM is false + # or when IPv6 Pod CIDR is not configured. Valid range is 64 to 126. + nodeCIDRMaskSizeIPv6: 64 +--- +# Source: antrea/templates/crds/antreaagentinfo.yaml +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: antreaagentinfos.crd.antrea.io + labels: + app: antrea +spec: + group: crd.antrea.io + versions: + - name: v1beta1 + served: true + storage: true + schema: + openAPIV3Schema: + type: object + x-kubernetes-preserve-unknown-fields: true + additionalPrinterColumns: + - description: Health status of this Agent + jsonPath: ".agentConditions[?(@.type=='AgentHealthy')].status" + name: Healthy + type: string + - description: Last time the Healthy Condition was updated + jsonPath: ".agentConditions[?(@.type=='AgentHealthy')].lastHeartbeatTime" + name: Last Heartbeat + type: date + - description: Version of this Agent + jsonPath: ".version" + name: Version + type: string + priority: 1 + - description: Node on which this Agent is running + jsonPath: ".nodeRef.name" + name: Node + type: string + priority: 1 + - description: Number of local Pods managed by this Agent + jsonPath: ".localPodNum" + name: Num Pods + type: integer + priority: 2 + - description: Subnets used by this Agent for Pod IPAM + jsonPath: ".nodeSubnets" + name: Subnets + type: string + priority: 2 + scope: Cluster + names: + plural: antreaagentinfos + singular: antreaagentinfo + kind: AntreaAgentInfo + shortNames: + - aai +--- +# Source: antrea/templates/crds/antreacontrollerinfo.yaml +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: antreacontrollerinfos.crd.antrea.io + labels: + app: antrea +spec: + group: crd.antrea.io + versions: + - name: v1beta1 + served: true + storage: true + schema: + openAPIV3Schema: + type: object + x-kubernetes-preserve-unknown-fields: true + additionalPrinterColumns: + - description: Health status of the Controller + jsonPath: ".controllerConditions[?(@.type=='ControllerHealthy')].status" + name: Healthy + type: string + - description: Last time the Healthy Condition was updated + jsonPath: ".controllerConditions[?(@.type=='ControllerHealthy')].lastHeartbeatTime" + name: Last Heartbeat + type: date + - description: Version of the Controller + jsonPath: ".version" + name: Version + type: string + priority: 1 + - description: Number of Agents connected to the Controller + jsonPath: ".connectedAgentNum" + name: Connected Agents + type: integer + priority: 1 + - description: Node on which the Controller is running + jsonPath: ".nodeRef.name" + name: Node + type: string + priority: 1 + - description: Number of Network Policies computed by Controller + jsonPath: ".networkPolicyControllerInfo.networkPolicyNum" + name: Num Network Policies + type: integer + priority: 2 + scope: Cluster + names: + plural: antreacontrollerinfos + singular: antreacontrollerinfo + kind: AntreaControllerInfo + shortNames: + - aci +--- +# Source: antrea/templates/crds/clustergroup.yaml +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: clustergroups.crd.antrea.io + labels: + app: antrea +spec: + group: crd.antrea.io + versions: + - name: v1alpha2 + served: true + storage: false + schema: + openAPIV3Schema: + type: object + properties: + spec: + type: object + properties: + childGroups: + type: array + items: + type: string + podSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + externalEntitySelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + ipBlock: + type: object + properties: + cidr: + type: string + format: cidr + ipBlocks: + type: array + items: + type: object + properties: + cidr: + type: string + format: cidr + serviceReference: + type: object + properties: + name: + type: string + namespace: + type: string + status: + type: object + properties: + conditions: + type: array + items: + type: object + properties: + type: + type: string + status: + type: string + lastTransitionTime: + type: string + - name: v1alpha3 + served: true + storage: true + schema: + openAPIV3Schema: + type: object + properties: + spec: + type: object + properties: + childGroups: + type: array + items: + type: string + podSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + externalEntitySelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + ipBlocks: + type: array + items: + type: object + properties: + cidr: + type: string + format: cidr + serviceReference: + type: object + properties: + name: + type: string + namespace: + type: string + status: + type: object + properties: + conditions: + type: array + items: + type: object + properties: + type: + type: string + status: + type: string + lastTransitionTime: + type: string + subresources: + status: {} + conversion: + strategy: Webhook + webhook: + conversionReviewVersions: ["v1", "v1beta1"] + clientConfig: + service: + name: "antrea" + namespace: "kube-system" + path: "/convert/clustergroup" + scope: Cluster + names: + plural: clustergroups + singular: clustergroup + kind: ClusterGroup + shortNames: + - cg +--- +# Source: antrea/templates/crds/clusternetworkpolicy.yaml +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: clusternetworkpolicies.crd.antrea.io + labels: + app: antrea +spec: + group: crd.antrea.io + versions: + - name: v1alpha1 + served: true + storage: true + additionalPrinterColumns: + - name: Tier + type: string + description: The Tier to which this ClusterNetworkPolicy belongs to. + jsonPath: .spec.tier + - name: Priority + type: number + format: float + description: The Priority of this ClusterNetworkPolicy relative to other policies. + jsonPath: .spec.priority + - name: Desired Nodes + type: number + format: int32 + description: The total number of Nodes that should realize the NetworkPolicy. + jsonPath: .status.desiredNodesRealized + - name: Current Nodes + type: number + format: int32 + description: The number of Nodes that have realized the NetworkPolicy. + jsonPath: .status.currentNodesRealized + - name: Age + type: date + jsonPath: .metadata.creationTimestamp + schema: + openAPIV3Schema: + type: object + properties: + spec: + # Ensure that Spec.Priority field is set + required: + - priority + type: object + properties: + tier: + type: string + priority: + type: number + format: float + # Ensure that Spec.Priority field is between 1 and 10000 + minimum: 1.0 + maximum: 10000.0 + appliedTo: + type: array + items: + type: object + # Ensure that Spec.AppliedTo does not allow IPBlock field + properties: + podSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + group: + type: string + serviceAccount: + type: object + properties: + name: + type: string + namespace: + type: string + required: + - name + - namespace + ingress: + type: array + items: + type: object + required: + - action + properties: + appliedTo: + type: array + items: + type: object + # Ensure that rule AppliedTo does not allow IPBlock field + properties: + podSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + group: + type: string + serviceAccount: + type: object + properties: + name: + type: string + namespace: + type: string + required: + - name + - namespace + # Ensure that Action field allows only ALLOW, DROP, REJECT and PASS values + action: + type: string + enum: ['Allow', 'Drop', 'Reject', 'Pass'] + ports: + type: array + items: + type: object + properties: + protocol: + type: string + enum: ['TCP', 'UDP', 'SCTP'] + port: + x-kubernetes-int-or-string: true + endPort: + type: integer + protocols: + type: array + items: + type: object + oneOf: + - required: [icmp] + properties: + icmp: + type: object + properties: + icmpType: + type: integer + minimum: 0 + maximum: 255 + icmpCode: + type: integer + minimum: 0 + maximum: 255 + from: + type: array + items: + type: object + properties: + podSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + namespaces: + type: object + properties: + match: + enum: + - Self + type: string + ipBlock: + type: object + properties: + cidr: + type: string + format: cidr + group: + type: string + serviceAccount: + type: object + properties: + name: + type: string + namespace: + type: string + required: + - name + - namespace + nodeSelector: + type: object + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + type: array + type: object + type: array + matchLabels: + x-kubernetes-preserve-unknown-fields: true + name: + type: string + enableLogging: + type: boolean + egress: + type: array + items: + type: object + required: + - action + properties: + appliedTo: + type: array + items: + type: object + # Ensure that rule AppliedTo does not allow IPBlock field + properties: + podSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + group: + type: string + serviceAccount: + type: object + properties: + name: + type: string + namespace: + type: string + required: + - name + - namespace + # Ensure that Action field allows only ALLOW, DROP, REJECT and PASS values + action: + type: string + enum: ['Allow', 'Drop', 'Reject', 'Pass'] + ports: + type: array + items: + type: object + properties: + protocol: + type: string + enum: ['TCP', 'UDP', 'SCTP'] + port: + x-kubernetes-int-or-string: true + endPort: + type: integer + protocols: + type: array + items: + type: object + oneOf: + - required: [icmp] + properties: + icmp: + type: object + properties: + icmpType: + type: integer + minimum: 0 + maximum: 255 + icmpCode: + type: integer + minimum: 0 + maximum: 255 + to: + type: array + items: + type: object + properties: + podSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + namespaces: + type: object + properties: + match: + enum: + - Self + type: string + ipBlock: + type: object + properties: + cidr: + type: string + format: cidr + group: + type: string + fqdn: + type: string + serviceAccount: + type: object + properties: + name: + type: string + namespace: + type: string + required: + - name + - namespace + nodeSelector: + type: object + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + type: array + type: object + type: array + matchLabels: + x-kubernetes-preserve-unknown-fields: true + toServices: + type: array + items: + type: object + required: + - name + - namespace + properties: + name: + type: string + namespace: + type: string + name: + type: string + enableLogging: + type: boolean + status: + type: object + properties: + phase: + type: string + observedGeneration: + type: integer + currentNodesRealized: + type: integer + desiredNodesRealized: + type: integer + subresources: + status: {} + scope: Cluster + names: + plural: clusternetworkpolicies + singular: clusternetworkpolicy + kind: ClusterNetworkPolicy + shortNames: + - acnp +--- +# Source: antrea/templates/crds/egress.yaml +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: egresses.crd.antrea.io + labels: + app: antrea +spec: + group: crd.antrea.io + versions: + - name: v1alpha2 + served: true + storage: true + schema: + openAPIV3Schema: + type: object + required: + - spec + properties: + spec: + type: object + required: + - appliedTo + anyOf: + - required: + - egressIP + - required: + - externalIPPool + properties: + appliedTo: + type: object + properties: + podSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + egressIP: + type: string + oneOf: + - format: ipv4 + - format: ipv6 + externalIPPool: + type: string + status: + type: object + properties: + egressNode: + type: string + additionalPrinterColumns: + - description: Specifies the SNAT IP address for the selected workloads. + jsonPath: .spec.egressIP + name: EgressIP + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + - description: The Owner Node of egress IP + jsonPath: .status.egressNode + name: Node + type: string + subresources: + status: {} + scope: Cluster + names: + plural: egresses + singular: egress + kind: Egress + shortNames: + - eg +--- +# Source: antrea/templates/crds/externalentity.yaml +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: externalentities.crd.antrea.io + labels: + app: antrea +spec: + group: crd.antrea.io + versions: + - name: v1alpha2 + served: true + storage: true + schema: + openAPIV3Schema: + type: object + properties: + spec: + type: object + properties: + endpoints: + type: array + items: + type: object + properties: + ip: + type: string + oneOf: + - format: ipv4 + - format: ipv6 + name: + type: string + ports: + type: array + items: + type: object + properties: + protocol: + type: string + enum: ['TCP', 'UDP', 'SCTP'] + port: + x-kubernetes-int-or-string: true + name: + type: string + externalNode: + type: string + - name: v1alpha1 + served: false + storage: false + schema: + openAPIV3Schema: + type: object + scope: Namespaced + names: + plural: externalentities + singular: externalentity + kind: ExternalEntity + shortNames: + - ee +--- +# Source: antrea/templates/crds/externalippool.yaml +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: externalippools.crd.antrea.io + labels: + app: antrea +spec: + group: crd.antrea.io + versions: + - name: v1alpha2 + served: true + storage: true + schema: + openAPIV3Schema: + type: object + required: + - spec + properties: + spec: + type: object + required: + - ipRanges + - nodeSelector + properties: + ipRanges: + type: array + items: + type: object + oneOf: + - required: + - cidr + - required: + - start + - end + properties: + cidr: + type: string + format: cidr + start: + type: string + oneOf: + - format: ipv4 + - format: ipv6 + end: + type: string + oneOf: + - format: ipv4 + - format: ipv6 + nodeSelector: + type: object + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + type: array + type: object + type: array + matchLabels: + x-kubernetes-preserve-unknown-fields: true + status: + type: object + properties: + usage: + type: object + properties: + total: + type: integer + used: + type: integer + additionalPrinterColumns: + - description: The number of total IPs + jsonPath: .status.usage.total + name: Total + type: integer + - description: The number of allocated IPs + jsonPath: .status.usage.used + name: Used + type: integer + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + subresources: + status: {} + scope: Cluster + names: + plural: externalippools + singular: externalippool + kind: ExternalIPPool + shortNames: + - eip +--- +# Source: antrea/templates/crds/ippool.yaml +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: ippools.crd.antrea.io + labels: + app: antrea +spec: + group: crd.antrea.io + versions: + - name: v1alpha2 + served: true + storage: true + schema: + openAPIV3Schema: + type: object + required: + - spec + properties: + spec: + required: + - ipVersion + - ipRanges + type: object + properties: + ipVersion: + type: integer + ipRanges: + items: + oneOf: + - required: + - cidr + - gateway + - prefixLength + - required: + - start + - end + - gateway + - prefixLength + properties: + cidr: + format: cidr + type: string + start: + oneOf: + - format: ipv4 + - format: ipv6 + type: string + end: + oneOf: + - format: ipv4 + - format: ipv6 + type: string + gateway: + oneOf: + - format: ipv4 + - format: ipv6 + type: string + prefixLength: + type: integer + vlan: + type: integer + minimum: 0 + maximum: 4094 + type: object + type: array + status: + properties: + ipAddresses: + items: + properties: + ipAddress: + type: string + owner: + properties: + pod: + properties: + name: + type: string + namespace: + type: string + containerID: + type: string + ifName: + type: string + type: object + statefulSet: + properties: + name: + type: string + namespace: + type: string + index: + type: integer + type: object + type: object + phase: + type: string + type: object + type: array + type: object + subresources: + status: {} + scope: Cluster + names: + plural: ippools + singular: ippool + kind: IPPool + shortNames: + - ipp +--- +# Source: antrea/templates/crds/networkpolicy.yaml +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: networkpolicies.crd.antrea.io + labels: + app: antrea +spec: + group: crd.antrea.io + versions: + - name: v1alpha1 + served: true + storage: true + additionalPrinterColumns: + - name: Tier + type: string + description: The Tier to which this Antrea NetworkPolicy belongs to. + jsonPath: .spec.tier + - name: Priority + type: number + format: float + description: The Priority of this Antrea NetworkPolicy relative to other policies. + jsonPath: .spec.priority + - name: Desired Nodes + type: number + format: int32 + description: The total number of Nodes that should realize the NetworkPolicy. + jsonPath: .status.desiredNodesRealized + - name: Current Nodes + type: number + format: int32 + description: The number of Nodes that have realized the NetworkPolicy. + jsonPath: .status.currentNodesRealized + - name: Age + type: date + jsonPath: .metadata.creationTimestamp + schema: + openAPIV3Schema: + type: object + properties: + spec: + # Ensure that Spec.Priority field is set + required: + - priority + type: object + properties: + tier: + type: string + priority: + type: number + format: float + # Ensure that Spec.Priority field is between 1 and 10000 + minimum: 1.0 + maximum: 10000.0 + appliedTo: + type: array + items: + type: object + # Ensure that Spec.AppliedTo does not allow NamespaceSelector/IPBlock field + properties: + podSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + ingress: + type: array + items: + type: object + required: + - action + properties: + appliedTo: + type: array + items: + type: object + # Ensure that rule AppliedTo does not allow NamespaceSelector/IPBlock field + properties: + podSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + # Ensure that Action field allows only ALLOW, DROP, REJECT and PASS values + action: + type: string + enum: ['Allow', 'Drop', 'Reject', 'Pass'] + ports: + type: array + items: + type: object + properties: + protocol: + type: string + enum: ['TCP', 'UDP', 'SCTP'] + port: + x-kubernetes-int-or-string: true + endPort: + type: integer + protocols: + type: array + items: + type: object + oneOf: + - required: [icmp] + properties: + icmp: + type: object + properties: + icmpType: + type: integer + minimum: 0 + maximum: 255 + icmpCode: + type: integer + minimum: 0 + maximum: 255 + from: + type: array + items: + type: object + properties: + podSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + externalEntitySelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + ipBlock: + type: object + properties: + cidr: + type: string + format: cidr + nodeSelector: + type: object + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + type: array + type: object + type: array + matchLabels: + x-kubernetes-preserve-unknown-fields: true + name: + type: string + enableLogging: + type: boolean + egress: + type: array + items: + type: object + required: + - action + properties: + appliedTo: + type: array + items: + type: object + # Ensure that rule AppliedTo does not allow NamespaceSelector/IPBlock field + properties: + podSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + # Ensure that Action field allows only ALLOW, DROP, REJECT and PASS values + action: + type: string + enum: ['Allow', 'Drop', 'Reject', 'Pass'] + ports: + type: array + items: + type: object + properties: + protocol: + type: string + enum: ['TCP', 'UDP', 'SCTP'] + port: + x-kubernetes-int-or-string: true + endPort: + type: integer + protocols: + type: array + items: + type: object + oneOf: + - required: [icmp] + properties: + icmp: + type: object + properties: + icmpType: + type: integer + minimum: 0 + maximum: 255 + icmpCode: + type: integer + minimum: 0 + maximum: 255 + to: + type: array + items: + type: object + properties: + podSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + externalEntitySelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + ipBlock: + type: object + properties: + cidr: + type: string + format: cidr + fqdn: + type: string + nodeSelector: + type: object + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + type: array + type: object + type: array + matchLabels: + x-kubernetes-preserve-unknown-fields: true + toServices: + type: array + items: + type: object + required: + - name + properties: + name: + type: string + namespace: + type: string + name: + type: string + enableLogging: + type: boolean + status: + type: object + properties: + phase: + type: string + observedGeneration: + type: integer + currentNodesRealized: + type: integer + desiredNodesRealized: + type: integer + subresources: + status: {} + scope: Namespaced + names: + plural: networkpolicies + singular: networkpolicy + kind: NetworkPolicy + shortNames: + - anp +--- +# Source: antrea/templates/crds/tier.yaml +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: tiers.crd.antrea.io + labels: + app: antrea +spec: + group: crd.antrea.io + versions: + - name: v1alpha1 + served: true + storage: true + additionalPrinterColumns: + - name: Priority + type: integer + description: The Priority of this Tier relative to other Tiers. + jsonPath: .spec.priority + - name: Age + type: date + jsonPath: .metadata.creationTimestamp + schema: + openAPIV3Schema: + type: object + properties: + spec: + required: + - priority + type: object + properties: + priority: + type: integer + minimum: 0 + maximum: 255 + description: + type: string + scope: Cluster + names: + plural: tiers + singular: tier + kind: Tier + shortNames: + - tr +--- +# Source: antrea/templates/crds/traceflow.yaml +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: traceflows.crd.antrea.io + labels: + app: antrea +spec: + group: crd.antrea.io + versions: + - name: v1alpha1 + served: true + storage: true + additionalPrinterColumns: + - jsonPath: .status.phase + description: The phase of the Traceflow. + name: Phase + type: string + - jsonPath: .spec.source.pod + description: The name of the source Pod. + name: Source-Pod + type: string + priority: 10 + - jsonPath: .spec.destination.pod + description: The name of the destination Pod. + name: Destination-Pod + type: string + priority: 10 + - jsonPath: .spec.destination.ip + description: The IP address of the destination. + name: Destination-IP + type: string + priority: 10 + - jsonPath: .spec.liveTraffic + description: Trace live traffic. + name: Live-Traffic + type: boolean + priority: 10 + - jsonPath: .spec.droppedOnly + description: Capture only the dropped packet. + name: Dropped-Only + type: boolean + priority: 10 + - jsonPath: .spec.timeout + description: Timeout in seconds. + name: Timeout + type: integer + priority: 10 + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + schema: + openAPIV3Schema: + type: object + required: + - spec + properties: + spec: + type: object + properties: + source: + type: object + properties: + pod: + type: string + namespace: + type: string + ip: + type: string + oneOf: + - format: ipv4 + - format: ipv6 + destination: + type: object + properties: + pod: + type: string + service: + type: string + namespace: + type: string + ip: + type: string + oneOf: + - format: ipv4 + - format: ipv6 + packet: + type: object + properties: + ipHeader: + type: object + properties: + srcIP: + type: string + oneOf: + - format: ipv4 + - format: ipv6 + protocol: + type: integer + ttl: + type: integer + flags: + type: integer + ipv6Header: + type: object + properties: + srcIP: + type: string + format: ipv6 + nextHeader: + type: integer + hopLimit: + type: integer + transportHeader: + type: object + properties: + icmp: + type: object + properties: + id: + type: integer + sequence: + type: integer + udp: + type: object + properties: + srcPort: + type: integer + dstPort: + type: integer + tcp: + type: object + properties: + srcPort: + type: integer + dstPort: + type: integer + flags: + type: integer + liveTraffic: + type: boolean + droppedOnly: + type: boolean + timeout: + type: integer + status: + type: object + properties: + reason: + type: string + dataplaneTag: + type: integer + phase: + type: string + startTime: + type: string + results: + type: array + items: + type: object + properties: + node: + type: string + role: + type: string + timestamp: + type: integer + observations: + type: array + items: + type: object + properties: + component: + type: string + componentInfo: + type: string + action: + type: string + pod: + type: string + dstMAC: + type: string + networkPolicy: + type: string + ttl: + type: integer + translatedSrcIP: + type: string + translatedDstIP: + type: string + tunnelDstIP: + type: string + capturedPacket: + properties: + srcIP: + type: string + dstIP: + type: string + length: + type: integer + ipHeader: + properties: + flags: + type: integer + protocol: + type: integer + ttl: + type: integer + type: object + ipv6Header: + properties: + hopLimit: + type: integer + nextHeader: + type: integer + type: object + transportHeader: + properties: + tcp: + properties: + dstPort: + type: integer + srcPort: + type: integer + flags: + type: integer + type: object + udp: + properties: + dstPort: + type: integer + srcPort: + type: integer + type: object + icmp: + properties: + id: + type: integer + sequence: + type: integer + type: object + type: object + type: object + subresources: + status: {} + scope: Cluster + names: + plural: traceflows + singular: traceflow + kind: Traceflow + shortNames: + - tf +--- +# Source: antrea/templates/crds/trafficcontrol.yaml +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: trafficcontrols.crd.antrea.io +spec: + group: crd.antrea.io + versions: + - name: v1alpha2 + served: true + storage: true + schema: + openAPIV3Schema: + type: object + required: + - spec + properties: + spec: + type: object + required: + - appliedTo + - direction + - action + - targetPort + properties: + appliedTo: + type: object + properties: + podSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + direction: + type: string + enum: + - Ingress + - Egress + - Both + action: + type: string + enum: + - Mirror + - Redirect + targetPort: + type: object + oneOf: + - required: [ovsInternal] + - required: [device] + - required: [geneve] + - required: [vxlan] + - required: [gre] + - required: [erspan] + properties: + ovsInternal: + type: object + required: + - name + properties: + name: + type: string + device: + type: object + required: + - name + properties: + name: + type: string + geneve: + type: object + required: + - remoteIP + properties: + remoteIP: + type: string + oneOf: + - format: ipv4 + - format: ipv6 + vni: + type: integer + minimum: 0 + maximum: 16777215 + destinationPort: + type: integer + minimum: 1 + maximum: 65535 + vxlan: + type: object + required: + - remoteIP + properties: + remoteIP: + type: string + oneOf: + - format: ipv4 + - format: ipv6 + vni: + type: integer + minimum: 0 + maximum: 16777215 + destinationPort: + type: integer + minimum: 1 + maximum: 65535 + gre: + type: object + required: + - remoteIP + properties: + remoteIP: + type: string + oneOf: + - format: ipv4 + - format: ipv6 + key: + type: integer + minimum: 0 + maximum: 4294967295 + erspan: + type: object + required: + - remoteIP + - version + properties: + remoteIP: + type: string + oneOf: + - format: ipv4 + - format: ipv6 + sessionID: + type: integer + minimum: 0 + maximum: 1023 + version: + type: integer + enum: + - 1 + - 2 + index: + type: integer + dir: + type: integer + enum: + - 0 + - 1 + hardwareID: + type: integer + returnPort: + type: object + oneOf: + - required: [ovsInternal] + - required: [device] + - required: [geneve] + - required: [vxlan] + - required: [gre] + properties: + ovsInternal: + type: object + required: + - name + properties: + name: + type: string + device: + type: object + required: + - name + properties: + name: + type: string + geneve: + type: object + required: + - remoteIP + properties: + remoteIP: + type: string + oneOf: + - format: ipv4 + - format: ipv6 + vni: + type: integer + minimum: 0 + maximum: 16777215 + destinationPort: + type: integer + minimum: 1 + maximum: 65535 + vxlan: + type: object + required: + - remoteIP + properties: + remoteIP: + type: string + oneOf: + - format: ipv4 + - format: ipv6 + vni: + type: integer + minimum: 0 + maximum: 16777215 + destinationPort: + type: integer + minimum: 1 + maximum: 65535 + gre: + type: object + required: + - remoteIP + properties: + remoteIP: + type: string + oneOf: + - format: ipv4 + - format: ipv6 + key: + type: integer + minimum: 0 + maximum: 4294967295 + additionalPrinterColumns: + - description: Specifies the direction of traffic that should be matched. + jsonPath: .spec.direction + name: Direction + type: string + - description: Specifies the action that should be taken for the traffic. + jsonPath: .spec.action + name: Action + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + subresources: + status: {} + scope: Cluster + names: + plural: trafficcontrols + singular: trafficcontrol + kind: TrafficControl + shortNames: + - tc +--- +# Source: antrea/templates/agent/clusterrole.yaml +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: antrea-agent + labels: + app: antrea +rules: + - apiGroups: + - "" + resources: + - nodes + verbs: + - get + - watch + - list + - apiGroups: + - "" + resources: + - nodes/status + verbs: + - patch + - apiGroups: + - "" + resources: + - pods + verbs: + - get + - watch + - list + - apiGroups: + - "" + resources: + - pods/status + verbs: + - patch + - apiGroups: + - "" + resources: + - endpoints + - services + - namespaces + verbs: + - get + - watch + - list + - apiGroups: + - discovery.k8s.io + resources: + - endpointslices + verbs: + - get + - watch + - list + - apiGroups: + - crd.antrea.io + resources: + - antreaagentinfos + verbs: + - get + - create + - update + - delete + - apiGroups: + - controlplane.antrea.io + resources: + - networkpolicies + - appliedtogroups + - addressgroups + verbs: + - get + - watch + - list + - apiGroups: + - controlplane.antrea.io + resources: + - egressgroups + verbs: + - get + - watch + - list + - apiGroups: + - controlplane.antrea.io + resources: + - nodestatssummaries + verbs: + - create + - apiGroups: + - controlplane.antrea.io + resources: + - networkpolicies/status + verbs: + - create + - get + - apiGroups: + - authentication.k8s.io + resources: + - tokenreviews + verbs: + - create + - apiGroups: + - authorization.k8s.io + resources: + - subjectaccessreviews + verbs: + - create + # This is the content of built-in role kube-system/extension-apiserver-authentication-reader. + # But it doesn't have list/watch permission before K8s v1.17.0 so the extension apiserver (antrea-agent) will + # have permission issue after bumping up apiserver library to a version that supports dynamic authentication. + # See https://github.com/kubernetes/kubernetes/pull/85375 + # To support K8s clusters older than v1.17.0, we grant the required permissions directly instead of relying on + # the extension-apiserver-authentication role. + - apiGroups: + - "" + resourceNames: + - extension-apiserver-authentication + resources: + - configmaps + verbs: + - get + - list + - watch + - apiGroups: + - "" + resources: + - configmaps + resourceNames: + - antrea-ca + verbs: + - get + - watch + - list + - apiGroups: + - crd.antrea.io + resources: + - traceflows + - traceflows/status + verbs: + - get + - watch + - list + - update + - patch + - create + - delete + - apiGroups: + - crd.antrea.io + resources: + - egresses + verbs: + - get + - watch + - list + - apiGroups: + - crd.antrea.io + resources: + - egresses/status + verbs: + - update + - apiGroups: + - crd.antrea.io + resources: + - externalippools + - ippools + - trafficcontrols + verbs: + - get + - watch + - list + - apiGroups: + - crd.antrea.io + resources: + - ippools/status + verbs: + - update + - apiGroups: + - k8s.cni.cncf.io + resources: + - network-attachment-definitions + verbs: + - get + - list + - watch +--- +# Source: antrea/templates/antctl/clusterrole.yaml +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: antctl + labels: + app: antrea +rules: + - apiGroups: + - controlplane.antrea.io + resources: + - networkpolicies + - appliedtogroups + - addressgroups + verbs: + - get + - list + - apiGroups: + - stats.antrea.io + resources: + - networkpolicystats + - antreaclusternetworkpolicystats + - antreanetworkpolicystats + verbs: + - get + - list + - apiGroups: + - system.antrea.io + resources: + - controllerinfos + - agentinfos + verbs: + - get + - apiGroups: + - system.antrea.io + resources: + - supportbundles + verbs: + - get + - post + - apiGroups: + - system.antrea.io + resources: + - supportbundles/download + verbs: + - get + - nonResourceURLs: + - /agentinfo + - /addressgroups + - /appliedtogroups + - /loglevel + - /networkpolicies + - /ovsflows + - /ovstracing + - /podinterfaces + - /featuregates + - /serviceexternalip + verbs: + - get +--- +# Source: antrea/templates/cluster-identity-reader/clusterrolebinding.yaml +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: antrea-cluster-identity-reader + labels: + app: antrea +rules: + - apiGroups: + - "" + resources: + - configmaps + resourceNames: + - antrea-cluster-identity + verbs: + - get +--- +# Source: antrea/templates/controller/clusterrole.yaml +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: antrea-controller + labels: + app: antrea +rules: + - apiGroups: + - "" + resources: + - pods + - services + - namespaces + - configmaps + verbs: + - get + - watch + - list + - apiGroups: + - "" + resources: + - nodes + verbs: + - get + - watch + - list + - patch + - apiGroups: + - "" + resources: + - services/status + verbs: + - update + - apiGroups: + - networking.k8s.io + resources: + - networkpolicies + verbs: + - get + - watch + - list + - apiGroups: + - authentication.k8s.io + resources: + - tokenreviews + verbs: + - create + - apiGroups: + - authorization.k8s.io + resources: + - subjectaccessreviews + verbs: + - create + - apiGroups: + - apiextensions.k8s.io + resources: + - customresourcedefinitions + verbs: + - get + - update + # This is the content of built-in role kube-system/extension-apiserver-authentication-reader. + # But it doesn't have list/watch permission before K8s v1.17.0 so the extension apiserver (antrea-controller) will + # have permission issue after bumping up apiserver library to a version that supports dynamic authentication. + # See https://github.com/kubernetes/kubernetes/pull/85375 + # To support K8s clusters older than v1.17.0, we grant the required permissions directly instead of relying on + # the extension-apiserver-authentication role. + - apiGroups: + - "" + resourceNames: + - extension-apiserver-authentication + resources: + - configmaps + verbs: + - get + - list + - watch + - apiGroups: + - "" + resources: + - configmaps + resourceNames: + - antrea-ca + - antrea-cluster-identity + verbs: + - get + - update + - apiGroups: + - "" + resources: + - configmaps + verbs: + - create + - apiGroups: + - apiregistration.k8s.io + resources: + - apiservices + resourceNames: + - v1alpha1.stats.antrea.io + - v1beta1.system.antrea.io + - v1beta2.controlplane.antrea.io + verbs: + - get + - update + - apiGroups: + - apiregistration.k8s.io + resources: + - apiservices + resourceNames: + - v1beta1.networking.antrea.tanzu.vmware.com + - v1beta1.controlplane.antrea.tanzu.vmware.com + - v1alpha1.stats.antrea.tanzu.vmware.com + - v1beta1.system.antrea.tanzu.vmware.com + - v1beta2.controlplane.antrea.tanzu.vmware.com + verbs: + - delete + - apiGroups: + - admissionregistration.k8s.io + resources: + - mutatingwebhookconfigurations + - validatingwebhookconfigurations + resourceNames: + # always give permissions for labelsmutator.antrea.io, even when the + # feature is disabled, to avoid errors in antrea-controller when updating + # the CA cert. + - labelsmutator.antrea.io + - crdmutator.antrea.io + - crdvalidator.antrea.io + verbs: + - get + - update + - apiGroups: + - crd.antrea.io + resources: + - antreacontrollerinfos + verbs: + - get + - create + - update + - delete + - apiGroups: + - crd.antrea.io + resources: + - antreaagentinfos + verbs: + - list + - delete + - apiGroups: + - crd.antrea.io + resources: + - clusternetworkpolicies + - networkpolicies + verbs: + - get + - watch + - list + - update + - patch + - create + - delete + - apiGroups: + - crd.antrea.io + resources: + - clusternetworkpolicies/status + - networkpolicies/status + verbs: + - update + - apiGroups: + - crd.antrea.io + resources: + - tiers + verbs: + - get + - watch + - list + - update + - patch + - create + - delete + - apiGroups: + - crd.antrea.io + resources: + - traceflows + - traceflows/status + verbs: + - get + - watch + - list + - update + - patch + - create + - delete + - apiGroups: + - crd.antrea.io + resources: + - externalentities + - clustergroups + verbs: + - get + - watch + - list + - update + - patch + - create + - delete + - apiGroups: + - crd.antrea.io + resources: + - clustergroups/status + verbs: + - update + - apiGroups: + - crd.antrea.io + resources: + - egresses + verbs: + - get + - watch + - list + - update + - patch + - apiGroups: + - crd.antrea.io + resources: + - externalippools + - ippools + verbs: + - get + - watch + - list + - apiGroups: + - crd.antrea.io + resources: + - externalippools/status + - ippools/status + verbs: + - update + - apiGroups: + - apps + resources: + - statefulsets + verbs: + - get + - list + - watch +--- +# Source: antrea/templates/crds-rbac/clusterroles.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole metadata: + name: aggregate-antrea-policies-edit labels: app: antrea - name: antrea-config-c9ck44454h - namespace: kube-system + # Add these permissions to the "admin" and "edit" default roles. + rbac.authorization.k8s.io/aggregate-to-admin: "true" + rbac.authorization.k8s.io/aggregate-to-edit: "true" +rules: +- apiGroups: ["crd.antrea.io"] + resources: ["clusternetworkpolicies", "networkpolicies"] + verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] --- -apiVersion: v1 -kind: Service +# Source: antrea/templates/crds-rbac/clusterroles.yaml +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: aggregate-antrea-policies-view + labels: + app: antrea + # Add these permissions to the "view" default role. + rbac.authorization.k8s.io/aggregate-to-view: "true" +rules: +- apiGroups: ["crd.antrea.io"] + resources: ["clusternetworkpolicies", "networkpolicies"] + verbs: ["get", "list", "watch"] +--- +# Source: antrea/templates/crds-rbac/clusterroles.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: aggregate-traceflows-edit + labels: + app: antrea + # Add these permissions to the "admin" and "edit" default roles. + rbac.authorization.k8s.io/aggregate-to-admin: "true" + rbac.authorization.k8s.io/aggregate-to-edit: "true" +rules: +- apiGroups: ["crd.antrea.io"] + resources: ["traceflows"] + verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] +--- +# Source: antrea/templates/crds-rbac/clusterroles.yaml +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 metadata: + name: aggregate-traceflows-view + labels: + app: antrea + # Add these permissions to the "view" default role. + rbac.authorization.k8s.io/aggregate-to-view: "true" +rules: +- apiGroups: ["crd.antrea.io"] + resources: ["traceflows"] + verbs: ["get", "list", "watch"] +--- +# Source: antrea/templates/crds-rbac/clusterroles.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: aggregate-antrea-clustergroups-edit + labels: + app: antrea + # Add these permissions to the "admin" and "edit" default roles. + rbac.authorization.k8s.io/aggregate-to-admin: "true" + rbac.authorization.k8s.io/aggregate-to-edit: "true" +rules: +- apiGroups: ["crd.antrea.io"] + resources: ["clustergroups"] + verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] +--- +# Source: antrea/templates/crds-rbac/clusterroles.yaml +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: aggregate-antrea-clustergroups-view + labels: + app: antrea + # Add these permissions to the "view" default role. + rbac.authorization.k8s.io/aggregate-to-view: "true" +rules: +- apiGroups: ["crd.antrea.io"] + resources: ["clustergroups"] + verbs: ["get", "list", "watch"] +--- +# Source: antrea/templates/agent/clusterrolebinding.yaml +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: antrea-agent + labels: + app: antrea +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: antrea-agent +subjects: + - kind: ServiceAccount + name: antrea-agent + namespace: kube-system +--- +# Source: antrea/templates/antctl/clusterrolebinding.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + labels: + app: antrea + name: antctl +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: antctl +subjects: + - kind: ServiceAccount + name: antctl + namespace: kube-system +--- +# Source: antrea/templates/controller/clusterrolebinding.yaml +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: antrea-controller labels: app: antrea +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: antrea-controller +subjects: + - kind: ServiceAccount + name: antrea-controller + namespace: kube-system +--- +# Source: antrea/templates/controller/service.yaml +apiVersion: v1 +kind: Service +metadata: name: antrea namespace: kube-system + labels: + app: antrea spec: ports: - - port: 443 - protocol: TCP - targetPort: api + - port: 443 + protocol: TCP + targetPort: api selector: app: antrea component: antrea-controller --- +# Source: antrea/templates/agent/daemonset.yaml apiVersion: apps/v1 -kind: Deployment +kind: DaemonSet metadata: + name: antrea-agent + namespace: kube-system labels: app: antrea - component: antrea-controller + component: antrea-agent +spec: + selector: + matchLabels: + app: antrea + component: antrea-agent + updateStrategy: + type: RollingUpdate + template: + metadata: + annotations: + # Starting with v1.21, Kubernetes supports default container annotation. + # Using "kubectl logs/exec/attach/cp" doesn't have to specify "-c antrea-agent" when troubleshooting. + kubectl.kubernetes.io/default-container: antrea-agent + # Automatically restart Pods with a RollingUpdate if the ConfigMap changes + # See https://helm.sh/docs/howto/charts_tips_and_tricks/#automatically-roll-deployments + checksum/config: 7e0d8c70d728f9f981756d8238d9b19a9c2321206b09a814a1cdb4ac604b190c + labels: + app: antrea + component: antrea-agent + spec: + hostNetwork: true + dnsPolicy: ClusterFirstWithHostNet + priorityClassName: system-node-critical + nodeSelector: + kubernetes.io/os: linux + tolerations: + - key: CriticalAddonsOnly + operator: Exists + - effect: NoSchedule + operator: Exists + - effect: NoExecute + operator: Exists + serviceAccountName: antrea-agent + initContainers: + - name: install-cni + image: "projects.registry.vmware.com/antrea/antrea-ubuntu:latest" + imagePullPolicy: IfNotPresent + resources: + requests: + cpu: 100m + command: ["install_cni"] + securityContext: + capabilities: + add: + # SYS_MODULE is required to load the OVS kernel module. + - SYS_MODULE + env: + # SKIP_CNI_BINARIES takes in values as a comma separated list of + # binaries that need to be skipped for installation, e.g. "portmap, bandwidth". + - name: SKIP_CNI_BINARIES + value: "" + volumeMounts: + - name: antrea-config + mountPath: /etc/antrea/antrea-cni.conflist + subPath: antrea-cni.conflist + readOnly: true + - name: host-cni-conf + mountPath: /host/etc/cni/net.d + - name: host-cni-bin + mountPath: /host/opt/cni/bin + # For loading the OVS kernel module. + - name: host-lib-modules + mountPath: /lib/modules + readOnly: true + # For changing the default permissions of the run directory. + - name: host-var-run-antrea + mountPath: /var/run/antrea + containers: + - name: antrea-agent + image: "projects.registry.vmware.com/antrea/antrea-ubuntu:latest" + imagePullPolicy: IfNotPresent + command: ["antrea-agent"] + # Log to both "/var/log/antrea/" and stderr (so "kubectl logs" can work).- + args: + - "--config=/etc/antrea/antrea-agent.conf" + - "--logtostderr=false" + - "--log_dir=/var/log/antrea" + - "--alsologtostderr" + - "--log_file_max_size=100" + - "--log_file_max_num=4" + env: + # Provide pod and node information for clusterinformation CRD. + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: NODE_NAME + valueFrom: + fieldRef: + fieldPath: spec.nodeName + resources: + requests: + cpu: 200m + ports: + - containerPort: 10350 + name: api + protocol: TCP + livenessProbe: + exec: + command: + - /bin/sh + - -c + - container_liveness_probe agent + initialDelaySeconds: 5 + timeoutSeconds: 5 + periodSeconds: 10 + failureThreshold: 5 + readinessProbe: + httpGet: + host: localhost + path: /readyz + port: api + scheme: HTTPS + initialDelaySeconds: 5 + timeoutSeconds: 5 + periodSeconds: 10 + # In large-scale clusters, it may take up to 40~50 seconds for the antrea-agent to reconnect to the antrea + # Service after the antrea-controller restarts. The antrea-agent shouldn't be reported as NotReady in this + # scenario, otherwise the DaemonSet controller would restart all agents at once, as opposed to performing a + # rolling update. Set failureThreshold to 8 so it can tolerate 70s of disconnection. + failureThreshold: 8 + securityContext: + # antrea-agent needs to perform sysctl configuration. + privileged: true + volumeMounts: + - name: antrea-config + mountPath: /etc/antrea/antrea-agent.conf + subPath: antrea-agent.conf + readOnly: true + - name: host-var-run-antrea + mountPath: /var/run/antrea + - name: host-var-run-antrea + mountPath: /var/run/openvswitch + subPath: openvswitch + # host-local IPAM stores allocated IP addresses as files in /var/lib/cni/networks/$NETWORK_NAME. + # Mount a sub-directory of host-var-run-antrea to it for persistence of IP allocation. + - name: host-var-run-antrea + mountPath: /var/lib/cni + subPath: cni + # We need to mount both the /proc directory and the /var/run/netns directory so that + # antrea-agent can open the network namespace path when setting up Pod + # networking. Different container runtimes may use /proc or /var/run/netns when invoking + # the CNI commands. Docker uses /proc and containerd uses /var/run/netns. + - name: host-var-log-antrea + mountPath: /var/log/antrea + - name: host-proc + mountPath: /host/proc + readOnly: true + - name: host-var-run-netns + mountPath: /host/var/run/netns + readOnly: true + # When a container is created, a mount point for the network namespace is added under + # /var/run/netns on the host, which needs to be propagated to the antrea-agent container. + mountPropagation: HostToContainer + - name: xtables-lock + mountPath: /run/xtables.lock + - name: antrea-ovs + image: "projects.registry.vmware.com/antrea/antrea-ubuntu:latest" + imagePullPolicy: IfNotPresent + resources: + requests: + cpu: 200m + command: ["start_ovs"] + args: + - "--log_file_max_size=100" + - "--log_file_max_num=4" + securityContext: + # capabilities required by OVS daemons + capabilities: + add: + - SYS_NICE + - NET_ADMIN + - SYS_ADMIN + - IPC_LOCK + livenessProbe: + exec: + # docker CRI doesn't honor timeoutSeconds, add "timeout" to the command as a workaround. + # https://github.com/kubernetes/kubernetes/issues/51901 + command: + - /bin/sh + - -c + - timeout 10 container_liveness_probe ovs + initialDelaySeconds: 5 + timeoutSeconds: 10 + periodSeconds: 10 + failureThreshold: 5 + volumeMounts: + - name: host-var-run-antrea + mountPath: /var/run/openvswitch + subPath: openvswitch + - name: host-var-log-antrea + mountPath: /var/log/openvswitch + subPath: openvswitch + volumes: + - name: antrea-config + configMap: + name: antrea-config + - name: host-cni-conf + hostPath: + path: /etc/cni/net.d + - name: host-cni-bin + hostPath: + path: /home/kubernetes/bin + - name: host-proc + hostPath: + path: /proc + - name: host-var-run-netns + hostPath: + path: /var/run/netns + - name: host-var-run-antrea + hostPath: + path: /var/run/antrea + # we use subPath to create run subdirectories for different component (e.g. OVS) and + # subPath requires the base volume to exist + type: DirectoryOrCreate + - name: host-var-log-antrea + hostPath: + path: /var/log/antrea + # we use subPath to create logging subdirectories for different component (e.g. OVS) + type: DirectoryOrCreate + - name: host-lib-modules + hostPath: + path: /lib/modules + - name: xtables-lock + hostPath: + path: /run/xtables.lock + type: FileOrCreate +--- +# Source: antrea/templates/controller/deployment.yaml +apiVersion: apps/v1 +kind: Deployment +metadata: name: antrea-controller namespace: kube-system + labels: + app: antrea + component: antrea-controller spec: - replicas: 1 + strategy: + # Ensure the existing Pod is stopped before the new one is created. + type: Recreate selector: matchLabels: app: antrea component: antrea-controller - strategy: - type: Recreate + replicas: 1 template: metadata: + annotations: + # Automatically restart Pod if the ConfigMap changes + # See https://helm.sh/docs/howto/charts_tips_and_tricks/#automatically-roll-deployments + checksum/config: 7e0d8c70d728f9f981756d8238d9b19a9c2321206b09a814a1cdb4ac604b190c labels: app: antrea component: antrea-controller spec: - containers: - - args: - - --config - - /etc/antrea/antrea-controller.conf - - --logtostderr=false - - --log_dir=/var/log/antrea - - --alsologtostderr - - --log_file_max_size=100 - - --log_file_max_num=4 - - --v=0 - command: - - antrea-controller - env: - - name: POD_NAME - valueFrom: - fieldRef: - fieldPath: metadata.name - - name: POD_NAMESPACE - valueFrom: - fieldRef: - fieldPath: metadata.namespace - - name: NODE_NAME - valueFrom: - fieldRef: - fieldPath: spec.nodeName - - name: SERVICEACCOUNT_NAME - valueFrom: - fieldRef: - fieldPath: spec.serviceAccountName - - name: ANTREA_CONFIG_MAP_NAME - value: antrea-config-c9ck44454h - image: projects.registry.vmware.com/antrea/antrea-ubuntu:latest - imagePullPolicy: IfNotPresent - livenessProbe: - failureThreshold: 5 - httpGet: - host: localhost - path: /livez - port: api - scheme: HTTPS - periodSeconds: 10 - timeoutSeconds: 5 - name: antrea-controller - ports: - - containerPort: 10349 - name: api - protocol: TCP - readinessProbe: - failureThreshold: 5 - httpGet: - host: localhost - path: /readyz - port: api - scheme: HTTPS - initialDelaySeconds: 5 - periodSeconds: 10 - timeoutSeconds: 5 - resources: - requests: - cpu: 200m - volumeMounts: - - mountPath: /etc/antrea/antrea-controller.conf - name: antrea-config - readOnly: true - subPath: antrea-controller.conf - - mountPath: /var/run/antrea/antrea-controller-tls - name: antrea-controller-tls - - mountPath: /var/log/antrea - name: host-var-log-antrea - hostNetwork: true nodeSelector: kubernetes.io/os: linux + hostNetwork: true priorityClassName: system-cluster-critical - serviceAccountName: antrea-controller tolerations: - - key: CriticalAddonsOnly - operator: Exists - - effect: NoSchedule - key: node-role.kubernetes.io/master + - key: CriticalAddonsOnly + operator: Exists + - effect: NoSchedule + key: node-role.kubernetes.io/master + - effect: NoSchedule + key: node-role.kubernetes.io/control-plane + serviceAccountName: antrea-controller + containers: + - name: antrea-controller + image: "projects.registry.vmware.com/antrea/antrea-ubuntu:latest" + imagePullPolicy: IfNotPresent + resources: + requests: + cpu: 200m + command: ["antrea-controller"] + # Log to both "/var/log/antrea/" and stderr (so "kubectl logs" can work). + args: + - "--config=/etc/antrea/antrea-controller.conf" + - "--logtostderr=false" + - "--log_dir=/var/log/antrea" + - "--alsologtostderr" + - "--log_file_max_size=100" + - "--log_file_max_num=4" + env: + # Provide pod and node information for clusterinformation CRD. + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: NODE_NAME + valueFrom: + fieldRef: + fieldPath: spec.nodeName + # Provide ServiceAccount name for validation webhook. + - name: SERVICEACCOUNT_NAME + valueFrom: + fieldRef: + fieldPath: spec.serviceAccountName + - name: ANTREA_CONFIG_MAP_NAME + value: antrea-config + ports: + - containerPort: 10349 + name: api + protocol: TCP + readinessProbe: + httpGet: + host: localhost + path: /readyz + port: api + scheme: HTTPS + initialDelaySeconds: 5 + timeoutSeconds: 5 + periodSeconds: 10 + failureThreshold: 5 + livenessProbe: + httpGet: + host: localhost + path: /livez + port: api + scheme: HTTPS + timeoutSeconds: 5 + periodSeconds: 10 + failureThreshold: 5 + volumeMounts: + - name: antrea-config + mountPath: /etc/antrea/antrea-controller.conf + subPath: antrea-controller.conf + readOnly: true + - name: antrea-controller-tls + mountPath: /var/run/antrea/antrea-controller-tls + - name: host-var-log-antrea + mountPath: /var/log/antrea volumes: - - configMap: - name: antrea-config-c9ck44454h - name: antrea-config - - name: antrea-controller-tls - secret: - defaultMode: 256 - optional: true - secretName: antrea-controller-tls - - hostPath: - path: /var/log/antrea - type: DirectoryOrCreate - name: host-var-log-antrea + - name: antrea-config + configMap: + name: antrea-config + # Make it optional as we only read it when selfSignedCert=false. + - name: antrea-controller-tls + secret: + secretName: antrea-controller-tls + defaultMode: 0400 + optional: true + - name: host-var-log-antrea + hostPath: + path: /var/log/antrea + type: DirectoryOrCreate --- +# Source: antrea/templates/controller/apiservices.yaml apiVersion: apiregistration.k8s.io/v1 kind: APIService metadata: + name: v1beta2.controlplane.antrea.io labels: app: antrea - name: v1alpha1.stats.antrea.io spec: - group: stats.antrea.io + group: controlplane.antrea.io groupPriorityMinimum: 100 + version: v1beta2 + versionPriority: 100 service: name: antrea namespace: kube-system - version: v1alpha1 - versionPriority: 100 --- +# Source: antrea/templates/controller/apiservices.yaml apiVersion: apiregistration.k8s.io/v1 kind: APIService metadata: + name: v1beta1.system.antrea.io labels: app: antrea - name: v1beta1.system.antrea.io spec: group: system.antrea.io groupPriorityMinimum: 100 + version: v1beta1 + versionPriority: 100 service: name: antrea namespace: kube-system - version: v1beta1 - versionPriority: 100 --- +# Source: antrea/templates/controller/apiservices.yaml apiVersion: apiregistration.k8s.io/v1 kind: APIService metadata: + name: v1alpha1.stats.antrea.io labels: app: antrea - name: v1beta2.controlplane.antrea.io spec: - group: controlplane.antrea.io + group: stats.antrea.io groupPriorityMinimum: 100 + version: v1alpha1 + versionPriority: 100 service: name: antrea namespace: kube-system - version: v1beta2 - versionPriority: 100 ---- -apiVersion: apps/v1 -kind: DaemonSet -metadata: - labels: - app: antrea - component: antrea-agent - name: antrea-agent - namespace: kube-system -spec: - selector: - matchLabels: - app: antrea - component: antrea-agent - template: - metadata: - annotations: - kubectl.kubernetes.io/default-container: antrea-agent - labels: - app: antrea - component: antrea-agent - spec: - containers: - - args: - - --config - - /etc/antrea/antrea-agent.conf - - --logtostderr=false - - --log_dir=/var/log/antrea - - --alsologtostderr - - --log_file_max_size=100 - - --log_file_max_num=4 - - --v=0 - command: - - antrea-agent - env: - - name: POD_NAME - valueFrom: - fieldRef: - fieldPath: metadata.name - - name: POD_NAMESPACE - valueFrom: - fieldRef: - fieldPath: metadata.namespace - - name: NODE_NAME - valueFrom: - fieldRef: - fieldPath: spec.nodeName - image: projects.registry.vmware.com/antrea/antrea-ubuntu:latest - imagePullPolicy: IfNotPresent - livenessProbe: - exec: - command: - - /bin/sh - - -c - - container_liveness_probe agent - failureThreshold: 5 - initialDelaySeconds: 5 - periodSeconds: 10 - timeoutSeconds: 5 - name: antrea-agent - ports: - - containerPort: 10350 - name: api - protocol: TCP - readinessProbe: - failureThreshold: 8 - httpGet: - host: localhost - path: /readyz - port: api - scheme: HTTPS - initialDelaySeconds: 5 - periodSeconds: 10 - timeoutSeconds: 5 - resources: - requests: - cpu: 200m - securityContext: - privileged: true - volumeMounts: - - mountPath: /etc/antrea/antrea-agent.conf - name: antrea-config - readOnly: true - subPath: antrea-agent.conf - - mountPath: /var/run/antrea - name: host-var-run-antrea - - mountPath: /var/run/openvswitch - name: host-var-run-antrea - subPath: openvswitch - - mountPath: /var/lib/cni - name: host-var-run-antrea - subPath: cni - - mountPath: /var/log/antrea - name: host-var-log-antrea - - mountPath: /host/proc - name: host-proc - readOnly: true - - mountPath: /host/var/run/netns - mountPropagation: HostToContainer - name: host-var-run-netns - readOnly: true - - mountPath: /run/xtables.lock - name: xtables-lock - - args: - - --log_file_max_size=100 - - --log_file_max_num=4 - command: - - start_ovs - image: projects.registry.vmware.com/antrea/antrea-ubuntu:latest - imagePullPolicy: IfNotPresent - livenessProbe: - exec: - command: - - /bin/sh - - -c - - timeout 10 container_liveness_probe ovs - failureThreshold: 5 - initialDelaySeconds: 5 - periodSeconds: 10 - timeoutSeconds: 10 - name: antrea-ovs - resources: - requests: - cpu: 200m - securityContext: - capabilities: - add: - - SYS_NICE - - NET_ADMIN - - SYS_ADMIN - - IPC_LOCK - volumeMounts: - - mountPath: /var/run/openvswitch - name: host-var-run-antrea - subPath: openvswitch - - mountPath: /var/log/openvswitch - name: host-var-log-antrea - subPath: openvswitch - dnsPolicy: ClusterFirstWithHostNet - hostNetwork: true - initContainers: - - command: - - install_cni - env: - - name: SKIP_CNI_BINARIES - value: "" - image: projects.registry.vmware.com/antrea/antrea-ubuntu:latest - imagePullPolicy: IfNotPresent - name: install-cni - resources: - requests: - cpu: 100m - securityContext: - capabilities: - add: - - SYS_MODULE - volumeMounts: - - mountPath: /etc/antrea/antrea-cni.conflist - name: antrea-config - readOnly: true - subPath: antrea-cni.conflist - - mountPath: /host/etc/cni/net.d - name: host-cni-conf - - mountPath: /host/opt/cni/bin - name: host-cni-bin - - mountPath: /lib/modules - name: host-lib-modules - readOnly: true - - mountPath: /var/run/antrea - name: host-var-run-antrea - nodeSelector: - kubernetes.io/os: linux - priorityClassName: system-node-critical - serviceAccountName: antrea-agent - tolerations: - - key: CriticalAddonsOnly - operator: Exists - - effect: NoSchedule - operator: Exists - - effect: NoExecute - operator: Exists - volumes: - - hostPath: - path: /home/kubernetes/bin - name: host-cni-bin - - configMap: - name: antrea-config-c9ck44454h - name: antrea-config - - hostPath: - path: /etc/cni/net.d - name: host-cni-conf - - hostPath: - path: /proc - name: host-proc - - hostPath: - path: /var/run/netns - name: host-var-run-netns - - hostPath: - path: /var/run/antrea - type: DirectoryOrCreate - name: host-var-run-antrea - - hostPath: - path: /var/log/antrea - type: DirectoryOrCreate - name: host-var-log-antrea - - hostPath: - path: /lib/modules - name: host-lib-modules - - hostPath: - path: /run/xtables.lock - type: FileOrCreate - name: xtables-lock - updateStrategy: - type: RollingUpdate --- +# Source: antrea/templates/webhooks/mutating/crdmutator.yaml apiVersion: admissionregistration.k8s.io/v1 kind: MutatingWebhookConfiguration metadata: + name: "crdmutator.antrea.io" labels: app: antrea - name: crdmutator.antrea.io webhooks: -- admissionReviewVersions: - - v1 - - v1beta1 - clientConfig: - service: - name: antrea - namespace: kube-system - path: /mutate/acnp - name: acnpmutator.antrea.io - rules: - - apiGroups: - - crd.antrea.io - apiVersions: - - v1alpha1 - operations: - - CREATE - - UPDATE - resources: - - clusternetworkpolicies - scope: Cluster - sideEffects: None - timeoutSeconds: 5 -- admissionReviewVersions: - - v1 - - v1beta1 - clientConfig: - service: - name: antrea - namespace: kube-system - path: /mutate/anp - name: anpmutator.antrea.io - rules: - - apiGroups: - - crd.antrea.io - apiVersions: - - v1alpha1 - operations: - - CREATE - - UPDATE - resources: - - networkpolicies - scope: Namespaced - sideEffects: None - timeoutSeconds: 5 + - name: "acnpmutator.antrea.io" + clientConfig: + service: + name: "antrea" + namespace: kube-system + path: "/mutate/acnp" + rules: + - operations: ["CREATE", "UPDATE"] + apiGroups: ["crd.antrea.io"] + apiVersions: ["v1alpha1"] + resources: ["clusternetworkpolicies"] + scope: "Cluster" + admissionReviewVersions: ["v1", "v1beta1"] + sideEffects: None + timeoutSeconds: 5 + - name: "anpmutator.antrea.io" + clientConfig: + service: + name: "antrea" + namespace: kube-system + path: "/mutate/anp" + rules: + - operations: ["CREATE", "UPDATE"] + apiGroups: ["crd.antrea.io"] + apiVersions: ["v1alpha1"] + resources: ["networkpolicies"] + scope: "Namespaced" + admissionReviewVersions: ["v1", "v1beta1"] + sideEffects: None + timeoutSeconds: 5 --- +# Source: antrea/templates/webhooks/validating/crdvalidator.yaml apiVersion: admissionregistration.k8s.io/v1 kind: ValidatingWebhookConfiguration metadata: + name: "crdvalidator.antrea.io" labels: app: antrea - name: crdvalidator.antrea.io webhooks: -- admissionReviewVersions: - - v1 - - v1beta1 - clientConfig: - service: - name: antrea - namespace: kube-system - path: /validate/tier - name: tiervalidator.antrea.io - rules: - - apiGroups: - - crd.antrea.io - apiVersions: - - v1alpha1 - operations: - - CREATE - - UPDATE - - DELETE - resources: - - tiers - scope: Cluster - sideEffects: None - timeoutSeconds: 5 -- admissionReviewVersions: - - v1 - - v1beta1 - clientConfig: - service: - name: antrea - namespace: kube-system - path: /validate/acnp - name: acnpvalidator.antrea.io - rules: - - apiGroups: - - crd.antrea.io - apiVersions: - - v1alpha1 - operations: - - CREATE - - UPDATE - resources: - - clusternetworkpolicies - scope: Cluster - sideEffects: None - timeoutSeconds: 5 -- admissionReviewVersions: - - v1 - - v1beta1 - clientConfig: - service: - name: antrea - namespace: kube-system - path: /validate/anp - name: anpvalidator.antrea.io - rules: - - apiGroups: - - crd.antrea.io - apiVersions: - - v1alpha1 - operations: - - CREATE - - UPDATE - resources: - - networkpolicies - scope: Namespaced - sideEffects: None - timeoutSeconds: 5 -- admissionReviewVersions: - - v1 - - v1beta1 - clientConfig: - service: - name: antrea - namespace: kube-system - path: /validate/clustergroup - name: clustergroupvalidator.antrea.io - rules: - - apiGroups: - - crd.antrea.io - apiVersions: - - v1alpha3 - - v1alpha2 - operations: - - CREATE - - UPDATE - resources: - - clustergroups - scope: Cluster - sideEffects: None - timeoutSeconds: 5 -- admissionReviewVersions: - - v1 - - v1beta1 - clientConfig: - service: - name: antrea - namespace: kube-system - path: /validate/externalippool - name: externalippoolvalidator.antrea.io - rules: - - apiGroups: - - crd.antrea.io - apiVersions: - - v1alpha2 - operations: - - UPDATE - resources: - - externalippools - scope: Cluster - sideEffects: None - timeoutSeconds: 5 -- admissionReviewVersions: - - v1 - - v1beta1 - clientConfig: - service: - name: antrea - namespace: kube-system - path: /validate/egress - name: egressvalidator.antrea.io - rules: - - apiGroups: - - crd.antrea.io - apiVersions: - - v1alpha2 - operations: - - CREATE - - UPDATE - resources: - - egresses - scope: Cluster - sideEffects: None - timeoutSeconds: 5 -- admissionReviewVersions: - - v1 - - v1beta1 - clientConfig: - service: - name: antrea - namespace: kube-system - path: /validate/ippool - name: ippoolvalidator.antrea.io - rules: - - apiGroups: - - crd.antrea.io - apiVersions: - - v1alpha2 - operations: - - CREATE - - UPDATE - - DELETE - resources: - - ippools - scope: Cluster - sideEffects: None - timeoutSeconds: 5 + - name: "tiervalidator.antrea.io" + clientConfig: + service: + name: "antrea" + namespace: kube-system + path: "/validate/tier" + rules: + - operations: ["CREATE", "UPDATE", "DELETE"] + apiGroups: ["crd.antrea.io"] + apiVersions: ["v1alpha1"] + resources: ["tiers"] + scope: "Cluster" + admissionReviewVersions: ["v1", "v1beta1"] + sideEffects: None + timeoutSeconds: 5 + - name: "acnpvalidator.antrea.io" + clientConfig: + service: + name: "antrea" + namespace: kube-system + path: "/validate/acnp" + rules: + - operations: ["CREATE", "UPDATE"] + apiGroups: ["crd.antrea.io"] + apiVersions: ["v1alpha1"] + resources: ["clusternetworkpolicies"] + scope: "Cluster" + admissionReviewVersions: ["v1", "v1beta1"] + sideEffects: None + timeoutSeconds: 5 + - name: "anpvalidator.antrea.io" + clientConfig: + service: + name: "antrea" + namespace: kube-system + path: "/validate/anp" + rules: + - operations: ["CREATE", "UPDATE"] + apiGroups: ["crd.antrea.io"] + apiVersions: ["v1alpha1"] + resources: ["networkpolicies"] + scope: "Namespaced" + admissionReviewVersions: ["v1", "v1beta1"] + sideEffects: None + timeoutSeconds: 5 + - name: "clustergroupvalidator.antrea.io" + clientConfig: + service: + name: "antrea" + namespace: kube-system + path: "/validate/clustergroup" + rules: + - operations: ["CREATE", "UPDATE"] + apiGroups: ["crd.antrea.io"] + apiVersions: ["v1alpha3", "v1alpha2"] + resources: ["clustergroups"] + scope: "Cluster" + admissionReviewVersions: ["v1", "v1beta1"] + sideEffects: None + timeoutSeconds: 5 + - name: "externalippoolvalidator.antrea.io" + clientConfig: + service: + name: "antrea" + namespace: kube-system + path: "/validate/externalippool" + rules: + - operations: ["UPDATE"] + apiGroups: ["crd.antrea.io"] + apiVersions: ["v1alpha2"] + resources: ["externalippools"] + scope: "Cluster" + admissionReviewVersions: ["v1", "v1beta1"] + sideEffects: None + timeoutSeconds: 5 + - name: "egressvalidator.antrea.io" + clientConfig: + service: + name: "antrea" + namespace: kube-system + path: "/validate/egress" + rules: + - operations: ["CREATE", "UPDATE"] + apiGroups: ["crd.antrea.io"] + apiVersions: ["v1alpha2"] + resources: ["egresses"] + scope: "Cluster" + admissionReviewVersions: ["v1", "v1beta1"] + sideEffects: None + timeoutSeconds: 5 + - name: "ippoolvalidator.antrea.io" + clientConfig: + service: + name: "antrea" + namespace: kube-system + path: "/validate/ippool" + rules: + - operations: ["CREATE", "UPDATE", "DELETE"] + apiGroups: ["crd.antrea.io"] + apiVersions: ["v1alpha2"] + resources: ["ippools"] + scope: "Cluster" + admissionReviewVersions: ["v1", "v1beta1"] + sideEffects: None + timeoutSeconds: 5 diff --git a/build/yamls/antrea-ipsec.yml b/build/yamls/antrea-ipsec.yml index 9241703a4f8..2047b52f63d 100644 --- a/build/yamls/antrea-ipsec.yml +++ b/build/yamls/antrea-ipsec.yml @@ -1,2740 +1,72 @@ -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition +--- +# Source: antrea/templates/agent/serviceaccount.yaml +apiVersion: v1 +kind: ServiceAccount metadata: + name: antrea-agent + namespace: kube-system labels: app: antrea - name: antreaagentinfos.crd.antrea.io -spec: - group: crd.antrea.io - names: - kind: AntreaAgentInfo - plural: antreaagentinfos - shortNames: - - aai - singular: antreaagentinfo - scope: Cluster - versions: - - additionalPrinterColumns: - - description: Health status of this Agent - jsonPath: .agentConditions[?(@.type=='AgentHealthy')].status - name: Healthy - type: string - - description: Last time the Healthy Condition was updated - jsonPath: .agentConditions[?(@.type=='AgentHealthy')].lastHeartbeatTime - name: Last Heartbeat - type: date - - description: Version of this Agent - jsonPath: .version - name: Version - priority: 1 - type: string - - description: Node on which this Agent is running - jsonPath: .nodeRef.name - name: Node - priority: 1 - type: string - - description: Number of local Pods managed by this Agent - jsonPath: .localPodNum - name: Num Pods - priority: 2 - type: integer - - description: Subnets used by this Agent for Pod IPAM - jsonPath: .nodeSubnets - name: Subnets - priority: 2 - type: string - name: v1beta1 - schema: - openAPIV3Schema: - type: object - x-kubernetes-preserve-unknown-fields: true - served: true - storage: true --- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition +# Source: antrea/templates/antctl/serviceaccount.yaml +apiVersion: v1 +kind: ServiceAccount metadata: + name: antctl + namespace: kube-system labels: app: antrea - name: antreacontrollerinfos.crd.antrea.io -spec: - group: crd.antrea.io - names: - kind: AntreaControllerInfo - plural: antreacontrollerinfos - shortNames: - - aci - singular: antreacontrollerinfo - scope: Cluster - versions: - - additionalPrinterColumns: - - description: Health status of the Controller - jsonPath: .controllerConditions[?(@.type=='ControllerHealthy')].status - name: Healthy - type: string - - description: Last time the Healthy Condition was updated - jsonPath: .controllerConditions[?(@.type=='ControllerHealthy')].lastHeartbeatTime - name: Last Heartbeat - type: date - - description: Version of the Controller - jsonPath: .version - name: Version - priority: 1 - type: string - - description: Number of Agents connected to the Controller - jsonPath: .connectedAgentNum - name: Connected Agents - priority: 1 - type: integer - - description: Node on which the Controller is running - jsonPath: .nodeRef.name - name: Node - priority: 1 - type: string - - description: Number of Network Policies computed by Controller - jsonPath: .networkPolicyControllerInfo.networkPolicyNum - name: Num Network Policies - priority: 2 - type: integer - name: v1beta1 - schema: - openAPIV3Schema: - type: object - x-kubernetes-preserve-unknown-fields: true - served: true - storage: true --- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition +# Source: antrea/templates/controller/serviceaccount.yaml +apiVersion: v1 +kind: ServiceAccount metadata: + name: antrea-controller + namespace: kube-system labels: app: antrea - name: clustergroups.crd.antrea.io -spec: - conversion: - strategy: Webhook - webhook: - clientConfig: - service: - name: antrea - namespace: kube-system - path: /convert/clustergroup - conversionReviewVersions: - - v1 - - v1beta1 - group: crd.antrea.io - names: - kind: ClusterGroup - plural: clustergroups - shortNames: - - cg - singular: clustergroup - scope: Cluster - versions: - - name: v1alpha2 - schema: - openAPIV3Schema: - properties: - spec: - properties: - childGroups: - items: - type: string - type: array - externalEntitySelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - ipBlock: - properties: - cidr: - format: cidr - type: string - type: object - ipBlocks: - items: - properties: - cidr: - format: cidr - type: string - type: object - type: array - namespaceSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - podSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - serviceReference: - properties: - name: - type: string - namespace: - type: string - type: object - type: object - status: - properties: - conditions: - items: - properties: - lastTransitionTime: - type: string - status: - type: string - type: - type: string - type: object - type: array - type: object - type: object - served: true - storage: false - - name: v1alpha3 - schema: - openAPIV3Schema: - properties: - spec: - properties: - childGroups: - items: - type: string - type: array - externalEntitySelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - ipBlocks: - items: - properties: - cidr: - format: cidr - type: string - type: object - type: array - namespaceSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - podSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - serviceReference: - properties: - name: - type: string - namespace: - type: string - type: object - type: object - status: - properties: - conditions: - items: - properties: - lastTransitionTime: - type: string - status: - type: string - type: - type: string - type: object - type: array - type: object - type: object - served: true - storage: true - subresources: - status: {} --- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition +# Source: antrea/templates/agent/ipsec-secret.yaml +apiVersion: v1 +kind: Secret metadata: + name: antrea-ipsec + namespace: kube-system labels: app: antrea - name: clusternetworkpolicies.crd.antrea.io -spec: - group: crd.antrea.io - names: - kind: ClusterNetworkPolicy - plural: clusternetworkpolicies - shortNames: - - acnp - singular: clusternetworkpolicy - scope: Cluster - versions: - - additionalPrinterColumns: - - description: The Tier to which this ClusterNetworkPolicy belongs to. - jsonPath: .spec.tier - name: Tier - type: string - - description: The Priority of this ClusterNetworkPolicy relative to other policies. - format: float - jsonPath: .spec.priority - name: Priority - type: number - - description: The total number of Nodes that should realize the NetworkPolicy. - format: int32 - jsonPath: .status.desiredNodesRealized - name: Desired Nodes - type: number - - description: The number of Nodes that have realized the NetworkPolicy. - format: int32 - jsonPath: .status.currentNodesRealized - name: Current Nodes - type: number - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha1 - schema: - openAPIV3Schema: - properties: - spec: - properties: - appliedTo: - items: - properties: - group: - type: string - namespaceSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - podSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - serviceAccount: - properties: - name: - type: string - namespace: - type: string - required: - - name - - namespace - type: object - type: object - type: array - egress: - items: - properties: - action: - enum: - - Allow - - Drop - - Reject - - Pass - type: string - appliedTo: - items: - properties: - group: - type: string - namespaceSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - podSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - serviceAccount: - properties: - name: - type: string - namespace: - type: string - required: - - name - - namespace - type: object - type: object - type: array - enableLogging: - type: boolean - name: - type: string - ports: - items: - properties: - endPort: - type: integer - port: - x-kubernetes-int-or-string: true - protocol: - enum: - - TCP - - UDP - - SCTP - type: string - type: object - type: array - to: - items: - properties: - fqdn: - type: string - group: - type: string - ipBlock: - properties: - cidr: - format: cidr - type: string - type: object - namespaceSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - namespaces: - properties: - match: - type: string - type: object - nodeSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - podSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - serviceAccount: - properties: - name: - type: string - namespace: - type: string - required: - - name - - namespace - type: object - type: object - type: array - toServices: - items: - properties: - name: - type: string - namespace: - type: string - required: - - name - - namespace - type: object - type: array - required: - - action - type: object - type: array - ingress: - items: - properties: - action: - enum: - - Allow - - Drop - - Reject - - Pass - type: string - appliedTo: - items: - properties: - group: - type: string - namespaceSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - podSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - serviceAccount: - properties: - name: - type: string - namespace: - type: string - required: - - name - - namespace - type: object - type: object - type: array - enableLogging: - type: boolean - from: - items: - properties: - group: - type: string - ipBlock: - properties: - cidr: - format: cidr - type: string - type: object - namespaceSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - namespaces: - properties: - match: - enum: - - Self - type: string - type: object - nodeSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - podSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - serviceAccount: - properties: - name: - type: string - namespace: - type: string - required: - - name - - namespace - type: object - type: object - type: array - name: - type: string - ports: - items: - properties: - endPort: - type: integer - port: - x-kubernetes-int-or-string: true - protocol: - enum: - - TCP - - UDP - - SCTP - type: string - type: object - type: array - required: - - action - type: object - type: array - priority: - format: float - maximum: 10000 - minimum: 1 - type: number - tier: - type: string - required: - - priority - type: object - status: - properties: - currentNodesRealized: - type: integer - desiredNodesRealized: - type: integer - observedGeneration: - type: integer - phase: - type: string - type: object - type: object - served: true - storage: true - subresources: - status: {} +type: Opaque +stringData: + # Preshared Key used by IKE for authentication with peers. + psk: "changeme" --- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition +# Source: antrea/templates/agent/secret.yaml +apiVersion: v1 +kind: Secret +metadata: + name: antrea-agent-service-account-token + namespace: kube-system + annotations: + kubernetes.io/service-account.name: antrea-agent +type: kubernetes.io/service-account-token +--- +# Source: antrea/templates/antctl/secret.yaml +apiVersion: v1 +kind: Secret +metadata: + name: antctl-service-account-token + namespace: kube-system + annotations: + kubernetes.io/service-account.name: antctl +type: kubernetes.io/service-account-token +--- +# Source: antrea/templates/configmap.yaml +apiVersion: v1 +kind: ConfigMap metadata: + name: antrea-config + namespace: kube-system labels: app: antrea - name: egresses.crd.antrea.io -spec: - group: crd.antrea.io - names: - kind: Egress - plural: egresses - shortNames: - - eg - singular: egress - scope: Cluster - versions: - - additionalPrinterColumns: - - description: Specifies the SNAT IP address for the selected workloads. - jsonPath: .spec.egressIP - name: EgressIP - type: string - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - - description: The Owner Node of egress IP - jsonPath: .status.egressNode - name: Node - type: string - name: v1alpha2 - schema: - openAPIV3Schema: - properties: - spec: - anyOf: - - required: - - egressIP - - required: - - externalIPPool - properties: - appliedTo: - properties: - namespaceSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - podSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - type: object - egressIP: - oneOf: - - format: ipv4 - - format: ipv6 - type: string - externalIPPool: - type: string - required: - - appliedTo - type: object - status: - properties: - egressNode: - type: string - type: object - required: - - spec - type: object - served: true - storage: true - subresources: - status: {} ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - labels: - app: antrea - name: externalentities.crd.antrea.io -spec: - group: crd.antrea.io - names: - kind: ExternalEntity - plural: externalentities - shortNames: - - ee - singular: externalentity - scope: Namespaced - versions: - - name: v1alpha2 - schema: - openAPIV3Schema: - properties: - spec: - properties: - endpoints: - items: - properties: - ip: - oneOf: - - format: ipv4 - - format: ipv6 - type: string - name: - type: string - type: object - type: array - externalNode: - type: string - ports: - items: - properties: - name: - type: string - port: - x-kubernetes-int-or-string: true - protocol: - enum: - - TCP - - UDP - - SCTP - type: string - type: object - type: array - type: object - type: object - served: true - storage: true - - name: v1alpha1 - schema: - openAPIV3Schema: - type: object - served: false - storage: false ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - labels: - app: antrea - name: externalippools.crd.antrea.io -spec: - group: crd.antrea.io - names: - kind: ExternalIPPool - plural: externalippools - shortNames: - - eip - singular: externalippool - scope: Cluster - versions: - - additionalPrinterColumns: - - description: The number of total IPs - jsonPath: .status.usage.total - name: Total - type: integer - - description: The number of allocated IPs - jsonPath: .status.usage.used - name: Used - type: integer - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha2 - schema: - openAPIV3Schema: - properties: - spec: - properties: - ipRanges: - items: - oneOf: - - required: - - cidr - - required: - - start - - end - properties: - cidr: - format: cidr - type: string - end: - oneOf: - - format: ipv4 - - format: ipv6 - type: string - start: - oneOf: - - format: ipv4 - - format: ipv6 - type: string - type: object - type: array - nodeSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - required: - - ipRanges - - nodeSelector - type: object - status: - properties: - usage: - properties: - total: - type: integer - used: - type: integer - type: object - type: object - required: - - spec - type: object - served: true - storage: true - subresources: - status: {} ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - labels: - app: antrea - name: ippools.crd.antrea.io -spec: - group: crd.antrea.io - names: - kind: IPPool - plural: ippools - shortNames: - - ipp - singular: ippool - scope: Cluster - versions: - - name: v1alpha2 - schema: - openAPIV3Schema: - properties: - spec: - properties: - ipRanges: - items: - oneOf: - - required: - - cidr - - gateway - - prefixLength - - required: - - start - - end - - gateway - - prefixLength - properties: - cidr: - format: cidr - type: string - end: - oneOf: - - format: ipv4 - - format: ipv6 - type: string - gateway: - oneOf: - - format: ipv4 - - format: ipv6 - type: string - prefixLength: - type: integer - start: - oneOf: - - format: ipv4 - - format: ipv6 - type: string - vlan: - maximum: 4094 - minimum: 0 - type: integer - type: object - type: array - ipVersion: - type: integer - required: - - ipVersion - - ipRanges - type: object - status: - properties: - ipAddresses: - items: - properties: - ipAddress: - type: string - owner: - properties: - pod: - properties: - containerID: - type: string - name: - type: string - namespace: - type: string - type: object - statefulSet: - properties: - index: - type: integer - name: - type: string - namespace: - type: string - type: object - type: object - phase: - type: string - type: object - type: array - type: object - required: - - spec - type: object - served: true - storage: true - subresources: - status: {} ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - labels: - app: antrea - name: networkpolicies.crd.antrea.io -spec: - group: crd.antrea.io - names: - kind: NetworkPolicy - plural: networkpolicies - shortNames: - - anp - singular: networkpolicy - scope: Namespaced - versions: - - additionalPrinterColumns: - - description: The Tier to which this Antrea NetworkPolicy belongs to. - jsonPath: .spec.tier - name: Tier - type: string - - description: The Priority of this Antrea NetworkPolicy relative to other policies. - format: float - jsonPath: .spec.priority - name: Priority - type: number - - description: The total number of Nodes that should realize the NetworkPolicy. - format: int32 - jsonPath: .status.desiredNodesRealized - name: Desired Nodes - type: number - - description: The number of Nodes that have realized the NetworkPolicy. - format: int32 - jsonPath: .status.currentNodesRealized - name: Current Nodes - type: number - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha1 - schema: - openAPIV3Schema: - properties: - spec: - properties: - appliedTo: - items: - properties: - podSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - type: object - type: array - egress: - items: - properties: - action: - enum: - - Allow - - Drop - - Reject - - Pass - type: string - appliedTo: - items: - properties: - podSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - type: object - type: array - enableLogging: - type: boolean - name: - type: string - ports: - items: - properties: - endPort: - type: integer - port: - x-kubernetes-int-or-string: true - protocol: - enum: - - TCP - - UDP - - SCTP - type: string - type: object - type: array - to: - items: - properties: - externalEntitySelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - fqdn: - type: string - ipBlock: - properties: - cidr: - format: cidr - type: string - type: object - namespaceSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - nodeSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - podSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - type: object - type: array - toServices: - items: - properties: - name: - type: string - namespace: - type: string - required: - - name - type: object - type: array - required: - - action - type: object - type: array - ingress: - items: - properties: - action: - enum: - - Allow - - Drop - - Reject - - Pass - type: string - appliedTo: - items: - properties: - podSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - type: object - type: array - enableLogging: - type: boolean - from: - items: - properties: - externalEntitySelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - ipBlock: - properties: - cidr: - format: cidr - type: string - type: object - namespaceSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - nodeSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - podSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - type: object - type: array - name: - type: string - ports: - items: - properties: - endPort: - type: integer - port: - x-kubernetes-int-or-string: true - protocol: - enum: - - TCP - - UDP - - SCTP - type: string - type: object - type: array - required: - - action - type: object - type: array - priority: - format: float - maximum: 10000 - minimum: 1 - type: number - tier: - type: string - required: - - priority - type: object - status: - properties: - currentNodesRealized: - type: integer - desiredNodesRealized: - type: integer - observedGeneration: - type: integer - phase: - type: string - type: object - type: object - served: true - storage: true - subresources: - status: {} ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - labels: - app: antrea - name: tiers.crd.antrea.io -spec: - group: crd.antrea.io - names: - kind: Tier - plural: tiers - shortNames: - - tr - singular: tier - scope: Cluster - versions: - - additionalPrinterColumns: - - description: The Priority of this Tier relative to other Tiers. - jsonPath: .spec.priority - name: Priority - type: integer - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha1 - schema: - openAPIV3Schema: - properties: - spec: - properties: - description: - type: string - priority: - maximum: 255 - minimum: 0 - type: integer - required: - - priority - type: object - type: object - served: true - storage: true ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - labels: - app: antrea - name: traceflows.crd.antrea.io -spec: - group: crd.antrea.io - names: - kind: Traceflow - plural: traceflows - shortNames: - - tf - singular: traceflow - scope: Cluster - versions: - - additionalPrinterColumns: - - description: The phase of the Traceflow. - jsonPath: .status.phase - name: Phase - type: string - - description: The name of the source Pod. - jsonPath: .spec.source.pod - name: Source-Pod - priority: 10 - type: string - - description: The name of the destination Pod. - jsonPath: .spec.destination.pod - name: Destination-Pod - priority: 10 - type: string - - description: The IP address of the destination. - jsonPath: .spec.destination.ip - name: Destination-IP - priority: 10 - type: string - - description: Trace live traffic. - jsonPath: .spec.liveTraffic - name: Live-Traffic - priority: 10 - type: boolean - - description: Capture only the dropped packet. - jsonPath: .spec.droppedOnly - name: Dropped-Only - priority: 10 - type: boolean - - description: Timeout in seconds. - jsonPath: .spec.timeout - name: Timeout - priority: 10 - type: integer - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha1 - schema: - openAPIV3Schema: - properties: - spec: - properties: - destination: - properties: - ip: - oneOf: - - format: ipv4 - - format: ipv6 - type: string - namespace: - type: string - pod: - type: string - service: - type: string - type: object - droppedOnly: - type: boolean - liveTraffic: - type: boolean - packet: - properties: - ipHeader: - properties: - flags: - type: integer - protocol: - type: integer - srcIP: - oneOf: - - format: ipv4 - - format: ipv6 - type: string - ttl: - type: integer - type: object - ipv6Header: - properties: - hopLimit: - type: integer - nextHeader: - type: integer - srcIP: - format: ipv6 - type: string - type: object - transportHeader: - properties: - icmp: - properties: - id: - type: integer - sequence: - type: integer - type: object - tcp: - properties: - dstPort: - type: integer - flags: - type: integer - srcPort: - type: integer - type: object - udp: - properties: - dstPort: - type: integer - srcPort: - type: integer - type: object - type: object - type: object - source: - properties: - ip: - oneOf: - - format: ipv4 - - format: ipv6 - type: string - namespace: - type: string - pod: - type: string - type: object - timeout: - type: integer - type: object - status: - properties: - capturedPacket: - properties: - dstIP: - type: string - ipHeader: - properties: - flags: - type: integer - protocol: - type: integer - ttl: - type: integer - type: object - ipv6Header: - properties: - hopLimit: - type: integer - nextHeader: - type: integer - type: object - length: - type: integer - srcIP: - type: string - transportHeader: - properties: - icmp: - properties: - id: - type: integer - sequence: - type: integer - type: object - tcp: - properties: - dstPort: - type: integer - flags: - type: integer - srcPort: - type: integer - type: object - udp: - properties: - dstPort: - type: integer - srcPort: - type: integer - type: object - type: object - type: object - dataplaneTag: - type: integer - phase: - type: string - reason: - type: string - results: - items: - properties: - node: - type: string - observations: - items: - properties: - action: - type: string - component: - type: string - componentInfo: - type: string - dstMAC: - type: string - networkPolicy: - type: string - pod: - type: string - translatedDstIP: - type: string - translatedSrcIP: - type: string - ttl: - type: integer - tunnelDstIP: - type: string - type: object - type: array - role: - type: string - timestamp: - type: integer - type: object - type: array - startTime: - type: string - type: object - required: - - spec - type: object - served: true - storage: true - subresources: - status: {} ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - labels: - app: antrea - name: antctl - namespace: kube-system ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - labels: - app: antrea - name: antrea-agent - namespace: kube-system ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - labels: - app: antrea - name: antrea-controller - namespace: kube-system ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - labels: - app: antrea - rbac.authorization.k8s.io/aggregate-to-admin: "true" - rbac.authorization.k8s.io/aggregate-to-edit: "true" - name: aggregate-antrea-clustergroups-edit -rules: -- apiGroups: - - crd.antrea.io - resources: - - clustergroups - verbs: - - get - - list - - watch - - create - - update - - patch - - delete ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - labels: - app: antrea - rbac.authorization.k8s.io/aggregate-to-view: "true" - name: aggregate-antrea-clustergroups-view -rules: -- apiGroups: - - crd.antrea.io - resources: - - clustergroups - verbs: - - get - - list - - watch ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - labels: - app: antrea - rbac.authorization.k8s.io/aggregate-to-admin: "true" - rbac.authorization.k8s.io/aggregate-to-edit: "true" - name: aggregate-antrea-policies-edit -rules: -- apiGroups: - - crd.antrea.io - resources: - - clusternetworkpolicies - - networkpolicies - verbs: - - get - - list - - watch - - create - - update - - patch - - delete ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - labels: - app: antrea - rbac.authorization.k8s.io/aggregate-to-view: "true" - name: aggregate-antrea-policies-view -rules: -- apiGroups: - - crd.antrea.io - resources: - - clusternetworkpolicies - - networkpolicies - verbs: - - get - - list - - watch ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - labels: - app: antrea - rbac.authorization.k8s.io/aggregate-to-admin: "true" - rbac.authorization.k8s.io/aggregate-to-edit: "true" - name: aggregate-traceflows-edit -rules: -- apiGroups: - - crd.antrea.io - resources: - - traceflows - verbs: - - get - - list - - watch - - create - - update - - patch - - delete ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - labels: - app: antrea - rbac.authorization.k8s.io/aggregate-to-view: "true" - name: aggregate-traceflows-view -rules: -- apiGroups: - - crd.antrea.io - resources: - - traceflows - verbs: - - get - - list - - watch ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - labels: - app: antrea - name: antctl -rules: -- apiGroups: - - controlplane.antrea.io - resources: - - networkpolicies - - appliedtogroups - - addressgroups - verbs: - - get - - list -- apiGroups: - - stats.antrea.io - resources: - - networkpolicystats - - antreaclusternetworkpolicystats - - antreanetworkpolicystats - verbs: - - get - - list -- apiGroups: - - system.antrea.io - resources: - - controllerinfos - - agentinfos - verbs: - - get -- apiGroups: - - system.antrea.io - resources: - - supportbundles - verbs: - - get - - post -- apiGroups: - - system.antrea.io - resources: - - supportbundles/download - verbs: - - get -- nonResourceURLs: - - /agentinfo - - /addressgroups - - /appliedtogroups - - /loglevel - - /networkpolicies - - /ovsflows - - /ovstracing - - /podinterfaces - - /featuregates - verbs: - - get ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - labels: - app: antrea - name: antrea-agent -rules: -- apiGroups: - - "" - resources: - - nodes - verbs: - - get - - watch - - list -- apiGroups: - - "" - resources: - - nodes/status - verbs: - - patch -- apiGroups: - - "" - resources: - - pods - verbs: - - get - - watch - - list -- apiGroups: - - "" - resources: - - pods/status - verbs: - - patch -- apiGroups: - - "" - resources: - - endpoints - - services - - namespaces - verbs: - - get - - watch - - list -- apiGroups: - - "" - resources: - - services/status - verbs: - - update -- apiGroups: - - discovery.k8s.io - resources: - - endpointslices - verbs: - - get - - watch - - list -- apiGroups: - - crd.antrea.io - resources: - - antreaagentinfos - verbs: - - get - - create - - update - - delete -- apiGroups: - - controlplane.antrea.io - resources: - - networkpolicies - - appliedtogroups - - addressgroups - verbs: - - get - - watch - - list -- apiGroups: - - controlplane.antrea.io - resources: - - egressgroups - verbs: - - get - - watch - - list -- apiGroups: - - controlplane.antrea.io - resources: - - nodestatssummaries - verbs: - - create -- apiGroups: - - controlplane.antrea.io - resources: - - networkpolicies/status - verbs: - - create - - get -- apiGroups: - - authentication.k8s.io - resources: - - tokenreviews - verbs: - - create -- apiGroups: - - authorization.k8s.io - resources: - - subjectaccessreviews - verbs: - - create -- apiGroups: - - "" - resourceNames: - - extension-apiserver-authentication - resources: - - configmaps - verbs: - - get - - list - - watch -- apiGroups: - - "" - resourceNames: - - antrea-ca - resources: - - configmaps - verbs: - - get - - watch - - list -- apiGroups: - - crd.antrea.io - resources: - - traceflows - - traceflows/status - verbs: - - get - - watch - - list - - update - - patch - - create - - delete -- apiGroups: - - crd.antrea.io - resources: - - egresses - verbs: - - get - - watch - - list -- apiGroups: - - crd.antrea.io - resources: - - egresses/status - verbs: - - update -- apiGroups: - - crd.antrea.io - resources: - - externalippools - - ippools - verbs: - - get - - watch - - list -- apiGroups: - - crd.antrea.io - resources: - - ippools/status - verbs: - - update -- apiGroups: - - k8s.cni.cncf.io - resources: - - network-attachment-definitions - verbs: - - get - - list - - watch ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - labels: - app: antrea - name: antrea-cluster-identity-reader -rules: -- apiGroups: - - "" - resourceNames: - - antrea-cluster-identity - resources: - - configmaps - verbs: - - get ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - labels: - app: antrea - name: antrea-controller -rules: -- apiGroups: - - "" - resources: - - pods - - services - - namespaces - - configmaps - verbs: - - get - - watch - - list -- apiGroups: - - "" - resources: - - nodes - verbs: - - get - - watch - - list - - patch -- apiGroups: - - "" - resources: - - services/status - verbs: - - update -- apiGroups: - - networking.k8s.io - resources: - - networkpolicies - verbs: - - get - - watch - - list -- apiGroups: - - authentication.k8s.io - resources: - - tokenreviews - verbs: - - create -- apiGroups: - - authorization.k8s.io - resources: - - subjectaccessreviews - verbs: - - create -- apiGroups: - - apiextensions.k8s.io - resources: - - customresourcedefinitions - verbs: - - get - - update -- apiGroups: - - "" - resourceNames: - - extension-apiserver-authentication - resources: - - configmaps - verbs: - - get - - list - - watch -- apiGroups: - - "" - resourceNames: - - antrea-ca - - antrea-cluster-identity - resources: - - configmaps - verbs: - - get - - update -- apiGroups: - - "" - resources: - - configmaps - verbs: - - create -- apiGroups: - - apiregistration.k8s.io - resourceNames: - - v1alpha1.stats.antrea.io - - v1beta1.system.antrea.io - - v1beta2.controlplane.antrea.io - resources: - - apiservices - verbs: - - get - - update -- apiGroups: - - apiregistration.k8s.io - resourceNames: - - v1beta1.networking.antrea.tanzu.vmware.com - - v1beta1.controlplane.antrea.tanzu.vmware.com - - v1alpha1.stats.antrea.tanzu.vmware.com - - v1beta1.system.antrea.tanzu.vmware.com - - v1beta2.controlplane.antrea.tanzu.vmware.com - resources: - - apiservices - verbs: - - delete -- apiGroups: - - admissionregistration.k8s.io - resourceNames: - - labelsmutator.antrea.io - - crdmutator.antrea.io - - crdvalidator.antrea.io - resources: - - mutatingwebhookconfigurations - - validatingwebhookconfigurations - verbs: - - get - - update -- apiGroups: - - crd.antrea.io - resources: - - antreacontrollerinfos - verbs: - - get - - create - - update - - delete -- apiGroups: - - crd.antrea.io - resources: - - antreaagentinfos - verbs: - - list - - delete -- apiGroups: - - crd.antrea.io - resources: - - clusternetworkpolicies - - networkpolicies - verbs: - - get - - watch - - list - - update - - patch - - create - - delete -- apiGroups: - - crd.antrea.io - resources: - - clusternetworkpolicies/status - - networkpolicies/status - verbs: - - update -- apiGroups: - - crd.antrea.io - resources: - - tiers - verbs: - - get - - watch - - list - - update - - patch - - create - - delete -- apiGroups: - - crd.antrea.io - resources: - - traceflows - - traceflows/status - verbs: - - get - - watch - - list - - update - - patch - - create - - delete -- apiGroups: - - crd.antrea.io - resources: - - externalentities - - clustergroups - verbs: - - get - - watch - - list - - update - - patch - - create - - delete -- apiGroups: - - crd.antrea.io - resources: - - clustergroups/status - verbs: - - update -- apiGroups: - - crd.antrea.io - resources: - - egresses - verbs: - - get - - watch - - list - - update - - patch -- apiGroups: - - crd.antrea.io - resources: - - externalippools - - ippools - verbs: - - get - - watch - - list -- apiGroups: - - crd.antrea.io - resources: - - externalippools/status - - ippools/status - verbs: - - update -- apiGroups: - - apps - resources: - - statefulsets - verbs: - - get - - list - - watch ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - labels: - app: antrea - name: antctl - namespace: kube-system -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: antctl -subjects: -- kind: ServiceAccount - name: antctl - namespace: kube-system ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - labels: - app: antrea - name: antrea-agent -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: antrea-agent -subjects: -- kind: ServiceAccount - name: antrea-agent - namespace: kube-system ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - labels: - app: antrea - name: antrea-controller -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: antrea-controller -subjects: -- kind: ServiceAccount - name: antrea-controller - namespace: kube-system ---- -apiVersion: v1 data: antrea-agent.conf: | # FeatureGates is a map of feature names to bools that enable or disable experimental features. @@ -2771,7 +103,8 @@ data: # Egress: true # Enable AntreaIPAM, which can allocate IP addresses from IPPools. AntreaIPAM is required by the - # bridging mode and allocates IPs to Pods in bridging mode. + # bridging mode and allocates IPs to Pods in bridging mode. It is also required to use Antrea for + # IPAM when configuring secondary network interfaces with Multus. # AntreaIPAM: false # Enable multicast traffic. This feature is supported only with noEncap mode. @@ -2785,21 +118,23 @@ data: # Enable managing external IPs of Services of LoadBalancer type. # ServiceExternalIP: false + # Enable mirroring or redirecting the traffic Pods send or receive. + # TrafficControl: false + # Name of the OpenVSwitch bridge antrea-agent will create and use. # Make sure it doesn't conflict with your existing OpenVSwitch bridges. - #ovsBridge: br-int + ovsBridge: "br-int" # Datapath type to use for the OpenVSwitch bridge created by Antrea. Supported values are: # - system # - netdev # 'system' is the default value and corresponds to the kernel datapath. Use 'netdev' to run - # OVS in userspace mode (not fully supported yet). Userspace mode requires the tun device driver to - # be available. + # OVS in userspace mode. Userspace mode requires the tun device driver to be available. #ovsDatapathType: system # Name of the interface antrea-agent will create and use for host <--> pod communication. # Make sure it doesn't conflict with your existing interfaces. - #hostGateway: antrea-gw0 + hostGateway: "antrea-gw0" # Determines how traffic is encapsulated. It has the following options: # encap(default): Inter-node Pod traffic is always encapsulated and Pod to external network @@ -2811,14 +146,14 @@ data: # networkPolicyOnly: Antrea enforces NetworkPolicy only, and utilizes CNI chaining and delegates Pod # IPAM and connectivity to the primary CNI. # - #trafficEncapMode: encap + trafficEncapMode: "encap" # Whether or not to SNAT (using the Node IP) the egress traffic from a Pod to the external network. # This option is for the noEncap traffic mode only, and the default value is false. In the noEncap # mode, if the cluster's Pod CIDR is reachable from the external network, then the Pod traffic to # the external network needs not be SNAT'd. In the networkPolicyOnly mode, antrea-agent never # performs SNAT and this option will be ignored; for other modes it must be set to false. - #noSNAT: false + noSNAT: false # Tunnel protocols used for encapsulating traffic across Nodes. If WireGuard is enabled in trafficEncryptionMode, # this option will not take effect. Supported values: @@ -2827,7 +162,7 @@ data: # - gre # - stt # Note that "gre" is not supported for IPv6 clusters (IPv6-only or dual-stack clusters). - tunnelType: gre + tunnelType: "gre" # Determines how tunnel traffic is encrypted. Currently encryption only works with encap mode. # It has the following options: @@ -2837,49 +172,54 @@ data: # the PSK value must be passed to Antrea Agent through an environment # variable: ANTREA_IPSEC_PSK. # - wireGuard: Enable WireGuard for tunnel traffic encryption. - trafficEncryptionMode: ipsec + trafficEncryptionMode: "ipsec" # Enable bridging mode of Pod network on Nodes, in which the Node's transport interface is connected - # to the OVS bridge, and cross-Node/VLAN traffic from AntreaIPAM Pods (Pods whose IP addresses are - # allocated by AntreaIPAM from IPPools) is sent to the underlay network via the uplink, and - # forwarded/routed by the underlay network. + # to the OVS bridge, and cross-Node/VLAN traffic of AntreaIPAM Pods (Pods whose IP addresses are + # allocated by AntreaIPAM from IPPools) is sent to the underlay network, and forwarded/routed by the + # underlay network. # This option requires the `AntreaIPAM` feature gate to be enabled. At this moment, it supports only # IPv4 and Linux Nodes, and can be enabled only when `ovsDatapathType` is `system`, # `trafficEncapMode` is `noEncap`, and `noSNAT` is true. - #enableBridgingMode: false + enableBridgingMode: false + + # Disable TX checksum offloading for container network interfaces. It's supposed to be set to true when the + # datapath doesn't support TX checksum offloading, which causes packets to be dropped due to bad checksum. + # It affects Pods running on Linux Nodes only. + disableTXChecksumOffload: false # Default MTU to use for the host gateway interface and the network interface of each Pod. # If omitted, antrea-agent will discover the MTU of the Node's primary interface and # also adjust MTU to accommodate for tunnel encapsulation overhead (if applicable). - #defaultMTU: 0 + defaultMTU: 0 # wireGuard specifies WireGuard related configurations. wireGuard: - # The port for WireGuard to receive traffic. - # port: 51820 + # The port for WireGuard to receive traffic. + port: 51820 egress: - # exceptCIDRs is the CIDR ranges to which outbound Pod traffic will not be SNAT'd by Egresses. - # exceptCIDRs: [] + # exceptCIDRs is the CIDR ranges to which outbound Pod traffic will not be SNAT'd by Egresses. + exceptCIDRs: # ClusterIP CIDR range for Services. It's required when AntreaProxy is not enabled, and should be # set to the same value as the one specified by --service-cluster-ip-range for kube-apiserver. When # AntreaProxy is enabled, this parameter is not needed and will be ignored if provided. - #serviceCIDR: 10.96.0.0/12 + serviceCIDR: "" # ClusterIP CIDR range for IPv6 Services. It's required when using kube-proxy to provide IPv6 Service in a Dual-Stack # cluster or an IPv6 only cluster. The value should be the same as the configuration for kube-apiserver specified by # --service-cluster-ip-range. When AntreaProxy is enabled, this parameter is not needed. # No default value for this field. - #serviceCIDRv6: + serviceCIDRv6: "" # The port for the antrea-agent APIServer to serve on. # Note that if it's set to another value, the `containerPort` of the `api` port of the # `antrea-agent` container must be set to the same value. - #apiPort: 10350 + apiPort: 10350 # Enable metrics exposure via Prometheus. Initializes Prometheus metrics listener. - #enablePrometheusMetrics: true + enablePrometheusMetrics: true # Provide the IPFIX collector address as a string with format :[][:]. # HOST can either be the DNS name or the IP of the Flow Collector. For example, @@ -2890,50 +230,50 @@ data: # If no PROTO is given, we consider "tls" as default. We support "tls", "tcp" and # "udp" protocols. "tls" is used for securing communication between flow exporter and # flow aggregator. - #flowCollectorAddr: "flow-aggregator.flow-aggregator.svc:4739:tls" + flowCollectorAddr: "flow-aggregator.flow-aggregator.svc:4739:tls" # Provide flow poll interval as a duration string. This determines how often the # flow exporter dumps connections from the conntrack module. Flow poll interval # should be greater than or equal to 1s (one second). # Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". - #flowPollInterval: "5s" + flowPollInterval: "5s" # Provide the active flow export timeout, which is the timeout after which a flow # record is sent to the collector for active flows. Thus, for flows with a continuous # stream of packets, a flow record will be exported to the collector once the elapsed # time since the last export event is equal to the value of this timeout. # Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". - #activeFlowExportTimeout: "30s" + activeFlowExportTimeout: "5s" # Provide the idle flow export timeout, which is the timeout after which a flow # record is sent to the collector for idle flows. A flow is considered idle if no # packet matching this flow has been observed since the last export event. # Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". - #idleFlowExportTimeout: "15s" + idleFlowExportTimeout: "15s" nodePortLocal: # Enable NodePortLocal, a feature used to make Pods reachable using port forwarding on the host. To # enable this feature, you need to set "enable" to true, and ensure that the NodePortLocal feature # gate is also enabled (which is the default). - # enable: false + enable: false # Provide the port range used by NodePortLocal. When the NodePortLocal feature is enabled, a port # from that range will be assigned whenever a Pod's container defines a specific port to be exposed # (each container can define a list of ports as pod.spec.containers[].ports), and all Node traffic # directed to that port will be forwarded to the Pod. - # portRange: 61000-62000 + portRange: "61000-62000" # Provide the address of Kubernetes apiserver, to override any value provided in kubeconfig or InClusterConfig. # Defaults to "". It must be a host string, a host:port pair, or a URL to the base of the apiserver. - #kubeAPIServerOverride: "" + kubeAPIServerOverride: "" # Comma-separated list of Cipher Suites. If omitted, the default Go Cipher Suites will be used. # https://golang.org/pkg/crypto/tls/#pkg-constants # Note that TLS1.3 Cipher Suites cannot be added to the list. But the apiserver will always # prefer TLS1.3 Cipher Suites whenever possible. - #tlsCipherSuites: + tlsCipherSuites: "" # TLS min version from: VersionTLS10, VersionTLS11, VersionTLS12, VersionTLS13. - #tlsMinVersion: + tlsMinVersion: "" # The name of the interface on Node which is used for tunneling or routing the traffic across Nodes. # If there are multiple IP addresses configured on the interface, the first one is used. The IP @@ -2942,11 +282,16 @@ data: # 1. transportInterface # 2. transportInterfaceCIDRs # 3. The Node IP - #transportInterface: + transportInterface: "" + multicast: # The names of the interfaces on Nodes that are used to forward multicast traffic. # Defaults to transport interface if not set. - #multicastInterfaces: [] + multicastInterfaces: + + # The interval at which the antrea-agent sends IGMP queries to Pods. + # Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". + igmpQueryInterval: "125s" # The network CIDRs of the interface on Node which is used for tunneling or routing the traffic across # Nodes. If there are multiple interfaces configured the same network CIDR, the first one is used. The @@ -2955,7 +300,7 @@ data: # 1. transportInterface # 2. transportInterfaceCIDRs # 3. The Node IP - #transportInterfaceCIDRs: [,] + transportInterfaceCIDRs: # Option antreaProxy contains AntreaProxy related configuration options. antreaProxy: @@ -2964,22 +309,22 @@ data: # feature to be enabled. # Note that this option is experimental. If kube-proxy is removed, option kubeAPIServerOverride must be used to access # apiserver directly. - #proxyAll: false + proxyAll: false # A string array of values which specifies the host IPv4/IPv6 addresses for NodePort. Values can be valid IP blocks. # (e.g. 1.2.3.0/24, 1.2.3.4/32). An empty string slice is meant to select all host IPv4/IPv6 addresses. # Note that the option is only valid when proxyAll is true. - #nodePortAddresses: [] + nodePortAddresses: # An array of string values to specify a list of Services which should be ignored by AntreaProxy (traffic to these # Services will not be load-balanced). Values can be a valid ClusterIP (e.g. 10.11.1.2) or a Service name # with Namespace (e.g. kube-system/kube-dns) - #skipServices: [] + skipServices: # When ProxyLoadBalancerIPs is set to false, AntreaProxy no longer load-balances traffic destined to the # External IPs of LoadBalancer Services. This is useful when the external LoadBalancer provides additional # capabilities (e.g. TLS termination) and it is desirable for Pod-to-ExternalIP traffic to be sent to the # external LoadBalancer instead of being load-balanced to an Endpoint directly by AntreaProxy. # Note that setting ProxyLoadBalancerIPs to false usually only makes sense when ProxyAll is set to true and # kube-proxy is removed from the cluser, otherwise kube-proxy will still load-balance this traffic. - #proxyLoadBalancerIPs: true + proxyLoadBalancerIPs: true antrea-cni.conflist: | { "cniVersion":"0.3.0", @@ -2990,11 +335,13 @@ data: "ipam": { "type": "host-local" } - }, + } + , { "type": "portmap", "capabilities": {"portMappings": true} - }, + } + , { "type": "bandwidth", "capabilities": {"bandwidth": true} @@ -3021,8 +368,9 @@ data: # Run Kubernetes NodeIPAMController with Antrea. # NodeIPAM: false - # Enable flexible IPAM mode for Antrea. This mode allows to assign IP Ranges to Namespaces, - # Deployments and StatefulSets via IP Pool annotation. + # Enable AntreaIPAM, which can allocate IP addresses from IPPools. AntreaIPAM is required by the + # bridging mode and allocates IPs to Pods in bridging mode. It is also required to use Antrea for + # IPAM when configuring secondary network interfaces with Multus. # AntreaIPAM: false # Enable managing external IPs of Services of LoadBalancer type. @@ -3031,703 +379,3710 @@ data: # The port for the antrea-controller APIServer to serve on. # Note that if it's set to another value, the `containerPort` of the `api` port of the # `antrea-controller` container must be set to the same value. - #apiPort: 10349 + apiPort: 10349 # Enable metrics exposure via Prometheus. Initializes Prometheus metrics listener. - #enablePrometheusMetrics: true + enablePrometheusMetrics: true # Indicates whether to use auto-generated self-signed TLS certificate. - # If false, A Secret named "antrea-controller-tls" must be provided with the following keys: + # If false, a Secret named "antrea-controller-tls" must be provided with the following keys: # ca.crt: # tls.crt: # tls.key: - # And the Secret must be mounted to directory "/var/run/antrea/antrea-controller-tls" of the - # antrea-controller container. - #selfSignedCert: true + selfSignedCert: true # Comma-separated list of Cipher Suites. If omitted, the default Go Cipher Suites will be used. # https://golang.org/pkg/crypto/tls/#pkg-constants # Note that TLS1.3 Cipher Suites cannot be added to the list. But the apiserver will always # prefer TLS1.3 Cipher Suites whenever possible. - #tlsCipherSuites: + tlsCipherSuites: "" # TLS min version from: VersionTLS10, VersionTLS11, VersionTLS12, VersionTLS13. - #tlsMinVersion: + tlsMinVersion: "" nodeIPAM: - # Enable the integrated Node IPAM controller within the Antrea controller. - # enableNodeIPAM: false - - # CIDR ranges for Pods in cluster. String array containing single CIDR range, or multiple ranges. - # The CIDRs could be either IPv4 or IPv6. At most one CIDR may be specified for each IP family. - # Value ignored when enableNodeIPAM is false. - # clusterCIDRs: [] - - # CIDR ranges for Services in cluster. It is not necessary to specify it when there is no overlap with clusterCIDRs. - # Value ignored when enableNodeIPAM is false. - # serviceCIDR: - # serviceCIDRv6: - - # Mask size for IPv4 Node CIDR in IPv4 or dual-stack cluster. Value ignored when enableNodeIPAM is false - # or when IPv4 Pod CIDR is not configured. Valid range is 16 to 30. - # nodeCIDRMaskSizeIPv4: 24 - - # Mask size for IPv6 Node CIDR in IPv6 or dual-stack cluster. Value ignored when enableNodeIPAM is false - # or when IPv6 Pod CIDR is not configured. Valid range is 64 to 126. - # nodeCIDRMaskSizeIPv6: 64 -kind: ConfigMap + # Enable the integrated Node IPAM controller within the Antrea controller. + enableNodeIPAM: false + # CIDR ranges for Pods in cluster. String array containing single CIDR range, or multiple ranges. + # The CIDRs could be either IPv4 or IPv6. At most one CIDR may be specified for each IP family. + # Value ignored when enableNodeIPAM is false. + clusterCIDRs: + # CIDR ranges for Services in cluster. It is not necessary to specify it when there is no overlap with clusterCIDRs. + # Value ignored when enableNodeIPAM is false. + serviceCIDR: "" + serviceCIDRv6: "" + # Mask size for IPv4 Node CIDR in IPv4 or dual-stack cluster. Value ignored when enableNodeIPAM is false + # or when IPv4 Pod CIDR is not configured. Valid range is 16 to 30. + nodeCIDRMaskSizeIPv4: 24 + # Mask size for IPv6 Node CIDR in IPv6 or dual-stack cluster. Value ignored when enableNodeIPAM is false + # or when IPv6 Pod CIDR is not configured. Valid range is 64 to 126. + nodeCIDRMaskSizeIPv6: 64 +--- +# Source: antrea/templates/crds/antreaagentinfo.yaml +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: antreaagentinfos.crd.antrea.io + labels: + app: antrea +spec: + group: crd.antrea.io + versions: + - name: v1beta1 + served: true + storage: true + schema: + openAPIV3Schema: + type: object + x-kubernetes-preserve-unknown-fields: true + additionalPrinterColumns: + - description: Health status of this Agent + jsonPath: ".agentConditions[?(@.type=='AgentHealthy')].status" + name: Healthy + type: string + - description: Last time the Healthy Condition was updated + jsonPath: ".agentConditions[?(@.type=='AgentHealthy')].lastHeartbeatTime" + name: Last Heartbeat + type: date + - description: Version of this Agent + jsonPath: ".version" + name: Version + type: string + priority: 1 + - description: Node on which this Agent is running + jsonPath: ".nodeRef.name" + name: Node + type: string + priority: 1 + - description: Number of local Pods managed by this Agent + jsonPath: ".localPodNum" + name: Num Pods + type: integer + priority: 2 + - description: Subnets used by this Agent for Pod IPAM + jsonPath: ".nodeSubnets" + name: Subnets + type: string + priority: 2 + scope: Cluster + names: + plural: antreaagentinfos + singular: antreaagentinfo + kind: AntreaAgentInfo + shortNames: + - aai +--- +# Source: antrea/templates/crds/antreacontrollerinfo.yaml +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: antreacontrollerinfos.crd.antrea.io + labels: + app: antrea +spec: + group: crd.antrea.io + versions: + - name: v1beta1 + served: true + storage: true + schema: + openAPIV3Schema: + type: object + x-kubernetes-preserve-unknown-fields: true + additionalPrinterColumns: + - description: Health status of the Controller + jsonPath: ".controllerConditions[?(@.type=='ControllerHealthy')].status" + name: Healthy + type: string + - description: Last time the Healthy Condition was updated + jsonPath: ".controllerConditions[?(@.type=='ControllerHealthy')].lastHeartbeatTime" + name: Last Heartbeat + type: date + - description: Version of the Controller + jsonPath: ".version" + name: Version + type: string + priority: 1 + - description: Number of Agents connected to the Controller + jsonPath: ".connectedAgentNum" + name: Connected Agents + type: integer + priority: 1 + - description: Node on which the Controller is running + jsonPath: ".nodeRef.name" + name: Node + type: string + priority: 1 + - description: Number of Network Policies computed by Controller + jsonPath: ".networkPolicyControllerInfo.networkPolicyNum" + name: Num Network Policies + type: integer + priority: 2 + scope: Cluster + names: + plural: antreacontrollerinfos + singular: antreacontrollerinfo + kind: AntreaControllerInfo + shortNames: + - aci +--- +# Source: antrea/templates/crds/clustergroup.yaml +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: clustergroups.crd.antrea.io + labels: + app: antrea +spec: + group: crd.antrea.io + versions: + - name: v1alpha2 + served: true + storage: false + schema: + openAPIV3Schema: + type: object + properties: + spec: + type: object + properties: + childGroups: + type: array + items: + type: string + podSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + externalEntitySelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + ipBlock: + type: object + properties: + cidr: + type: string + format: cidr + ipBlocks: + type: array + items: + type: object + properties: + cidr: + type: string + format: cidr + serviceReference: + type: object + properties: + name: + type: string + namespace: + type: string + status: + type: object + properties: + conditions: + type: array + items: + type: object + properties: + type: + type: string + status: + type: string + lastTransitionTime: + type: string + - name: v1alpha3 + served: true + storage: true + schema: + openAPIV3Schema: + type: object + properties: + spec: + type: object + properties: + childGroups: + type: array + items: + type: string + podSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + externalEntitySelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + ipBlocks: + type: array + items: + type: object + properties: + cidr: + type: string + format: cidr + serviceReference: + type: object + properties: + name: + type: string + namespace: + type: string + status: + type: object + properties: + conditions: + type: array + items: + type: object + properties: + type: + type: string + status: + type: string + lastTransitionTime: + type: string + subresources: + status: {} + conversion: + strategy: Webhook + webhook: + conversionReviewVersions: ["v1", "v1beta1"] + clientConfig: + service: + name: "antrea" + namespace: "kube-system" + path: "/convert/clustergroup" + scope: Cluster + names: + plural: clustergroups + singular: clustergroup + kind: ClusterGroup + shortNames: + - cg +--- +# Source: antrea/templates/crds/clusternetworkpolicy.yaml +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: clusternetworkpolicies.crd.antrea.io + labels: + app: antrea +spec: + group: crd.antrea.io + versions: + - name: v1alpha1 + served: true + storage: true + additionalPrinterColumns: + - name: Tier + type: string + description: The Tier to which this ClusterNetworkPolicy belongs to. + jsonPath: .spec.tier + - name: Priority + type: number + format: float + description: The Priority of this ClusterNetworkPolicy relative to other policies. + jsonPath: .spec.priority + - name: Desired Nodes + type: number + format: int32 + description: The total number of Nodes that should realize the NetworkPolicy. + jsonPath: .status.desiredNodesRealized + - name: Current Nodes + type: number + format: int32 + description: The number of Nodes that have realized the NetworkPolicy. + jsonPath: .status.currentNodesRealized + - name: Age + type: date + jsonPath: .metadata.creationTimestamp + schema: + openAPIV3Schema: + type: object + properties: + spec: + # Ensure that Spec.Priority field is set + required: + - priority + type: object + properties: + tier: + type: string + priority: + type: number + format: float + # Ensure that Spec.Priority field is between 1 and 10000 + minimum: 1.0 + maximum: 10000.0 + appliedTo: + type: array + items: + type: object + # Ensure that Spec.AppliedTo does not allow IPBlock field + properties: + podSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + group: + type: string + serviceAccount: + type: object + properties: + name: + type: string + namespace: + type: string + required: + - name + - namespace + ingress: + type: array + items: + type: object + required: + - action + properties: + appliedTo: + type: array + items: + type: object + # Ensure that rule AppliedTo does not allow IPBlock field + properties: + podSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + group: + type: string + serviceAccount: + type: object + properties: + name: + type: string + namespace: + type: string + required: + - name + - namespace + # Ensure that Action field allows only ALLOW, DROP, REJECT and PASS values + action: + type: string + enum: ['Allow', 'Drop', 'Reject', 'Pass'] + ports: + type: array + items: + type: object + properties: + protocol: + type: string + enum: ['TCP', 'UDP', 'SCTP'] + port: + x-kubernetes-int-or-string: true + endPort: + type: integer + protocols: + type: array + items: + type: object + oneOf: + - required: [icmp] + properties: + icmp: + type: object + properties: + icmpType: + type: integer + minimum: 0 + maximum: 255 + icmpCode: + type: integer + minimum: 0 + maximum: 255 + from: + type: array + items: + type: object + properties: + podSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + namespaces: + type: object + properties: + match: + enum: + - Self + type: string + ipBlock: + type: object + properties: + cidr: + type: string + format: cidr + group: + type: string + serviceAccount: + type: object + properties: + name: + type: string + namespace: + type: string + required: + - name + - namespace + nodeSelector: + type: object + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + type: array + type: object + type: array + matchLabels: + x-kubernetes-preserve-unknown-fields: true + name: + type: string + enableLogging: + type: boolean + egress: + type: array + items: + type: object + required: + - action + properties: + appliedTo: + type: array + items: + type: object + # Ensure that rule AppliedTo does not allow IPBlock field + properties: + podSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + group: + type: string + serviceAccount: + type: object + properties: + name: + type: string + namespace: + type: string + required: + - name + - namespace + # Ensure that Action field allows only ALLOW, DROP, REJECT and PASS values + action: + type: string + enum: ['Allow', 'Drop', 'Reject', 'Pass'] + ports: + type: array + items: + type: object + properties: + protocol: + type: string + enum: ['TCP', 'UDP', 'SCTP'] + port: + x-kubernetes-int-or-string: true + endPort: + type: integer + protocols: + type: array + items: + type: object + oneOf: + - required: [icmp] + properties: + icmp: + type: object + properties: + icmpType: + type: integer + minimum: 0 + maximum: 255 + icmpCode: + type: integer + minimum: 0 + maximum: 255 + to: + type: array + items: + type: object + properties: + podSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + namespaces: + type: object + properties: + match: + enum: + - Self + type: string + ipBlock: + type: object + properties: + cidr: + type: string + format: cidr + group: + type: string + fqdn: + type: string + serviceAccount: + type: object + properties: + name: + type: string + namespace: + type: string + required: + - name + - namespace + nodeSelector: + type: object + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + type: array + type: object + type: array + matchLabels: + x-kubernetes-preserve-unknown-fields: true + toServices: + type: array + items: + type: object + required: + - name + - namespace + properties: + name: + type: string + namespace: + type: string + name: + type: string + enableLogging: + type: boolean + status: + type: object + properties: + phase: + type: string + observedGeneration: + type: integer + currentNodesRealized: + type: integer + desiredNodesRealized: + type: integer + subresources: + status: {} + scope: Cluster + names: + plural: clusternetworkpolicies + singular: clusternetworkpolicy + kind: ClusterNetworkPolicy + shortNames: + - acnp +--- +# Source: antrea/templates/crds/egress.yaml +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: egresses.crd.antrea.io + labels: + app: antrea +spec: + group: crd.antrea.io + versions: + - name: v1alpha2 + served: true + storage: true + schema: + openAPIV3Schema: + type: object + required: + - spec + properties: + spec: + type: object + required: + - appliedTo + anyOf: + - required: + - egressIP + - required: + - externalIPPool + properties: + appliedTo: + type: object + properties: + podSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + egressIP: + type: string + oneOf: + - format: ipv4 + - format: ipv6 + externalIPPool: + type: string + status: + type: object + properties: + egressNode: + type: string + additionalPrinterColumns: + - description: Specifies the SNAT IP address for the selected workloads. + jsonPath: .spec.egressIP + name: EgressIP + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + - description: The Owner Node of egress IP + jsonPath: .status.egressNode + name: Node + type: string + subresources: + status: {} + scope: Cluster + names: + plural: egresses + singular: egress + kind: Egress + shortNames: + - eg +--- +# Source: antrea/templates/crds/externalentity.yaml +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: externalentities.crd.antrea.io + labels: + app: antrea +spec: + group: crd.antrea.io + versions: + - name: v1alpha2 + served: true + storage: true + schema: + openAPIV3Schema: + type: object + properties: + spec: + type: object + properties: + endpoints: + type: array + items: + type: object + properties: + ip: + type: string + oneOf: + - format: ipv4 + - format: ipv6 + name: + type: string + ports: + type: array + items: + type: object + properties: + protocol: + type: string + enum: ['TCP', 'UDP', 'SCTP'] + port: + x-kubernetes-int-or-string: true + name: + type: string + externalNode: + type: string + - name: v1alpha1 + served: false + storage: false + schema: + openAPIV3Schema: + type: object + scope: Namespaced + names: + plural: externalentities + singular: externalentity + kind: ExternalEntity + shortNames: + - ee +--- +# Source: antrea/templates/crds/externalippool.yaml +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: externalippools.crd.antrea.io + labels: + app: antrea +spec: + group: crd.antrea.io + versions: + - name: v1alpha2 + served: true + storage: true + schema: + openAPIV3Schema: + type: object + required: + - spec + properties: + spec: + type: object + required: + - ipRanges + - nodeSelector + properties: + ipRanges: + type: array + items: + type: object + oneOf: + - required: + - cidr + - required: + - start + - end + properties: + cidr: + type: string + format: cidr + start: + type: string + oneOf: + - format: ipv4 + - format: ipv6 + end: + type: string + oneOf: + - format: ipv4 + - format: ipv6 + nodeSelector: + type: object + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + type: array + type: object + type: array + matchLabels: + x-kubernetes-preserve-unknown-fields: true + status: + type: object + properties: + usage: + type: object + properties: + total: + type: integer + used: + type: integer + additionalPrinterColumns: + - description: The number of total IPs + jsonPath: .status.usage.total + name: Total + type: integer + - description: The number of allocated IPs + jsonPath: .status.usage.used + name: Used + type: integer + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + subresources: + status: {} + scope: Cluster + names: + plural: externalippools + singular: externalippool + kind: ExternalIPPool + shortNames: + - eip +--- +# Source: antrea/templates/crds/ippool.yaml +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: ippools.crd.antrea.io + labels: + app: antrea +spec: + group: crd.antrea.io + versions: + - name: v1alpha2 + served: true + storage: true + schema: + openAPIV3Schema: + type: object + required: + - spec + properties: + spec: + required: + - ipVersion + - ipRanges + type: object + properties: + ipVersion: + type: integer + ipRanges: + items: + oneOf: + - required: + - cidr + - gateway + - prefixLength + - required: + - start + - end + - gateway + - prefixLength + properties: + cidr: + format: cidr + type: string + start: + oneOf: + - format: ipv4 + - format: ipv6 + type: string + end: + oneOf: + - format: ipv4 + - format: ipv6 + type: string + gateway: + oneOf: + - format: ipv4 + - format: ipv6 + type: string + prefixLength: + type: integer + vlan: + type: integer + minimum: 0 + maximum: 4094 + type: object + type: array + status: + properties: + ipAddresses: + items: + properties: + ipAddress: + type: string + owner: + properties: + pod: + properties: + name: + type: string + namespace: + type: string + containerID: + type: string + ifName: + type: string + type: object + statefulSet: + properties: + name: + type: string + namespace: + type: string + index: + type: integer + type: object + type: object + phase: + type: string + type: object + type: array + type: object + subresources: + status: {} + scope: Cluster + names: + plural: ippools + singular: ippool + kind: IPPool + shortNames: + - ipp +--- +# Source: antrea/templates/crds/networkpolicy.yaml +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: networkpolicies.crd.antrea.io + labels: + app: antrea +spec: + group: crd.antrea.io + versions: + - name: v1alpha1 + served: true + storage: true + additionalPrinterColumns: + - name: Tier + type: string + description: The Tier to which this Antrea NetworkPolicy belongs to. + jsonPath: .spec.tier + - name: Priority + type: number + format: float + description: The Priority of this Antrea NetworkPolicy relative to other policies. + jsonPath: .spec.priority + - name: Desired Nodes + type: number + format: int32 + description: The total number of Nodes that should realize the NetworkPolicy. + jsonPath: .status.desiredNodesRealized + - name: Current Nodes + type: number + format: int32 + description: The number of Nodes that have realized the NetworkPolicy. + jsonPath: .status.currentNodesRealized + - name: Age + type: date + jsonPath: .metadata.creationTimestamp + schema: + openAPIV3Schema: + type: object + properties: + spec: + # Ensure that Spec.Priority field is set + required: + - priority + type: object + properties: + tier: + type: string + priority: + type: number + format: float + # Ensure that Spec.Priority field is between 1 and 10000 + minimum: 1.0 + maximum: 10000.0 + appliedTo: + type: array + items: + type: object + # Ensure that Spec.AppliedTo does not allow NamespaceSelector/IPBlock field + properties: + podSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + ingress: + type: array + items: + type: object + required: + - action + properties: + appliedTo: + type: array + items: + type: object + # Ensure that rule AppliedTo does not allow NamespaceSelector/IPBlock field + properties: + podSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + # Ensure that Action field allows only ALLOW, DROP, REJECT and PASS values + action: + type: string + enum: ['Allow', 'Drop', 'Reject', 'Pass'] + ports: + type: array + items: + type: object + properties: + protocol: + type: string + enum: ['TCP', 'UDP', 'SCTP'] + port: + x-kubernetes-int-or-string: true + endPort: + type: integer + protocols: + type: array + items: + type: object + oneOf: + - required: [icmp] + properties: + icmp: + type: object + properties: + icmpType: + type: integer + minimum: 0 + maximum: 255 + icmpCode: + type: integer + minimum: 0 + maximum: 255 + from: + type: array + items: + type: object + properties: + podSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + externalEntitySelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + ipBlock: + type: object + properties: + cidr: + type: string + format: cidr + nodeSelector: + type: object + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + type: array + type: object + type: array + matchLabels: + x-kubernetes-preserve-unknown-fields: true + name: + type: string + enableLogging: + type: boolean + egress: + type: array + items: + type: object + required: + - action + properties: + appliedTo: + type: array + items: + type: object + # Ensure that rule AppliedTo does not allow NamespaceSelector/IPBlock field + properties: + podSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + # Ensure that Action field allows only ALLOW, DROP, REJECT and PASS values + action: + type: string + enum: ['Allow', 'Drop', 'Reject', 'Pass'] + ports: + type: array + items: + type: object + properties: + protocol: + type: string + enum: ['TCP', 'UDP', 'SCTP'] + port: + x-kubernetes-int-or-string: true + endPort: + type: integer + protocols: + type: array + items: + type: object + oneOf: + - required: [icmp] + properties: + icmp: + type: object + properties: + icmpType: + type: integer + minimum: 0 + maximum: 255 + icmpCode: + type: integer + minimum: 0 + maximum: 255 + to: + type: array + items: + type: object + properties: + podSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + externalEntitySelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + ipBlock: + type: object + properties: + cidr: + type: string + format: cidr + fqdn: + type: string + nodeSelector: + type: object + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + type: array + type: object + type: array + matchLabels: + x-kubernetes-preserve-unknown-fields: true + toServices: + type: array + items: + type: object + required: + - name + properties: + name: + type: string + namespace: + type: string + name: + type: string + enableLogging: + type: boolean + status: + type: object + properties: + phase: + type: string + observedGeneration: + type: integer + currentNodesRealized: + type: integer + desiredNodesRealized: + type: integer + subresources: + status: {} + scope: Namespaced + names: + plural: networkpolicies + singular: networkpolicy + kind: NetworkPolicy + shortNames: + - anp +--- +# Source: antrea/templates/crds/tier.yaml +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: tiers.crd.antrea.io + labels: + app: antrea +spec: + group: crd.antrea.io + versions: + - name: v1alpha1 + served: true + storage: true + additionalPrinterColumns: + - name: Priority + type: integer + description: The Priority of this Tier relative to other Tiers. + jsonPath: .spec.priority + - name: Age + type: date + jsonPath: .metadata.creationTimestamp + schema: + openAPIV3Schema: + type: object + properties: + spec: + required: + - priority + type: object + properties: + priority: + type: integer + minimum: 0 + maximum: 255 + description: + type: string + scope: Cluster + names: + plural: tiers + singular: tier + kind: Tier + shortNames: + - tr +--- +# Source: antrea/templates/crds/traceflow.yaml +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: traceflows.crd.antrea.io + labels: + app: antrea +spec: + group: crd.antrea.io + versions: + - name: v1alpha1 + served: true + storage: true + additionalPrinterColumns: + - jsonPath: .status.phase + description: The phase of the Traceflow. + name: Phase + type: string + - jsonPath: .spec.source.pod + description: The name of the source Pod. + name: Source-Pod + type: string + priority: 10 + - jsonPath: .spec.destination.pod + description: The name of the destination Pod. + name: Destination-Pod + type: string + priority: 10 + - jsonPath: .spec.destination.ip + description: The IP address of the destination. + name: Destination-IP + type: string + priority: 10 + - jsonPath: .spec.liveTraffic + description: Trace live traffic. + name: Live-Traffic + type: boolean + priority: 10 + - jsonPath: .spec.droppedOnly + description: Capture only the dropped packet. + name: Dropped-Only + type: boolean + priority: 10 + - jsonPath: .spec.timeout + description: Timeout in seconds. + name: Timeout + type: integer + priority: 10 + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + schema: + openAPIV3Schema: + type: object + required: + - spec + properties: + spec: + type: object + properties: + source: + type: object + properties: + pod: + type: string + namespace: + type: string + ip: + type: string + oneOf: + - format: ipv4 + - format: ipv6 + destination: + type: object + properties: + pod: + type: string + service: + type: string + namespace: + type: string + ip: + type: string + oneOf: + - format: ipv4 + - format: ipv6 + packet: + type: object + properties: + ipHeader: + type: object + properties: + srcIP: + type: string + oneOf: + - format: ipv4 + - format: ipv6 + protocol: + type: integer + ttl: + type: integer + flags: + type: integer + ipv6Header: + type: object + properties: + srcIP: + type: string + format: ipv6 + nextHeader: + type: integer + hopLimit: + type: integer + transportHeader: + type: object + properties: + icmp: + type: object + properties: + id: + type: integer + sequence: + type: integer + udp: + type: object + properties: + srcPort: + type: integer + dstPort: + type: integer + tcp: + type: object + properties: + srcPort: + type: integer + dstPort: + type: integer + flags: + type: integer + liveTraffic: + type: boolean + droppedOnly: + type: boolean + timeout: + type: integer + status: + type: object + properties: + reason: + type: string + dataplaneTag: + type: integer + phase: + type: string + startTime: + type: string + results: + type: array + items: + type: object + properties: + node: + type: string + role: + type: string + timestamp: + type: integer + observations: + type: array + items: + type: object + properties: + component: + type: string + componentInfo: + type: string + action: + type: string + pod: + type: string + dstMAC: + type: string + networkPolicy: + type: string + ttl: + type: integer + translatedSrcIP: + type: string + translatedDstIP: + type: string + tunnelDstIP: + type: string + capturedPacket: + properties: + srcIP: + type: string + dstIP: + type: string + length: + type: integer + ipHeader: + properties: + flags: + type: integer + protocol: + type: integer + ttl: + type: integer + type: object + ipv6Header: + properties: + hopLimit: + type: integer + nextHeader: + type: integer + type: object + transportHeader: + properties: + tcp: + properties: + dstPort: + type: integer + srcPort: + type: integer + flags: + type: integer + type: object + udp: + properties: + dstPort: + type: integer + srcPort: + type: integer + type: object + icmp: + properties: + id: + type: integer + sequence: + type: integer + type: object + type: object + type: object + subresources: + status: {} + scope: Cluster + names: + plural: traceflows + singular: traceflow + kind: Traceflow + shortNames: + - tf +--- +# Source: antrea/templates/crds/trafficcontrol.yaml +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: trafficcontrols.crd.antrea.io +spec: + group: crd.antrea.io + versions: + - name: v1alpha2 + served: true + storage: true + schema: + openAPIV3Schema: + type: object + required: + - spec + properties: + spec: + type: object + required: + - appliedTo + - direction + - action + - targetPort + properties: + appliedTo: + type: object + properties: + podSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + direction: + type: string + enum: + - Ingress + - Egress + - Both + action: + type: string + enum: + - Mirror + - Redirect + targetPort: + type: object + oneOf: + - required: [ovsInternal] + - required: [device] + - required: [geneve] + - required: [vxlan] + - required: [gre] + - required: [erspan] + properties: + ovsInternal: + type: object + required: + - name + properties: + name: + type: string + device: + type: object + required: + - name + properties: + name: + type: string + geneve: + type: object + required: + - remoteIP + properties: + remoteIP: + type: string + oneOf: + - format: ipv4 + - format: ipv6 + vni: + type: integer + minimum: 0 + maximum: 16777215 + destinationPort: + type: integer + minimum: 1 + maximum: 65535 + vxlan: + type: object + required: + - remoteIP + properties: + remoteIP: + type: string + oneOf: + - format: ipv4 + - format: ipv6 + vni: + type: integer + minimum: 0 + maximum: 16777215 + destinationPort: + type: integer + minimum: 1 + maximum: 65535 + gre: + type: object + required: + - remoteIP + properties: + remoteIP: + type: string + oneOf: + - format: ipv4 + - format: ipv6 + key: + type: integer + minimum: 0 + maximum: 4294967295 + erspan: + type: object + required: + - remoteIP + - version + properties: + remoteIP: + type: string + oneOf: + - format: ipv4 + - format: ipv6 + sessionID: + type: integer + minimum: 0 + maximum: 1023 + version: + type: integer + enum: + - 1 + - 2 + index: + type: integer + dir: + type: integer + enum: + - 0 + - 1 + hardwareID: + type: integer + returnPort: + type: object + oneOf: + - required: [ovsInternal] + - required: [device] + - required: [geneve] + - required: [vxlan] + - required: [gre] + properties: + ovsInternal: + type: object + required: + - name + properties: + name: + type: string + device: + type: object + required: + - name + properties: + name: + type: string + geneve: + type: object + required: + - remoteIP + properties: + remoteIP: + type: string + oneOf: + - format: ipv4 + - format: ipv6 + vni: + type: integer + minimum: 0 + maximum: 16777215 + destinationPort: + type: integer + minimum: 1 + maximum: 65535 + vxlan: + type: object + required: + - remoteIP + properties: + remoteIP: + type: string + oneOf: + - format: ipv4 + - format: ipv6 + vni: + type: integer + minimum: 0 + maximum: 16777215 + destinationPort: + type: integer + minimum: 1 + maximum: 65535 + gre: + type: object + required: + - remoteIP + properties: + remoteIP: + type: string + oneOf: + - format: ipv4 + - format: ipv6 + key: + type: integer + minimum: 0 + maximum: 4294967295 + additionalPrinterColumns: + - description: Specifies the direction of traffic that should be matched. + jsonPath: .spec.direction + name: Direction + type: string + - description: Specifies the action that should be taken for the traffic. + jsonPath: .spec.action + name: Action + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + subresources: + status: {} + scope: Cluster + names: + plural: trafficcontrols + singular: trafficcontrol + kind: TrafficControl + shortNames: + - tc +--- +# Source: antrea/templates/agent/clusterrole.yaml +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: antrea-agent + labels: + app: antrea +rules: + - apiGroups: + - "" + resources: + - nodes + verbs: + - get + - watch + - list + - apiGroups: + - "" + resources: + - nodes/status + verbs: + - patch + - apiGroups: + - "" + resources: + - pods + verbs: + - get + - watch + - list + - apiGroups: + - "" + resources: + - pods/status + verbs: + - patch + - apiGroups: + - "" + resources: + - endpoints + - services + - namespaces + verbs: + - get + - watch + - list + - apiGroups: + - discovery.k8s.io + resources: + - endpointslices + verbs: + - get + - watch + - list + - apiGroups: + - crd.antrea.io + resources: + - antreaagentinfos + verbs: + - get + - create + - update + - delete + - apiGroups: + - controlplane.antrea.io + resources: + - networkpolicies + - appliedtogroups + - addressgroups + verbs: + - get + - watch + - list + - apiGroups: + - controlplane.antrea.io + resources: + - egressgroups + verbs: + - get + - watch + - list + - apiGroups: + - controlplane.antrea.io + resources: + - nodestatssummaries + verbs: + - create + - apiGroups: + - controlplane.antrea.io + resources: + - networkpolicies/status + verbs: + - create + - get + - apiGroups: + - authentication.k8s.io + resources: + - tokenreviews + verbs: + - create + - apiGroups: + - authorization.k8s.io + resources: + - subjectaccessreviews + verbs: + - create + # This is the content of built-in role kube-system/extension-apiserver-authentication-reader. + # But it doesn't have list/watch permission before K8s v1.17.0 so the extension apiserver (antrea-agent) will + # have permission issue after bumping up apiserver library to a version that supports dynamic authentication. + # See https://github.com/kubernetes/kubernetes/pull/85375 + # To support K8s clusters older than v1.17.0, we grant the required permissions directly instead of relying on + # the extension-apiserver-authentication role. + - apiGroups: + - "" + resourceNames: + - extension-apiserver-authentication + resources: + - configmaps + verbs: + - get + - list + - watch + - apiGroups: + - "" + resources: + - configmaps + resourceNames: + - antrea-ca + verbs: + - get + - watch + - list + - apiGroups: + - crd.antrea.io + resources: + - traceflows + - traceflows/status + verbs: + - get + - watch + - list + - update + - patch + - create + - delete + - apiGroups: + - crd.antrea.io + resources: + - egresses + verbs: + - get + - watch + - list + - apiGroups: + - crd.antrea.io + resources: + - egresses/status + verbs: + - update + - apiGroups: + - crd.antrea.io + resources: + - externalippools + - ippools + - trafficcontrols + verbs: + - get + - watch + - list + - apiGroups: + - crd.antrea.io + resources: + - ippools/status + verbs: + - update + - apiGroups: + - k8s.cni.cncf.io + resources: + - network-attachment-definitions + verbs: + - get + - list + - watch +--- +# Source: antrea/templates/antctl/clusterrole.yaml +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: antctl + labels: + app: antrea +rules: + - apiGroups: + - controlplane.antrea.io + resources: + - networkpolicies + - appliedtogroups + - addressgroups + verbs: + - get + - list + - apiGroups: + - stats.antrea.io + resources: + - networkpolicystats + - antreaclusternetworkpolicystats + - antreanetworkpolicystats + verbs: + - get + - list + - apiGroups: + - system.antrea.io + resources: + - controllerinfos + - agentinfos + verbs: + - get + - apiGroups: + - system.antrea.io + resources: + - supportbundles + verbs: + - get + - post + - apiGroups: + - system.antrea.io + resources: + - supportbundles/download + verbs: + - get + - nonResourceURLs: + - /agentinfo + - /addressgroups + - /appliedtogroups + - /loglevel + - /networkpolicies + - /ovsflows + - /ovstracing + - /podinterfaces + - /featuregates + - /serviceexternalip + verbs: + - get +--- +# Source: antrea/templates/cluster-identity-reader/clusterrolebinding.yaml +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: antrea-cluster-identity-reader + labels: + app: antrea +rules: + - apiGroups: + - "" + resources: + - configmaps + resourceNames: + - antrea-cluster-identity + verbs: + - get +--- +# Source: antrea/templates/controller/clusterrole.yaml +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: antrea-controller + labels: + app: antrea +rules: + - apiGroups: + - "" + resources: + - pods + - services + - namespaces + - configmaps + verbs: + - get + - watch + - list + - apiGroups: + - "" + resources: + - nodes + verbs: + - get + - watch + - list + - patch + - apiGroups: + - "" + resources: + - services/status + verbs: + - update + - apiGroups: + - networking.k8s.io + resources: + - networkpolicies + verbs: + - get + - watch + - list + - apiGroups: + - authentication.k8s.io + resources: + - tokenreviews + verbs: + - create + - apiGroups: + - authorization.k8s.io + resources: + - subjectaccessreviews + verbs: + - create + - apiGroups: + - apiextensions.k8s.io + resources: + - customresourcedefinitions + verbs: + - get + - update + # This is the content of built-in role kube-system/extension-apiserver-authentication-reader. + # But it doesn't have list/watch permission before K8s v1.17.0 so the extension apiserver (antrea-controller) will + # have permission issue after bumping up apiserver library to a version that supports dynamic authentication. + # See https://github.com/kubernetes/kubernetes/pull/85375 + # To support K8s clusters older than v1.17.0, we grant the required permissions directly instead of relying on + # the extension-apiserver-authentication role. + - apiGroups: + - "" + resourceNames: + - extension-apiserver-authentication + resources: + - configmaps + verbs: + - get + - list + - watch + - apiGroups: + - "" + resources: + - configmaps + resourceNames: + - antrea-ca + - antrea-cluster-identity + verbs: + - get + - update + - apiGroups: + - "" + resources: + - configmaps + verbs: + - create + - apiGroups: + - apiregistration.k8s.io + resources: + - apiservices + resourceNames: + - v1alpha1.stats.antrea.io + - v1beta1.system.antrea.io + - v1beta2.controlplane.antrea.io + verbs: + - get + - update + - apiGroups: + - apiregistration.k8s.io + resources: + - apiservices + resourceNames: + - v1beta1.networking.antrea.tanzu.vmware.com + - v1beta1.controlplane.antrea.tanzu.vmware.com + - v1alpha1.stats.antrea.tanzu.vmware.com + - v1beta1.system.antrea.tanzu.vmware.com + - v1beta2.controlplane.antrea.tanzu.vmware.com + verbs: + - delete + - apiGroups: + - admissionregistration.k8s.io + resources: + - mutatingwebhookconfigurations + - validatingwebhookconfigurations + resourceNames: + # always give permissions for labelsmutator.antrea.io, even when the + # feature is disabled, to avoid errors in antrea-controller when updating + # the CA cert. + - labelsmutator.antrea.io + - crdmutator.antrea.io + - crdvalidator.antrea.io + verbs: + - get + - update + - apiGroups: + - crd.antrea.io + resources: + - antreacontrollerinfos + verbs: + - get + - create + - update + - delete + - apiGroups: + - crd.antrea.io + resources: + - antreaagentinfos + verbs: + - list + - delete + - apiGroups: + - crd.antrea.io + resources: + - clusternetworkpolicies + - networkpolicies + verbs: + - get + - watch + - list + - update + - patch + - create + - delete + - apiGroups: + - crd.antrea.io + resources: + - clusternetworkpolicies/status + - networkpolicies/status + verbs: + - update + - apiGroups: + - crd.antrea.io + resources: + - tiers + verbs: + - get + - watch + - list + - update + - patch + - create + - delete + - apiGroups: + - crd.antrea.io + resources: + - traceflows + - traceflows/status + verbs: + - get + - watch + - list + - update + - patch + - create + - delete + - apiGroups: + - crd.antrea.io + resources: + - externalentities + - clustergroups + verbs: + - get + - watch + - list + - update + - patch + - create + - delete + - apiGroups: + - crd.antrea.io + resources: + - clustergroups/status + verbs: + - update + - apiGroups: + - crd.antrea.io + resources: + - egresses + verbs: + - get + - watch + - list + - update + - patch + - apiGroups: + - crd.antrea.io + resources: + - externalippools + - ippools + verbs: + - get + - watch + - list + - apiGroups: + - crd.antrea.io + resources: + - externalippools/status + - ippools/status + verbs: + - update + - apiGroups: + - apps + resources: + - statefulsets + verbs: + - get + - list + - watch +--- +# Source: antrea/templates/crds-rbac/clusterroles.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole metadata: + name: aggregate-antrea-policies-edit labels: app: antrea - name: antrea-config-tmhkc66d6c - namespace: kube-system + # Add these permissions to the "admin" and "edit" default roles. + rbac.authorization.k8s.io/aggregate-to-admin: "true" + rbac.authorization.k8s.io/aggregate-to-edit: "true" +rules: +- apiGroups: ["crd.antrea.io"] + resources: ["clusternetworkpolicies", "networkpolicies"] + verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] --- -apiVersion: v1 -kind: Secret +# Source: antrea/templates/crds-rbac/clusterroles.yaml +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 metadata: - name: antrea-ipsec - namespace: kube-system -stringData: - psk: changeme -type: Opaque + name: aggregate-antrea-policies-view + labels: + app: antrea + # Add these permissions to the "view" default role. + rbac.authorization.k8s.io/aggregate-to-view: "true" +rules: +- apiGroups: ["crd.antrea.io"] + resources: ["clusternetworkpolicies", "networkpolicies"] + verbs: ["get", "list", "watch"] --- -apiVersion: v1 -kind: Service +# Source: antrea/templates/crds-rbac/clusterroles.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: aggregate-traceflows-edit + labels: + app: antrea + # Add these permissions to the "admin" and "edit" default roles. + rbac.authorization.k8s.io/aggregate-to-admin: "true" + rbac.authorization.k8s.io/aggregate-to-edit: "true" +rules: +- apiGroups: ["crd.antrea.io"] + resources: ["traceflows"] + verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] +--- +# Source: antrea/templates/crds-rbac/clusterroles.yaml +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 metadata: + name: aggregate-traceflows-view + labels: + app: antrea + # Add these permissions to the "view" default role. + rbac.authorization.k8s.io/aggregate-to-view: "true" +rules: +- apiGroups: ["crd.antrea.io"] + resources: ["traceflows"] + verbs: ["get", "list", "watch"] +--- +# Source: antrea/templates/crds-rbac/clusterroles.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: aggregate-antrea-clustergroups-edit + labels: + app: antrea + # Add these permissions to the "admin" and "edit" default roles. + rbac.authorization.k8s.io/aggregate-to-admin: "true" + rbac.authorization.k8s.io/aggregate-to-edit: "true" +rules: +- apiGroups: ["crd.antrea.io"] + resources: ["clustergroups"] + verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] +--- +# Source: antrea/templates/crds-rbac/clusterroles.yaml +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: aggregate-antrea-clustergroups-view + labels: + app: antrea + # Add these permissions to the "view" default role. + rbac.authorization.k8s.io/aggregate-to-view: "true" +rules: +- apiGroups: ["crd.antrea.io"] + resources: ["clustergroups"] + verbs: ["get", "list", "watch"] +--- +# Source: antrea/templates/agent/clusterrolebinding.yaml +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: antrea-agent + labels: + app: antrea +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: antrea-agent +subjects: + - kind: ServiceAccount + name: antrea-agent + namespace: kube-system +--- +# Source: antrea/templates/antctl/clusterrolebinding.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + labels: + app: antrea + name: antctl +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: antctl +subjects: + - kind: ServiceAccount + name: antctl + namespace: kube-system +--- +# Source: antrea/templates/controller/clusterrolebinding.yaml +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: antrea-controller labels: app: antrea +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: antrea-controller +subjects: + - kind: ServiceAccount + name: antrea-controller + namespace: kube-system +--- +# Source: antrea/templates/controller/service.yaml +apiVersion: v1 +kind: Service +metadata: name: antrea namespace: kube-system + labels: + app: antrea spec: ports: - - port: 443 - protocol: TCP - targetPort: api + - port: 443 + protocol: TCP + targetPort: api selector: app: antrea component: antrea-controller --- +# Source: antrea/templates/agent/daemonset.yaml apiVersion: apps/v1 -kind: Deployment +kind: DaemonSet metadata: + name: antrea-agent + namespace: kube-system labels: app: antrea - component: antrea-controller + component: antrea-agent +spec: + selector: + matchLabels: + app: antrea + component: antrea-agent + updateStrategy: + type: RollingUpdate + template: + metadata: + annotations: + # Starting with v1.21, Kubernetes supports default container annotation. + # Using "kubectl logs/exec/attach/cp" doesn't have to specify "-c antrea-agent" when troubleshooting. + kubectl.kubernetes.io/default-container: antrea-agent + # Automatically restart Pods with a RollingUpdate if the ConfigMap changes + # See https://helm.sh/docs/howto/charts_tips_and_tricks/#automatically-roll-deployments + checksum/config: d5038309e5a226d5d860b167b95e0d8ed55af1914526f52e5ef8600e527695e5 + checksum/ipsec-secret: d0eb9c52d0cd4311b6d252a951126bf9bea27ec05590bed8a394f0f792dcb2a4 + labels: + app: antrea + component: antrea-agent + spec: + hostNetwork: true + dnsPolicy: ClusterFirstWithHostNet + priorityClassName: system-node-critical + nodeSelector: + kubernetes.io/os: linux + tolerations: + - key: CriticalAddonsOnly + operator: Exists + - effect: NoSchedule + operator: Exists + - effect: NoExecute + operator: Exists + serviceAccountName: antrea-agent + initContainers: + - name: install-cni + image: "projects.registry.vmware.com/antrea/antrea-ubuntu:latest" + imagePullPolicy: IfNotPresent + resources: + requests: + cpu: 100m + command: ["install_cni"] + securityContext: + capabilities: + add: + # SYS_MODULE is required to load the OVS kernel module. + - SYS_MODULE + env: + # SKIP_CNI_BINARIES takes in values as a comma separated list of + # binaries that need to be skipped for installation, e.g. "portmap, bandwidth". + - name: SKIP_CNI_BINARIES + value: "" + volumeMounts: + - name: antrea-config + mountPath: /etc/antrea/antrea-cni.conflist + subPath: antrea-cni.conflist + readOnly: true + - name: host-cni-conf + mountPath: /host/etc/cni/net.d + - name: host-cni-bin + mountPath: /host/opt/cni/bin + # For loading the OVS kernel module. + - name: host-lib-modules + mountPath: /lib/modules + readOnly: true + # For changing the default permissions of the run directory. + - name: host-var-run-antrea + mountPath: /var/run/antrea + containers: + - name: antrea-agent + image: "projects.registry.vmware.com/antrea/antrea-ubuntu:latest" + imagePullPolicy: IfNotPresent + command: ["antrea-agent"] + # Log to both "/var/log/antrea/" and stderr (so "kubectl logs" can work).- + args: + - "--config=/etc/antrea/antrea-agent.conf" + - "--logtostderr=false" + - "--log_dir=/var/log/antrea" + - "--alsologtostderr" + - "--log_file_max_size=100" + - "--log_file_max_num=4" + env: + # Provide pod and node information for clusterinformation CRD. + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: NODE_NAME + valueFrom: + fieldRef: + fieldPath: spec.nodeName + # Pre-shared key for IPsec IKE. + - name: ANTREA_IPSEC_PSK + valueFrom: + secretKeyRef: + name: antrea-ipsec + key: psk + resources: + requests: + cpu: 200m + ports: + - containerPort: 10350 + name: api + protocol: TCP + livenessProbe: + exec: + command: + - /bin/sh + - -c + - container_liveness_probe agent + initialDelaySeconds: 5 + timeoutSeconds: 5 + periodSeconds: 10 + failureThreshold: 5 + readinessProbe: + httpGet: + host: localhost + path: /readyz + port: api + scheme: HTTPS + initialDelaySeconds: 5 + timeoutSeconds: 5 + periodSeconds: 10 + # In large-scale clusters, it may take up to 40~50 seconds for the antrea-agent to reconnect to the antrea + # Service after the antrea-controller restarts. The antrea-agent shouldn't be reported as NotReady in this + # scenario, otherwise the DaemonSet controller would restart all agents at once, as opposed to performing a + # rolling update. Set failureThreshold to 8 so it can tolerate 70s of disconnection. + failureThreshold: 8 + securityContext: + # antrea-agent needs to perform sysctl configuration. + privileged: true + volumeMounts: + - name: antrea-config + mountPath: /etc/antrea/antrea-agent.conf + subPath: antrea-agent.conf + readOnly: true + - name: host-var-run-antrea + mountPath: /var/run/antrea + - name: host-var-run-antrea + mountPath: /var/run/openvswitch + subPath: openvswitch + # host-local IPAM stores allocated IP addresses as files in /var/lib/cni/networks/$NETWORK_NAME. + # Mount a sub-directory of host-var-run-antrea to it for persistence of IP allocation. + - name: host-var-run-antrea + mountPath: /var/lib/cni + subPath: cni + # We need to mount both the /proc directory and the /var/run/netns directory so that + # antrea-agent can open the network namespace path when setting up Pod + # networking. Different container runtimes may use /proc or /var/run/netns when invoking + # the CNI commands. Docker uses /proc and containerd uses /var/run/netns. + - name: host-var-log-antrea + mountPath: /var/log/antrea + - name: host-proc + mountPath: /host/proc + readOnly: true + - name: host-var-run-netns + mountPath: /host/var/run/netns + readOnly: true + # When a container is created, a mount point for the network namespace is added under + # /var/run/netns on the host, which needs to be propagated to the antrea-agent container. + mountPropagation: HostToContainer + - name: xtables-lock + mountPath: /run/xtables.lock + - name: antrea-ovs + image: "projects.registry.vmware.com/antrea/antrea-ubuntu:latest" + imagePullPolicy: IfNotPresent + resources: + requests: + cpu: 200m + command: ["start_ovs"] + args: + - "--log_file_max_size=100" + - "--log_file_max_num=4" + securityContext: + # capabilities required by OVS daemons + capabilities: + add: + - SYS_NICE + - NET_ADMIN + - SYS_ADMIN + - IPC_LOCK + livenessProbe: + exec: + # docker CRI doesn't honor timeoutSeconds, add "timeout" to the command as a workaround. + # https://github.com/kubernetes/kubernetes/issues/51901 + command: + - /bin/sh + - -c + - timeout 10 container_liveness_probe ovs + initialDelaySeconds: 5 + timeoutSeconds: 10 + periodSeconds: 10 + failureThreshold: 5 + volumeMounts: + - name: host-var-run-antrea + mountPath: /var/run/openvswitch + subPath: openvswitch + - name: host-var-log-antrea + mountPath: /var/log/openvswitch + subPath: openvswitch + - name: antrea-ipsec + image: "projects.registry.vmware.com/antrea/antrea-ubuntu:latest" + imagePullPolicy: IfNotPresent + resources: + requests: + cpu: 50m + command: ["start_ovs_ipsec"] + livenessProbe: + exec: + command: + - /bin/sh + - -c + - timeout 5 container_liveness_probe ovs-ipsec + initialDelaySeconds: 5 + periodSeconds: 5 + securityContext: + capabilities: + add: + - NET_ADMIN + volumeMounts: + - name: host-var-run-antrea + mountPath: /var/run/openvswitch + subPath: openvswitch + - name: host-var-log-antrea + mountPath: /var/log/openvswitch + subPath: openvswitch + - name: host-var-log-antrea + mountPath: /var/log/strongswan + subPath: strongswan + volumes: + - name: antrea-config + configMap: + name: antrea-config + - name: host-cni-conf + hostPath: + path: /etc/cni/net.d + - name: host-cni-bin + hostPath: + path: /opt/cni/bin + - name: host-proc + hostPath: + path: /proc + - name: host-var-run-netns + hostPath: + path: /var/run/netns + - name: host-var-run-antrea + hostPath: + path: /var/run/antrea + # we use subPath to create run subdirectories for different component (e.g. OVS) and + # subPath requires the base volume to exist + type: DirectoryOrCreate + - name: host-var-log-antrea + hostPath: + path: /var/log/antrea + # we use subPath to create logging subdirectories for different component (e.g. OVS) + type: DirectoryOrCreate + - name: host-lib-modules + hostPath: + path: /lib/modules + - name: xtables-lock + hostPath: + path: /run/xtables.lock + type: FileOrCreate +--- +# Source: antrea/templates/controller/deployment.yaml +apiVersion: apps/v1 +kind: Deployment +metadata: name: antrea-controller namespace: kube-system + labels: + app: antrea + component: antrea-controller spec: - replicas: 1 + strategy: + # Ensure the existing Pod is stopped before the new one is created. + type: Recreate selector: matchLabels: app: antrea component: antrea-controller - strategy: - type: Recreate + replicas: 1 template: metadata: + annotations: + # Automatically restart Pod if the ConfigMap changes + # See https://helm.sh/docs/howto/charts_tips_and_tricks/#automatically-roll-deployments + checksum/config: d5038309e5a226d5d860b167b95e0d8ed55af1914526f52e5ef8600e527695e5 labels: app: antrea component: antrea-controller spec: - containers: - - args: - - --config - - /etc/antrea/antrea-controller.conf - - --logtostderr=false - - --log_dir=/var/log/antrea - - --alsologtostderr - - --log_file_max_size=100 - - --log_file_max_num=4 - - --v=0 - command: - - antrea-controller - env: - - name: POD_NAME - valueFrom: - fieldRef: - fieldPath: metadata.name - - name: POD_NAMESPACE - valueFrom: - fieldRef: - fieldPath: metadata.namespace - - name: NODE_NAME - valueFrom: - fieldRef: - fieldPath: spec.nodeName - - name: SERVICEACCOUNT_NAME - valueFrom: - fieldRef: - fieldPath: spec.serviceAccountName - - name: ANTREA_CONFIG_MAP_NAME - value: antrea-config-tmhkc66d6c - image: projects.registry.vmware.com/antrea/antrea-ubuntu:latest - imagePullPolicy: IfNotPresent - livenessProbe: - failureThreshold: 5 - httpGet: - host: localhost - path: /livez - port: api - scheme: HTTPS - periodSeconds: 10 - timeoutSeconds: 5 - name: antrea-controller - ports: - - containerPort: 10349 - name: api - protocol: TCP - readinessProbe: - failureThreshold: 5 - httpGet: - host: localhost - path: /readyz - port: api - scheme: HTTPS - initialDelaySeconds: 5 - periodSeconds: 10 - timeoutSeconds: 5 - resources: - requests: - cpu: 200m - volumeMounts: - - mountPath: /etc/antrea/antrea-controller.conf - name: antrea-config - readOnly: true - subPath: antrea-controller.conf - - mountPath: /var/run/antrea/antrea-controller-tls - name: antrea-controller-tls - - mountPath: /var/log/antrea - name: host-var-log-antrea - hostNetwork: true nodeSelector: kubernetes.io/os: linux + hostNetwork: true priorityClassName: system-cluster-critical - serviceAccountName: antrea-controller tolerations: - - key: CriticalAddonsOnly - operator: Exists - - effect: NoSchedule - key: node-role.kubernetes.io/master + - key: CriticalAddonsOnly + operator: Exists + - effect: NoSchedule + key: node-role.kubernetes.io/master + - effect: NoSchedule + key: node-role.kubernetes.io/control-plane + serviceAccountName: antrea-controller + containers: + - name: antrea-controller + image: "projects.registry.vmware.com/antrea/antrea-ubuntu:latest" + imagePullPolicy: IfNotPresent + resources: + requests: + cpu: 200m + command: ["antrea-controller"] + # Log to both "/var/log/antrea/" and stderr (so "kubectl logs" can work). + args: + - "--config=/etc/antrea/antrea-controller.conf" + - "--logtostderr=false" + - "--log_dir=/var/log/antrea" + - "--alsologtostderr" + - "--log_file_max_size=100" + - "--log_file_max_num=4" + env: + # Provide pod and node information for clusterinformation CRD. + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: NODE_NAME + valueFrom: + fieldRef: + fieldPath: spec.nodeName + # Provide ServiceAccount name for validation webhook. + - name: SERVICEACCOUNT_NAME + valueFrom: + fieldRef: + fieldPath: spec.serviceAccountName + - name: ANTREA_CONFIG_MAP_NAME + value: antrea-config + ports: + - containerPort: 10349 + name: api + protocol: TCP + readinessProbe: + httpGet: + host: localhost + path: /readyz + port: api + scheme: HTTPS + initialDelaySeconds: 5 + timeoutSeconds: 5 + periodSeconds: 10 + failureThreshold: 5 + livenessProbe: + httpGet: + host: localhost + path: /livez + port: api + scheme: HTTPS + timeoutSeconds: 5 + periodSeconds: 10 + failureThreshold: 5 + volumeMounts: + - name: antrea-config + mountPath: /etc/antrea/antrea-controller.conf + subPath: antrea-controller.conf + readOnly: true + - name: antrea-controller-tls + mountPath: /var/run/antrea/antrea-controller-tls + - name: host-var-log-antrea + mountPath: /var/log/antrea volumes: - - configMap: - name: antrea-config-tmhkc66d6c - name: antrea-config - - name: antrea-controller-tls - secret: - defaultMode: 256 - optional: true - secretName: antrea-controller-tls - - hostPath: - path: /var/log/antrea - type: DirectoryOrCreate - name: host-var-log-antrea + - name: antrea-config + configMap: + name: antrea-config + # Make it optional as we only read it when selfSignedCert=false. + - name: antrea-controller-tls + secret: + secretName: antrea-controller-tls + defaultMode: 0400 + optional: true + - name: host-var-log-antrea + hostPath: + path: /var/log/antrea + type: DirectoryOrCreate --- +# Source: antrea/templates/controller/apiservices.yaml apiVersion: apiregistration.k8s.io/v1 kind: APIService metadata: + name: v1beta2.controlplane.antrea.io labels: app: antrea - name: v1alpha1.stats.antrea.io spec: - group: stats.antrea.io + group: controlplane.antrea.io groupPriorityMinimum: 100 + version: v1beta2 + versionPriority: 100 service: name: antrea namespace: kube-system - version: v1alpha1 - versionPriority: 100 --- +# Source: antrea/templates/controller/apiservices.yaml apiVersion: apiregistration.k8s.io/v1 kind: APIService metadata: + name: v1beta1.system.antrea.io labels: app: antrea - name: v1beta1.system.antrea.io spec: group: system.antrea.io groupPriorityMinimum: 100 + version: v1beta1 + versionPriority: 100 service: name: antrea namespace: kube-system - version: v1beta1 - versionPriority: 100 --- +# Source: antrea/templates/controller/apiservices.yaml apiVersion: apiregistration.k8s.io/v1 kind: APIService metadata: + name: v1alpha1.stats.antrea.io labels: app: antrea - name: v1beta2.controlplane.antrea.io spec: - group: controlplane.antrea.io + group: stats.antrea.io groupPriorityMinimum: 100 + version: v1alpha1 + versionPriority: 100 service: name: antrea namespace: kube-system - version: v1beta2 - versionPriority: 100 ---- -apiVersion: apps/v1 -kind: DaemonSet -metadata: - labels: - app: antrea - component: antrea-agent - name: antrea-agent - namespace: kube-system -spec: - selector: - matchLabels: - app: antrea - component: antrea-agent - template: - metadata: - annotations: - kubectl.kubernetes.io/default-container: antrea-agent - labels: - app: antrea - component: antrea-agent - spec: - containers: - - command: - - start_ovs_ipsec - image: projects.registry.vmware.com/antrea/antrea-ubuntu:latest - imagePullPolicy: IfNotPresent - livenessProbe: - exec: - command: - - /bin/sh - - -c - - timeout 5 container_liveness_probe ovs-ipsec - initialDelaySeconds: 5 - periodSeconds: 5 - name: antrea-ipsec - resources: - requests: - cpu: 50m - securityContext: - capabilities: - add: - - NET_ADMIN - volumeMounts: - - mountPath: /var/run/openvswitch - name: host-var-run-antrea - subPath: openvswitch - - mountPath: /var/log/openvswitch - name: host-var-log-antrea - subPath: openvswitch - - mountPath: /var/log/strongswan - name: host-var-log-antrea - subPath: strongswan - - args: - - --config - - /etc/antrea/antrea-agent.conf - - --logtostderr=false - - --log_dir=/var/log/antrea - - --alsologtostderr - - --log_file_max_size=100 - - --log_file_max_num=4 - - --v=0 - command: - - antrea-agent - env: - - name: ANTREA_IPSEC_PSK - valueFrom: - secretKeyRef: - key: psk - name: antrea-ipsec - - name: POD_NAME - valueFrom: - fieldRef: - fieldPath: metadata.name - - name: POD_NAMESPACE - valueFrom: - fieldRef: - fieldPath: metadata.namespace - - name: NODE_NAME - valueFrom: - fieldRef: - fieldPath: spec.nodeName - image: projects.registry.vmware.com/antrea/antrea-ubuntu:latest - imagePullPolicy: IfNotPresent - livenessProbe: - exec: - command: - - /bin/sh - - -c - - container_liveness_probe agent - failureThreshold: 5 - initialDelaySeconds: 5 - periodSeconds: 10 - timeoutSeconds: 5 - name: antrea-agent - ports: - - containerPort: 10350 - name: api - protocol: TCP - readinessProbe: - failureThreshold: 8 - httpGet: - host: localhost - path: /readyz - port: api - scheme: HTTPS - initialDelaySeconds: 5 - periodSeconds: 10 - timeoutSeconds: 5 - resources: - requests: - cpu: 200m - securityContext: - privileged: true - volumeMounts: - - mountPath: /etc/antrea/antrea-agent.conf - name: antrea-config - readOnly: true - subPath: antrea-agent.conf - - mountPath: /var/run/antrea - name: host-var-run-antrea - - mountPath: /var/run/openvswitch - name: host-var-run-antrea - subPath: openvswitch - - mountPath: /var/lib/cni - name: host-var-run-antrea - subPath: cni - - mountPath: /var/log/antrea - name: host-var-log-antrea - - mountPath: /host/proc - name: host-proc - readOnly: true - - mountPath: /host/var/run/netns - mountPropagation: HostToContainer - name: host-var-run-netns - readOnly: true - - mountPath: /run/xtables.lock - name: xtables-lock - - args: - - --log_file_max_size=100 - - --log_file_max_num=4 - command: - - start_ovs - image: projects.registry.vmware.com/antrea/antrea-ubuntu:latest - imagePullPolicy: IfNotPresent - livenessProbe: - exec: - command: - - /bin/sh - - -c - - timeout 10 container_liveness_probe ovs - failureThreshold: 5 - initialDelaySeconds: 5 - periodSeconds: 10 - timeoutSeconds: 10 - name: antrea-ovs - resources: - requests: - cpu: 200m - securityContext: - capabilities: - add: - - SYS_NICE - - NET_ADMIN - - SYS_ADMIN - - IPC_LOCK - volumeMounts: - - mountPath: /var/run/openvswitch - name: host-var-run-antrea - subPath: openvswitch - - mountPath: /var/log/openvswitch - name: host-var-log-antrea - subPath: openvswitch - dnsPolicy: ClusterFirstWithHostNet - hostNetwork: true - initContainers: - - command: - - install_cni - env: - - name: SKIP_CNI_BINARIES - value: "" - image: projects.registry.vmware.com/antrea/antrea-ubuntu:latest - imagePullPolicy: IfNotPresent - name: install-cni - resources: - requests: - cpu: 100m - securityContext: - capabilities: - add: - - SYS_MODULE - volumeMounts: - - mountPath: /etc/antrea/antrea-cni.conflist - name: antrea-config - readOnly: true - subPath: antrea-cni.conflist - - mountPath: /host/etc/cni/net.d - name: host-cni-conf - - mountPath: /host/opt/cni/bin - name: host-cni-bin - - mountPath: /lib/modules - name: host-lib-modules - readOnly: true - - mountPath: /var/run/antrea - name: host-var-run-antrea - nodeSelector: - kubernetes.io/os: linux - priorityClassName: system-node-critical - serviceAccountName: antrea-agent - tolerations: - - key: CriticalAddonsOnly - operator: Exists - - effect: NoSchedule - operator: Exists - - effect: NoExecute - operator: Exists - volumes: - - configMap: - name: antrea-config-tmhkc66d6c - name: antrea-config - - hostPath: - path: /etc/cni/net.d - name: host-cni-conf - - hostPath: - path: /opt/cni/bin - name: host-cni-bin - - hostPath: - path: /proc - name: host-proc - - hostPath: - path: /var/run/netns - name: host-var-run-netns - - hostPath: - path: /var/run/antrea - type: DirectoryOrCreate - name: host-var-run-antrea - - hostPath: - path: /var/log/antrea - type: DirectoryOrCreate - name: host-var-log-antrea - - hostPath: - path: /lib/modules - name: host-lib-modules - - hostPath: - path: /run/xtables.lock - type: FileOrCreate - name: xtables-lock - updateStrategy: - type: RollingUpdate --- +# Source: antrea/templates/webhooks/mutating/crdmutator.yaml apiVersion: admissionregistration.k8s.io/v1 kind: MutatingWebhookConfiguration metadata: + name: "crdmutator.antrea.io" labels: app: antrea - name: crdmutator.antrea.io webhooks: -- admissionReviewVersions: - - v1 - - v1beta1 - clientConfig: - service: - name: antrea - namespace: kube-system - path: /mutate/acnp - name: acnpmutator.antrea.io - rules: - - apiGroups: - - crd.antrea.io - apiVersions: - - v1alpha1 - operations: - - CREATE - - UPDATE - resources: - - clusternetworkpolicies - scope: Cluster - sideEffects: None - timeoutSeconds: 5 -- admissionReviewVersions: - - v1 - - v1beta1 - clientConfig: - service: - name: antrea - namespace: kube-system - path: /mutate/anp - name: anpmutator.antrea.io - rules: - - apiGroups: - - crd.antrea.io - apiVersions: - - v1alpha1 - operations: - - CREATE - - UPDATE - resources: - - networkpolicies - scope: Namespaced - sideEffects: None - timeoutSeconds: 5 + - name: "acnpmutator.antrea.io" + clientConfig: + service: + name: "antrea" + namespace: kube-system + path: "/mutate/acnp" + rules: + - operations: ["CREATE", "UPDATE"] + apiGroups: ["crd.antrea.io"] + apiVersions: ["v1alpha1"] + resources: ["clusternetworkpolicies"] + scope: "Cluster" + admissionReviewVersions: ["v1", "v1beta1"] + sideEffects: None + timeoutSeconds: 5 + - name: "anpmutator.antrea.io" + clientConfig: + service: + name: "antrea" + namespace: kube-system + path: "/mutate/anp" + rules: + - operations: ["CREATE", "UPDATE"] + apiGroups: ["crd.antrea.io"] + apiVersions: ["v1alpha1"] + resources: ["networkpolicies"] + scope: "Namespaced" + admissionReviewVersions: ["v1", "v1beta1"] + sideEffects: None + timeoutSeconds: 5 --- +# Source: antrea/templates/webhooks/validating/crdvalidator.yaml apiVersion: admissionregistration.k8s.io/v1 kind: ValidatingWebhookConfiguration metadata: + name: "crdvalidator.antrea.io" labels: app: antrea - name: crdvalidator.antrea.io webhooks: -- admissionReviewVersions: - - v1 - - v1beta1 - clientConfig: - service: - name: antrea - namespace: kube-system - path: /validate/tier - name: tiervalidator.antrea.io - rules: - - apiGroups: - - crd.antrea.io - apiVersions: - - v1alpha1 - operations: - - CREATE - - UPDATE - - DELETE - resources: - - tiers - scope: Cluster - sideEffects: None - timeoutSeconds: 5 -- admissionReviewVersions: - - v1 - - v1beta1 - clientConfig: - service: - name: antrea - namespace: kube-system - path: /validate/acnp - name: acnpvalidator.antrea.io - rules: - - apiGroups: - - crd.antrea.io - apiVersions: - - v1alpha1 - operations: - - CREATE - - UPDATE - resources: - - clusternetworkpolicies - scope: Cluster - sideEffects: None - timeoutSeconds: 5 -- admissionReviewVersions: - - v1 - - v1beta1 - clientConfig: - service: - name: antrea - namespace: kube-system - path: /validate/anp - name: anpvalidator.antrea.io - rules: - - apiGroups: - - crd.antrea.io - apiVersions: - - v1alpha1 - operations: - - CREATE - - UPDATE - resources: - - networkpolicies - scope: Namespaced - sideEffects: None - timeoutSeconds: 5 -- admissionReviewVersions: - - v1 - - v1beta1 - clientConfig: - service: - name: antrea - namespace: kube-system - path: /validate/clustergroup - name: clustergroupvalidator.antrea.io - rules: - - apiGroups: - - crd.antrea.io - apiVersions: - - v1alpha3 - - v1alpha2 - operations: - - CREATE - - UPDATE - resources: - - clustergroups - scope: Cluster - sideEffects: None - timeoutSeconds: 5 -- admissionReviewVersions: - - v1 - - v1beta1 - clientConfig: - service: - name: antrea - namespace: kube-system - path: /validate/externalippool - name: externalippoolvalidator.antrea.io - rules: - - apiGroups: - - crd.antrea.io - apiVersions: - - v1alpha2 - operations: - - UPDATE - resources: - - externalippools - scope: Cluster - sideEffects: None - timeoutSeconds: 5 -- admissionReviewVersions: - - v1 - - v1beta1 - clientConfig: - service: - name: antrea - namespace: kube-system - path: /validate/egress - name: egressvalidator.antrea.io - rules: - - apiGroups: - - crd.antrea.io - apiVersions: - - v1alpha2 - operations: - - CREATE - - UPDATE - resources: - - egresses - scope: Cluster - sideEffects: None - timeoutSeconds: 5 -- admissionReviewVersions: - - v1 - - v1beta1 - clientConfig: - service: - name: antrea - namespace: kube-system - path: /validate/ippool - name: ippoolvalidator.antrea.io - rules: - - apiGroups: - - crd.antrea.io - apiVersions: - - v1alpha2 - operations: - - CREATE - - UPDATE - - DELETE - resources: - - ippools - scope: Cluster - sideEffects: None - timeoutSeconds: 5 + - name: "tiervalidator.antrea.io" + clientConfig: + service: + name: "antrea" + namespace: kube-system + path: "/validate/tier" + rules: + - operations: ["CREATE", "UPDATE", "DELETE"] + apiGroups: ["crd.antrea.io"] + apiVersions: ["v1alpha1"] + resources: ["tiers"] + scope: "Cluster" + admissionReviewVersions: ["v1", "v1beta1"] + sideEffects: None + timeoutSeconds: 5 + - name: "acnpvalidator.antrea.io" + clientConfig: + service: + name: "antrea" + namespace: kube-system + path: "/validate/acnp" + rules: + - operations: ["CREATE", "UPDATE"] + apiGroups: ["crd.antrea.io"] + apiVersions: ["v1alpha1"] + resources: ["clusternetworkpolicies"] + scope: "Cluster" + admissionReviewVersions: ["v1", "v1beta1"] + sideEffects: None + timeoutSeconds: 5 + - name: "anpvalidator.antrea.io" + clientConfig: + service: + name: "antrea" + namespace: kube-system + path: "/validate/anp" + rules: + - operations: ["CREATE", "UPDATE"] + apiGroups: ["crd.antrea.io"] + apiVersions: ["v1alpha1"] + resources: ["networkpolicies"] + scope: "Namespaced" + admissionReviewVersions: ["v1", "v1beta1"] + sideEffects: None + timeoutSeconds: 5 + - name: "clustergroupvalidator.antrea.io" + clientConfig: + service: + name: "antrea" + namespace: kube-system + path: "/validate/clustergroup" + rules: + - operations: ["CREATE", "UPDATE"] + apiGroups: ["crd.antrea.io"] + apiVersions: ["v1alpha3", "v1alpha2"] + resources: ["clustergroups"] + scope: "Cluster" + admissionReviewVersions: ["v1", "v1beta1"] + sideEffects: None + timeoutSeconds: 5 + - name: "externalippoolvalidator.antrea.io" + clientConfig: + service: + name: "antrea" + namespace: kube-system + path: "/validate/externalippool" + rules: + - operations: ["UPDATE"] + apiGroups: ["crd.antrea.io"] + apiVersions: ["v1alpha2"] + resources: ["externalippools"] + scope: "Cluster" + admissionReviewVersions: ["v1", "v1beta1"] + sideEffects: None + timeoutSeconds: 5 + - name: "egressvalidator.antrea.io" + clientConfig: + service: + name: "antrea" + namespace: kube-system + path: "/validate/egress" + rules: + - operations: ["CREATE", "UPDATE"] + apiGroups: ["crd.antrea.io"] + apiVersions: ["v1alpha2"] + resources: ["egresses"] + scope: "Cluster" + admissionReviewVersions: ["v1", "v1beta1"] + sideEffects: None + timeoutSeconds: 5 + - name: "ippoolvalidator.antrea.io" + clientConfig: + service: + name: "antrea" + namespace: kube-system + path: "/validate/ippool" + rules: + - operations: ["CREATE", "UPDATE", "DELETE"] + apiGroups: ["crd.antrea.io"] + apiVersions: ["v1alpha2"] + resources: ["ippools"] + scope: "Cluster" + admissionReviewVersions: ["v1", "v1beta1"] + sideEffects: None + timeoutSeconds: 5 diff --git a/build/yamls/antrea-prometheus.yml b/build/yamls/antrea-prometheus.yml index 3ee508fa0c9..84a5bbbb7b7 100644 --- a/build/yamls/antrea-prometheus.yml +++ b/build/yamls/antrea-prometheus.yml @@ -12,6 +12,16 @@ metadata: name: prometheus namespace: monitoring --- +# This is useful for testing and manual access to the /metrics endpoints +apiVersion: v1 +kind: Secret +metadata: + name: prometheus-service-account-token + namespace: monitoring + annotations: + kubernetes.io/service-account.name: prometheus +type: kubernetes.io/service-account-token +--- # Authorize Prometheus to view Kubernetes cluster components for service discovery purposes # Authorize Prometheus to retrieve metrics apiVersion: rbac.authorization.k8s.io/v1 diff --git a/build/yamls/antrea-windows.yml b/build/yamls/antrea-windows.yml index 100e0c7783b..7af06ec8e24 100644 --- a/build/yamls/antrea-windows.yml +++ b/build/yamls/antrea-windows.yml @@ -5,12 +5,12 @@ data: # wins will rename the binary when executing it. So we need to copy the binary everytime before running it. mkdir -force /host/k/antrea/bin cp /k/antrea/bin/* /host/k/antrea/bin/ - C:/k/antrea/utils/wins.exe cli process run --path /k/antrea/bin/antrea-agent.exe --args "--config=/k/antrea/etc/antrea-agent.conf --logtostderr=false --log_dir=/k/antrea/logs/ --alsologtostderr --log_file_max_size=100 --log_file_max_num=4 --v=0" --envs "KUBERNETES_SERVICE_HOST=$env:KUBERNETES_SERVICE_HOST KUBERNETES_SERVICE_PORT=$env:KUBERNETES_SERVICE_PORT ANTREA_SERVICE_HOST=$env:ANTREA_SERVICE_HOST ANTREA_SERVICE_PORT=$env:ANTREA_SERVICE_PORT NODE_NAME=$env:NODE_NAME KUBE_DNS_SERVICE_HOST=$env:KUBE_DNS_SERVICE_HOST KUBE_DNS_SERVICE_PORT=$env:KUBE_DNS_SERVICE_PORT" + C:/k/antrea/utils/wins.exe cli process run --path /k/antrea/bin/antrea-agent.exe --args "--config=/k/antrea/etc/antrea-agent.conf --logtostderr=false --log_dir=/var/log/antrea/ --alsologtostderr --log_file_max_size=100 --log_file_max_num=4 --v=0" --envs "KUBERNETES_SERVICE_HOST=$env:KUBERNETES_SERVICE_HOST KUBERNETES_SERVICE_PORT=$env:KUBERNETES_SERVICE_PORT ANTREA_SERVICE_HOST=$env:ANTREA_SERVICE_HOST ANTREA_SERVICE_PORT=$env:ANTREA_SERVICE_PORT NODE_NAME=$env:NODE_NAME KUBE_DNS_SERVICE_HOST=$env:KUBE_DNS_SERVICE_HOST KUBE_DNS_SERVICE_PORT=$env:KUBE_DNS_SERVICE_PORT" kind: ConfigMap metadata: labels: app: antrea - name: antrea-agent-windows-d99k4g5264 + name: antrea-agent-windows-kht6m7hthm namespace: kube-system --- apiVersion: v1 @@ -28,6 +28,9 @@ data: # this flag will not take effect. # EndpointSlice: false + # Enable NodePortLocal feature to make the Pods reachable externally through NodePort + # NodePortLocal: true + # Enable flowexporter which exports polled conntrack connections as IPFIX flow records from each agent to a configured collector. # FlowExporter: false @@ -131,6 +134,17 @@ data: # Note that this option is experimental. If kube-proxy is removed, option kubeAPIServerOverride must be used to access # apiserver directly. #proxyAll: false + + nodePortLocal: + # Enable NodePortLocal, a feature used to make Pods reachable using port forwarding on the host. To + # enable this feature, you need to set "enable" to true, and ensure that the NodePortLocal feature + # gate is also enabled (which is the default). + # enable: false + # Provide the port range used by NodePortLocal. When the NodePortLocal feature is enabled, a port + # from that range will be assigned whenever a Pod's container defines a specific port to be exposed + # (each container can define a list of ports as pod.spec.containers[].ports), and all Node traffic + # directed to that port will be forwarded to the Pod. + # portRange: 61000-62000 antrea-cni.conflist: | { "cniVersion":"0.3.0", @@ -149,7 +163,7 @@ kind: ConfigMap metadata: labels: app: antrea - name: antrea-windows-config-mf82kffb45 + name: antrea-windows-config-8kfkb8t957 namespace: kube-system --- apiVersion: apps/v1 @@ -194,8 +208,6 @@ spec: imagePullPolicy: IfNotPresent name: antrea-agent volumeMounts: - - mountPath: /host - name: host - mountPath: \\.\pipe\rancher_wins name: wins - mountPath: /etc/antrea @@ -204,6 +216,8 @@ spec: name: antrea-agent-windows - mountPath: /host/k/antrea/ name: host-antrea-home + - mountPath: /var/log/antrea/ + name: var-log-antrea hostNetwork: true initContainers: - args: @@ -224,8 +238,8 @@ spec: name: host-cni-bin - mountPath: /host/k/antrea/ name: host-antrea-home - - mountPath: /host - name: host + - mountPath: /host/var/run/secrets/ + name: host-secrets-path nodeSelector: kubernetes.io/os: windows priorityClassName: system-node-critical @@ -237,11 +251,11 @@ spec: operator: Exists volumes: - configMap: - name: antrea-windows-config-mf82kffb45 + name: antrea-windows-config-8kfkb8t957 name: antrea-windows-config - configMap: defaultMode: 420 - name: antrea-agent-windows-d99k4g5264 + name: antrea-agent-windows-kht6m7hthm name: antrea-agent-windows - hostPath: path: /etc/cni/net.d @@ -255,11 +269,16 @@ spec: path: /k/antrea type: DirectoryOrCreate name: host-antrea-home - - hostPath: - path: / - name: host - hostPath: path: \\.\pipe\rancher_wins name: wins + - hostPath: + path: /var/log/antrea/ + type: DirectoryOrCreate + name: var-log-antrea + - hostPath: + path: /var/run/secrets/ + type: DirectoryOrCreate + name: host-secrets-path updateStrategy: type: RollingUpdate diff --git a/build/yamls/antrea.yml b/build/yamls/antrea.yml index d5a7d4db29f..2b02024377d 100644 --- a/build/yamls/antrea.yml +++ b/build/yamls/antrea.yml @@ -1,2740 +1,59 @@ -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition +--- +# Source: antrea/templates/agent/serviceaccount.yaml +apiVersion: v1 +kind: ServiceAccount metadata: + name: antrea-agent + namespace: kube-system labels: app: antrea - name: antreaagentinfos.crd.antrea.io -spec: - group: crd.antrea.io - names: - kind: AntreaAgentInfo - plural: antreaagentinfos - shortNames: - - aai - singular: antreaagentinfo - scope: Cluster - versions: - - additionalPrinterColumns: - - description: Health status of this Agent - jsonPath: .agentConditions[?(@.type=='AgentHealthy')].status - name: Healthy - type: string - - description: Last time the Healthy Condition was updated - jsonPath: .agentConditions[?(@.type=='AgentHealthy')].lastHeartbeatTime - name: Last Heartbeat - type: date - - description: Version of this Agent - jsonPath: .version - name: Version - priority: 1 - type: string - - description: Node on which this Agent is running - jsonPath: .nodeRef.name - name: Node - priority: 1 - type: string - - description: Number of local Pods managed by this Agent - jsonPath: .localPodNum - name: Num Pods - priority: 2 - type: integer - - description: Subnets used by this Agent for Pod IPAM - jsonPath: .nodeSubnets - name: Subnets - priority: 2 - type: string - name: v1beta1 - schema: - openAPIV3Schema: - type: object - x-kubernetes-preserve-unknown-fields: true - served: true - storage: true --- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition +# Source: antrea/templates/antctl/serviceaccount.yaml +apiVersion: v1 +kind: ServiceAccount metadata: + name: antctl + namespace: kube-system labels: app: antrea - name: antreacontrollerinfos.crd.antrea.io -spec: - group: crd.antrea.io - names: - kind: AntreaControllerInfo - plural: antreacontrollerinfos - shortNames: - - aci - singular: antreacontrollerinfo - scope: Cluster - versions: - - additionalPrinterColumns: - - description: Health status of the Controller - jsonPath: .controllerConditions[?(@.type=='ControllerHealthy')].status - name: Healthy - type: string - - description: Last time the Healthy Condition was updated - jsonPath: .controllerConditions[?(@.type=='ControllerHealthy')].lastHeartbeatTime - name: Last Heartbeat - type: date - - description: Version of the Controller - jsonPath: .version - name: Version - priority: 1 - type: string - - description: Number of Agents connected to the Controller - jsonPath: .connectedAgentNum - name: Connected Agents - priority: 1 - type: integer - - description: Node on which the Controller is running - jsonPath: .nodeRef.name - name: Node - priority: 1 - type: string - - description: Number of Network Policies computed by Controller - jsonPath: .networkPolicyControllerInfo.networkPolicyNum - name: Num Network Policies - priority: 2 - type: integer - name: v1beta1 - schema: - openAPIV3Schema: - type: object - x-kubernetes-preserve-unknown-fields: true - served: true - storage: true --- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition +# Source: antrea/templates/controller/serviceaccount.yaml +apiVersion: v1 +kind: ServiceAccount metadata: + name: antrea-controller + namespace: kube-system labels: app: antrea - name: clustergroups.crd.antrea.io -spec: - conversion: - strategy: Webhook - webhook: - clientConfig: - service: - name: antrea - namespace: kube-system - path: /convert/clustergroup - conversionReviewVersions: - - v1 - - v1beta1 - group: crd.antrea.io - names: - kind: ClusterGroup - plural: clustergroups - shortNames: - - cg - singular: clustergroup - scope: Cluster - versions: - - name: v1alpha2 - schema: - openAPIV3Schema: - properties: - spec: - properties: - childGroups: - items: - type: string - type: array - externalEntitySelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - ipBlock: - properties: - cidr: - format: cidr - type: string - type: object - ipBlocks: - items: - properties: - cidr: - format: cidr - type: string - type: object - type: array - namespaceSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - podSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - serviceReference: - properties: - name: - type: string - namespace: - type: string - type: object - type: object - status: - properties: - conditions: - items: - properties: - lastTransitionTime: - type: string - status: - type: string - type: - type: string - type: object - type: array - type: object - type: object - served: true - storage: false - - name: v1alpha3 - schema: - openAPIV3Schema: - properties: - spec: - properties: - childGroups: - items: - type: string - type: array - externalEntitySelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - ipBlocks: - items: - properties: - cidr: - format: cidr - type: string - type: object - type: array - namespaceSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - podSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - serviceReference: - properties: - name: - type: string - namespace: - type: string - type: object - type: object - status: - properties: - conditions: - items: - properties: - lastTransitionTime: - type: string - status: - type: string - type: - type: string - type: object - type: array - type: object - type: object - served: true - storage: true - subresources: - status: {} --- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition +# Source: antrea/templates/agent/secret.yaml +apiVersion: v1 +kind: Secret +metadata: + name: antrea-agent-service-account-token + namespace: kube-system + annotations: + kubernetes.io/service-account.name: antrea-agent +type: kubernetes.io/service-account-token +--- +# Source: antrea/templates/antctl/secret.yaml +apiVersion: v1 +kind: Secret +metadata: + name: antctl-service-account-token + namespace: kube-system + annotations: + kubernetes.io/service-account.name: antctl +type: kubernetes.io/service-account-token +--- +# Source: antrea/templates/configmap.yaml +apiVersion: v1 +kind: ConfigMap metadata: + name: antrea-config + namespace: kube-system labels: app: antrea - name: clusternetworkpolicies.crd.antrea.io -spec: - group: crd.antrea.io - names: - kind: ClusterNetworkPolicy - plural: clusternetworkpolicies - shortNames: - - acnp - singular: clusternetworkpolicy - scope: Cluster - versions: - - additionalPrinterColumns: - - description: The Tier to which this ClusterNetworkPolicy belongs to. - jsonPath: .spec.tier - name: Tier - type: string - - description: The Priority of this ClusterNetworkPolicy relative to other policies. - format: float - jsonPath: .spec.priority - name: Priority - type: number - - description: The total number of Nodes that should realize the NetworkPolicy. - format: int32 - jsonPath: .status.desiredNodesRealized - name: Desired Nodes - type: number - - description: The number of Nodes that have realized the NetworkPolicy. - format: int32 - jsonPath: .status.currentNodesRealized - name: Current Nodes - type: number - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha1 - schema: - openAPIV3Schema: - properties: - spec: - properties: - appliedTo: - items: - properties: - group: - type: string - namespaceSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - podSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - serviceAccount: - properties: - name: - type: string - namespace: - type: string - required: - - name - - namespace - type: object - type: object - type: array - egress: - items: - properties: - action: - enum: - - Allow - - Drop - - Reject - - Pass - type: string - appliedTo: - items: - properties: - group: - type: string - namespaceSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - podSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - serviceAccount: - properties: - name: - type: string - namespace: - type: string - required: - - name - - namespace - type: object - type: object - type: array - enableLogging: - type: boolean - name: - type: string - ports: - items: - properties: - endPort: - type: integer - port: - x-kubernetes-int-or-string: true - protocol: - enum: - - TCP - - UDP - - SCTP - type: string - type: object - type: array - to: - items: - properties: - fqdn: - type: string - group: - type: string - ipBlock: - properties: - cidr: - format: cidr - type: string - type: object - namespaceSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - namespaces: - properties: - match: - type: string - type: object - nodeSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - podSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - serviceAccount: - properties: - name: - type: string - namespace: - type: string - required: - - name - - namespace - type: object - type: object - type: array - toServices: - items: - properties: - name: - type: string - namespace: - type: string - required: - - name - - namespace - type: object - type: array - required: - - action - type: object - type: array - ingress: - items: - properties: - action: - enum: - - Allow - - Drop - - Reject - - Pass - type: string - appliedTo: - items: - properties: - group: - type: string - namespaceSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - podSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - serviceAccount: - properties: - name: - type: string - namespace: - type: string - required: - - name - - namespace - type: object - type: object - type: array - enableLogging: - type: boolean - from: - items: - properties: - group: - type: string - ipBlock: - properties: - cidr: - format: cidr - type: string - type: object - namespaceSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - namespaces: - properties: - match: - enum: - - Self - type: string - type: object - nodeSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - podSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - serviceAccount: - properties: - name: - type: string - namespace: - type: string - required: - - name - - namespace - type: object - type: object - type: array - name: - type: string - ports: - items: - properties: - endPort: - type: integer - port: - x-kubernetes-int-or-string: true - protocol: - enum: - - TCP - - UDP - - SCTP - type: string - type: object - type: array - required: - - action - type: object - type: array - priority: - format: float - maximum: 10000 - minimum: 1 - type: number - tier: - type: string - required: - - priority - type: object - status: - properties: - currentNodesRealized: - type: integer - desiredNodesRealized: - type: integer - observedGeneration: - type: integer - phase: - type: string - type: object - type: object - served: true - storage: true - subresources: - status: {} ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - labels: - app: antrea - name: egresses.crd.antrea.io -spec: - group: crd.antrea.io - names: - kind: Egress - plural: egresses - shortNames: - - eg - singular: egress - scope: Cluster - versions: - - additionalPrinterColumns: - - description: Specifies the SNAT IP address for the selected workloads. - jsonPath: .spec.egressIP - name: EgressIP - type: string - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - - description: The Owner Node of egress IP - jsonPath: .status.egressNode - name: Node - type: string - name: v1alpha2 - schema: - openAPIV3Schema: - properties: - spec: - anyOf: - - required: - - egressIP - - required: - - externalIPPool - properties: - appliedTo: - properties: - namespaceSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - podSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - type: object - egressIP: - oneOf: - - format: ipv4 - - format: ipv6 - type: string - externalIPPool: - type: string - required: - - appliedTo - type: object - status: - properties: - egressNode: - type: string - type: object - required: - - spec - type: object - served: true - storage: true - subresources: - status: {} ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - labels: - app: antrea - name: externalentities.crd.antrea.io -spec: - group: crd.antrea.io - names: - kind: ExternalEntity - plural: externalentities - shortNames: - - ee - singular: externalentity - scope: Namespaced - versions: - - name: v1alpha2 - schema: - openAPIV3Schema: - properties: - spec: - properties: - endpoints: - items: - properties: - ip: - oneOf: - - format: ipv4 - - format: ipv6 - type: string - name: - type: string - type: object - type: array - externalNode: - type: string - ports: - items: - properties: - name: - type: string - port: - x-kubernetes-int-or-string: true - protocol: - enum: - - TCP - - UDP - - SCTP - type: string - type: object - type: array - type: object - type: object - served: true - storage: true - - name: v1alpha1 - schema: - openAPIV3Schema: - type: object - served: false - storage: false ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - labels: - app: antrea - name: externalippools.crd.antrea.io -spec: - group: crd.antrea.io - names: - kind: ExternalIPPool - plural: externalippools - shortNames: - - eip - singular: externalippool - scope: Cluster - versions: - - additionalPrinterColumns: - - description: The number of total IPs - jsonPath: .status.usage.total - name: Total - type: integer - - description: The number of allocated IPs - jsonPath: .status.usage.used - name: Used - type: integer - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha2 - schema: - openAPIV3Schema: - properties: - spec: - properties: - ipRanges: - items: - oneOf: - - required: - - cidr - - required: - - start - - end - properties: - cidr: - format: cidr - type: string - end: - oneOf: - - format: ipv4 - - format: ipv6 - type: string - start: - oneOf: - - format: ipv4 - - format: ipv6 - type: string - type: object - type: array - nodeSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - required: - - ipRanges - - nodeSelector - type: object - status: - properties: - usage: - properties: - total: - type: integer - used: - type: integer - type: object - type: object - required: - - spec - type: object - served: true - storage: true - subresources: - status: {} ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - labels: - app: antrea - name: ippools.crd.antrea.io -spec: - group: crd.antrea.io - names: - kind: IPPool - plural: ippools - shortNames: - - ipp - singular: ippool - scope: Cluster - versions: - - name: v1alpha2 - schema: - openAPIV3Schema: - properties: - spec: - properties: - ipRanges: - items: - oneOf: - - required: - - cidr - - gateway - - prefixLength - - required: - - start - - end - - gateway - - prefixLength - properties: - cidr: - format: cidr - type: string - end: - oneOf: - - format: ipv4 - - format: ipv6 - type: string - gateway: - oneOf: - - format: ipv4 - - format: ipv6 - type: string - prefixLength: - type: integer - start: - oneOf: - - format: ipv4 - - format: ipv6 - type: string - vlan: - maximum: 4094 - minimum: 0 - type: integer - type: object - type: array - ipVersion: - type: integer - required: - - ipVersion - - ipRanges - type: object - status: - properties: - ipAddresses: - items: - properties: - ipAddress: - type: string - owner: - properties: - pod: - properties: - containerID: - type: string - name: - type: string - namespace: - type: string - type: object - statefulSet: - properties: - index: - type: integer - name: - type: string - namespace: - type: string - type: object - type: object - phase: - type: string - type: object - type: array - type: object - required: - - spec - type: object - served: true - storage: true - subresources: - status: {} ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - labels: - app: antrea - name: networkpolicies.crd.antrea.io -spec: - group: crd.antrea.io - names: - kind: NetworkPolicy - plural: networkpolicies - shortNames: - - anp - singular: networkpolicy - scope: Namespaced - versions: - - additionalPrinterColumns: - - description: The Tier to which this Antrea NetworkPolicy belongs to. - jsonPath: .spec.tier - name: Tier - type: string - - description: The Priority of this Antrea NetworkPolicy relative to other policies. - format: float - jsonPath: .spec.priority - name: Priority - type: number - - description: The total number of Nodes that should realize the NetworkPolicy. - format: int32 - jsonPath: .status.desiredNodesRealized - name: Desired Nodes - type: number - - description: The number of Nodes that have realized the NetworkPolicy. - format: int32 - jsonPath: .status.currentNodesRealized - name: Current Nodes - type: number - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha1 - schema: - openAPIV3Schema: - properties: - spec: - properties: - appliedTo: - items: - properties: - podSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - type: object - type: array - egress: - items: - properties: - action: - enum: - - Allow - - Drop - - Reject - - Pass - type: string - appliedTo: - items: - properties: - podSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - type: object - type: array - enableLogging: - type: boolean - name: - type: string - ports: - items: - properties: - endPort: - type: integer - port: - x-kubernetes-int-or-string: true - protocol: - enum: - - TCP - - UDP - - SCTP - type: string - type: object - type: array - to: - items: - properties: - externalEntitySelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - fqdn: - type: string - ipBlock: - properties: - cidr: - format: cidr - type: string - type: object - namespaceSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - nodeSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - podSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - type: object - type: array - toServices: - items: - properties: - name: - type: string - namespace: - type: string - required: - - name - type: object - type: array - required: - - action - type: object - type: array - ingress: - items: - properties: - action: - enum: - - Allow - - Drop - - Reject - - Pass - type: string - appliedTo: - items: - properties: - podSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - type: object - type: array - enableLogging: - type: boolean - from: - items: - properties: - externalEntitySelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - ipBlock: - properties: - cidr: - format: cidr - type: string - type: object - namespaceSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - nodeSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - podSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ - type: string - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - type: object - type: object - type: array - name: - type: string - ports: - items: - properties: - endPort: - type: integer - port: - x-kubernetes-int-or-string: true - protocol: - enum: - - TCP - - UDP - - SCTP - type: string - type: object - type: array - required: - - action - type: object - type: array - priority: - format: float - maximum: 10000 - minimum: 1 - type: number - tier: - type: string - required: - - priority - type: object - status: - properties: - currentNodesRealized: - type: integer - desiredNodesRealized: - type: integer - observedGeneration: - type: integer - phase: - type: string - type: object - type: object - served: true - storage: true - subresources: - status: {} ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - labels: - app: antrea - name: tiers.crd.antrea.io -spec: - group: crd.antrea.io - names: - kind: Tier - plural: tiers - shortNames: - - tr - singular: tier - scope: Cluster - versions: - - additionalPrinterColumns: - - description: The Priority of this Tier relative to other Tiers. - jsonPath: .spec.priority - name: Priority - type: integer - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha1 - schema: - openAPIV3Schema: - properties: - spec: - properties: - description: - type: string - priority: - maximum: 255 - minimum: 0 - type: integer - required: - - priority - type: object - type: object - served: true - storage: true ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - labels: - app: antrea - name: traceflows.crd.antrea.io -spec: - group: crd.antrea.io - names: - kind: Traceflow - plural: traceflows - shortNames: - - tf - singular: traceflow - scope: Cluster - versions: - - additionalPrinterColumns: - - description: The phase of the Traceflow. - jsonPath: .status.phase - name: Phase - type: string - - description: The name of the source Pod. - jsonPath: .spec.source.pod - name: Source-Pod - priority: 10 - type: string - - description: The name of the destination Pod. - jsonPath: .spec.destination.pod - name: Destination-Pod - priority: 10 - type: string - - description: The IP address of the destination. - jsonPath: .spec.destination.ip - name: Destination-IP - priority: 10 - type: string - - description: Trace live traffic. - jsonPath: .spec.liveTraffic - name: Live-Traffic - priority: 10 - type: boolean - - description: Capture only the dropped packet. - jsonPath: .spec.droppedOnly - name: Dropped-Only - priority: 10 - type: boolean - - description: Timeout in seconds. - jsonPath: .spec.timeout - name: Timeout - priority: 10 - type: integer - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha1 - schema: - openAPIV3Schema: - properties: - spec: - properties: - destination: - properties: - ip: - oneOf: - - format: ipv4 - - format: ipv6 - type: string - namespace: - type: string - pod: - type: string - service: - type: string - type: object - droppedOnly: - type: boolean - liveTraffic: - type: boolean - packet: - properties: - ipHeader: - properties: - flags: - type: integer - protocol: - type: integer - srcIP: - oneOf: - - format: ipv4 - - format: ipv6 - type: string - ttl: - type: integer - type: object - ipv6Header: - properties: - hopLimit: - type: integer - nextHeader: - type: integer - srcIP: - format: ipv6 - type: string - type: object - transportHeader: - properties: - icmp: - properties: - id: - type: integer - sequence: - type: integer - type: object - tcp: - properties: - dstPort: - type: integer - flags: - type: integer - srcPort: - type: integer - type: object - udp: - properties: - dstPort: - type: integer - srcPort: - type: integer - type: object - type: object - type: object - source: - properties: - ip: - oneOf: - - format: ipv4 - - format: ipv6 - type: string - namespace: - type: string - pod: - type: string - type: object - timeout: - type: integer - type: object - status: - properties: - capturedPacket: - properties: - dstIP: - type: string - ipHeader: - properties: - flags: - type: integer - protocol: - type: integer - ttl: - type: integer - type: object - ipv6Header: - properties: - hopLimit: - type: integer - nextHeader: - type: integer - type: object - length: - type: integer - srcIP: - type: string - transportHeader: - properties: - icmp: - properties: - id: - type: integer - sequence: - type: integer - type: object - tcp: - properties: - dstPort: - type: integer - flags: - type: integer - srcPort: - type: integer - type: object - udp: - properties: - dstPort: - type: integer - srcPort: - type: integer - type: object - type: object - type: object - dataplaneTag: - type: integer - phase: - type: string - reason: - type: string - results: - items: - properties: - node: - type: string - observations: - items: - properties: - action: - type: string - component: - type: string - componentInfo: - type: string - dstMAC: - type: string - networkPolicy: - type: string - pod: - type: string - translatedDstIP: - type: string - translatedSrcIP: - type: string - ttl: - type: integer - tunnelDstIP: - type: string - type: object - type: array - role: - type: string - timestamp: - type: integer - type: object - type: array - startTime: - type: string - type: object - required: - - spec - type: object - served: true - storage: true - subresources: - status: {} ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - labels: - app: antrea - name: antctl - namespace: kube-system ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - labels: - app: antrea - name: antrea-agent - namespace: kube-system ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - labels: - app: antrea - name: antrea-controller - namespace: kube-system ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - labels: - app: antrea - rbac.authorization.k8s.io/aggregate-to-admin: "true" - rbac.authorization.k8s.io/aggregate-to-edit: "true" - name: aggregate-antrea-clustergroups-edit -rules: -- apiGroups: - - crd.antrea.io - resources: - - clustergroups - verbs: - - get - - list - - watch - - create - - update - - patch - - delete ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - labels: - app: antrea - rbac.authorization.k8s.io/aggregate-to-view: "true" - name: aggregate-antrea-clustergroups-view -rules: -- apiGroups: - - crd.antrea.io - resources: - - clustergroups - verbs: - - get - - list - - watch ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - labels: - app: antrea - rbac.authorization.k8s.io/aggregate-to-admin: "true" - rbac.authorization.k8s.io/aggregate-to-edit: "true" - name: aggregate-antrea-policies-edit -rules: -- apiGroups: - - crd.antrea.io - resources: - - clusternetworkpolicies - - networkpolicies - verbs: - - get - - list - - watch - - create - - update - - patch - - delete ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - labels: - app: antrea - rbac.authorization.k8s.io/aggregate-to-view: "true" - name: aggregate-antrea-policies-view -rules: -- apiGroups: - - crd.antrea.io - resources: - - clusternetworkpolicies - - networkpolicies - verbs: - - get - - list - - watch ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - labels: - app: antrea - rbac.authorization.k8s.io/aggregate-to-admin: "true" - rbac.authorization.k8s.io/aggregate-to-edit: "true" - name: aggregate-traceflows-edit -rules: -- apiGroups: - - crd.antrea.io - resources: - - traceflows - verbs: - - get - - list - - watch - - create - - update - - patch - - delete ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - labels: - app: antrea - rbac.authorization.k8s.io/aggregate-to-view: "true" - name: aggregate-traceflows-view -rules: -- apiGroups: - - crd.antrea.io - resources: - - traceflows - verbs: - - get - - list - - watch ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - labels: - app: antrea - name: antctl -rules: -- apiGroups: - - controlplane.antrea.io - resources: - - networkpolicies - - appliedtogroups - - addressgroups - verbs: - - get - - list -- apiGroups: - - stats.antrea.io - resources: - - networkpolicystats - - antreaclusternetworkpolicystats - - antreanetworkpolicystats - verbs: - - get - - list -- apiGroups: - - system.antrea.io - resources: - - controllerinfos - - agentinfos - verbs: - - get -- apiGroups: - - system.antrea.io - resources: - - supportbundles - verbs: - - get - - post -- apiGroups: - - system.antrea.io - resources: - - supportbundles/download - verbs: - - get -- nonResourceURLs: - - /agentinfo - - /addressgroups - - /appliedtogroups - - /loglevel - - /networkpolicies - - /ovsflows - - /ovstracing - - /podinterfaces - - /featuregates - verbs: - - get ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - labels: - app: antrea - name: antrea-agent -rules: -- apiGroups: - - "" - resources: - - nodes - verbs: - - get - - watch - - list -- apiGroups: - - "" - resources: - - nodes/status - verbs: - - patch -- apiGroups: - - "" - resources: - - pods - verbs: - - get - - watch - - list -- apiGroups: - - "" - resources: - - pods/status - verbs: - - patch -- apiGroups: - - "" - resources: - - endpoints - - services - - namespaces - verbs: - - get - - watch - - list -- apiGroups: - - "" - resources: - - services/status - verbs: - - update -- apiGroups: - - discovery.k8s.io - resources: - - endpointslices - verbs: - - get - - watch - - list -- apiGroups: - - crd.antrea.io - resources: - - antreaagentinfos - verbs: - - get - - create - - update - - delete -- apiGroups: - - controlplane.antrea.io - resources: - - networkpolicies - - appliedtogroups - - addressgroups - verbs: - - get - - watch - - list -- apiGroups: - - controlplane.antrea.io - resources: - - egressgroups - verbs: - - get - - watch - - list -- apiGroups: - - controlplane.antrea.io - resources: - - nodestatssummaries - verbs: - - create -- apiGroups: - - controlplane.antrea.io - resources: - - networkpolicies/status - verbs: - - create - - get -- apiGroups: - - authentication.k8s.io - resources: - - tokenreviews - verbs: - - create -- apiGroups: - - authorization.k8s.io - resources: - - subjectaccessreviews - verbs: - - create -- apiGroups: - - "" - resourceNames: - - extension-apiserver-authentication - resources: - - configmaps - verbs: - - get - - list - - watch -- apiGroups: - - "" - resourceNames: - - antrea-ca - resources: - - configmaps - verbs: - - get - - watch - - list -- apiGroups: - - crd.antrea.io - resources: - - traceflows - - traceflows/status - verbs: - - get - - watch - - list - - update - - patch - - create - - delete -- apiGroups: - - crd.antrea.io - resources: - - egresses - verbs: - - get - - watch - - list -- apiGroups: - - crd.antrea.io - resources: - - egresses/status - verbs: - - update -- apiGroups: - - crd.antrea.io - resources: - - externalippools - - ippools - verbs: - - get - - watch - - list -- apiGroups: - - crd.antrea.io - resources: - - ippools/status - verbs: - - update -- apiGroups: - - k8s.cni.cncf.io - resources: - - network-attachment-definitions - verbs: - - get - - list - - watch ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - labels: - app: antrea - name: antrea-cluster-identity-reader -rules: -- apiGroups: - - "" - resourceNames: - - antrea-cluster-identity - resources: - - configmaps - verbs: - - get ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - labels: - app: antrea - name: antrea-controller -rules: -- apiGroups: - - "" - resources: - - pods - - services - - namespaces - - configmaps - verbs: - - get - - watch - - list -- apiGroups: - - "" - resources: - - nodes - verbs: - - get - - watch - - list - - patch -- apiGroups: - - "" - resources: - - services/status - verbs: - - update -- apiGroups: - - networking.k8s.io - resources: - - networkpolicies - verbs: - - get - - watch - - list -- apiGroups: - - authentication.k8s.io - resources: - - tokenreviews - verbs: - - create -- apiGroups: - - authorization.k8s.io - resources: - - subjectaccessreviews - verbs: - - create -- apiGroups: - - apiextensions.k8s.io - resources: - - customresourcedefinitions - verbs: - - get - - update -- apiGroups: - - "" - resourceNames: - - extension-apiserver-authentication - resources: - - configmaps - verbs: - - get - - list - - watch -- apiGroups: - - "" - resourceNames: - - antrea-ca - - antrea-cluster-identity - resources: - - configmaps - verbs: - - get - - update -- apiGroups: - - "" - resources: - - configmaps - verbs: - - create -- apiGroups: - - apiregistration.k8s.io - resourceNames: - - v1alpha1.stats.antrea.io - - v1beta1.system.antrea.io - - v1beta2.controlplane.antrea.io - resources: - - apiservices - verbs: - - get - - update -- apiGroups: - - apiregistration.k8s.io - resourceNames: - - v1beta1.networking.antrea.tanzu.vmware.com - - v1beta1.controlplane.antrea.tanzu.vmware.com - - v1alpha1.stats.antrea.tanzu.vmware.com - - v1beta1.system.antrea.tanzu.vmware.com - - v1beta2.controlplane.antrea.tanzu.vmware.com - resources: - - apiservices - verbs: - - delete -- apiGroups: - - admissionregistration.k8s.io - resourceNames: - - labelsmutator.antrea.io - - crdmutator.antrea.io - - crdvalidator.antrea.io - resources: - - mutatingwebhookconfigurations - - validatingwebhookconfigurations - verbs: - - get - - update -- apiGroups: - - crd.antrea.io - resources: - - antreacontrollerinfos - verbs: - - get - - create - - update - - delete -- apiGroups: - - crd.antrea.io - resources: - - antreaagentinfos - verbs: - - list - - delete -- apiGroups: - - crd.antrea.io - resources: - - clusternetworkpolicies - - networkpolicies - verbs: - - get - - watch - - list - - update - - patch - - create - - delete -- apiGroups: - - crd.antrea.io - resources: - - clusternetworkpolicies/status - - networkpolicies/status - verbs: - - update -- apiGroups: - - crd.antrea.io - resources: - - tiers - verbs: - - get - - watch - - list - - update - - patch - - create - - delete -- apiGroups: - - crd.antrea.io - resources: - - traceflows - - traceflows/status - verbs: - - get - - watch - - list - - update - - patch - - create - - delete -- apiGroups: - - crd.antrea.io - resources: - - externalentities - - clustergroups - verbs: - - get - - watch - - list - - update - - patch - - create - - delete -- apiGroups: - - crd.antrea.io - resources: - - clustergroups/status - verbs: - - update -- apiGroups: - - crd.antrea.io - resources: - - egresses - verbs: - - get - - watch - - list - - update - - patch -- apiGroups: - - crd.antrea.io - resources: - - externalippools - - ippools - verbs: - - get - - watch - - list -- apiGroups: - - crd.antrea.io - resources: - - externalippools/status - - ippools/status - verbs: - - update -- apiGroups: - - apps - resources: - - statefulsets - verbs: - - get - - list - - watch ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - labels: - app: antrea - name: antctl - namespace: kube-system -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: antctl -subjects: -- kind: ServiceAccount - name: antctl - namespace: kube-system ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - labels: - app: antrea - name: antrea-agent -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: antrea-agent -subjects: -- kind: ServiceAccount - name: antrea-agent - namespace: kube-system ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - labels: - app: antrea - name: antrea-controller -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: antrea-controller -subjects: -- kind: ServiceAccount - name: antrea-controller - namespace: kube-system ---- -apiVersion: v1 data: antrea-agent.conf: | # FeatureGates is a map of feature names to bools that enable or disable experimental features. @@ -2771,7 +90,8 @@ data: # Egress: true # Enable AntreaIPAM, which can allocate IP addresses from IPPools. AntreaIPAM is required by the - # bridging mode and allocates IPs to Pods in bridging mode. + # bridging mode and allocates IPs to Pods in bridging mode. It is also required to use Antrea for + # IPAM when configuring secondary network interfaces with Multus. # AntreaIPAM: false # Enable multicast traffic. This feature is supported only with noEncap mode. @@ -2785,21 +105,23 @@ data: # Enable managing external IPs of Services of LoadBalancer type. # ServiceExternalIP: false + # Enable mirroring or redirecting the traffic Pods send or receive. + # TrafficControl: false + # Name of the OpenVSwitch bridge antrea-agent will create and use. # Make sure it doesn't conflict with your existing OpenVSwitch bridges. - #ovsBridge: br-int + ovsBridge: "br-int" # Datapath type to use for the OpenVSwitch bridge created by Antrea. Supported values are: # - system # - netdev # 'system' is the default value and corresponds to the kernel datapath. Use 'netdev' to run - # OVS in userspace mode (not fully supported yet). Userspace mode requires the tun device driver to - # be available. + # OVS in userspace mode. Userspace mode requires the tun device driver to be available. #ovsDatapathType: system # Name of the interface antrea-agent will create and use for host <--> pod communication. # Make sure it doesn't conflict with your existing interfaces. - #hostGateway: antrea-gw0 + hostGateway: "antrea-gw0" # Determines how traffic is encapsulated. It has the following options: # encap(default): Inter-node Pod traffic is always encapsulated and Pod to external network @@ -2811,14 +133,14 @@ data: # networkPolicyOnly: Antrea enforces NetworkPolicy only, and utilizes CNI chaining and delegates Pod # IPAM and connectivity to the primary CNI. # - #trafficEncapMode: encap + trafficEncapMode: "encap" # Whether or not to SNAT (using the Node IP) the egress traffic from a Pod to the external network. # This option is for the noEncap traffic mode only, and the default value is false. In the noEncap # mode, if the cluster's Pod CIDR is reachable from the external network, then the Pod traffic to # the external network needs not be SNAT'd. In the networkPolicyOnly mode, antrea-agent never # performs SNAT and this option will be ignored; for other modes it must be set to false. - #noSNAT: false + noSNAT: false # Tunnel protocols used for encapsulating traffic across Nodes. If WireGuard is enabled in trafficEncryptionMode, # this option will not take effect. Supported values: @@ -2827,7 +149,7 @@ data: # - gre # - stt # Note that "gre" is not supported for IPv6 clusters (IPv6-only or dual-stack clusters). - #tunnelType: geneve + tunnelType: "geneve" # Determines how tunnel traffic is encrypted. Currently encryption only works with encap mode. # It has the following options: @@ -2837,49 +159,54 @@ data: # the PSK value must be passed to Antrea Agent through an environment # variable: ANTREA_IPSEC_PSK. # - wireGuard: Enable WireGuard for tunnel traffic encryption. - #trafficEncryptionMode: none + trafficEncryptionMode: "none" # Enable bridging mode of Pod network on Nodes, in which the Node's transport interface is connected - # to the OVS bridge, and cross-Node/VLAN traffic from AntreaIPAM Pods (Pods whose IP addresses are - # allocated by AntreaIPAM from IPPools) is sent to the underlay network via the uplink, and - # forwarded/routed by the underlay network. + # to the OVS bridge, and cross-Node/VLAN traffic of AntreaIPAM Pods (Pods whose IP addresses are + # allocated by AntreaIPAM from IPPools) is sent to the underlay network, and forwarded/routed by the + # underlay network. # This option requires the `AntreaIPAM` feature gate to be enabled. At this moment, it supports only # IPv4 and Linux Nodes, and can be enabled only when `ovsDatapathType` is `system`, # `trafficEncapMode` is `noEncap`, and `noSNAT` is true. - #enableBridgingMode: false + enableBridgingMode: false + + # Disable TX checksum offloading for container network interfaces. It's supposed to be set to true when the + # datapath doesn't support TX checksum offloading, which causes packets to be dropped due to bad checksum. + # It affects Pods running on Linux Nodes only. + disableTXChecksumOffload: false # Default MTU to use for the host gateway interface and the network interface of each Pod. # If omitted, antrea-agent will discover the MTU of the Node's primary interface and # also adjust MTU to accommodate for tunnel encapsulation overhead (if applicable). - #defaultMTU: 0 + defaultMTU: 0 # wireGuard specifies WireGuard related configurations. wireGuard: - # The port for WireGuard to receive traffic. - # port: 51820 + # The port for WireGuard to receive traffic. + port: 51820 egress: - # exceptCIDRs is the CIDR ranges to which outbound Pod traffic will not be SNAT'd by Egresses. - # exceptCIDRs: [] + # exceptCIDRs is the CIDR ranges to which outbound Pod traffic will not be SNAT'd by Egresses. + exceptCIDRs: # ClusterIP CIDR range for Services. It's required when AntreaProxy is not enabled, and should be # set to the same value as the one specified by --service-cluster-ip-range for kube-apiserver. When # AntreaProxy is enabled, this parameter is not needed and will be ignored if provided. - #serviceCIDR: 10.96.0.0/12 + serviceCIDR: "" # ClusterIP CIDR range for IPv6 Services. It's required when using kube-proxy to provide IPv6 Service in a Dual-Stack # cluster or an IPv6 only cluster. The value should be the same as the configuration for kube-apiserver specified by # --service-cluster-ip-range. When AntreaProxy is enabled, this parameter is not needed. # No default value for this field. - #serviceCIDRv6: + serviceCIDRv6: "" # The port for the antrea-agent APIServer to serve on. # Note that if it's set to another value, the `containerPort` of the `api` port of the # `antrea-agent` container must be set to the same value. - #apiPort: 10350 + apiPort: 10350 # Enable metrics exposure via Prometheus. Initializes Prometheus metrics listener. - #enablePrometheusMetrics: true + enablePrometheusMetrics: true # Provide the IPFIX collector address as a string with format :[][:]. # HOST can either be the DNS name or the IP of the Flow Collector. For example, @@ -2890,50 +217,50 @@ data: # If no PROTO is given, we consider "tls" as default. We support "tls", "tcp" and # "udp" protocols. "tls" is used for securing communication between flow exporter and # flow aggregator. - #flowCollectorAddr: "flow-aggregator.flow-aggregator.svc:4739:tls" + flowCollectorAddr: "flow-aggregator.flow-aggregator.svc:4739:tls" # Provide flow poll interval as a duration string. This determines how often the # flow exporter dumps connections from the conntrack module. Flow poll interval # should be greater than or equal to 1s (one second). # Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". - #flowPollInterval: "5s" + flowPollInterval: "5s" # Provide the active flow export timeout, which is the timeout after which a flow # record is sent to the collector for active flows. Thus, for flows with a continuous # stream of packets, a flow record will be exported to the collector once the elapsed # time since the last export event is equal to the value of this timeout. # Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". - #activeFlowExportTimeout: "30s" + activeFlowExportTimeout: "5s" # Provide the idle flow export timeout, which is the timeout after which a flow # record is sent to the collector for idle flows. A flow is considered idle if no # packet matching this flow has been observed since the last export event. # Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". - #idleFlowExportTimeout: "15s" + idleFlowExportTimeout: "15s" nodePortLocal: # Enable NodePortLocal, a feature used to make Pods reachable using port forwarding on the host. To # enable this feature, you need to set "enable" to true, and ensure that the NodePortLocal feature # gate is also enabled (which is the default). - # enable: false + enable: false # Provide the port range used by NodePortLocal. When the NodePortLocal feature is enabled, a port # from that range will be assigned whenever a Pod's container defines a specific port to be exposed # (each container can define a list of ports as pod.spec.containers[].ports), and all Node traffic # directed to that port will be forwarded to the Pod. - # portRange: 61000-62000 + portRange: "61000-62000" # Provide the address of Kubernetes apiserver, to override any value provided in kubeconfig or InClusterConfig. # Defaults to "". It must be a host string, a host:port pair, or a URL to the base of the apiserver. - #kubeAPIServerOverride: "" + kubeAPIServerOverride: "" # Comma-separated list of Cipher Suites. If omitted, the default Go Cipher Suites will be used. # https://golang.org/pkg/crypto/tls/#pkg-constants # Note that TLS1.3 Cipher Suites cannot be added to the list. But the apiserver will always # prefer TLS1.3 Cipher Suites whenever possible. - #tlsCipherSuites: + tlsCipherSuites: "" # TLS min version from: VersionTLS10, VersionTLS11, VersionTLS12, VersionTLS13. - #tlsMinVersion: + tlsMinVersion: "" # The name of the interface on Node which is used for tunneling or routing the traffic across Nodes. # If there are multiple IP addresses configured on the interface, the first one is used. The IP @@ -2942,11 +269,16 @@ data: # 1. transportInterface # 2. transportInterfaceCIDRs # 3. The Node IP - #transportInterface: + transportInterface: "" + multicast: # The names of the interfaces on Nodes that are used to forward multicast traffic. # Defaults to transport interface if not set. - #multicastInterfaces: [] + multicastInterfaces: + + # The interval at which the antrea-agent sends IGMP queries to Pods. + # Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". + igmpQueryInterval: "125s" # The network CIDRs of the interface on Node which is used for tunneling or routing the traffic across # Nodes. If there are multiple interfaces configured the same network CIDR, the first one is used. The @@ -2955,7 +287,7 @@ data: # 1. transportInterface # 2. transportInterfaceCIDRs # 3. The Node IP - #transportInterfaceCIDRs: [,] + transportInterfaceCIDRs: # Option antreaProxy contains AntreaProxy related configuration options. antreaProxy: @@ -2964,22 +296,22 @@ data: # feature to be enabled. # Note that this option is experimental. If kube-proxy is removed, option kubeAPIServerOverride must be used to access # apiserver directly. - #proxyAll: false + proxyAll: false # A string array of values which specifies the host IPv4/IPv6 addresses for NodePort. Values can be valid IP blocks. # (e.g. 1.2.3.0/24, 1.2.3.4/32). An empty string slice is meant to select all host IPv4/IPv6 addresses. # Note that the option is only valid when proxyAll is true. - #nodePortAddresses: [] + nodePortAddresses: # An array of string values to specify a list of Services which should be ignored by AntreaProxy (traffic to these # Services will not be load-balanced). Values can be a valid ClusterIP (e.g. 10.11.1.2) or a Service name # with Namespace (e.g. kube-system/kube-dns) - #skipServices: [] + skipServices: # When ProxyLoadBalancerIPs is set to false, AntreaProxy no longer load-balances traffic destined to the # External IPs of LoadBalancer Services. This is useful when the external LoadBalancer provides additional # capabilities (e.g. TLS termination) and it is desirable for Pod-to-ExternalIP traffic to be sent to the # external LoadBalancer instead of being load-balanced to an Endpoint directly by AntreaProxy. # Note that setting ProxyLoadBalancerIPs to false usually only makes sense when ProxyAll is set to true and # kube-proxy is removed from the cluser, otherwise kube-proxy will still load-balance this traffic. - #proxyLoadBalancerIPs: true + proxyLoadBalancerIPs: true antrea-cni.conflist: | { "cniVersion":"0.3.0", @@ -2990,11 +322,13 @@ data: "ipam": { "type": "host-local" } - }, + } + , { "type": "portmap", "capabilities": {"portMappings": true} - }, + } + , { "type": "bandwidth", "capabilities": {"bandwidth": true} @@ -3021,8 +355,9 @@ data: # Run Kubernetes NodeIPAMController with Antrea. # NodeIPAM: false - # Enable flexible IPAM mode for Antrea. This mode allows to assign IP Ranges to Namespaces, - # Deployments and StatefulSets via IP Pool annotation. + # Enable AntreaIPAM, which can allocate IP addresses from IPPools. AntreaIPAM is required by the + # bridging mode and allocates IPs to Pods in bridging mode. It is also required to use Antrea for + # IPAM when configuring secondary network interfaces with Multus. # AntreaIPAM: false # Enable managing external IPs of Services of LoadBalancer type. @@ -3031,659 +366,3674 @@ data: # The port for the antrea-controller APIServer to serve on. # Note that if it's set to another value, the `containerPort` of the `api` port of the # `antrea-controller` container must be set to the same value. - #apiPort: 10349 + apiPort: 10349 # Enable metrics exposure via Prometheus. Initializes Prometheus metrics listener. - #enablePrometheusMetrics: true + enablePrometheusMetrics: true # Indicates whether to use auto-generated self-signed TLS certificate. - # If false, A Secret named "antrea-controller-tls" must be provided with the following keys: + # If false, a Secret named "antrea-controller-tls" must be provided with the following keys: # ca.crt: # tls.crt: # tls.key: - # And the Secret must be mounted to directory "/var/run/antrea/antrea-controller-tls" of the - # antrea-controller container. - #selfSignedCert: true + selfSignedCert: true # Comma-separated list of Cipher Suites. If omitted, the default Go Cipher Suites will be used. # https://golang.org/pkg/crypto/tls/#pkg-constants # Note that TLS1.3 Cipher Suites cannot be added to the list. But the apiserver will always # prefer TLS1.3 Cipher Suites whenever possible. - #tlsCipherSuites: + tlsCipherSuites: "" # TLS min version from: VersionTLS10, VersionTLS11, VersionTLS12, VersionTLS13. - #tlsMinVersion: + tlsMinVersion: "" nodeIPAM: - # Enable the integrated Node IPAM controller within the Antrea controller. - # enableNodeIPAM: false - - # CIDR ranges for Pods in cluster. String array containing single CIDR range, or multiple ranges. - # The CIDRs could be either IPv4 or IPv6. At most one CIDR may be specified for each IP family. - # Value ignored when enableNodeIPAM is false. - # clusterCIDRs: [] - - # CIDR ranges for Services in cluster. It is not necessary to specify it when there is no overlap with clusterCIDRs. - # Value ignored when enableNodeIPAM is false. - # serviceCIDR: - # serviceCIDRv6: - - # Mask size for IPv4 Node CIDR in IPv4 or dual-stack cluster. Value ignored when enableNodeIPAM is false - # or when IPv4 Pod CIDR is not configured. Valid range is 16 to 30. - # nodeCIDRMaskSizeIPv4: 24 - - # Mask size for IPv6 Node CIDR in IPv6 or dual-stack cluster. Value ignored when enableNodeIPAM is false - # or when IPv6 Pod CIDR is not configured. Valid range is 64 to 126. - # nodeCIDRMaskSizeIPv6: 64 -kind: ConfigMap + # Enable the integrated Node IPAM controller within the Antrea controller. + enableNodeIPAM: false + # CIDR ranges for Pods in cluster. String array containing single CIDR range, or multiple ranges. + # The CIDRs could be either IPv4 or IPv6. At most one CIDR may be specified for each IP family. + # Value ignored when enableNodeIPAM is false. + clusterCIDRs: + # CIDR ranges for Services in cluster. It is not necessary to specify it when there is no overlap with clusterCIDRs. + # Value ignored when enableNodeIPAM is false. + serviceCIDR: "" + serviceCIDRv6: "" + # Mask size for IPv4 Node CIDR in IPv4 or dual-stack cluster. Value ignored when enableNodeIPAM is false + # or when IPv4 Pod CIDR is not configured. Valid range is 16 to 30. + nodeCIDRMaskSizeIPv4: 24 + # Mask size for IPv6 Node CIDR in IPv6 or dual-stack cluster. Value ignored when enableNodeIPAM is false + # or when IPv6 Pod CIDR is not configured. Valid range is 64 to 126. + nodeCIDRMaskSizeIPv6: 64 +--- +# Source: antrea/templates/crds/antreaagentinfo.yaml +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: antreaagentinfos.crd.antrea.io + labels: + app: antrea +spec: + group: crd.antrea.io + versions: + - name: v1beta1 + served: true + storage: true + schema: + openAPIV3Schema: + type: object + x-kubernetes-preserve-unknown-fields: true + additionalPrinterColumns: + - description: Health status of this Agent + jsonPath: ".agentConditions[?(@.type=='AgentHealthy')].status" + name: Healthy + type: string + - description: Last time the Healthy Condition was updated + jsonPath: ".agentConditions[?(@.type=='AgentHealthy')].lastHeartbeatTime" + name: Last Heartbeat + type: date + - description: Version of this Agent + jsonPath: ".version" + name: Version + type: string + priority: 1 + - description: Node on which this Agent is running + jsonPath: ".nodeRef.name" + name: Node + type: string + priority: 1 + - description: Number of local Pods managed by this Agent + jsonPath: ".localPodNum" + name: Num Pods + type: integer + priority: 2 + - description: Subnets used by this Agent for Pod IPAM + jsonPath: ".nodeSubnets" + name: Subnets + type: string + priority: 2 + scope: Cluster + names: + plural: antreaagentinfos + singular: antreaagentinfo + kind: AntreaAgentInfo + shortNames: + - aai +--- +# Source: antrea/templates/crds/antreacontrollerinfo.yaml +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: antreacontrollerinfos.crd.antrea.io + labels: + app: antrea +spec: + group: crd.antrea.io + versions: + - name: v1beta1 + served: true + storage: true + schema: + openAPIV3Schema: + type: object + x-kubernetes-preserve-unknown-fields: true + additionalPrinterColumns: + - description: Health status of the Controller + jsonPath: ".controllerConditions[?(@.type=='ControllerHealthy')].status" + name: Healthy + type: string + - description: Last time the Healthy Condition was updated + jsonPath: ".controllerConditions[?(@.type=='ControllerHealthy')].lastHeartbeatTime" + name: Last Heartbeat + type: date + - description: Version of the Controller + jsonPath: ".version" + name: Version + type: string + priority: 1 + - description: Number of Agents connected to the Controller + jsonPath: ".connectedAgentNum" + name: Connected Agents + type: integer + priority: 1 + - description: Node on which the Controller is running + jsonPath: ".nodeRef.name" + name: Node + type: string + priority: 1 + - description: Number of Network Policies computed by Controller + jsonPath: ".networkPolicyControllerInfo.networkPolicyNum" + name: Num Network Policies + type: integer + priority: 2 + scope: Cluster + names: + plural: antreacontrollerinfos + singular: antreacontrollerinfo + kind: AntreaControllerInfo + shortNames: + - aci +--- +# Source: antrea/templates/crds/clustergroup.yaml +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: clustergroups.crd.antrea.io + labels: + app: antrea +spec: + group: crd.antrea.io + versions: + - name: v1alpha2 + served: true + storage: false + schema: + openAPIV3Schema: + type: object + properties: + spec: + type: object + properties: + childGroups: + type: array + items: + type: string + podSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + externalEntitySelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + ipBlock: + type: object + properties: + cidr: + type: string + format: cidr + ipBlocks: + type: array + items: + type: object + properties: + cidr: + type: string + format: cidr + serviceReference: + type: object + properties: + name: + type: string + namespace: + type: string + status: + type: object + properties: + conditions: + type: array + items: + type: object + properties: + type: + type: string + status: + type: string + lastTransitionTime: + type: string + - name: v1alpha3 + served: true + storage: true + schema: + openAPIV3Schema: + type: object + properties: + spec: + type: object + properties: + childGroups: + type: array + items: + type: string + podSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + externalEntitySelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + ipBlocks: + type: array + items: + type: object + properties: + cidr: + type: string + format: cidr + serviceReference: + type: object + properties: + name: + type: string + namespace: + type: string + status: + type: object + properties: + conditions: + type: array + items: + type: object + properties: + type: + type: string + status: + type: string + lastTransitionTime: + type: string + subresources: + status: {} + conversion: + strategy: Webhook + webhook: + conversionReviewVersions: ["v1", "v1beta1"] + clientConfig: + service: + name: "antrea" + namespace: "kube-system" + path: "/convert/clustergroup" + scope: Cluster + names: + plural: clustergroups + singular: clustergroup + kind: ClusterGroup + shortNames: + - cg +--- +# Source: antrea/templates/crds/clusternetworkpolicy.yaml +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: clusternetworkpolicies.crd.antrea.io + labels: + app: antrea +spec: + group: crd.antrea.io + versions: + - name: v1alpha1 + served: true + storage: true + additionalPrinterColumns: + - name: Tier + type: string + description: The Tier to which this ClusterNetworkPolicy belongs to. + jsonPath: .spec.tier + - name: Priority + type: number + format: float + description: The Priority of this ClusterNetworkPolicy relative to other policies. + jsonPath: .spec.priority + - name: Desired Nodes + type: number + format: int32 + description: The total number of Nodes that should realize the NetworkPolicy. + jsonPath: .status.desiredNodesRealized + - name: Current Nodes + type: number + format: int32 + description: The number of Nodes that have realized the NetworkPolicy. + jsonPath: .status.currentNodesRealized + - name: Age + type: date + jsonPath: .metadata.creationTimestamp + schema: + openAPIV3Schema: + type: object + properties: + spec: + # Ensure that Spec.Priority field is set + required: + - priority + type: object + properties: + tier: + type: string + priority: + type: number + format: float + # Ensure that Spec.Priority field is between 1 and 10000 + minimum: 1.0 + maximum: 10000.0 + appliedTo: + type: array + items: + type: object + # Ensure that Spec.AppliedTo does not allow IPBlock field + properties: + podSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + group: + type: string + serviceAccount: + type: object + properties: + name: + type: string + namespace: + type: string + required: + - name + - namespace + ingress: + type: array + items: + type: object + required: + - action + properties: + appliedTo: + type: array + items: + type: object + # Ensure that rule AppliedTo does not allow IPBlock field + properties: + podSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + group: + type: string + serviceAccount: + type: object + properties: + name: + type: string + namespace: + type: string + required: + - name + - namespace + # Ensure that Action field allows only ALLOW, DROP, REJECT and PASS values + action: + type: string + enum: ['Allow', 'Drop', 'Reject', 'Pass'] + ports: + type: array + items: + type: object + properties: + protocol: + type: string + enum: ['TCP', 'UDP', 'SCTP'] + port: + x-kubernetes-int-or-string: true + endPort: + type: integer + protocols: + type: array + items: + type: object + oneOf: + - required: [icmp] + properties: + icmp: + type: object + properties: + icmpType: + type: integer + minimum: 0 + maximum: 255 + icmpCode: + type: integer + minimum: 0 + maximum: 255 + from: + type: array + items: + type: object + properties: + podSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + namespaces: + type: object + properties: + match: + enum: + - Self + type: string + ipBlock: + type: object + properties: + cidr: + type: string + format: cidr + group: + type: string + serviceAccount: + type: object + properties: + name: + type: string + namespace: + type: string + required: + - name + - namespace + nodeSelector: + type: object + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + type: array + type: object + type: array + matchLabels: + x-kubernetes-preserve-unknown-fields: true + name: + type: string + enableLogging: + type: boolean + egress: + type: array + items: + type: object + required: + - action + properties: + appliedTo: + type: array + items: + type: object + # Ensure that rule AppliedTo does not allow IPBlock field + properties: + podSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + group: + type: string + serviceAccount: + type: object + properties: + name: + type: string + namespace: + type: string + required: + - name + - namespace + # Ensure that Action field allows only ALLOW, DROP, REJECT and PASS values + action: + type: string + enum: ['Allow', 'Drop', 'Reject', 'Pass'] + ports: + type: array + items: + type: object + properties: + protocol: + type: string + enum: ['TCP', 'UDP', 'SCTP'] + port: + x-kubernetes-int-or-string: true + endPort: + type: integer + protocols: + type: array + items: + type: object + oneOf: + - required: [icmp] + properties: + icmp: + type: object + properties: + icmpType: + type: integer + minimum: 0 + maximum: 255 + icmpCode: + type: integer + minimum: 0 + maximum: 255 + to: + type: array + items: + type: object + properties: + podSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + namespaces: + type: object + properties: + match: + enum: + - Self + type: string + ipBlock: + type: object + properties: + cidr: + type: string + format: cidr + group: + type: string + fqdn: + type: string + serviceAccount: + type: object + properties: + name: + type: string + namespace: + type: string + required: + - name + - namespace + nodeSelector: + type: object + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + type: array + type: object + type: array + matchLabels: + x-kubernetes-preserve-unknown-fields: true + toServices: + type: array + items: + type: object + required: + - name + - namespace + properties: + name: + type: string + namespace: + type: string + name: + type: string + enableLogging: + type: boolean + status: + type: object + properties: + phase: + type: string + observedGeneration: + type: integer + currentNodesRealized: + type: integer + desiredNodesRealized: + type: integer + subresources: + status: {} + scope: Cluster + names: + plural: clusternetworkpolicies + singular: clusternetworkpolicy + kind: ClusterNetworkPolicy + shortNames: + - acnp +--- +# Source: antrea/templates/crds/egress.yaml +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: egresses.crd.antrea.io + labels: + app: antrea +spec: + group: crd.antrea.io + versions: + - name: v1alpha2 + served: true + storage: true + schema: + openAPIV3Schema: + type: object + required: + - spec + properties: + spec: + type: object + required: + - appliedTo + anyOf: + - required: + - egressIP + - required: + - externalIPPool + properties: + appliedTo: + type: object + properties: + podSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + egressIP: + type: string + oneOf: + - format: ipv4 + - format: ipv6 + externalIPPool: + type: string + status: + type: object + properties: + egressNode: + type: string + additionalPrinterColumns: + - description: Specifies the SNAT IP address for the selected workloads. + jsonPath: .spec.egressIP + name: EgressIP + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + - description: The Owner Node of egress IP + jsonPath: .status.egressNode + name: Node + type: string + subresources: + status: {} + scope: Cluster + names: + plural: egresses + singular: egress + kind: Egress + shortNames: + - eg +--- +# Source: antrea/templates/crds/externalentity.yaml +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: externalentities.crd.antrea.io + labels: + app: antrea +spec: + group: crd.antrea.io + versions: + - name: v1alpha2 + served: true + storage: true + schema: + openAPIV3Schema: + type: object + properties: + spec: + type: object + properties: + endpoints: + type: array + items: + type: object + properties: + ip: + type: string + oneOf: + - format: ipv4 + - format: ipv6 + name: + type: string + ports: + type: array + items: + type: object + properties: + protocol: + type: string + enum: ['TCP', 'UDP', 'SCTP'] + port: + x-kubernetes-int-or-string: true + name: + type: string + externalNode: + type: string + - name: v1alpha1 + served: false + storage: false + schema: + openAPIV3Schema: + type: object + scope: Namespaced + names: + plural: externalentities + singular: externalentity + kind: ExternalEntity + shortNames: + - ee +--- +# Source: antrea/templates/crds/externalippool.yaml +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: externalippools.crd.antrea.io + labels: + app: antrea +spec: + group: crd.antrea.io + versions: + - name: v1alpha2 + served: true + storage: true + schema: + openAPIV3Schema: + type: object + required: + - spec + properties: + spec: + type: object + required: + - ipRanges + - nodeSelector + properties: + ipRanges: + type: array + items: + type: object + oneOf: + - required: + - cidr + - required: + - start + - end + properties: + cidr: + type: string + format: cidr + start: + type: string + oneOf: + - format: ipv4 + - format: ipv6 + end: + type: string + oneOf: + - format: ipv4 + - format: ipv6 + nodeSelector: + type: object + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + type: array + type: object + type: array + matchLabels: + x-kubernetes-preserve-unknown-fields: true + status: + type: object + properties: + usage: + type: object + properties: + total: + type: integer + used: + type: integer + additionalPrinterColumns: + - description: The number of total IPs + jsonPath: .status.usage.total + name: Total + type: integer + - description: The number of allocated IPs + jsonPath: .status.usage.used + name: Used + type: integer + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + subresources: + status: {} + scope: Cluster + names: + plural: externalippools + singular: externalippool + kind: ExternalIPPool + shortNames: + - eip +--- +# Source: antrea/templates/crds/ippool.yaml +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: ippools.crd.antrea.io + labels: + app: antrea +spec: + group: crd.antrea.io + versions: + - name: v1alpha2 + served: true + storage: true + schema: + openAPIV3Schema: + type: object + required: + - spec + properties: + spec: + required: + - ipVersion + - ipRanges + type: object + properties: + ipVersion: + type: integer + ipRanges: + items: + oneOf: + - required: + - cidr + - gateway + - prefixLength + - required: + - start + - end + - gateway + - prefixLength + properties: + cidr: + format: cidr + type: string + start: + oneOf: + - format: ipv4 + - format: ipv6 + type: string + end: + oneOf: + - format: ipv4 + - format: ipv6 + type: string + gateway: + oneOf: + - format: ipv4 + - format: ipv6 + type: string + prefixLength: + type: integer + vlan: + type: integer + minimum: 0 + maximum: 4094 + type: object + type: array + status: + properties: + ipAddresses: + items: + properties: + ipAddress: + type: string + owner: + properties: + pod: + properties: + name: + type: string + namespace: + type: string + containerID: + type: string + ifName: + type: string + type: object + statefulSet: + properties: + name: + type: string + namespace: + type: string + index: + type: integer + type: object + type: object + phase: + type: string + type: object + type: array + type: object + subresources: + status: {} + scope: Cluster + names: + plural: ippools + singular: ippool + kind: IPPool + shortNames: + - ipp +--- +# Source: antrea/templates/crds/networkpolicy.yaml +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: networkpolicies.crd.antrea.io + labels: + app: antrea +spec: + group: crd.antrea.io + versions: + - name: v1alpha1 + served: true + storage: true + additionalPrinterColumns: + - name: Tier + type: string + description: The Tier to which this Antrea NetworkPolicy belongs to. + jsonPath: .spec.tier + - name: Priority + type: number + format: float + description: The Priority of this Antrea NetworkPolicy relative to other policies. + jsonPath: .spec.priority + - name: Desired Nodes + type: number + format: int32 + description: The total number of Nodes that should realize the NetworkPolicy. + jsonPath: .status.desiredNodesRealized + - name: Current Nodes + type: number + format: int32 + description: The number of Nodes that have realized the NetworkPolicy. + jsonPath: .status.currentNodesRealized + - name: Age + type: date + jsonPath: .metadata.creationTimestamp + schema: + openAPIV3Schema: + type: object + properties: + spec: + # Ensure that Spec.Priority field is set + required: + - priority + type: object + properties: + tier: + type: string + priority: + type: number + format: float + # Ensure that Spec.Priority field is between 1 and 10000 + minimum: 1.0 + maximum: 10000.0 + appliedTo: + type: array + items: + type: object + # Ensure that Spec.AppliedTo does not allow NamespaceSelector/IPBlock field + properties: + podSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + ingress: + type: array + items: + type: object + required: + - action + properties: + appliedTo: + type: array + items: + type: object + # Ensure that rule AppliedTo does not allow NamespaceSelector/IPBlock field + properties: + podSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + # Ensure that Action field allows only ALLOW, DROP, REJECT and PASS values + action: + type: string + enum: ['Allow', 'Drop', 'Reject', 'Pass'] + ports: + type: array + items: + type: object + properties: + protocol: + type: string + enum: ['TCP', 'UDP', 'SCTP'] + port: + x-kubernetes-int-or-string: true + endPort: + type: integer + protocols: + type: array + items: + type: object + oneOf: + - required: [icmp] + properties: + icmp: + type: object + properties: + icmpType: + type: integer + minimum: 0 + maximum: 255 + icmpCode: + type: integer + minimum: 0 + maximum: 255 + from: + type: array + items: + type: object + properties: + podSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + externalEntitySelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + ipBlock: + type: object + properties: + cidr: + type: string + format: cidr + nodeSelector: + type: object + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + type: array + type: object + type: array + matchLabels: + x-kubernetes-preserve-unknown-fields: true + name: + type: string + enableLogging: + type: boolean + egress: + type: array + items: + type: object + required: + - action + properties: + appliedTo: + type: array + items: + type: object + # Ensure that rule AppliedTo does not allow NamespaceSelector/IPBlock field + properties: + podSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + # Ensure that Action field allows only ALLOW, DROP, REJECT and PASS values + action: + type: string + enum: ['Allow', 'Drop', 'Reject', 'Pass'] + ports: + type: array + items: + type: object + properties: + protocol: + type: string + enum: ['TCP', 'UDP', 'SCTP'] + port: + x-kubernetes-int-or-string: true + endPort: + type: integer + protocols: + type: array + items: + type: object + oneOf: + - required: [icmp] + properties: + icmp: + type: object + properties: + icmpType: + type: integer + minimum: 0 + maximum: 255 + icmpCode: + type: integer + minimum: 0 + maximum: 255 + to: + type: array + items: + type: object + properties: + podSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + externalEntitySelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + ipBlock: + type: object + properties: + cidr: + type: string + format: cidr + fqdn: + type: string + nodeSelector: + type: object + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + type: array + type: object + type: array + matchLabels: + x-kubernetes-preserve-unknown-fields: true + toServices: + type: array + items: + type: object + required: + - name + properties: + name: + type: string + namespace: + type: string + name: + type: string + enableLogging: + type: boolean + status: + type: object + properties: + phase: + type: string + observedGeneration: + type: integer + currentNodesRealized: + type: integer + desiredNodesRealized: + type: integer + subresources: + status: {} + scope: Namespaced + names: + plural: networkpolicies + singular: networkpolicy + kind: NetworkPolicy + shortNames: + - anp +--- +# Source: antrea/templates/crds/tier.yaml +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: tiers.crd.antrea.io + labels: + app: antrea +spec: + group: crd.antrea.io + versions: + - name: v1alpha1 + served: true + storage: true + additionalPrinterColumns: + - name: Priority + type: integer + description: The Priority of this Tier relative to other Tiers. + jsonPath: .spec.priority + - name: Age + type: date + jsonPath: .metadata.creationTimestamp + schema: + openAPIV3Schema: + type: object + properties: + spec: + required: + - priority + type: object + properties: + priority: + type: integer + minimum: 0 + maximum: 255 + description: + type: string + scope: Cluster + names: + plural: tiers + singular: tier + kind: Tier + shortNames: + - tr +--- +# Source: antrea/templates/crds/traceflow.yaml +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: traceflows.crd.antrea.io + labels: + app: antrea +spec: + group: crd.antrea.io + versions: + - name: v1alpha1 + served: true + storage: true + additionalPrinterColumns: + - jsonPath: .status.phase + description: The phase of the Traceflow. + name: Phase + type: string + - jsonPath: .spec.source.pod + description: The name of the source Pod. + name: Source-Pod + type: string + priority: 10 + - jsonPath: .spec.destination.pod + description: The name of the destination Pod. + name: Destination-Pod + type: string + priority: 10 + - jsonPath: .spec.destination.ip + description: The IP address of the destination. + name: Destination-IP + type: string + priority: 10 + - jsonPath: .spec.liveTraffic + description: Trace live traffic. + name: Live-Traffic + type: boolean + priority: 10 + - jsonPath: .spec.droppedOnly + description: Capture only the dropped packet. + name: Dropped-Only + type: boolean + priority: 10 + - jsonPath: .spec.timeout + description: Timeout in seconds. + name: Timeout + type: integer + priority: 10 + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + schema: + openAPIV3Schema: + type: object + required: + - spec + properties: + spec: + type: object + properties: + source: + type: object + properties: + pod: + type: string + namespace: + type: string + ip: + type: string + oneOf: + - format: ipv4 + - format: ipv6 + destination: + type: object + properties: + pod: + type: string + service: + type: string + namespace: + type: string + ip: + type: string + oneOf: + - format: ipv4 + - format: ipv6 + packet: + type: object + properties: + ipHeader: + type: object + properties: + srcIP: + type: string + oneOf: + - format: ipv4 + - format: ipv6 + protocol: + type: integer + ttl: + type: integer + flags: + type: integer + ipv6Header: + type: object + properties: + srcIP: + type: string + format: ipv6 + nextHeader: + type: integer + hopLimit: + type: integer + transportHeader: + type: object + properties: + icmp: + type: object + properties: + id: + type: integer + sequence: + type: integer + udp: + type: object + properties: + srcPort: + type: integer + dstPort: + type: integer + tcp: + type: object + properties: + srcPort: + type: integer + dstPort: + type: integer + flags: + type: integer + liveTraffic: + type: boolean + droppedOnly: + type: boolean + timeout: + type: integer + status: + type: object + properties: + reason: + type: string + dataplaneTag: + type: integer + phase: + type: string + startTime: + type: string + results: + type: array + items: + type: object + properties: + node: + type: string + role: + type: string + timestamp: + type: integer + observations: + type: array + items: + type: object + properties: + component: + type: string + componentInfo: + type: string + action: + type: string + pod: + type: string + dstMAC: + type: string + networkPolicy: + type: string + ttl: + type: integer + translatedSrcIP: + type: string + translatedDstIP: + type: string + tunnelDstIP: + type: string + capturedPacket: + properties: + srcIP: + type: string + dstIP: + type: string + length: + type: integer + ipHeader: + properties: + flags: + type: integer + protocol: + type: integer + ttl: + type: integer + type: object + ipv6Header: + properties: + hopLimit: + type: integer + nextHeader: + type: integer + type: object + transportHeader: + properties: + tcp: + properties: + dstPort: + type: integer + srcPort: + type: integer + flags: + type: integer + type: object + udp: + properties: + dstPort: + type: integer + srcPort: + type: integer + type: object + icmp: + properties: + id: + type: integer + sequence: + type: integer + type: object + type: object + type: object + subresources: + status: {} + scope: Cluster + names: + plural: traceflows + singular: traceflow + kind: Traceflow + shortNames: + - tf +--- +# Source: antrea/templates/crds/trafficcontrol.yaml +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: trafficcontrols.crd.antrea.io +spec: + group: crd.antrea.io + versions: + - name: v1alpha2 + served: true + storage: true + schema: + openAPIV3Schema: + type: object + required: + - spec + properties: + spec: + type: object + required: + - appliedTo + - direction + - action + - targetPort + properties: + appliedTo: + type: object + properties: + podSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true + direction: + type: string + enum: + - Ingress + - Egress + - Both + action: + type: string + enum: + - Mirror + - Redirect + targetPort: + type: object + oneOf: + - required: [ovsInternal] + - required: [device] + - required: [geneve] + - required: [vxlan] + - required: [gre] + - required: [erspan] + properties: + ovsInternal: + type: object + required: + - name + properties: + name: + type: string + device: + type: object + required: + - name + properties: + name: + type: string + geneve: + type: object + required: + - remoteIP + properties: + remoteIP: + type: string + oneOf: + - format: ipv4 + - format: ipv6 + vni: + type: integer + minimum: 0 + maximum: 16777215 + destinationPort: + type: integer + minimum: 1 + maximum: 65535 + vxlan: + type: object + required: + - remoteIP + properties: + remoteIP: + type: string + oneOf: + - format: ipv4 + - format: ipv6 + vni: + type: integer + minimum: 0 + maximum: 16777215 + destinationPort: + type: integer + minimum: 1 + maximum: 65535 + gre: + type: object + required: + - remoteIP + properties: + remoteIP: + type: string + oneOf: + - format: ipv4 + - format: ipv6 + key: + type: integer + minimum: 0 + maximum: 4294967295 + erspan: + type: object + required: + - remoteIP + - version + properties: + remoteIP: + type: string + oneOf: + - format: ipv4 + - format: ipv6 + sessionID: + type: integer + minimum: 0 + maximum: 1023 + version: + type: integer + enum: + - 1 + - 2 + index: + type: integer + dir: + type: integer + enum: + - 0 + - 1 + hardwareID: + type: integer + returnPort: + type: object + oneOf: + - required: [ovsInternal] + - required: [device] + - required: [geneve] + - required: [vxlan] + - required: [gre] + properties: + ovsInternal: + type: object + required: + - name + properties: + name: + type: string + device: + type: object + required: + - name + properties: + name: + type: string + geneve: + type: object + required: + - remoteIP + properties: + remoteIP: + type: string + oneOf: + - format: ipv4 + - format: ipv6 + vni: + type: integer + minimum: 0 + maximum: 16777215 + destinationPort: + type: integer + minimum: 1 + maximum: 65535 + vxlan: + type: object + required: + - remoteIP + properties: + remoteIP: + type: string + oneOf: + - format: ipv4 + - format: ipv6 + vni: + type: integer + minimum: 0 + maximum: 16777215 + destinationPort: + type: integer + minimum: 1 + maximum: 65535 + gre: + type: object + required: + - remoteIP + properties: + remoteIP: + type: string + oneOf: + - format: ipv4 + - format: ipv6 + key: + type: integer + minimum: 0 + maximum: 4294967295 + additionalPrinterColumns: + - description: Specifies the direction of traffic that should be matched. + jsonPath: .spec.direction + name: Direction + type: string + - description: Specifies the action that should be taken for the traffic. + jsonPath: .spec.action + name: Action + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + subresources: + status: {} + scope: Cluster + names: + plural: trafficcontrols + singular: trafficcontrol + kind: TrafficControl + shortNames: + - tc +--- +# Source: antrea/templates/agent/clusterrole.yaml +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: antrea-agent + labels: + app: antrea +rules: + - apiGroups: + - "" + resources: + - nodes + verbs: + - get + - watch + - list + - apiGroups: + - "" + resources: + - nodes/status + verbs: + - patch + - apiGroups: + - "" + resources: + - pods + verbs: + - get + - watch + - list + - apiGroups: + - "" + resources: + - pods/status + verbs: + - patch + - apiGroups: + - "" + resources: + - endpoints + - services + - namespaces + verbs: + - get + - watch + - list + - apiGroups: + - discovery.k8s.io + resources: + - endpointslices + verbs: + - get + - watch + - list + - apiGroups: + - crd.antrea.io + resources: + - antreaagentinfos + verbs: + - get + - create + - update + - delete + - apiGroups: + - controlplane.antrea.io + resources: + - networkpolicies + - appliedtogroups + - addressgroups + verbs: + - get + - watch + - list + - apiGroups: + - controlplane.antrea.io + resources: + - egressgroups + verbs: + - get + - watch + - list + - apiGroups: + - controlplane.antrea.io + resources: + - nodestatssummaries + verbs: + - create + - apiGroups: + - controlplane.antrea.io + resources: + - networkpolicies/status + verbs: + - create + - get + - apiGroups: + - authentication.k8s.io + resources: + - tokenreviews + verbs: + - create + - apiGroups: + - authorization.k8s.io + resources: + - subjectaccessreviews + verbs: + - create + # This is the content of built-in role kube-system/extension-apiserver-authentication-reader. + # But it doesn't have list/watch permission before K8s v1.17.0 so the extension apiserver (antrea-agent) will + # have permission issue after bumping up apiserver library to a version that supports dynamic authentication. + # See https://github.com/kubernetes/kubernetes/pull/85375 + # To support K8s clusters older than v1.17.0, we grant the required permissions directly instead of relying on + # the extension-apiserver-authentication role. + - apiGroups: + - "" + resourceNames: + - extension-apiserver-authentication + resources: + - configmaps + verbs: + - get + - list + - watch + - apiGroups: + - "" + resources: + - configmaps + resourceNames: + - antrea-ca + verbs: + - get + - watch + - list + - apiGroups: + - crd.antrea.io + resources: + - traceflows + - traceflows/status + verbs: + - get + - watch + - list + - update + - patch + - create + - delete + - apiGroups: + - crd.antrea.io + resources: + - egresses + verbs: + - get + - watch + - list + - apiGroups: + - crd.antrea.io + resources: + - egresses/status + verbs: + - update + - apiGroups: + - crd.antrea.io + resources: + - externalippools + - ippools + - trafficcontrols + verbs: + - get + - watch + - list + - apiGroups: + - crd.antrea.io + resources: + - ippools/status + verbs: + - update + - apiGroups: + - k8s.cni.cncf.io + resources: + - network-attachment-definitions + verbs: + - get + - list + - watch +--- +# Source: antrea/templates/antctl/clusterrole.yaml +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: antctl + labels: + app: antrea +rules: + - apiGroups: + - controlplane.antrea.io + resources: + - networkpolicies + - appliedtogroups + - addressgroups + verbs: + - get + - list + - apiGroups: + - stats.antrea.io + resources: + - networkpolicystats + - antreaclusternetworkpolicystats + - antreanetworkpolicystats + verbs: + - get + - list + - apiGroups: + - system.antrea.io + resources: + - controllerinfos + - agentinfos + verbs: + - get + - apiGroups: + - system.antrea.io + resources: + - supportbundles + verbs: + - get + - post + - apiGroups: + - system.antrea.io + resources: + - supportbundles/download + verbs: + - get + - nonResourceURLs: + - /agentinfo + - /addressgroups + - /appliedtogroups + - /loglevel + - /networkpolicies + - /ovsflows + - /ovstracing + - /podinterfaces + - /featuregates + - /serviceexternalip + verbs: + - get +--- +# Source: antrea/templates/cluster-identity-reader/clusterrolebinding.yaml +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: antrea-cluster-identity-reader + labels: + app: antrea +rules: + - apiGroups: + - "" + resources: + - configmaps + resourceNames: + - antrea-cluster-identity + verbs: + - get +--- +# Source: antrea/templates/controller/clusterrole.yaml +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: antrea-controller + labels: + app: antrea +rules: + - apiGroups: + - "" + resources: + - pods + - services + - namespaces + - configmaps + verbs: + - get + - watch + - list + - apiGroups: + - "" + resources: + - nodes + verbs: + - get + - watch + - list + - patch + - apiGroups: + - "" + resources: + - services/status + verbs: + - update + - apiGroups: + - networking.k8s.io + resources: + - networkpolicies + verbs: + - get + - watch + - list + - apiGroups: + - authentication.k8s.io + resources: + - tokenreviews + verbs: + - create + - apiGroups: + - authorization.k8s.io + resources: + - subjectaccessreviews + verbs: + - create + - apiGroups: + - apiextensions.k8s.io + resources: + - customresourcedefinitions + verbs: + - get + - update + # This is the content of built-in role kube-system/extension-apiserver-authentication-reader. + # But it doesn't have list/watch permission before K8s v1.17.0 so the extension apiserver (antrea-controller) will + # have permission issue after bumping up apiserver library to a version that supports dynamic authentication. + # See https://github.com/kubernetes/kubernetes/pull/85375 + # To support K8s clusters older than v1.17.0, we grant the required permissions directly instead of relying on + # the extension-apiserver-authentication role. + - apiGroups: + - "" + resourceNames: + - extension-apiserver-authentication + resources: + - configmaps + verbs: + - get + - list + - watch + - apiGroups: + - "" + resources: + - configmaps + resourceNames: + - antrea-ca + - antrea-cluster-identity + verbs: + - get + - update + - apiGroups: + - "" + resources: + - configmaps + verbs: + - create + - apiGroups: + - apiregistration.k8s.io + resources: + - apiservices + resourceNames: + - v1alpha1.stats.antrea.io + - v1beta1.system.antrea.io + - v1beta2.controlplane.antrea.io + verbs: + - get + - update + - apiGroups: + - apiregistration.k8s.io + resources: + - apiservices + resourceNames: + - v1beta1.networking.antrea.tanzu.vmware.com + - v1beta1.controlplane.antrea.tanzu.vmware.com + - v1alpha1.stats.antrea.tanzu.vmware.com + - v1beta1.system.antrea.tanzu.vmware.com + - v1beta2.controlplane.antrea.tanzu.vmware.com + verbs: + - delete + - apiGroups: + - admissionregistration.k8s.io + resources: + - mutatingwebhookconfigurations + - validatingwebhookconfigurations + resourceNames: + # always give permissions for labelsmutator.antrea.io, even when the + # feature is disabled, to avoid errors in antrea-controller when updating + # the CA cert. + - labelsmutator.antrea.io + - crdmutator.antrea.io + - crdvalidator.antrea.io + verbs: + - get + - update + - apiGroups: + - crd.antrea.io + resources: + - antreacontrollerinfos + verbs: + - get + - create + - update + - delete + - apiGroups: + - crd.antrea.io + resources: + - antreaagentinfos + verbs: + - list + - delete + - apiGroups: + - crd.antrea.io + resources: + - clusternetworkpolicies + - networkpolicies + verbs: + - get + - watch + - list + - update + - patch + - create + - delete + - apiGroups: + - crd.antrea.io + resources: + - clusternetworkpolicies/status + - networkpolicies/status + verbs: + - update + - apiGroups: + - crd.antrea.io + resources: + - tiers + verbs: + - get + - watch + - list + - update + - patch + - create + - delete + - apiGroups: + - crd.antrea.io + resources: + - traceflows + - traceflows/status + verbs: + - get + - watch + - list + - update + - patch + - create + - delete + - apiGroups: + - crd.antrea.io + resources: + - externalentities + - clustergroups + verbs: + - get + - watch + - list + - update + - patch + - create + - delete + - apiGroups: + - crd.antrea.io + resources: + - clustergroups/status + verbs: + - update + - apiGroups: + - crd.antrea.io + resources: + - egresses + verbs: + - get + - watch + - list + - update + - patch + - apiGroups: + - crd.antrea.io + resources: + - externalippools + - ippools + verbs: + - get + - watch + - list + - apiGroups: + - crd.antrea.io + resources: + - externalippools/status + - ippools/status + verbs: + - update + - apiGroups: + - apps + resources: + - statefulsets + verbs: + - get + - list + - watch +--- +# Source: antrea/templates/crds-rbac/clusterroles.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole metadata: + name: aggregate-antrea-policies-edit labels: app: antrea - name: antrea-config-hkhbh5gf99 - namespace: kube-system + # Add these permissions to the "admin" and "edit" default roles. + rbac.authorization.k8s.io/aggregate-to-admin: "true" + rbac.authorization.k8s.io/aggregate-to-edit: "true" +rules: +- apiGroups: ["crd.antrea.io"] + resources: ["clusternetworkpolicies", "networkpolicies"] + verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] --- -apiVersion: v1 -kind: Service +# Source: antrea/templates/crds-rbac/clusterroles.yaml +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: aggregate-antrea-policies-view + labels: + app: antrea + # Add these permissions to the "view" default role. + rbac.authorization.k8s.io/aggregate-to-view: "true" +rules: +- apiGroups: ["crd.antrea.io"] + resources: ["clusternetworkpolicies", "networkpolicies"] + verbs: ["get", "list", "watch"] +--- +# Source: antrea/templates/crds-rbac/clusterroles.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: aggregate-traceflows-edit + labels: + app: antrea + # Add these permissions to the "admin" and "edit" default roles. + rbac.authorization.k8s.io/aggregate-to-admin: "true" + rbac.authorization.k8s.io/aggregate-to-edit: "true" +rules: +- apiGroups: ["crd.antrea.io"] + resources: ["traceflows"] + verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] +--- +# Source: antrea/templates/crds-rbac/clusterroles.yaml +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 metadata: + name: aggregate-traceflows-view + labels: + app: antrea + # Add these permissions to the "view" default role. + rbac.authorization.k8s.io/aggregate-to-view: "true" +rules: +- apiGroups: ["crd.antrea.io"] + resources: ["traceflows"] + verbs: ["get", "list", "watch"] +--- +# Source: antrea/templates/crds-rbac/clusterroles.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: aggregate-antrea-clustergroups-edit + labels: + app: antrea + # Add these permissions to the "admin" and "edit" default roles. + rbac.authorization.k8s.io/aggregate-to-admin: "true" + rbac.authorization.k8s.io/aggregate-to-edit: "true" +rules: +- apiGroups: ["crd.antrea.io"] + resources: ["clustergroups"] + verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] +--- +# Source: antrea/templates/crds-rbac/clusterroles.yaml +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: aggregate-antrea-clustergroups-view + labels: + app: antrea + # Add these permissions to the "view" default role. + rbac.authorization.k8s.io/aggregate-to-view: "true" +rules: +- apiGroups: ["crd.antrea.io"] + resources: ["clustergroups"] + verbs: ["get", "list", "watch"] +--- +# Source: antrea/templates/agent/clusterrolebinding.yaml +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: antrea-agent + labels: + app: antrea +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: antrea-agent +subjects: + - kind: ServiceAccount + name: antrea-agent + namespace: kube-system +--- +# Source: antrea/templates/antctl/clusterrolebinding.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + labels: + app: antrea + name: antctl +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: antctl +subjects: + - kind: ServiceAccount + name: antctl + namespace: kube-system +--- +# Source: antrea/templates/controller/clusterrolebinding.yaml +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: antrea-controller labels: app: antrea +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: antrea-controller +subjects: + - kind: ServiceAccount + name: antrea-controller + namespace: kube-system +--- +# Source: antrea/templates/controller/service.yaml +apiVersion: v1 +kind: Service +metadata: name: antrea namespace: kube-system + labels: + app: antrea spec: ports: - - port: 443 - protocol: TCP - targetPort: api + - port: 443 + protocol: TCP + targetPort: api selector: app: antrea component: antrea-controller --- +# Source: antrea/templates/agent/daemonset.yaml apiVersion: apps/v1 -kind: Deployment +kind: DaemonSet metadata: + name: antrea-agent + namespace: kube-system labels: app: antrea - component: antrea-controller + component: antrea-agent +spec: + selector: + matchLabels: + app: antrea + component: antrea-agent + updateStrategy: + type: RollingUpdate + template: + metadata: + annotations: + # Starting with v1.21, Kubernetes supports default container annotation. + # Using "kubectl logs/exec/attach/cp" doesn't have to specify "-c antrea-agent" when troubleshooting. + kubectl.kubernetes.io/default-container: antrea-agent + # Automatically restart Pods with a RollingUpdate if the ConfigMap changes + # See https://helm.sh/docs/howto/charts_tips_and_tricks/#automatically-roll-deployments + checksum/config: 03ee0481c65f3ec8ff9e879ff10c3cf65991a347a7aec1c9bc866b019ec470f1 + labels: + app: antrea + component: antrea-agent + spec: + hostNetwork: true + dnsPolicy: ClusterFirstWithHostNet + priorityClassName: system-node-critical + nodeSelector: + kubernetes.io/os: linux + tolerations: + - key: CriticalAddonsOnly + operator: Exists + - effect: NoSchedule + operator: Exists + - effect: NoExecute + operator: Exists + serviceAccountName: antrea-agent + initContainers: + - name: install-cni + image: "projects.registry.vmware.com/antrea/antrea-ubuntu:latest" + imagePullPolicy: IfNotPresent + resources: + requests: + cpu: 100m + command: ["install_cni"] + securityContext: + capabilities: + add: + # SYS_MODULE is required to load the OVS kernel module. + - SYS_MODULE + env: + # SKIP_CNI_BINARIES takes in values as a comma separated list of + # binaries that need to be skipped for installation, e.g. "portmap, bandwidth". + - name: SKIP_CNI_BINARIES + value: "" + volumeMounts: + - name: antrea-config + mountPath: /etc/antrea/antrea-cni.conflist + subPath: antrea-cni.conflist + readOnly: true + - name: host-cni-conf + mountPath: /host/etc/cni/net.d + - name: host-cni-bin + mountPath: /host/opt/cni/bin + # For loading the OVS kernel module. + - name: host-lib-modules + mountPath: /lib/modules + readOnly: true + # For changing the default permissions of the run directory. + - name: host-var-run-antrea + mountPath: /var/run/antrea + containers: + - name: antrea-agent + image: "projects.registry.vmware.com/antrea/antrea-ubuntu:latest" + imagePullPolicy: IfNotPresent + command: ["antrea-agent"] + # Log to both "/var/log/antrea/" and stderr (so "kubectl logs" can work).- + args: + - "--config=/etc/antrea/antrea-agent.conf" + - "--logtostderr=false" + - "--log_dir=/var/log/antrea" + - "--alsologtostderr" + - "--log_file_max_size=100" + - "--log_file_max_num=4" + env: + # Provide pod and node information for clusterinformation CRD. + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: NODE_NAME + valueFrom: + fieldRef: + fieldPath: spec.nodeName + resources: + requests: + cpu: 200m + ports: + - containerPort: 10350 + name: api + protocol: TCP + livenessProbe: + exec: + command: + - /bin/sh + - -c + - container_liveness_probe agent + initialDelaySeconds: 5 + timeoutSeconds: 5 + periodSeconds: 10 + failureThreshold: 5 + readinessProbe: + httpGet: + host: localhost + path: /readyz + port: api + scheme: HTTPS + initialDelaySeconds: 5 + timeoutSeconds: 5 + periodSeconds: 10 + # In large-scale clusters, it may take up to 40~50 seconds for the antrea-agent to reconnect to the antrea + # Service after the antrea-controller restarts. The antrea-agent shouldn't be reported as NotReady in this + # scenario, otherwise the DaemonSet controller would restart all agents at once, as opposed to performing a + # rolling update. Set failureThreshold to 8 so it can tolerate 70s of disconnection. + failureThreshold: 8 + securityContext: + # antrea-agent needs to perform sysctl configuration. + privileged: true + volumeMounts: + - name: antrea-config + mountPath: /etc/antrea/antrea-agent.conf + subPath: antrea-agent.conf + readOnly: true + - name: host-var-run-antrea + mountPath: /var/run/antrea + - name: host-var-run-antrea + mountPath: /var/run/openvswitch + subPath: openvswitch + # host-local IPAM stores allocated IP addresses as files in /var/lib/cni/networks/$NETWORK_NAME. + # Mount a sub-directory of host-var-run-antrea to it for persistence of IP allocation. + - name: host-var-run-antrea + mountPath: /var/lib/cni + subPath: cni + # We need to mount both the /proc directory and the /var/run/netns directory so that + # antrea-agent can open the network namespace path when setting up Pod + # networking. Different container runtimes may use /proc or /var/run/netns when invoking + # the CNI commands. Docker uses /proc and containerd uses /var/run/netns. + - name: host-var-log-antrea + mountPath: /var/log/antrea + - name: host-proc + mountPath: /host/proc + readOnly: true + - name: host-var-run-netns + mountPath: /host/var/run/netns + readOnly: true + # When a container is created, a mount point for the network namespace is added under + # /var/run/netns on the host, which needs to be propagated to the antrea-agent container. + mountPropagation: HostToContainer + - name: xtables-lock + mountPath: /run/xtables.lock + - name: antrea-ovs + image: "projects.registry.vmware.com/antrea/antrea-ubuntu:latest" + imagePullPolicy: IfNotPresent + resources: + requests: + cpu: 200m + command: ["start_ovs"] + args: + - "--log_file_max_size=100" + - "--log_file_max_num=4" + securityContext: + # capabilities required by OVS daemons + capabilities: + add: + - SYS_NICE + - NET_ADMIN + - SYS_ADMIN + - IPC_LOCK + livenessProbe: + exec: + # docker CRI doesn't honor timeoutSeconds, add "timeout" to the command as a workaround. + # https://github.com/kubernetes/kubernetes/issues/51901 + command: + - /bin/sh + - -c + - timeout 10 container_liveness_probe ovs + initialDelaySeconds: 5 + timeoutSeconds: 10 + periodSeconds: 10 + failureThreshold: 5 + volumeMounts: + - name: host-var-run-antrea + mountPath: /var/run/openvswitch + subPath: openvswitch + - name: host-var-log-antrea + mountPath: /var/log/openvswitch + subPath: openvswitch + volumes: + - name: antrea-config + configMap: + name: antrea-config + - name: host-cni-conf + hostPath: + path: /etc/cni/net.d + - name: host-cni-bin + hostPath: + path: /opt/cni/bin + - name: host-proc + hostPath: + path: /proc + - name: host-var-run-netns + hostPath: + path: /var/run/netns + - name: host-var-run-antrea + hostPath: + path: /var/run/antrea + # we use subPath to create run subdirectories for different component (e.g. OVS) and + # subPath requires the base volume to exist + type: DirectoryOrCreate + - name: host-var-log-antrea + hostPath: + path: /var/log/antrea + # we use subPath to create logging subdirectories for different component (e.g. OVS) + type: DirectoryOrCreate + - name: host-lib-modules + hostPath: + path: /lib/modules + - name: xtables-lock + hostPath: + path: /run/xtables.lock + type: FileOrCreate +--- +# Source: antrea/templates/controller/deployment.yaml +apiVersion: apps/v1 +kind: Deployment +metadata: name: antrea-controller namespace: kube-system + labels: + app: antrea + component: antrea-controller spec: - replicas: 1 + strategy: + # Ensure the existing Pod is stopped before the new one is created. + type: Recreate selector: matchLabels: app: antrea component: antrea-controller - strategy: - type: Recreate + replicas: 1 template: metadata: + annotations: + # Automatically restart Pod if the ConfigMap changes + # See https://helm.sh/docs/howto/charts_tips_and_tricks/#automatically-roll-deployments + checksum/config: 03ee0481c65f3ec8ff9e879ff10c3cf65991a347a7aec1c9bc866b019ec470f1 labels: app: antrea component: antrea-controller spec: - containers: - - args: - - --config - - /etc/antrea/antrea-controller.conf - - --logtostderr=false - - --log_dir=/var/log/antrea - - --alsologtostderr - - --log_file_max_size=100 - - --log_file_max_num=4 - - --v=0 - command: - - antrea-controller - env: - - name: POD_NAME - valueFrom: - fieldRef: - fieldPath: metadata.name - - name: POD_NAMESPACE - valueFrom: - fieldRef: - fieldPath: metadata.namespace - - name: NODE_NAME - valueFrom: - fieldRef: - fieldPath: spec.nodeName - - name: SERVICEACCOUNT_NAME - valueFrom: - fieldRef: - fieldPath: spec.serviceAccountName - - name: ANTREA_CONFIG_MAP_NAME - value: antrea-config-hkhbh5gf99 - image: projects.registry.vmware.com/antrea/antrea-ubuntu:latest - imagePullPolicy: IfNotPresent - livenessProbe: - failureThreshold: 5 - httpGet: - host: localhost - path: /livez - port: api - scheme: HTTPS - periodSeconds: 10 - timeoutSeconds: 5 - name: antrea-controller - ports: - - containerPort: 10349 - name: api - protocol: TCP - readinessProbe: - failureThreshold: 5 - httpGet: - host: localhost - path: /readyz - port: api - scheme: HTTPS - initialDelaySeconds: 5 - periodSeconds: 10 - timeoutSeconds: 5 - resources: - requests: - cpu: 200m - volumeMounts: - - mountPath: /etc/antrea/antrea-controller.conf - name: antrea-config - readOnly: true - subPath: antrea-controller.conf - - mountPath: /var/run/antrea/antrea-controller-tls - name: antrea-controller-tls - - mountPath: /var/log/antrea - name: host-var-log-antrea - hostNetwork: true nodeSelector: kubernetes.io/os: linux + hostNetwork: true priorityClassName: system-cluster-critical - serviceAccountName: antrea-controller tolerations: - - key: CriticalAddonsOnly - operator: Exists - - effect: NoSchedule - key: node-role.kubernetes.io/master + - key: CriticalAddonsOnly + operator: Exists + - effect: NoSchedule + key: node-role.kubernetes.io/master + - effect: NoSchedule + key: node-role.kubernetes.io/control-plane + serviceAccountName: antrea-controller + containers: + - name: antrea-controller + image: "projects.registry.vmware.com/antrea/antrea-ubuntu:latest" + imagePullPolicy: IfNotPresent + resources: + requests: + cpu: 200m + command: ["antrea-controller"] + # Log to both "/var/log/antrea/" and stderr (so "kubectl logs" can work). + args: + - "--config=/etc/antrea/antrea-controller.conf" + - "--logtostderr=false" + - "--log_dir=/var/log/antrea" + - "--alsologtostderr" + - "--log_file_max_size=100" + - "--log_file_max_num=4" + env: + # Provide pod and node information for clusterinformation CRD. + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: NODE_NAME + valueFrom: + fieldRef: + fieldPath: spec.nodeName + # Provide ServiceAccount name for validation webhook. + - name: SERVICEACCOUNT_NAME + valueFrom: + fieldRef: + fieldPath: spec.serviceAccountName + - name: ANTREA_CONFIG_MAP_NAME + value: antrea-config + ports: + - containerPort: 10349 + name: api + protocol: TCP + readinessProbe: + httpGet: + host: localhost + path: /readyz + port: api + scheme: HTTPS + initialDelaySeconds: 5 + timeoutSeconds: 5 + periodSeconds: 10 + failureThreshold: 5 + livenessProbe: + httpGet: + host: localhost + path: /livez + port: api + scheme: HTTPS + timeoutSeconds: 5 + periodSeconds: 10 + failureThreshold: 5 + volumeMounts: + - name: antrea-config + mountPath: /etc/antrea/antrea-controller.conf + subPath: antrea-controller.conf + readOnly: true + - name: antrea-controller-tls + mountPath: /var/run/antrea/antrea-controller-tls + - name: host-var-log-antrea + mountPath: /var/log/antrea volumes: - - configMap: - name: antrea-config-hkhbh5gf99 - name: antrea-config - - name: antrea-controller-tls - secret: - defaultMode: 256 - optional: true - secretName: antrea-controller-tls - - hostPath: - path: /var/log/antrea - type: DirectoryOrCreate - name: host-var-log-antrea + - name: antrea-config + configMap: + name: antrea-config + # Make it optional as we only read it when selfSignedCert=false. + - name: antrea-controller-tls + secret: + secretName: antrea-controller-tls + defaultMode: 0400 + optional: true + - name: host-var-log-antrea + hostPath: + path: /var/log/antrea + type: DirectoryOrCreate --- +# Source: antrea/templates/controller/apiservices.yaml apiVersion: apiregistration.k8s.io/v1 kind: APIService metadata: + name: v1beta2.controlplane.antrea.io labels: app: antrea - name: v1alpha1.stats.antrea.io spec: - group: stats.antrea.io + group: controlplane.antrea.io groupPriorityMinimum: 100 + version: v1beta2 + versionPriority: 100 service: name: antrea namespace: kube-system - version: v1alpha1 - versionPriority: 100 --- +# Source: antrea/templates/controller/apiservices.yaml apiVersion: apiregistration.k8s.io/v1 kind: APIService metadata: + name: v1beta1.system.antrea.io labels: app: antrea - name: v1beta1.system.antrea.io spec: group: system.antrea.io groupPriorityMinimum: 100 + version: v1beta1 + versionPriority: 100 service: name: antrea namespace: kube-system - version: v1beta1 - versionPriority: 100 --- +# Source: antrea/templates/controller/apiservices.yaml apiVersion: apiregistration.k8s.io/v1 kind: APIService metadata: + name: v1alpha1.stats.antrea.io labels: app: antrea - name: v1beta2.controlplane.antrea.io spec: - group: controlplane.antrea.io + group: stats.antrea.io groupPriorityMinimum: 100 + version: v1alpha1 + versionPriority: 100 service: name: antrea namespace: kube-system - version: v1beta2 - versionPriority: 100 ---- -apiVersion: apps/v1 -kind: DaemonSet -metadata: - labels: - app: antrea - component: antrea-agent - name: antrea-agent - namespace: kube-system -spec: - selector: - matchLabels: - app: antrea - component: antrea-agent - template: - metadata: - annotations: - kubectl.kubernetes.io/default-container: antrea-agent - labels: - app: antrea - component: antrea-agent - spec: - containers: - - args: - - --config - - /etc/antrea/antrea-agent.conf - - --logtostderr=false - - --log_dir=/var/log/antrea - - --alsologtostderr - - --log_file_max_size=100 - - --log_file_max_num=4 - - --v=0 - command: - - antrea-agent - env: - - name: POD_NAME - valueFrom: - fieldRef: - fieldPath: metadata.name - - name: POD_NAMESPACE - valueFrom: - fieldRef: - fieldPath: metadata.namespace - - name: NODE_NAME - valueFrom: - fieldRef: - fieldPath: spec.nodeName - image: projects.registry.vmware.com/antrea/antrea-ubuntu:latest - imagePullPolicy: IfNotPresent - livenessProbe: - exec: - command: - - /bin/sh - - -c - - container_liveness_probe agent - failureThreshold: 5 - initialDelaySeconds: 5 - periodSeconds: 10 - timeoutSeconds: 5 - name: antrea-agent - ports: - - containerPort: 10350 - name: api - protocol: TCP - readinessProbe: - failureThreshold: 8 - httpGet: - host: localhost - path: /readyz - port: api - scheme: HTTPS - initialDelaySeconds: 5 - periodSeconds: 10 - timeoutSeconds: 5 - resources: - requests: - cpu: 200m - securityContext: - privileged: true - volumeMounts: - - mountPath: /etc/antrea/antrea-agent.conf - name: antrea-config - readOnly: true - subPath: antrea-agent.conf - - mountPath: /var/run/antrea - name: host-var-run-antrea - - mountPath: /var/run/openvswitch - name: host-var-run-antrea - subPath: openvswitch - - mountPath: /var/lib/cni - name: host-var-run-antrea - subPath: cni - - mountPath: /var/log/antrea - name: host-var-log-antrea - - mountPath: /host/proc - name: host-proc - readOnly: true - - mountPath: /host/var/run/netns - mountPropagation: HostToContainer - name: host-var-run-netns - readOnly: true - - mountPath: /run/xtables.lock - name: xtables-lock - - args: - - --log_file_max_size=100 - - --log_file_max_num=4 - command: - - start_ovs - image: projects.registry.vmware.com/antrea/antrea-ubuntu:latest - imagePullPolicy: IfNotPresent - livenessProbe: - exec: - command: - - /bin/sh - - -c - - timeout 10 container_liveness_probe ovs - failureThreshold: 5 - initialDelaySeconds: 5 - periodSeconds: 10 - timeoutSeconds: 10 - name: antrea-ovs - resources: - requests: - cpu: 200m - securityContext: - capabilities: - add: - - SYS_NICE - - NET_ADMIN - - SYS_ADMIN - - IPC_LOCK - volumeMounts: - - mountPath: /var/run/openvswitch - name: host-var-run-antrea - subPath: openvswitch - - mountPath: /var/log/openvswitch - name: host-var-log-antrea - subPath: openvswitch - dnsPolicy: ClusterFirstWithHostNet - hostNetwork: true - initContainers: - - command: - - install_cni - env: - - name: SKIP_CNI_BINARIES - value: "" - image: projects.registry.vmware.com/antrea/antrea-ubuntu:latest - imagePullPolicy: IfNotPresent - name: install-cni - resources: - requests: - cpu: 100m - securityContext: - capabilities: - add: - - SYS_MODULE - volumeMounts: - - mountPath: /etc/antrea/antrea-cni.conflist - name: antrea-config - readOnly: true - subPath: antrea-cni.conflist - - mountPath: /host/etc/cni/net.d - name: host-cni-conf - - mountPath: /host/opt/cni/bin - name: host-cni-bin - - mountPath: /lib/modules - name: host-lib-modules - readOnly: true - - mountPath: /var/run/antrea - name: host-var-run-antrea - nodeSelector: - kubernetes.io/os: linux - priorityClassName: system-node-critical - serviceAccountName: antrea-agent - tolerations: - - key: CriticalAddonsOnly - operator: Exists - - effect: NoSchedule - operator: Exists - - effect: NoExecute - operator: Exists - volumes: - - configMap: - name: antrea-config-hkhbh5gf99 - name: antrea-config - - hostPath: - path: /etc/cni/net.d - name: host-cni-conf - - hostPath: - path: /opt/cni/bin - name: host-cni-bin - - hostPath: - path: /proc - name: host-proc - - hostPath: - path: /var/run/netns - name: host-var-run-netns - - hostPath: - path: /var/run/antrea - type: DirectoryOrCreate - name: host-var-run-antrea - - hostPath: - path: /var/log/antrea - type: DirectoryOrCreate - name: host-var-log-antrea - - hostPath: - path: /lib/modules - name: host-lib-modules - - hostPath: - path: /run/xtables.lock - type: FileOrCreate - name: xtables-lock - updateStrategy: - type: RollingUpdate --- +# Source: antrea/templates/webhooks/mutating/crdmutator.yaml apiVersion: admissionregistration.k8s.io/v1 kind: MutatingWebhookConfiguration metadata: + name: "crdmutator.antrea.io" labels: app: antrea - name: crdmutator.antrea.io webhooks: -- admissionReviewVersions: - - v1 - - v1beta1 - clientConfig: - service: - name: antrea - namespace: kube-system - path: /mutate/acnp - name: acnpmutator.antrea.io - rules: - - apiGroups: - - crd.antrea.io - apiVersions: - - v1alpha1 - operations: - - CREATE - - UPDATE - resources: - - clusternetworkpolicies - scope: Cluster - sideEffects: None - timeoutSeconds: 5 -- admissionReviewVersions: - - v1 - - v1beta1 - clientConfig: - service: - name: antrea - namespace: kube-system - path: /mutate/anp - name: anpmutator.antrea.io - rules: - - apiGroups: - - crd.antrea.io - apiVersions: - - v1alpha1 - operations: - - CREATE - - UPDATE - resources: - - networkpolicies - scope: Namespaced - sideEffects: None - timeoutSeconds: 5 + - name: "acnpmutator.antrea.io" + clientConfig: + service: + name: "antrea" + namespace: kube-system + path: "/mutate/acnp" + rules: + - operations: ["CREATE", "UPDATE"] + apiGroups: ["crd.antrea.io"] + apiVersions: ["v1alpha1"] + resources: ["clusternetworkpolicies"] + scope: "Cluster" + admissionReviewVersions: ["v1", "v1beta1"] + sideEffects: None + timeoutSeconds: 5 + - name: "anpmutator.antrea.io" + clientConfig: + service: + name: "antrea" + namespace: kube-system + path: "/mutate/anp" + rules: + - operations: ["CREATE", "UPDATE"] + apiGroups: ["crd.antrea.io"] + apiVersions: ["v1alpha1"] + resources: ["networkpolicies"] + scope: "Namespaced" + admissionReviewVersions: ["v1", "v1beta1"] + sideEffects: None + timeoutSeconds: 5 --- +# Source: antrea/templates/webhooks/validating/crdvalidator.yaml apiVersion: admissionregistration.k8s.io/v1 kind: ValidatingWebhookConfiguration metadata: + name: "crdvalidator.antrea.io" labels: app: antrea - name: crdvalidator.antrea.io webhooks: -- admissionReviewVersions: - - v1 - - v1beta1 - clientConfig: - service: - name: antrea - namespace: kube-system - path: /validate/tier - name: tiervalidator.antrea.io - rules: - - apiGroups: - - crd.antrea.io - apiVersions: - - v1alpha1 - operations: - - CREATE - - UPDATE - - DELETE - resources: - - tiers - scope: Cluster - sideEffects: None - timeoutSeconds: 5 -- admissionReviewVersions: - - v1 - - v1beta1 - clientConfig: - service: - name: antrea - namespace: kube-system - path: /validate/acnp - name: acnpvalidator.antrea.io - rules: - - apiGroups: - - crd.antrea.io - apiVersions: - - v1alpha1 - operations: - - CREATE - - UPDATE - resources: - - clusternetworkpolicies - scope: Cluster - sideEffects: None - timeoutSeconds: 5 -- admissionReviewVersions: - - v1 - - v1beta1 - clientConfig: - service: - name: antrea - namespace: kube-system - path: /validate/anp - name: anpvalidator.antrea.io - rules: - - apiGroups: - - crd.antrea.io - apiVersions: - - v1alpha1 - operations: - - CREATE - - UPDATE - resources: - - networkpolicies - scope: Namespaced - sideEffects: None - timeoutSeconds: 5 -- admissionReviewVersions: - - v1 - - v1beta1 - clientConfig: - service: - name: antrea - namespace: kube-system - path: /validate/clustergroup - name: clustergroupvalidator.antrea.io - rules: - - apiGroups: - - crd.antrea.io - apiVersions: - - v1alpha3 - - v1alpha2 - operations: - - CREATE - - UPDATE - resources: - - clustergroups - scope: Cluster - sideEffects: None - timeoutSeconds: 5 -- admissionReviewVersions: - - v1 - - v1beta1 - clientConfig: - service: - name: antrea - namespace: kube-system - path: /validate/externalippool - name: externalippoolvalidator.antrea.io - rules: - - apiGroups: - - crd.antrea.io - apiVersions: - - v1alpha2 - operations: - - UPDATE - resources: - - externalippools - scope: Cluster - sideEffects: None - timeoutSeconds: 5 -- admissionReviewVersions: - - v1 - - v1beta1 - clientConfig: - service: - name: antrea - namespace: kube-system - path: /validate/egress - name: egressvalidator.antrea.io - rules: - - apiGroups: - - crd.antrea.io - apiVersions: - - v1alpha2 - operations: - - CREATE - - UPDATE - resources: - - egresses - scope: Cluster - sideEffects: None - timeoutSeconds: 5 -- admissionReviewVersions: - - v1 - - v1beta1 - clientConfig: - service: - name: antrea - namespace: kube-system - path: /validate/ippool - name: ippoolvalidator.antrea.io - rules: - - apiGroups: - - crd.antrea.io - apiVersions: - - v1alpha2 - operations: - - CREATE - - UPDATE - - DELETE - resources: - - ippools - scope: Cluster - sideEffects: None - timeoutSeconds: 5 + - name: "tiervalidator.antrea.io" + clientConfig: + service: + name: "antrea" + namespace: kube-system + path: "/validate/tier" + rules: + - operations: ["CREATE", "UPDATE", "DELETE"] + apiGroups: ["crd.antrea.io"] + apiVersions: ["v1alpha1"] + resources: ["tiers"] + scope: "Cluster" + admissionReviewVersions: ["v1", "v1beta1"] + sideEffects: None + timeoutSeconds: 5 + - name: "acnpvalidator.antrea.io" + clientConfig: + service: + name: "antrea" + namespace: kube-system + path: "/validate/acnp" + rules: + - operations: ["CREATE", "UPDATE"] + apiGroups: ["crd.antrea.io"] + apiVersions: ["v1alpha1"] + resources: ["clusternetworkpolicies"] + scope: "Cluster" + admissionReviewVersions: ["v1", "v1beta1"] + sideEffects: None + timeoutSeconds: 5 + - name: "anpvalidator.antrea.io" + clientConfig: + service: + name: "antrea" + namespace: kube-system + path: "/validate/anp" + rules: + - operations: ["CREATE", "UPDATE"] + apiGroups: ["crd.antrea.io"] + apiVersions: ["v1alpha1"] + resources: ["networkpolicies"] + scope: "Namespaced" + admissionReviewVersions: ["v1", "v1beta1"] + sideEffects: None + timeoutSeconds: 5 + - name: "clustergroupvalidator.antrea.io" + clientConfig: + service: + name: "antrea" + namespace: kube-system + path: "/validate/clustergroup" + rules: + - operations: ["CREATE", "UPDATE"] + apiGroups: ["crd.antrea.io"] + apiVersions: ["v1alpha3", "v1alpha2"] + resources: ["clustergroups"] + scope: "Cluster" + admissionReviewVersions: ["v1", "v1beta1"] + sideEffects: None + timeoutSeconds: 5 + - name: "externalippoolvalidator.antrea.io" + clientConfig: + service: + name: "antrea" + namespace: kube-system + path: "/validate/externalippool" + rules: + - operations: ["UPDATE"] + apiGroups: ["crd.antrea.io"] + apiVersions: ["v1alpha2"] + resources: ["externalippools"] + scope: "Cluster" + admissionReviewVersions: ["v1", "v1beta1"] + sideEffects: None + timeoutSeconds: 5 + - name: "egressvalidator.antrea.io" + clientConfig: + service: + name: "antrea" + namespace: kube-system + path: "/validate/egress" + rules: + - operations: ["CREATE", "UPDATE"] + apiGroups: ["crd.antrea.io"] + apiVersions: ["v1alpha2"] + resources: ["egresses"] + scope: "Cluster" + admissionReviewVersions: ["v1", "v1beta1"] + sideEffects: None + timeoutSeconds: 5 + - name: "ippoolvalidator.antrea.io" + clientConfig: + service: + name: "antrea" + namespace: kube-system + path: "/validate/ippool" + rules: + - operations: ["CREATE", "UPDATE", "DELETE"] + apiGroups: ["crd.antrea.io"] + apiVersions: ["v1alpha2"] + resources: ["ippools"] + scope: "Cluster" + admissionReviewVersions: ["v1", "v1beta1"] + sideEffects: None + timeoutSeconds: 5 diff --git a/build/yamls/base/conf/antrea-controller.conf b/build/yamls/base/conf/antrea-controller.conf deleted file mode 100644 index 7db2983b300..00000000000 --- a/build/yamls/base/conf/antrea-controller.conf +++ /dev/null @@ -1,73 +0,0 @@ -# FeatureGates is a map of feature names to bools that enable or disable experimental features. -featureGates: -# Enable traceflow which provides packet tracing feature to diagnose network issue. -# Traceflow: true - -# Enable Antrea ClusterNetworkPolicy feature to complement K8s NetworkPolicy for cluster admins -# to define security policies which apply to the entire cluster, and Antrea NetworkPolicy -# feature that supports priorities, rule actions and externalEntities in the future. -# AntreaPolicy: true - -# Enable collecting and exposing NetworkPolicy statistics. -# NetworkPolicyStats: true - -# Enable controlling SNAT IPs of Pod egress traffic. -# Egress: true - -# Run Kubernetes NodeIPAMController with Antrea. -# NodeIPAM: false - -# Enable flexible IPAM mode for Antrea. This mode allows to assign IP Ranges to Namespaces, -# Deployments and StatefulSets via IP Pool annotation. -# AntreaIPAM: false - -# Enable managing external IPs of Services of LoadBalancer type. -# ServiceExternalIP: false - -# The port for the antrea-controller APIServer to serve on. -# Note that if it's set to another value, the `containerPort` of the `api` port of the -# `antrea-controller` container must be set to the same value. -#apiPort: 10349 - -# Enable metrics exposure via Prometheus. Initializes Prometheus metrics listener. -#enablePrometheusMetrics: true - -# Indicates whether to use auto-generated self-signed TLS certificate. -# If false, A Secret named "antrea-controller-tls" must be provided with the following keys: -# ca.crt: -# tls.crt: -# tls.key: -# And the Secret must be mounted to directory "/var/run/antrea/antrea-controller-tls" of the -# antrea-controller container. -#selfSignedCert: true - -# Comma-separated list of Cipher Suites. If omitted, the default Go Cipher Suites will be used. -# https://golang.org/pkg/crypto/tls/#pkg-constants -# Note that TLS1.3 Cipher Suites cannot be added to the list. But the apiserver will always -# prefer TLS1.3 Cipher Suites whenever possible. -#tlsCipherSuites: - -# TLS min version from: VersionTLS10, VersionTLS11, VersionTLS12, VersionTLS13. -#tlsMinVersion: - -nodeIPAM: -# Enable the integrated Node IPAM controller within the Antrea controller. -# enableNodeIPAM: false - -# CIDR ranges for Pods in cluster. String array containing single CIDR range, or multiple ranges. -# The CIDRs could be either IPv4 or IPv6. At most one CIDR may be specified for each IP family. -# Value ignored when enableNodeIPAM is false. -# clusterCIDRs: [] - -# CIDR ranges for Services in cluster. It is not necessary to specify it when there is no overlap with clusterCIDRs. -# Value ignored when enableNodeIPAM is false. -# serviceCIDR: -# serviceCIDRv6: - -# Mask size for IPv4 Node CIDR in IPv4 or dual-stack cluster. Value ignored when enableNodeIPAM is false -# or when IPv4 Pod CIDR is not configured. Valid range is 16 to 30. -# nodeCIDRMaskSizeIPv4: 24 - -# Mask size for IPv6 Node CIDR in IPv6 or dual-stack cluster. Value ignored when enableNodeIPAM is false -# or when IPv6 Pod CIDR is not configured. Valid range is 64 to 126. -# nodeCIDRMaskSizeIPv6: 64 diff --git a/build/yamls/base/controller.yml b/build/yamls/base/controller.yml deleted file mode 100644 index 7ce4a28da36..00000000000 --- a/build/yamls/base/controller.yml +++ /dev/null @@ -1,306 +0,0 @@ ---- -apiVersion: v1 -kind: Service -metadata: - name: antrea -spec: - ports: - - port: 443 - protocol: TCP - targetPort: api - selector: - component: antrea-controller ---- -apiVersion: apiregistration.k8s.io/v1 -kind: APIService -metadata: - name: v1beta2.controlplane.antrea.io -spec: - group: controlplane.antrea.io - groupPriorityMinimum: 100 - version: v1beta2 - versionPriority: 100 - service: - name: antrea - namespace: kube-system ---- -apiVersion: apiregistration.k8s.io/v1 -kind: APIService -metadata: - name: v1beta1.system.antrea.io -spec: - group: system.antrea.io - groupPriorityMinimum: 100 - version: v1beta1 - versionPriority: 100 - service: - name: antrea - namespace: kube-system ---- -apiVersion: admissionregistration.k8s.io/v1 -kind: MutatingWebhookConfiguration -metadata: - name: "crdmutator.antrea.io" -webhooks: - - name: "acnpmutator.antrea.io" - clientConfig: - service: - name: "antrea" - namespace: "kube-system" - path: "/mutate/acnp" - rules: - - operations: ["CREATE", "UPDATE"] - apiGroups: ["crd.antrea.io"] - apiVersions: ["v1alpha1"] - resources: ["clusternetworkpolicies"] - scope: "Cluster" - admissionReviewVersions: ["v1", "v1beta1"] - sideEffects: None - timeoutSeconds: 5 - - name: "anpmutator.antrea.io" - clientConfig: - service: - name: "antrea" - namespace: "kube-system" - path: "/mutate/anp" - rules: - - operations: ["CREATE", "UPDATE"] - apiGroups: ["crd.antrea.io"] - apiVersions: ["v1alpha1"] - resources: ["networkpolicies"] - scope: "Namespaced" - admissionReviewVersions: ["v1", "v1beta1"] - sideEffects: None - timeoutSeconds: 5 ---- -apiVersion: admissionregistration.k8s.io/v1 -kind: ValidatingWebhookConfiguration -metadata: - name: "crdvalidator.antrea.io" -webhooks: - - name: "tiervalidator.antrea.io" - clientConfig: - service: - name: "antrea" - namespace: "kube-system" - path: "/validate/tier" - rules: - - operations: ["CREATE", "UPDATE", "DELETE"] - apiGroups: ["crd.antrea.io"] - apiVersions: ["v1alpha1"] - resources: ["tiers"] - scope: "Cluster" - admissionReviewVersions: ["v1", "v1beta1"] - sideEffects: None - timeoutSeconds: 5 - - name: "acnpvalidator.antrea.io" - clientConfig: - service: - name: "antrea" - namespace: "kube-system" - path: "/validate/acnp" - rules: - - operations: ["CREATE", "UPDATE"] - apiGroups: ["crd.antrea.io"] - apiVersions: ["v1alpha1"] - resources: ["clusternetworkpolicies"] - scope: "Cluster" - admissionReviewVersions: ["v1", "v1beta1"] - sideEffects: None - timeoutSeconds: 5 - - name: "anpvalidator.antrea.io" - clientConfig: - service: - name: "antrea" - namespace: "kube-system" - path: "/validate/anp" - rules: - - operations: ["CREATE", "UPDATE"] - apiGroups: ["crd.antrea.io"] - apiVersions: ["v1alpha1"] - resources: ["networkpolicies"] - scope: "Namespaced" - admissionReviewVersions: ["v1", "v1beta1"] - sideEffects: None - timeoutSeconds: 5 - - name: "clustergroupvalidator.antrea.io" - clientConfig: - service: - name: "antrea" - namespace: "kube-system" - path: "/validate/clustergroup" - rules: - - operations: ["CREATE", "UPDATE"] - apiGroups: ["crd.antrea.io"] - apiVersions: ["v1alpha3", "v1alpha2"] - resources: ["clustergroups"] - scope: "Cluster" - admissionReviewVersions: ["v1", "v1beta1"] - sideEffects: None - timeoutSeconds: 5 - - name: "externalippoolvalidator.antrea.io" - clientConfig: - service: - name: "antrea" - namespace: "kube-system" - path: "/validate/externalippool" - rules: - - operations: ["UPDATE"] - apiGroups: ["crd.antrea.io"] - apiVersions: ["v1alpha2"] - resources: ["externalippools"] - scope: "Cluster" - admissionReviewVersions: ["v1", "v1beta1"] - sideEffects: None - timeoutSeconds: 5 - - name: "egressvalidator.antrea.io" - clientConfig: - service: - name: "antrea" - namespace: "kube-system" - path: "/validate/egress" - rules: - - operations: ["CREATE", "UPDATE"] - apiGroups: ["crd.antrea.io"] - apiVersions: ["v1alpha2"] - resources: ["egresses"] - scope: "Cluster" - admissionReviewVersions: ["v1", "v1beta1"] - sideEffects: None - timeoutSeconds: 5 - - name: "ippoolvalidator.antrea.io" - clientConfig: - service: - name: "antrea" - namespace: "kube-system" - path: "/validate/ippool" - rules: - - operations: ["CREATE", "UPDATE", "DELETE"] - apiGroups: ["crd.antrea.io"] - apiVersions: ["v1alpha2"] - resources: ["ippools"] - scope: "Cluster" - admissionReviewVersions: ["v1", "v1beta1"] - sideEffects: None - timeoutSeconds: 5 ---- -apiVersion: apiregistration.k8s.io/v1 -kind: APIService -metadata: - name: v1alpha1.stats.antrea.io -spec: - group: stats.antrea.io - groupPriorityMinimum: 100 - version: v1alpha1 - versionPriority: 100 - service: - name: antrea - namespace: kube-system ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: antrea-controller - labels: - component: antrea-controller -spec: - strategy: - # Ensure the existing Pod is stopped before the new one is created. - type: Recreate - selector: - matchLabels: - component: antrea-controller - template: - metadata: - labels: - component: antrea-controller - spec: - nodeSelector: - kubernetes.io/os: linux - hostNetwork: true - priorityClassName: system-cluster-critical - tolerations: - # Mark it as a critical add-on. - - key: CriticalAddonsOnly - operator: Exists - # Allow it to schedule onto master nodes. - - key: node-role.kubernetes.io/master - effect: NoSchedule - serviceAccountName: antrea-controller - containers: - - name: antrea-controller - image: antrea - resources: - requests: - cpu: "200m" - command: ["antrea-controller"] - # Log to both "/var/log/antrea/" and stderr (so "kubectl logs" can work). - args: ["--config", "/etc/antrea/antrea-controller.conf", "--logtostderr=false", "--log_dir=/var/log/antrea", "--alsologtostderr", "--log_file_max_size=100", "--log_file_max_num=4", "--v=0"] - env: - # Provide pod and node information for clusterinformation CRD. - - name: POD_NAME - valueFrom: - fieldRef: - fieldPath: metadata.name - - name: POD_NAMESPACE - valueFrom: - fieldRef: - fieldPath: metadata.namespace - - name: NODE_NAME - valueFrom: - fieldRef: - fieldPath: spec.nodeName - # Provide ServiceAccount name for validation webhook. - - name: SERVICEACCOUNT_NAME - valueFrom: - fieldRef: - fieldPath: spec.serviceAccountName - - name: ANTREA_CONFIG_MAP_NAME - value: "$(ANTREA_CONFIG_MAP_NAME)" - ports: - - containerPort: 10349 - name: api - protocol: TCP - readinessProbe: - httpGet: - host: localhost - path: /readyz - port: api - scheme: HTTPS - initialDelaySeconds: 5 - timeoutSeconds: 5 - periodSeconds: 10 - failureThreshold: 5 - livenessProbe: - httpGet: - host: localhost - path: /livez - port: api - scheme: HTTPS - timeoutSeconds: 5 - periodSeconds: 10 - failureThreshold: 5 - volumeMounts: - - name: antrea-config - mountPath: /etc/antrea/antrea-controller.conf - subPath: antrea-controller.conf - readOnly: true - - name: antrea-controller-tls - mountPath: /var/run/antrea/antrea-controller-tls - - name: host-var-log-antrea - mountPath: /var/log/antrea - volumes: - - name: antrea-config - configMap: - name: antrea-config - # Make it optional as we only read it when selfSignedCert=false. - - name: antrea-controller-tls - secret: - secretName: antrea-controller-tls - defaultMode: 0400 - optional: true - - name: host-var-log-antrea - hostPath: - path: /var/log/antrea - type: DirectoryOrCreate ---- diff --git a/build/yamls/base/crds.yml b/build/yamls/base/crds.yml deleted file mode 100644 index b4176f40846..00000000000 --- a/build/yamls/base/crds.yml +++ /dev/null @@ -1,2016 +0,0 @@ ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - name: egresses.crd.antrea.io -spec: - group: crd.antrea.io - versions: - - name: v1alpha2 - served: true - storage: true - schema: - openAPIV3Schema: - type: object - required: - - spec - properties: - spec: - type: object - required: - - appliedTo - anyOf: - - required: - - egressIP - - required: - - externalIPPool - properties: - appliedTo: - type: object - properties: - podSelector: - type: object - properties: - matchExpressions: - type: array - items: - type: object - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - type: array - items: - type: string - pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" - matchLabels: - x-kubernetes-preserve-unknown-fields: true - namespaceSelector: - type: object - properties: - matchExpressions: - type: array - items: - type: object - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - type: array - items: - type: string - pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" - matchLabels: - x-kubernetes-preserve-unknown-fields: true - egressIP: - type: string - oneOf: - - format: ipv4 - - format: ipv6 - externalIPPool: - type: string - status: - type: object - properties: - egressNode: - type: string - additionalPrinterColumns: - - description: Specifies the SNAT IP address for the selected workloads. - jsonPath: .spec.egressIP - name: EgressIP - type: string - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - - description: The Owner Node of egress IP - jsonPath: .status.egressNode - name: Node - type: string - subresources: - status: {} - scope: Cluster - names: - plural: egresses - singular: egress - kind: Egress - shortNames: - - eg ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - name: externalippools.crd.antrea.io -spec: - group: crd.antrea.io - versions: - - name: v1alpha2 - served: true - storage: true - schema: - openAPIV3Schema: - type: object - required: - - spec - properties: - spec: - type: object - required: - - ipRanges - - nodeSelector - properties: - ipRanges: - type: array - items: - type: object - oneOf: - - required: - - cidr - - required: - - start - - end - properties: - cidr: - type: string - format: cidr - start: - type: string - oneOf: - - format: ipv4 - - format: ipv6 - end: - type: string - oneOf: - - format: ipv4 - - format: ipv6 - nodeSelector: - type: object - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - type: string - pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - status: - type: object - properties: - usage: - type: object - properties: - total: - type: integer - used: - type: integer - additionalPrinterColumns: - - description: The number of total IPs - jsonPath: .status.usage.total - name: Total - type: integer - - description: The number of allocated IPs - jsonPath: .status.usage.used - name: Used - type: integer - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - subresources: - status: {} - scope: Cluster - names: - plural: externalippools - singular: externalippool - kind: ExternalIPPool - shortNames: - - eip ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - name: ippools.crd.antrea.io -spec: - group: crd.antrea.io - versions: - - name: v1alpha2 - served: true - storage: true - schema: - openAPIV3Schema: - type: object - required: - - spec - properties: - spec: - required: - - ipVersion - - ipRanges - type: object - properties: - ipVersion: - type: integer - ipRanges: - items: - oneOf: - - required: - - cidr - - gateway - - prefixLength - - required: - - start - - end - - gateway - - prefixLength - properties: - cidr: - format: cidr - type: string - start: - oneOf: - - format: ipv4 - - format: ipv6 - type: string - end: - oneOf: - - format: ipv4 - - format: ipv6 - type: string - gateway: - oneOf: - - format: ipv4 - - format: ipv6 - type: string - prefixLength: - type: integer - vlan: - type: integer - minimum: 0 - maximum: 4094 - type: object - type: array - status: - properties: - ipAddresses: - items: - properties: - ipAddress: - type: string - owner: - properties: - pod: - properties: - name: - type: string - namespace: - type: string - containerID: - type: string - type: object - statefulSet: - properties: - name: - type: string - namespace: - type: string - index: - type: integer - type: object - type: object - phase: - type: string - type: object - type: array - type: object - subresources: - status: {} - scope: Cluster - names: - plural: ippools - singular: ippool - kind: IPPool - shortNames: - - ipp ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - name: antreacontrollerinfos.crd.antrea.io -spec: - group: crd.antrea.io - versions: - - name: v1beta1 - served: true - storage: true - schema: - openAPIV3Schema: - type: object - x-kubernetes-preserve-unknown-fields: true - additionalPrinterColumns: - - description: Health status of the Controller - jsonPath: ".controllerConditions[?(@.type=='ControllerHealthy')].status" - name: Healthy - type: string - - description: Last time the Healthy Condition was updated - jsonPath: ".controllerConditions[?(@.type=='ControllerHealthy')].lastHeartbeatTime" - name: Last Heartbeat - type: date - - description: Version of the Controller - jsonPath: ".version" - name: Version - type: string - priority: 1 - - description: Number of Agents connected to the Controller - jsonPath: ".connectedAgentNum" - name: Connected Agents - type: integer - priority: 1 - - description: Node on which the Controller is running - jsonPath: ".nodeRef.name" - name: Node - type: string - priority: 1 - - description: Number of Network Policies computed by Controller - jsonPath: ".networkPolicyControllerInfo.networkPolicyNum" - name: Num Network Policies - type: integer - priority: 2 - scope: Cluster - names: - plural: antreacontrollerinfos - singular: antreacontrollerinfo - kind: AntreaControllerInfo - shortNames: - - aci ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - name: antreaagentinfos.crd.antrea.io -spec: - group: crd.antrea.io - versions: - - name: v1beta1 - served: true - storage: true - schema: - openAPIV3Schema: - type: object - x-kubernetes-preserve-unknown-fields: true - additionalPrinterColumns: - - description: Health status of this Agent - jsonPath: ".agentConditions[?(@.type=='AgentHealthy')].status" - name: Healthy - type: string - - description: Last time the Healthy Condition was updated - jsonPath: ".agentConditions[?(@.type=='AgentHealthy')].lastHeartbeatTime" - name: Last Heartbeat - type: date - - description: Version of this Agent - jsonPath: ".version" - name: Version - type: string - priority: 1 - - description: Node on which this Agent is running - jsonPath: ".nodeRef.name" - name: Node - type: string - priority: 1 - - description: Number of local Pods managed by this Agent - jsonPath: ".localPodNum" - name: Num Pods - type: integer - priority: 2 - - description: Subnets used by this Agent for Pod IPAM - jsonPath: ".nodeSubnets" - name: Subnets - type: string - priority: 2 - scope: Cluster - names: - plural: antreaagentinfos - singular: antreaagentinfo - kind: AntreaAgentInfo - shortNames: - - aai ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - name: traceflows.crd.antrea.io -spec: - group: crd.antrea.io - versions: - - name: v1alpha1 - served: true - storage: true - additionalPrinterColumns: - - jsonPath: .status.phase - description: The phase of the Traceflow. - name: Phase - type: string - - jsonPath: .spec.source.pod - description: The name of the source Pod. - name: Source-Pod - type: string - priority: 10 - - jsonPath: .spec.destination.pod - description: The name of the destination Pod. - name: Destination-Pod - type: string - priority: 10 - - jsonPath: .spec.destination.ip - description: The IP address of the destination. - name: Destination-IP - type: string - priority: 10 - - jsonPath: .spec.liveTraffic - description: Trace live traffic. - name: Live-Traffic - type: boolean - priority: 10 - - jsonPath: .spec.droppedOnly - description: Capture only the dropped packet. - name: Dropped-Only - type: boolean - priority: 10 - - jsonPath: .spec.timeout - description: Timeout in seconds. - name: Timeout - type: integer - priority: 10 - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - schema: - openAPIV3Schema: - type: object - required: - - spec - properties: - spec: - type: object - properties: - source: - type: object - properties: - pod: - type: string - namespace: - type: string - ip: - type: string - oneOf: - - format: ipv4 - - format: ipv6 - destination: - type: object - properties: - pod: - type: string - service: - type: string - namespace: - type: string - ip: - type: string - oneOf: - - format: ipv4 - - format: ipv6 - packet: - type: object - properties: - ipHeader: - type: object - properties: - srcIP: - type: string - oneOf: - - format: ipv4 - - format: ipv6 - protocol: - type: integer - ttl: - type: integer - flags: - type: integer - ipv6Header: - type: object - properties: - srcIP: - type: string - format: ipv6 - nextHeader: - type: integer - hopLimit: - type: integer - transportHeader: - type: object - properties: - icmp: - type: object - properties: - id: - type: integer - sequence: - type: integer - udp: - type: object - properties: - srcPort: - type: integer - dstPort: - type: integer - tcp: - type: object - properties: - srcPort: - type: integer - dstPort: - type: integer - flags: - type: integer - liveTraffic: - type: boolean - droppedOnly: - type: boolean - timeout: - type: integer - status: - type: object - properties: - reason: - type: string - dataplaneTag: - type: integer - phase: - type: string - startTime: - type: string - results: - type: array - items: - type: object - properties: - node: - type: string - role: - type: string - timestamp: - type: integer - observations: - type: array - items: - type: object - properties: - component: - type: string - componentInfo: - type: string - action: - type: string - pod: - type: string - dstMAC: - type: string - networkPolicy: - type: string - ttl: - type: integer - translatedSrcIP: - type: string - translatedDstIP: - type: string - tunnelDstIP: - type: string - capturedPacket: - properties: - srcIP: - type: string - dstIP: - type: string - length: - type: integer - ipHeader: - properties: - flags: - type: integer - protocol: - type: integer - ttl: - type: integer - type: object - ipv6Header: - properties: - hopLimit: - type: integer - nextHeader: - type: integer - type: object - transportHeader: - properties: - tcp: - properties: - dstPort: - type: integer - srcPort: - type: integer - flags: - type: integer - type: object - udp: - properties: - dstPort: - type: integer - srcPort: - type: integer - type: object - icmp: - properties: - id: - type: integer - sequence: - type: integer - type: object - type: object - type: object - subresources: - status: {} - scope: Cluster - names: - plural: traceflows - singular: traceflow - kind: Traceflow - shortNames: - - tf ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - name: tiers.crd.antrea.io -spec: - group: crd.antrea.io - versions: - - name: v1alpha1 - served: true - storage: true - additionalPrinterColumns: - - name: Priority - type: integer - description: The Priority of this Tier relative to other Tiers. - jsonPath: .spec.priority - - name: Age - type: date - jsonPath: .metadata.creationTimestamp - schema: - openAPIV3Schema: - type: object - properties: - spec: - required: - - priority - type: object - properties: - priority: - type: integer - minimum: 0 - maximum: 255 - description: - type: string - scope: Cluster - names: - plural: tiers - singular: tier - kind: Tier - shortNames: - - tr ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - name: clusternetworkpolicies.crd.antrea.io -spec: - group: crd.antrea.io - versions: - - name: v1alpha1 - served: true - storage: true - additionalPrinterColumns: - - name: Tier - type: string - description: The Tier to which this ClusterNetworkPolicy belongs to. - jsonPath: .spec.tier - - name: Priority - type: number - format: float - description: The Priority of this ClusterNetworkPolicy relative to other policies. - jsonPath: .spec.priority - - name: Desired Nodes - type: number - format: int32 - description: The total number of Nodes that should realize the NetworkPolicy. - jsonPath: .status.desiredNodesRealized - - name: Current Nodes - type: number - format: int32 - description: The number of Nodes that have realized the NetworkPolicy. - jsonPath: .status.currentNodesRealized - - name: Age - type: date - jsonPath: .metadata.creationTimestamp - schema: - openAPIV3Schema: - type: object - properties: - spec: - # Ensure that Spec.Priority field is set - required: - - priority - type: object - properties: - tier: - type: string - priority: - type: number - format: float - # Ensure that Spec.Priority field is between 1 and 10000 - minimum: 1.0 - maximum: 10000.0 - appliedTo: - type: array - items: - type: object - # Ensure that Spec.AppliedTo does not allow IPBlock field - properties: - podSelector: - type: object - properties: - matchExpressions: - type: array - items: - type: object - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - type: array - items: - type: string - pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" - matchLabels: - x-kubernetes-preserve-unknown-fields: true - namespaceSelector: - type: object - properties: - matchExpressions: - type: array - items: - type: object - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - type: array - items: - type: string - pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" - matchLabels: - x-kubernetes-preserve-unknown-fields: true - group: - type: string - serviceAccount: - type: object - properties: - name: - type: string - namespace: - type: string - required: - - name - - namespace - ingress: - type: array - items: - type: object - required: - - action - properties: - appliedTo: - type: array - items: - type: object - # Ensure that rule AppliedTo does not allow IPBlock field - properties: - podSelector: - type: object - properties: - matchExpressions: - type: array - items: - type: object - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - type: array - items: - type: string - pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" - matchLabels: - x-kubernetes-preserve-unknown-fields: true - namespaceSelector: - type: object - properties: - matchExpressions: - type: array - items: - type: object - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - type: array - items: - type: string - pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" - matchLabels: - x-kubernetes-preserve-unknown-fields: true - group: - type: string - serviceAccount: - type: object - properties: - name: - type: string - namespace: - type: string - required: - - name - - namespace - # Ensure that Action field allows only ALLOW, DROP and REJECT values - action: - type: string - enum: ['Allow', 'Drop', 'Reject', 'Pass'] - ports: - type: array - items: - type: object - properties: - protocol: - type: string - enum: ['TCP', 'UDP', 'SCTP'] - port: - x-kubernetes-int-or-string: true - endPort: - type: integer - from: - type: array - items: - type: object - properties: - podSelector: - type: object - properties: - matchExpressions: - type: array - items: - type: object - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - type: array - items: - type: string - pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" - matchLabels: - x-kubernetes-preserve-unknown-fields: true - namespaceSelector: - type: object - properties: - matchExpressions: - type: array - items: - type: object - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - type: array - items: - type: string - pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" - matchLabels: - x-kubernetes-preserve-unknown-fields: true - namespaces: - type: object - properties: - match: - enum: - - Self - type: string - ipBlock: - type: object - properties: - cidr: - type: string - format: cidr - group: - type: string - serviceAccount: - type: object - properties: - name: - type: string - namespace: - type: string - required: - - name - - namespace - nodeSelector: - type: object - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - type: string - pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - name: - type: string - enableLogging: - type: boolean - egress: - type: array - items: - type: object - required: - - action - properties: - appliedTo: - type: array - items: - type: object - # Ensure that rule AppliedTo does not allow IPBlock field - properties: - podSelector: - type: object - properties: - matchExpressions: - type: array - items: - type: object - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - type: array - items: - type: string - pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" - matchLabels: - x-kubernetes-preserve-unknown-fields: true - namespaceSelector: - type: object - properties: - matchExpressions: - type: array - items: - type: object - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - type: array - items: - type: string - pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" - matchLabels: - x-kubernetes-preserve-unknown-fields: true - group: - type: string - serviceAccount: - type: object - properties: - name: - type: string - namespace: - type: string - required: - - name - - namespace - # Ensure that Action field allows only ALLOW, DROP and REJECT values - action: - type: string - enum: ['Allow', 'Drop', 'Reject', 'Pass'] - ports: - type: array - items: - type: object - properties: - protocol: - type: string - enum: ['TCP', 'UDP', 'SCTP'] - port: - x-kubernetes-int-or-string: true - endPort: - type: integer - to: - type: array - items: - type: object - properties: - podSelector: - type: object - properties: - matchExpressions: - type: array - items: - type: object - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - type: array - items: - type: string - pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" - matchLabels: - x-kubernetes-preserve-unknown-fields: true - namespaceSelector: - type: object - properties: - matchExpressions: - type: array - items: - type: object - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - type: array - items: - type: string - pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" - matchLabels: - x-kubernetes-preserve-unknown-fields: true - namespaces: - type: object - properties: - match: - type: string - ipBlock: - type: object - properties: - cidr: - type: string - format: cidr - group: - type: string - fqdn: - type: string - serviceAccount: - type: object - properties: - name: - type: string - namespace: - type: string - required: - - name - - namespace - nodeSelector: - type: object - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - type: string - pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - toServices: - type: array - items: - type: object - required: - - name - - namespace - properties: - name: - type: string - namespace: - type: string - name: - type: string - enableLogging: - type: boolean - status: - type: object - properties: - phase: - type: string - observedGeneration: - type: integer - currentNodesRealized: - type: integer - desiredNodesRealized: - type: integer - subresources: - status: {} - scope: Cluster - names: - plural: clusternetworkpolicies - singular: clusternetworkpolicy - kind: ClusterNetworkPolicy - shortNames: - - acnp ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - name: networkpolicies.crd.antrea.io -spec: - group: crd.antrea.io - versions: - - name: v1alpha1 - served: true - storage: true - additionalPrinterColumns: - - name: Tier - type: string - description: The Tier to which this Antrea NetworkPolicy belongs to. - jsonPath: .spec.tier - - name: Priority - type: number - format: float - description: The Priority of this Antrea NetworkPolicy relative to other policies. - jsonPath: .spec.priority - - name: Desired Nodes - type: number - format: int32 - description: The total number of Nodes that should realize the NetworkPolicy. - jsonPath: .status.desiredNodesRealized - - name: Current Nodes - type: number - format: int32 - description: The number of Nodes that have realized the NetworkPolicy. - jsonPath: .status.currentNodesRealized - - name: Age - type: date - jsonPath: .metadata.creationTimestamp - schema: - openAPIV3Schema: - type: object - properties: - spec: - # Ensure that Spec.Priority field is set - required: - - priority - type: object - properties: - tier: - type: string - priority: - type: number - format: float - # Ensure that Spec.Priority field is between 1 and 10000 - minimum: 1.0 - maximum: 10000.0 - appliedTo: - type: array - items: - type: object - # Ensure that Spec.AppliedTo does not allow NamespaceSelector/IPBlock field - properties: - podSelector: - type: object - properties: - matchExpressions: - type: array - items: - type: object - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - type: array - items: - type: string - pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" - matchLabels: - x-kubernetes-preserve-unknown-fields: true - ingress: - type: array - items: - type: object - required: - - action - properties: - appliedTo: - type: array - items: - type: object - # Ensure that rule AppliedTo does not allow NamespaceSelector/IPBlock field - properties: - podSelector: - type: object - properties: - matchExpressions: - type: array - items: - type: object - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - type: array - items: - type: string - pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" - matchLabels: - x-kubernetes-preserve-unknown-fields: true - # Ensure that Action field allows only ALLOW, DROP and REJECT values - action: - type: string - enum: ['Allow', 'Drop', 'Reject', 'Pass'] - ports: - type: array - items: - type: object - properties: - protocol: - type: string - enum: ['TCP', 'UDP', 'SCTP'] - port: - x-kubernetes-int-or-string: true - endPort: - type: integer - from: - type: array - items: - type: object - properties: - podSelector: - type: object - properties: - matchExpressions: - type: array - items: - type: object - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - type: array - items: - type: string - pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" - matchLabels: - x-kubernetes-preserve-unknown-fields: true - namespaceSelector: - type: object - properties: - matchExpressions: - type: array - items: - type: object - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - type: array - items: - type: string - pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" - matchLabels: - x-kubernetes-preserve-unknown-fields: true - externalEntitySelector: - type: object - properties: - matchExpressions: - type: array - items: - type: object - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - type: array - items: - type: string - pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" - matchLabels: - x-kubernetes-preserve-unknown-fields: true - ipBlock: - type: object - properties: - cidr: - type: string - format: cidr - nodeSelector: - type: object - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - type: string - pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - name: - type: string - enableLogging: - type: boolean - egress: - type: array - items: - type: object - required: - - action - properties: - appliedTo: - type: array - items: - type: object - # Ensure that rule AppliedTo does not allow NamespaceSelector/IPBlock field - properties: - podSelector: - type: object - properties: - matchExpressions: - type: array - items: - type: object - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - type: array - items: - type: string - pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" - matchLabels: - x-kubernetes-preserve-unknown-fields: true - # Ensure that Action field allows only ALLOW, DROP and REJECT values - action: - type: string - enum: ['Allow', 'Drop', 'Reject', 'Pass'] - ports: - type: array - items: - type: object - properties: - # Ensure that Protocol field allows only TCP, UDP and SCTP values - protocol: - type: string - enum: ['TCP', 'UDP', 'SCTP'] - port: - x-kubernetes-int-or-string: true - endPort: - type: integer - to: - type: array - items: - type: object - properties: - podSelector: - type: object - properties: - matchExpressions: - type: array - items: - type: object - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - type: array - items: - type: string - pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" - matchLabels: - x-kubernetes-preserve-unknown-fields: true - namespaceSelector: - type: object - properties: - matchExpressions: - type: array - items: - type: object - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - type: array - items: - type: string - pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" - matchLabels: - x-kubernetes-preserve-unknown-fields: true - externalEntitySelector: - type: object - properties: - matchExpressions: - type: array - items: - type: object - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - type: array - items: - type: string - pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" - matchLabels: - x-kubernetes-preserve-unknown-fields: true - ipBlock: - type: object - properties: - cidr: - type: string - format: cidr - fqdn: - type: string - nodeSelector: - type: object - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - items: - type: string - pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" - type: array - type: object - type: array - matchLabels: - x-kubernetes-preserve-unknown-fields: true - toServices: - type: array - items: - type: object - required: - - name - properties: - name: - type: string - namespace: - type: string - name: - type: string - enableLogging: - type: boolean - status: - type: object - properties: - phase: - type: string - observedGeneration: - type: integer - currentNodesRealized: - type: integer - desiredNodesRealized: - type: integer - subresources: - status: {} - scope: Namespaced - names: - plural: networkpolicies - singular: networkpolicy - kind: NetworkPolicy - shortNames: - - anp ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - name: externalentities.crd.antrea.io -spec: - group: crd.antrea.io - versions: - - name: v1alpha2 - served: true - storage: true - schema: - openAPIV3Schema: - type: object - properties: - spec: - type: object - properties: - endpoints: - type: array - items: - type: object - properties: - ip: - type: string - oneOf: - - format: ipv4 - - format: ipv6 - name: - type: string - ports: - type: array - items: - type: object - properties: - protocol: - type: string - enum: ['TCP', 'UDP', 'SCTP'] - port: - x-kubernetes-int-or-string: true - name: - type: string - externalNode: - type: string - - name: v1alpha1 - served: false - storage: false - schema: - openAPIV3Schema: - type: object - scope: Namespaced - names: - plural: externalentities - singular: externalentity - kind: ExternalEntity - shortNames: - - ee ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - name: clustergroups.crd.antrea.io -spec: - group: crd.antrea.io - versions: - - name: v1alpha2 - served: true - storage: false - schema: - openAPIV3Schema: - type: object - properties: - spec: - type: object - properties: - childGroups: - type: array - items: - type: string - podSelector: - type: object - properties: - matchExpressions: - type: array - items: - type: object - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - type: array - items: - type: string - pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" - matchLabels: - x-kubernetes-preserve-unknown-fields: true - namespaceSelector: - type: object - properties: - matchExpressions: - type: array - items: - type: object - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - type: array - items: - type: string - pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" - matchLabels: - x-kubernetes-preserve-unknown-fields: true - externalEntitySelector: - type: object - properties: - matchExpressions: - type: array - items: - type: object - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - type: array - items: - type: string - pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" - matchLabels: - x-kubernetes-preserve-unknown-fields: true - ipBlock: - type: object - properties: - cidr: - type: string - format: cidr - ipBlocks: - type: array - items: - type: object - properties: - cidr: - type: string - format: cidr - serviceReference: - type: object - properties: - name: - type: string - namespace: - type: string - status: - type: object - properties: - conditions: - type: array - items: - type: object - properties: - type: - type: string - status: - type: string - lastTransitionTime: - type: string - - name: v1alpha3 - served: true - storage: true - schema: - openAPIV3Schema: - type: object - properties: - spec: - type: object - properties: - childGroups: - type: array - items: - type: string - podSelector: - type: object - properties: - matchExpressions: - type: array - items: - type: object - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - type: array - items: - type: string - pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" - matchLabels: - x-kubernetes-preserve-unknown-fields: true - namespaceSelector: - type: object - properties: - matchExpressions: - type: array - items: - type: object - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - type: array - items: - type: string - pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" - matchLabels: - x-kubernetes-preserve-unknown-fields: true - externalEntitySelector: - type: object - properties: - matchExpressions: - type: array - items: - type: object - properties: - key: - type: string - operator: - enum: - - In - - NotIn - - Exists - - DoesNotExist - type: string - values: - type: array - items: - type: string - pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" - matchLabels: - x-kubernetes-preserve-unknown-fields: true - ipBlocks: - type: array - items: - type: object - properties: - cidr: - type: string - format: cidr - serviceReference: - type: object - properties: - name: - type: string - namespace: - type: string - status: - type: object - properties: - conditions: - type: array - items: - type: object - properties: - type: - type: string - status: - type: string - lastTransitionTime: - type: string - subresources: - status: {} - conversion: - strategy: Webhook - webhook: - conversionReviewVersions: ["v1", "v1beta1"] - clientConfig: - service: - name: "antrea" - namespace: "kube-system" - path: "/convert/clustergroup" - scope: Cluster - names: - plural: clustergroups - singular: clustergroup - kind: ClusterGroup - shortNames: - - cg ---- diff --git a/build/yamls/base/kustomization.yml b/build/yamls/base/kustomization.yml deleted file mode 100644 index 10bdbae589e..00000000000 --- a/build/yamls/base/kustomization.yml +++ /dev/null @@ -1,31 +0,0 @@ -resources: -- crds.yml -- crds-rbac.yml -- antctl.yml -- controller-rbac.yml -- controller.yml -- agent-rbac.yml -- agent.yml -- cluster-identity-reader.yml -configMapGenerator: -- files: - - conf/antrea-controller.conf - - conf/antrea-agent.conf - - conf/antrea-cni.conflist - name: antrea-config -commonLabels: - app: antrea -namespace: kube-system - # Only a single active instance is supported for now. -replicas: -- count: 1 - name: antrea-controller -vars: - - name: ANTREA_CONFIG_MAP_NAME - objref: - kind: ConfigMap - name: antrea-config - apiVersion: v1 - -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization diff --git a/build/yamls/chart-values/antrea-aks.yml b/build/yamls/chart-values/antrea-aks.yml new file mode 100644 index 00000000000..1bb20cea215 --- /dev/null +++ b/build/yamls/chart-values/antrea-aks.yml @@ -0,0 +1,3 @@ +trafficEncapMode: "networkPolicyOnly" +agent: + dnsPolicy: "ClusterFirst" diff --git a/build/yamls/chart-values/antrea-eks.yml b/build/yamls/chart-values/antrea-eks.yml new file mode 100644 index 00000000000..cc97b5b7462 --- /dev/null +++ b/build/yamls/chart-values/antrea-eks.yml @@ -0,0 +1,7 @@ +trafficEncapMode: "networkPolicyOnly" +agent: + antreaAgent: + extraEnv: + # Antrea Agent needs to be aware that it is being used in EKS, as + # additional iptables rules may have to be installed. + ANTREA_CLOUD_EKS: "true" diff --git a/build/yamls/chart-values/antrea-gke.yml b/build/yamls/chart-values/antrea-gke.yml new file mode 100644 index 00000000000..9944593cc16 --- /dev/null +++ b/build/yamls/chart-values/antrea-gke.yml @@ -0,0 +1,3 @@ +trafficEncapMode: "noEncap" +cni: + hostBinPath: "/home/kubernetes/bin" diff --git a/build/yamls/chart-values/antrea-ipsec.yml b/build/yamls/chart-values/antrea-ipsec.yml new file mode 100644 index 00000000000..d6770ea44a7 --- /dev/null +++ b/build/yamls/chart-values/antrea-ipsec.yml @@ -0,0 +1,3 @@ +trafficEncryptionMode: "ipsec" +# change the tunnel type to GRE which works better with IPsec encryption than other types. +tunnelType: "gre" diff --git a/build/yamls/chart-values/antrea.yml b/build/yamls/chart-values/antrea.yml new file mode 100644 index 00000000000..e69de29bb2d diff --git a/build/yamls/clickhouse-operator-install-bundle.yml b/build/yamls/clickhouse-operator-install-bundle.yml index 7d7a6fee28f..1b677e90cda 100644 --- a/build/yamls/clickhouse-operator-install-bundle.yml +++ b/build/yamls/clickhouse-operator-install-bundle.yml @@ -3487,7 +3487,7 @@ data: "containers" : [ { "name": "clickhouse", - "image": "projects.registry.vmware.com/antrea/flow-visibility-clickhouse-server:21.3", + "image": "projects.registry.vmware.com/antrea/flow-visibility-clickhouse-server:21.11", "ports": [ { "name": "http", diff --git a/build/yamls/elk-flow-collector/elk-flow-collector.yml b/build/yamls/elk-flow-collector/elk-flow-collector.yml deleted file mode 100644 index 9fa8cd3b11d..00000000000 --- a/build/yamls/elk-flow-collector/elk-flow-collector.yml +++ /dev/null @@ -1,277 +0,0 @@ -apiVersion: storage.k8s.io/v1 -kind: StorageClass -metadata: - name: elastic-storage -provisioner: kubernetes.io/no-provisioner -volumeBindingMode: Immediate -reclaimPolicy: Delete -allowVolumeExpansion: True ---- -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: elasticsearch-pvc -spec: - storageClassName: elastic-storage - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 2Gi ---- -apiVersion: v1 -kind: PersistentVolume -metadata: - name: elasticsearch-pv -spec: - storageClassName: elastic-storage - capacity: - storage: 2Gi - accessModes: - - ReadWriteOnce - hostPath: - path: "/data/elasticsearch/" ---- -apiVersion: v1 -kind: Service -metadata: - name: elasticsearch - labels: - app: elasticsearch -spec: - selector: - app: elasticsearch - ports: - - port: 9200 - targetPort: 9200 ---- -apiVersion: apps/v1 -kind: StatefulSet -metadata: - name: elasticsearch - labels: - app: elasticsearch -spec: - selector: - matchLabels: - app: elasticsearch - serviceName: elasticsearch - replicas: 1 - template: - metadata: - labels: - app: elasticsearch - spec: - initContainers: - - name: init-sysctl - image: busybox:1.27.2 - command: - - sysctl - - -w - - vm.max_map_count=262144 - securityContext: - privileged: true - containers: - - name: es-data - image: docker.elastic.co/elasticsearch/elasticsearch-oss:7.8.0 - env: - - name: ES_JAVA_OPTS - value: "-Xms512m -Xmx1g" - - name: cluster.name - value: "elk-flow-collector" - - name: bootstrap.memory_lock - value: "false" - - name: network.host - valueFrom: - fieldRef: - fieldPath: status.podIP - - name: http.port - value: "9200" - - name: discovery.type - value: "single-node" - - name: indices.query.bool.max_clause_count - value: "8192" - - name: search.max_buckets - value: "100000" - - name: action.destructive_requires_name - value: "true" - ports: - - containerPort: 9200 - name: http - - containerPort: 9300 - name: transport - livenessProbe: - tcpSocket: - port: transport - initialDelaySeconds: 90 - periodSeconds: 10 - readinessProbe: - httpGet: - path: /_cluster/health - port: http - initialDelaySeconds: 90 - timeoutSeconds: 20 - volumeMounts: - - name: es-data - mountPath: /data - nodeSelector: - kubernetes.io/os: linux - kubernetes.io/arch: amd64 - volumes: - - name: es-data - persistentVolumeClaim: - claimName: elasticsearch-pvc ---- -apiVersion: v1 -kind: Service -metadata: - name: kibana - labels: - app: kibana -spec: - type: NodePort - selector: - app: kibana - ports: - - port: 5601 - targetPort: 5601 - nodePort: 30007 ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: kibana - labels: - app: kibana -spec: - replicas: 1 - selector: - matchLabels: - app: kibana - template: - metadata: - labels: - app: kibana - spec: - containers: - - name: kibana - image: docker.elastic.co/kibana/kibana-oss:7.8.0 - env: - - name: action.destructive_requires_name - value: "true" - - name: SERVER_HOST - valueFrom: - fieldRef: - fieldPath: status.podIP - - name: SERVER_PORT - value: "5601" - - name: ELASTICSEARCH_URL - value: "http://elasticsearch:9200" - - name: KIBANA_DEFAULTAPPID - value: "dashboard/3b331b30-b987-11ea-b16e-fb06687c3589" - - name: LOGGING_QUIET - value: "true" - - name: KIBANA_AUTOCOMPLETETERMINATEAFTER - value: "100000" - ports: - - containerPort: 5601 - name: http - nodeSelector: - kubernetes.io/os: linux - kubernetes.io/arch: amd64 ---- -apiVersion: v1 -kind: Service -metadata: - name: logstash - labels: - app: logstash -spec: - selector: - app: logstash - ports: - - port: 4736 - targetPort: 4736 - protocol: TCP - name: tcp-json - - port: 4736 - targetPort: 4736 - protocol: UDP - name: udp-json - - port: 4739 - targetPort: 4739 - protocol: TCP - name: tcp-ipfix - - port: 4739 - targetPort: 4739 - protocol: UDP - name: udp-ipfix ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: logstash - labels: - app: logstash -spec: - replicas: 1 - selector: - matchLabels: - app: logstash - template: - metadata: - labels: - app: logstash - spec: - containers: - - name: logstash - image: docker.elastic.co/logstash/logstash-oss:7.8.0 - env: - - name: POD_IP - valueFrom: - fieldRef: - fieldPath: status.podIP - volumeMounts: - - name: logstash-definition-volume - mountPath: /usr/share/logstash/definitions - - name: config-volume - mountPath: /usr/share/logstash/config - - name: logstash-pipeline-volume - mountPath: /usr/share/logstash/pipeline - ports: - - containerPort: 4736 - protocol: TCP - name: tcp-json - - containerPort: 4736 - protocol: UDP - name: udp-json - - containerPort: 4739 - protocol: TCP - name: tcp-ipfix - - containerPort: 4739 - protocol: UDP - name: udp-ipfix - nodeSelector: - kubernetes.io/os: linux - kubernetes.io/arch: amd64 - volumes: - - name: logstash-definition-volume - configMap: - name: logstash-configmap - items: - - key: ipfix.yml - path: ipfix.yml - - name: config-volume - configMap: - name: logstash-configmap - items: - - key: logstash.yml - path: logstash.yml - - key: filter.rb - path: filter.rb - - name: logstash-pipeline-volume - configMap: - name: logstash-configmap - items: - - key: logstash.conf - path: logstash.conf diff --git a/build/yamls/elk-flow-collector/kibana.ndjson b/build/yamls/elk-flow-collector/kibana.ndjson deleted file mode 100644 index 310d3e3decd..00000000000 --- a/build/yamls/elk-flow-collector/kibana.ndjson +++ /dev/null @@ -1,70 +0,0 @@ -{"attributes":{"fields":"[{\"name\":\"@timestamp\",\"type\":\"date\",\"esTypes\":[\"date\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"@version\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"@version.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"@version\"}}},{\"name\":\"_id\",\"type\":\"string\",\"esTypes\":[\"_id\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":false},{\"name\":\"_index\",\"type\":\"string\",\"esTypes\":[\"_index\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":false},{\"name\":\"_score\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":false,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"_source\",\"type\":\"_source\",\"esTypes\":[\"_source\"],\"count\":0,\"scripted\":false,\"searchable\":false,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"_type\",\"type\":\"string\",\"esTypes\":[\"_type\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":false},{\"name\":\"host\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"host.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"host\"}}},{\"name\":\"ipfix.bytes\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"ipfix.destinationClusterIPv4\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"ipfix.destinationClusterIPv4.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"ipfix.destinationClusterIPv4\"}}},{\"name\":\"ipfix.destinationIP\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"ipfix.destinationIP.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"ipfix.destinationIP\"}}},{\"name\":\"ipfix.destinationIPv4Address\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"ipfix.destinationIPv4Address.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"ipfix.destinationIPv4Address\"}}},{\"name\":\"ipfix.destinationNodeName\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"ipfix.destinationNodeName.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"ipfix.destinationNodeName\"}}},{\"name\":\"ipfix.destinationPodLabels\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"ipfix.destinationPodLabels.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"ipfix.destinationPodLabels\"}}},{\"name\":\"ipfix.destinationPodName\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"ipfix.destinationPodName.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"ipfix.destinationPodName\"}}},{\"name\":\"ipfix.destinationPodNamespace\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"ipfix.destinationPodNamespace.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"ipfix.destinationPodNamespace\"}}},{\"name\":\"ipfix.destinationServicePort\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"ipfix.destinationServicePortName\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"ipfix.destinationServicePortName.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"ipfix.destinationServicePortName\"}}},{\"name\":\"ipfix.destinationTransportPort\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"ipfix.egressNetworkPolicyName\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"ipfix.egressNetworkPolicyName.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"ipfix.egressNetworkPolicyName\"}}},{\"name\":\"ipfix.egressNetworkPolicyNamespace\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"ipfix.egressNetworkPolicyNamespace.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"ipfix.egressNetworkPolicyNamespace\"}}},{\"name\":\"ipfix.egressNetworkPolicyRuleAction\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"ipfix.egressNetworkPolicyRuleActionStr\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"ipfix.egressNetworkPolicyRuleActionStr.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"ipfix.egressNetworkPolicyRuleActionStr\"}}},{\"name\":\"ipfix.egressNetworkPolicyRuleName\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"ipfix.egressNetworkPolicyRuleName.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"ipfix.egressNetworkPolicyRuleName\"}}},{\"name\":\"ipfix.egressNetworkPolicyType\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"ipfix.flowEndReason\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"ipfix.flowEndSeconds\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"ipfix.flowKey\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"ipfix.flowKey.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"ipfix.flowKey\"}}},{\"name\":\"ipfix.flowKeyPodToExternal\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"ipfix.flowKeyPodToExternal.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"ipfix.flowKeyPodToExternal\"}}},{\"name\":\"ipfix.flowKeyPodToPod\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"ipfix.flowKeyPodToPod.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"ipfix.flowKeyPodToPod\"}}},{\"name\":\"ipfix.flowKeyPodToService\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"ipfix.flowKeyPodToService.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"ipfix.flowKeyPodToService\"}}},{\"name\":\"ipfix.flowStartSeconds\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"ipfix.flowType\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"ipfix.flowTypeStr\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"ipfix.flowTypeStr.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"ipfix.flowTypeStr\"}}},{\"name\":\"ipfix.ingressNetworkPolicyName\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"ipfix.ingressNetworkPolicyName.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"ipfix.ingressNetworkPolicyName\"}}},{\"name\":\"ipfix.ingressNetworkPolicyNamespace\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"ipfix.ingressNetworkPolicyNamespace.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"ipfix.ingressNetworkPolicyNamespace\"}}},{\"name\":\"ipfix.ingressNetworkPolicyRuleAction\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"ipfix.ingressNetworkPolicyRuleActionStr\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"ipfix.ingressNetworkPolicyRuleActionStr.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"ipfix.ingressNetworkPolicyRuleActionStr\"}}},{\"name\":\"ipfix.ingressNetworkPolicyRuleName\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"ipfix.ingressNetworkPolicyRuleName.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"ipfix.ingressNetworkPolicyRuleName\"}}},{\"name\":\"ipfix.ingressNetworkPolicyType\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"ipfix.octetDeltaCount\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"ipfix.octetDeltaCountFromDestinationNode\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"ipfix.octetDeltaCountFromSourceNode\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"ipfix.octetTotalCount\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"ipfix.octetTotalCountFromDestinationNode\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"ipfix.octetTotalCountFromSourceNode\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"ipfix.packetDeltaCount\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"ipfix.packetDeltaCountFromDestinationNode\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"ipfix.packetDeltaCountFromSourceNode\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"ipfix.packetTotalCount\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"ipfix.packetTotalCountFromDestinationNode\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"ipfix.packetTotalCountFromSourceNode\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"ipfix.packets\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"ipfix.protocolIdentifier\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"ipfix.protocolIdentifier.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"ipfix.protocolIdentifier\"}}},{\"name\":\"ipfix.reverseOctetDeltaCount\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"ipfix.reverseOctetDeltaCountFromDestinationNode\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"ipfix.reverseOctetDeltaCountFromSourceNode\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"ipfix.reverseOctetTotalCount\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"ipfix.reverseOctetTotalCountFromDestinationNode\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"ipfix.reverseOctetTotalCountFromSourceNode\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"ipfix.reversePacketDeltaCount\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"ipfix.reversePacketDeltaCountFromDestinationNode\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"ipfix.reversePacketDeltaCountFromSourceNode\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"ipfix.reversePacketTotalCount\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"ipfix.reversePacketTotalCountFromDestinationNode\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"ipfix.reversePacketTotalCountFromSourceNode\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"ipfix.reverseThroughput\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"ipfix.sourceIP\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"ipfix.sourceIP.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"ipfix.sourceIP\"}}},{\"name\":\"ipfix.sourceIPv4Address\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"ipfix.sourceIPv4Address.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"ipfix.sourceIPv4Address\"}}},{\"name\":\"ipfix.sourceNodeName\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"ipfix.sourceNodeName.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"ipfix.sourceNodeName\"}}},{\"name\":\"ipfix.sourcePodLabels\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"ipfix.sourcePodLabels.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"ipfix.sourcePodLabels\"}}},{\"name\":\"ipfix.sourcePodName\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"ipfix.sourcePodName.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"ipfix.sourcePodName\"}}},{\"name\":\"ipfix.sourcePodNamespace\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"ipfix.sourcePodNamespace.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"ipfix.sourcePodNamespace\"}}},{\"name\":\"ipfix.sourceTransportPort\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"ipfix.tcpState\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"ipfix.tcpState.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"ipfix.tcpState\"}}},{\"name\":\"ipfix.throughput\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"port\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"tags\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"tags.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"tags\"}}}]","timeFieldName":"@timestamp","title":"flow-*"},"id":"e2ab2c50-b981-11ea-b16e-fb06687c3589","migrationVersion":{"index-pattern":"7.6.0"},"references":[],"type":"index-pattern","updated_at":"2021-08-07T23:32:23.467Z","version":"Wzc2LDFd"} -{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\",\"filter\":[]}"},"title":"Destination Pod Bytes","uiStateJSON":"{}","version":1,"visState":"{\"type\":\"pie\",\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"sum\",\"schema\":\"metric\",\"params\":{\"field\":\"ipfix.bytes\"}},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"segment\",\"params\":{\"field\":\"ipfix.destinationPodName.keyword\",\"orderBy\":\"1\",\"order\":\"desc\",\"size\":30,\"otherBucket\":true,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\",\"customLabel\":\"Server\"}}],\"params\":{\"type\":\"pie\",\"addTooltip\":true,\"addLegend\":true,\"legendPosition\":\"right\",\"isDonut\":true,\"labels\":{\"show\":false,\"values\":true,\"last_level\":true,\"truncate\":100},\"dimensions\":{\"metric\":{\"accessor\":0,\"format\":{\"id\":\"number\"},\"params\":{},\"aggType\":\"count\"}}},\"title\":\"Destination Pod Bytes\"}"},"id":"051d3d60-b986-11ea-b16e-fb06687c3589","migrationVersion":{"visualization":"7.8.0"},"references":[{"id":"e2ab2c50-b981-11ea-b16e-fb06687c3589","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"}],"type":"visualization","updated_at":"2021-08-07T23:30:40.150Z","version":"WzIsMV0="} -{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}"},"title":"Aggregated Rx Mbps by Node Acting as Source","uiStateJSON":"{}","version":1,"visState":"{\"type\":\"metrics\",\"aggs\":[],\"params\":{\"id\":\"61ca57f0-469d-11e7-af02-69e470af7417\",\"type\":\"timeseries\",\"axis_position\":\"left\",\"axis_formatter\":\"number\",\"show_legend\":1,\"show_grid\":1,\"axis_min\":\"0\",\"filter\":\"\",\"axis_scale\":\"normal\",\"default_index_pattern\":\"flow-*\",\"default_timefield\":\"@timestamp\",\"isModelInvalid\":false,\"index_pattern\":\"flow-*\",\"interval\":\"1m\",\"time_field\":\"ipfix.flowEndSeconds\",\"series\":[{\"id\":\"61ca57f1-469d-11e7-af02-69e470af7417\",\"color\":\"rgba(144,201,227,1)\",\"split_mode\":\"terms\",\"metrics\":[{\"id\":\"a1ba0060-b9a7-11ea-9740-552c943910e4\",\"type\":\"sum\",\"field\":\"ipfix.reverseThroughput\"},{\"script\":\"params.bytes * 8 \",\"id\":\"dd0b81d0-b9a6-11ea-9740-552c943910e4\",\"type\":\"calculation\",\"variables\":[{\"id\":\"e1f87e50-b9a6-11ea-9740-552c943910e4\",\"name\":\"bytes\",\"field\":\"a1ba0060-b9a7-11ea-9740-552c943910e4\"}]}],\"separate_axis\":0,\"axis_position\":\"right\",\"formatter\":\"bytes\",\"chart_type\":\"line\",\"line_width\":\"2\",\"point_size\":\"0\",\"fill\":\"0.6\",\"stacked\":\"none\",\"split_color_mode\":\"rainbow\",\"label\":\"Bytes\",\"terms_field\":\"ipfix.sourceNodeName.keyword\",\"terms_size\":\"30\",\"terms_order_by\":\"a1ba0060-b9a7-11ea-9740-552c943910e4\",\"value_template\":\"{{value}}its/s\",\"type\":\"timeseries\"}]},\"title\":\"Aggregated Rx Mbps by Node Acting as Source\"}"},"id":"089a7d70-cd33-11ea-8911-87da3aad0324","migrationVersion":{"visualization":"7.8.0"},"references":[],"type":"visualization","updated_at":"2021-08-07T23:30:40.150Z","version":"WzMsMV0="} -{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"lucene\"},\"filter\":[]}"},"title":"Pod-to-External Traffic Reverse Cumulative Bytes","uiStateJSON":"{}","version":1,"visState":"{\"type\":\"vega\",\"aggs\":[],\"params\":{\"spec\":\"{\\n \\\"$schema\\\": \\\"https://vega.github.io/schema/vega/v3.0.json\\\",\\n \\\"data\\\": [\\n {\\n \\\"name\\\": \\\"rawData\\\",\\n \\\"url\\\": {\\n \\\"%context%\\\": true,\\n \\\"%timefield%\\\": \\\"@timestamp\\\",\\n \\\"index\\\": \\\"flow-*\\\",\\n \\\"body\\\": {\\n \\\"size\\\": 0,\\n \\\"aggs\\\": {\\n \\\"table\\\": {\\n \\\"composite\\\": {\\n \\\"size\\\": 1000,\\n \\\"sources\\\": [\\n {\\\"stk1\\\": {\\\"terms\\\": {\\\"field\\\": \\\"ipfix.sourcePodName.keyword\\\"}}},\\n {\\\"stk1ns\\\": {\\\"terms\\\": {\\\"field\\\": \\\"ipfix.sourcePodNamespace.keyword\\\"}}},\\n {\\\"stk2\\\": {\\\"terms\\\": {\\\"field\\\": \\\"ipfix.destinationIP.keyword\\\"}}},\\n {\\\"stk3\\\": {\\\"terms\\\": {\\\"field\\\": \\\"ipfix.sourceIP.keyword\\\"}}},\\n {\\\"stk4\\\": {\\\"terms\\\": {\\\"field\\\": \\\"ipfix.flowTypeStr.keyword\\\"}}},\\n ]\\n },\\n \\t\\t\\t\\\"aggs\\\": {\\n \\t\\t\\t\\t\\\"bytes\\\": {\\n \\t\\t\\t\\t\\t\\\"sum\\\": {\\n \\t\\t\\t\\t\\t\\t\\\"field\\\": \\\"ipfix.reverseOctetDeltaCountFromSourceNode\\\"\\n \\t\\t\\t\\t\\t}\\n \\t\\t\\t\\t}\\n \\t\\t\\t}\\n }\\n }\\n }\\n },\\n \\\"format\\\": {\\\"property\\\": \\\"aggregations.table.buckets\\\"},\\n \\\"transform\\\": [\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"datum.key.stk1ns +'/'+ datum.key.stk1\\\", \\\"as\\\": \\\"stk1s\\\"},\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"(datum.key.stk1==''?datum.key.stk3:datum.stk1s)\\\", \\\"as\\\": \\\"stk1\\\"},\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"datum.key.stk2\\\", \\\"as\\\": \\\"stk2\\\"},\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"datum.key.stk3\\\", \\\"as\\\": \\\"stk3\\\"},\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"datum.key.stk4\\\", \\\"as\\\": \\\"stk4\\\"},\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"datum.bytes.value\\\", \\\"as\\\": \\\"size\\\"}\\n ]\\n },\\n {\\n \\\"name\\\": \\\"nodes\\\",\\n \\\"source\\\": \\\"rawData\\\",\\n \\\"transform\\\": [\\n {\\n \\\"type\\\": \\\"filter\\\",\\n \\\"expr\\\": \\\"datum.stk4 == 'To External' && !groupSelector || groupSelector.stk1 == datum.stk1 || groupSelector.stk2 == datum.stk2\\\"\\n },\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"datum.stk1+datum.stk2\\\", \\\"as\\\": \\\"key\\\"},\\n {\\\"type\\\": \\\"fold\\\", \\\"fields\\\": [\\\"stk1\\\", \\\"stk2\\\"], \\\"as\\\": [\\\"stack\\\", \\\"grpId\\\"]},\\n {\\n \\\"type\\\": \\\"formula\\\",\\n \\\"expr\\\": \\\"datum.stack == 'stk1' ? datum.stk1+datum.stk2 : datum.stk2+datum.stk1\\\",\\n \\\"as\\\": \\\"sortField\\\"\\n },\\n {\\n \\\"type\\\": \\\"stack\\\",\\n \\\"groupby\\\": [\\\"stack\\\"],\\n \\\"sort\\\": {\\\"field\\\": \\\"sortField\\\", \\\"order\\\": \\\"descending\\\"},\\n \\\"field\\\": \\\"size\\\"\\n },\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"(datum.y0+datum.y1)/2\\\", \\\"as\\\": \\\"yc\\\"}\\n ]\\n },\\n {\\n \\\"name\\\": \\\"groups\\\",\\n \\\"source\\\": \\\"nodes\\\",\\n \\\"transform\\\": [\\n {\\n \\\"type\\\": \\\"aggregate\\\",\\n \\\"groupby\\\": [\\\"stack\\\", \\\"grpId\\\"],\\n \\\"fields\\\": [\\\"size\\\"],\\n \\\"ops\\\": [\\\"sum\\\"],\\n \\\"as\\\": [\\\"total\\\"]\\n },\\n {\\n \\\"type\\\": \\\"stack\\\",\\n \\\"groupby\\\": [\\\"stack\\\"],\\n \\\"sort\\\": {\\\"field\\\": \\\"grpId\\\", \\\"order\\\": \\\"descending\\\"},\\n \\\"field\\\": \\\"total\\\"\\n },\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"scale('y', datum.y0)\\\", \\\"as\\\": \\\"scaledY0\\\"},\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"scale('y', datum.y1)\\\", \\\"as\\\": \\\"scaledY1\\\"},\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"datum.stack == 'stk1'\\\", \\\"as\\\": \\\"rightLabel\\\"},\\n {\\n \\\"type\\\": \\\"formula\\\",\\n \\\"expr\\\": \\\"datum.total/domain('y')[1]\\\",\\n \\\"as\\\": \\\"percentage\\\"\\n }\\n ]\\n },\\n {\\n \\\"name\\\": \\\"destinationNodes\\\",\\n \\\"source\\\": \\\"nodes\\\",\\n \\\"transform\\\": [{\\\"type\\\": \\\"filter\\\", \\\"expr\\\": \\\"datum.stack == 'stk2'\\\"}]\\n },\\n {\\n \\\"name\\\": \\\"edges\\\",\\n \\\"source\\\": \\\"nodes\\\",\\n \\\"transform\\\": [\\n {\\\"type\\\": \\\"filter\\\", \\\"expr\\\": \\\"datum.stack == 'stk1'\\\"},\\n {\\n \\\"type\\\": \\\"lookup\\\",\\n \\\"from\\\": \\\"destinationNodes\\\",\\n \\\"key\\\": \\\"key\\\",\\n \\\"fields\\\": [\\\"key\\\"],\\n \\\"as\\\": [\\\"target\\\"]\\n },\\n {\\n \\\"type\\\": \\\"linkpath\\\",\\n \\\"orient\\\": \\\"horizontal\\\",\\n \\\"shape\\\": \\\"diagonal\\\",\\n \\\"sourceY\\\": {\\\"expr\\\": \\\"scale('y', datum.yc)\\\"},\\n \\\"sourceX\\\": {\\\"expr\\\": \\\"scale('x', 'stk1') + bandwidth('x')\\\"},\\n \\\"targetY\\\": {\\\"expr\\\": \\\"scale('y', datum.target.yc)\\\"},\\n \\\"targetX\\\": {\\\"expr\\\": \\\"scale('x', 'stk2')\\\"}\\n },\\n {\\n \\\"type\\\": \\\"formula\\\",\\n \\\"expr\\\": \\\"range('y')[0]-scale('y', datum.size)\\\",\\n \\\"as\\\": \\\"strokeWidth\\\"\\n },\\n {\\n \\\"type\\\": \\\"formula\\\",\\n \\\"expr\\\": \\\"datum.size/domain('y')[1]\\\",\\n \\\"as\\\": \\\"percentage\\\"\\n }\\n ]\\n }\\n ],\\n \\\"scales\\\": [\\n {\\n \\\"name\\\": \\\"x\\\",\\n \\\"type\\\": \\\"band\\\",\\n \\\"range\\\": \\\"width\\\",\\n \\\"domain\\\": [\\\"stk1\\\", \\\"stk2\\\"],\\n \\\"paddingOuter\\\": 0.01,\\n \\\"paddingInner\\\": 0.98\\n },\\n {\\n \\\"name\\\": \\\"y\\\",\\n \\\"type\\\": \\\"linear\\\",\\n \\\"range\\\": \\\"height\\\",\\n \\\"domain\\\": {\\\"data\\\": \\\"nodes\\\", \\\"field\\\": \\\"y1\\\"}\\n },\\n {\\n \\\"name\\\": \\\"color\\\",\\n \\\"type\\\": \\\"ordinal\\\",\\n \\\"range\\\": \\\"category\\\",\\n \\\"domain\\\": {\\\"data\\\": \\\"rawData\\\", \\\"fields\\\": [\\\"stk1\\\",\\\"stk2\\\"]}\\n },\\n {\\n \\\"name\\\": \\\"stackNames\\\",\\n \\\"type\\\": \\\"ordinal\\\",\\n \\\"range\\\": [\\\"Source Pod\\\", \\\"Destination IP\\\"],\\n \\\"domain\\\": [\\\"stk1\\\", \\\"stk2\\\"]\\n }\\n ],\\n \\\"axes\\\": [\\n {\\n \\\"orient\\\": \\\"bottom\\\",\\n \\\"scale\\\": \\\"x\\\",\\n \\\"labelColor\\\": {\\n \\\"value\\\": \\\"#888888\\\"\\n },\\n \\\"encode\\\": {\\n \\\"labels\\\": {\\n \\\"update\\\": {\\n \\\"text\\\": {\\\"scale\\\": \\\"stackNames\\\", \\\"field\\\": \\\"value\\\"},\\n \\\"fontSize\\\": {\\\"value\\\": 14}\\n }\\n }\\n }\\n },\\n {\\n \\\"orient\\\": \\\"left\\\",\\n \\\"scale\\\": \\\"y\\\",\\n \\\"labelColor\\\": {\\n \\\"value\\\": \\\"#888888\\\"\\n },\\n \\\"encode\\\": {\\n \\\"labels\\\": {\\n \\\"update\\\": {\\n \\\"text\\\": {\\\"signal\\\": \\\"format(datum.value, '.2s') + 'B'\\\"},\\n \\\"fontSize\\\": {\\\"value\\\": 12}\\n }\\n }\\n }\\n }\\n ],\\n \\\"marks\\\": [\\n {\\n \\\"type\\\": \\\"path\\\",\\n \\\"name\\\": \\\"edgeMark\\\",\\n \\\"from\\\": {\\\"data\\\": \\\"edges\\\"},\\n \\\"clip\\\": true,\\n \\\"encode\\\": {\\n \\\"update\\\": {\\n \\\"stroke\\\": [\\n {\\n \\\"test\\\": \\\"groupSelector && groupSelector.stack=='stk1'\\\",\\n \\\"scale\\\": \\\"color\\\",\\n \\\"field\\\": \\\"stk2\\\"\\n },\\n {\\\"scale\\\": \\\"color\\\", \\\"field\\\": \\\"stk1\\\"}\\n ],\\n \\\"strokeWidth\\\": {\\\"field\\\": \\\"strokeWidth\\\"},\\n \\\"path\\\": {\\\"field\\\": \\\"path\\\"},\\n \\\"strokeOpacity\\\": {\\n \\\"signal\\\": \\\"!groupSelector && (groupHover.stk1 == datum.stk1 || groupHover.stk2 == datum.stk2) ? 0.75 : 0.3\\\"\\n },\\n \\\"zindex\\\": {\\n \\\"signal\\\": \\\"!groupSelector && (groupHover.stk1 == datum.stk1 || groupHover.stk2 == datum.stk2) ? 1 : 0\\\"\\n },\\n \\\"tooltip\\\": {\\n \\\"signal\\\": \\\"{'title': datum.stk1 + ' → ' + datum.stk2 + ' ' + format(datum.size, '.2s') + 'B (' + format(datum.percentage, '.1%') + ')', 'IP Address': datum.stk3 + ' → ' + datum.stk2}\\\"\\n }\\n },\\n \\\"hover\\\": {\\\"strokeOpacity\\\": {\\\"value\\\": 0.75}}\\n }\\n },\\n {\\n \\\"type\\\": \\\"rect\\\",\\n \\\"name\\\": \\\"groupMark\\\",\\n \\\"from\\\": {\\\"data\\\": \\\"groups\\\"},\\n \\\"encode\\\": {\\n \\\"enter\\\": {\\n \\\"fill\\\": {\\\"scale\\\": \\\"color\\\", \\\"field\\\": \\\"grpId\\\"},\\n \\\"width\\\": {\\\"scale\\\": \\\"x\\\", \\\"band\\\": 1}\\n },\\n \\\"update\\\": {\\n \\\"x\\\": {\\\"scale\\\": \\\"x\\\", \\\"field\\\": \\\"stack\\\"},\\n \\\"y\\\": {\\\"field\\\": \\\"scaledY0\\\"},\\n \\\"y2\\\": {\\\"field\\\": \\\"scaledY1\\\"},\\n \\\"fillOpacity\\\": {\\\"value\\\": 0.7},\\n \\\"tooltip\\\": {\\n \\\"signal\\\": \\\"datum.grpId + ' ' + format(datum.total, '.2s') + 'B (' + format(datum.percentage, '.1%') + ')'\\\"\\n }\\n },\\n \\\"hover\\\": {\\\"fillOpacity\\\": {\\\"value\\\": 1}}\\n }\\n },\\n {\\n \\\"type\\\": \\\"text\\\",\\n \\\"from\\\": {\\\"data\\\": \\\"groups\\\"},\\n \\\"interactive\\\": false,\\n \\\"encode\\\": {\\n \\\"update\\\": {\\n \\\"x\\\": {\\n \\\"signal\\\": \\\"scale('x', datum.stack) + (datum.rightLabel ? bandwidth('x') + 8 : -8)\\\"\\n },\\n \\\"yc\\\": {\\\"signal\\\": \\\"(datum.scaledY0 + datum.scaledY1)/2\\\"},\\n \\\"align\\\": {\\\"signal\\\": \\\"datum.rightLabel ? 'left' : 'right'\\\"},\\n \\\"baseline\\\": {\\\"value\\\": \\\"middle\\\"},\\n \\\"fontWeight\\\": {\\\"value\\\": \\\"bold\\\"},\\n \\\"fontSize\\\": {\\\"value\\\": 12},\\n \\\"text\\\": {\\n \\\"signal\\\": \\\"abs(datum.scaledY0-datum.scaledY1) > 10 ? datum.grpId : ''\\\"\\n }\\n }\\n }\\n },\\n {\\n \\\"type\\\": \\\"group\\\",\\n \\\"data\\\": [\\n {\\n \\\"name\\\": \\\"dataForShowAll\\\",\\n \\\"values\\\": [{}],\\n \\\"transform\\\": [{\\\"type\\\": \\\"filter\\\", \\\"expr\\\": \\\"groupSelector\\\"}]\\n }\\n ],\\n \\\"encode\\\": {\\n \\\"enter\\\": {\\n \\\"xc\\\": {\\\"signal\\\": \\\"width/2\\\"},\\n \\\"y\\\": {\\\"value\\\": 30},\\n \\\"width\\\": {\\\"value\\\": 100},\\n \\\"height\\\": {\\\"value\\\": 36}\\n }\\n },\\n \\\"marks\\\": [\\n {\\n \\\"type\\\": \\\"group\\\",\\n \\\"name\\\": \\\"groupReset\\\",\\n \\\"from\\\": {\\\"data\\\": \\\"dataForShowAll\\\"},\\n \\\"encode\\\": {\\n \\\"enter\\\": {\\n \\\"cornerRadius\\\": {\\\"value\\\": 3.5},\\n \\\"fill\\\": {\\\"value\\\": \\\"#666666\\\"},\\n \\\"height\\\": {\\\"field\\\": {\\\"group\\\": \\\"height\\\"}},\\n \\\"width\\\": {\\\"field\\\": {\\\"group\\\": \\\"width\\\"}}\\n },\\n \\\"update\\\": {\\\"opacity\\\": {\\\"value\\\": 1}},\\n \\\"hover\\\": {\\\"fill\\\": {\\\"value\\\": \\\"#444444\\\"}}\\n },\\n \\\"marks\\\": [\\n {\\n \\\"type\\\": \\\"text\\\",\\n \\\"interactive\\\": false,\\n \\\"encode\\\": {\\n \\\"enter\\\": {\\n \\\"xc\\\": {\\\"field\\\": {\\\"group\\\": \\\"width\\\"}, \\\"mult\\\": 0.5},\\n \\\"yc\\\": {\\\"field\\\": {\\\"group\\\": \\\"height\\\"}, \\\"mult\\\": 0.5, \\\"offset\\\": 1},\\n \\\"align\\\": {\\\"value\\\": \\\"center\\\"},\\n \\\"baseline\\\": {\\\"value\\\": \\\"middle\\\"},\\n \\\"text\\\": {\\\"value\\\": \\\"Show All\\\"},\\n \\\"fontSize\\\": {\\\"value\\\": 14},\\n \\\"stroke\\\": {\\\"value\\\": \\\"#ecf0f1\\\"}\\n }\\n }\\n }\\n ]\\n }\\n ]\\n }\\n ],\\n \\\"signals\\\": [\\n {\\n \\\"name\\\": \\\"groupHover\\\",\\n \\\"value\\\": {},\\n \\\"on\\\": [\\n {\\n \\\"events\\\": \\\"@groupMark:mouseover\\\",\\n \\\"update\\\": \\\"{stk1:datum.stack=='stk1' && datum.grpId, stk2:datum.stack=='stk2' && datum.grpId}\\\"\\n },\\n {\\\"events\\\": \\\"mouseout\\\", \\\"update\\\": \\\"{}\\\"}\\n ]\\n },\\n {\\n \\\"name\\\": \\\"groupSelector\\\",\\n \\\"value\\\": false,\\n \\\"on\\\": [\\n {\\n \\\"events\\\": \\\"@groupMark:click!\\\",\\n \\\"update\\\": \\\"{stack:datum.stack, stk1:datum.stack=='stk1' && datum.grpId, stk2:datum.stack=='stk2' && datum.grpId}\\\"\\n },\\n {\\n \\\"events\\\": [\\n {\\\"type\\\": \\\"click\\\", \\\"markname\\\": \\\"groupReset\\\"},\\n {\\\"type\\\": \\\"dblclick\\\"}\\n ],\\n \\\"update\\\": \\\"false\\\"\\n }\\n ]\\n }\\n ]\\n}\"},\"title\":\"Pod-to-External Traffic Reverse Cumulative Bytes\"}"},"id":"0d0aac60-a93b-11eb-a7ef-5dcb53008c10","migrationVersion":{"visualization":"7.8.0"},"references":[],"type":"visualization","updated_at":"2021-08-07T23:30:40.150Z","version":"WzQsMV0="} -{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}"},"title":"Aggregated Tx Mbps by Pod Acting as Source","uiStateJSON":"{}","version":1,"visState":"{\"type\":\"metrics\",\"aggs\":[],\"params\":{\"id\":\"61ca57f0-469d-11e7-af02-69e470af7417\",\"type\":\"timeseries\",\"axis_position\":\"left\",\"axis_formatter\":\"number\",\"show_legend\":1,\"show_grid\":1,\"axis_min\":\"0\",\"filter\":\"\",\"axis_scale\":\"normal\",\"default_index_pattern\":\"flow-*\",\"default_timefield\":\"@timestamp\",\"isModelInvalid\":false,\"index_pattern\":\"flow-*\",\"interval\":\"1m\",\"time_field\":\"ipfix.flowEndSeconds\",\"series\":[{\"id\":\"61ca57f1-469d-11e7-af02-69e470af7417\",\"color\":\"rgba(144,201,227,1)\",\"split_mode\":\"terms\",\"metrics\":[{\"id\":\"a1ba0060-b9a7-11ea-9740-552c943910e4\",\"type\":\"sum\",\"field\":\"ipfix.throughput\"},{\"script\":\"params.bytes * 8 \",\"id\":\"dd0b81d0-b9a6-11ea-9740-552c943910e4\",\"type\":\"calculation\",\"variables\":[{\"id\":\"e1f87e50-b9a6-11ea-9740-552c943910e4\",\"name\":\"bytes\",\"field\":\"a1ba0060-b9a7-11ea-9740-552c943910e4\"}]}],\"separate_axis\":0,\"axis_position\":\"right\",\"formatter\":\"bytes\",\"chart_type\":\"line\",\"line_width\":\"2\",\"point_size\":\"0\",\"fill\":\"0.6\",\"stacked\":\"none\",\"split_color_mode\":\"rainbow\",\"label\":\"Bytes\",\"terms_field\":\"ipfix.sourcePodName.keyword\",\"terms_size\":\"30\",\"terms_order_by\":\"a1ba0060-b9a7-11ea-9740-552c943910e4\",\"value_template\":\"{{value}}its/s\",\"type\":\"timeseries\"}]},\"title\":\"Aggregated Tx Mbps by Pod Acting as Source\"}"},"id":"114eba40-55d4-11e8-a695-171fb712da36","migrationVersion":{"visualization":"7.8.0"},"references":[],"type":"visualization","updated_at":"2021-08-07T23:30:40.150Z","version":"WzUsMV0="} -{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}"},"title":"Reverse Cumulative Bandwidth by Pod-to-Service Flow","uiStateJSON":"{}","version":1,"visState":"{\"type\":\"metrics\",\"aggs\":[],\"params\":{\"id\":\"61ca57f0-469d-11e7-af02-69e470af7417\",\"type\":\"timeseries\",\"axis_position\":\"left\",\"axis_formatter\":\"number\",\"show_legend\":1,\"show_grid\":1,\"axis_min\":\"0\",\"filter\":\"\",\"axis_scale\":\"normal\",\"default_index_pattern\":\"flow-*\",\"default_timefield\":\"@timestamp\",\"isModelInvalid\":false,\"index_pattern\":\"flow-*\",\"interval\":\"1m\",\"time_field\":\"ipfix.flowEndSeconds\",\"series\":[{\"id\":\"61ca57f1-469d-11e7-af02-69e470af7417\",\"color\":\"rgba(144,201,227,1)\",\"split_mode\":\"terms\",\"metrics\":[{\"id\":\"a1ba0060-b9a7-11ea-9740-552c943910e4\",\"type\":\"sum\",\"field\":\"ipfix.reverseOctetTotalCountFromSourceNode\"},{\"script\":\"params.bytes * 8\",\"id\":\"dd0b81d0-b9a6-11ea-9740-552c943910e4\",\"type\":\"calculation\",\"variables\":[{\"id\":\"e1f87e50-b9a6-11ea-9740-552c943910e4\",\"name\":\"bytes\",\"field\":\"a1ba0060-b9a7-11ea-9740-552c943910e4\"}]}],\"separate_axis\":0,\"axis_position\":\"right\",\"formatter\":\"bytes\",\"chart_type\":\"line\",\"line_width\":1,\"point_size\":\"0\",\"fill\":\"0.6\",\"stacked\":\"none\",\"split_color_mode\":\"rainbow\",\"label\":\"Bytes\",\"terms_field\":\"ipfix.flowKeyPodToService.keyword\",\"terms_size\":\"30\",\"terms_order_by\":\"a1ba0060-b9a7-11ea-9740-552c943910e4\",\"value_template\":\"{{value}}\",\"type\":\"timeseries\"}]},\"title\":\"Reverse Cumulative Bandwidth by Pod-to-Service Flow\"}"},"id":"19374b20-4eea-11eb-b841-6bf6243fda88","migrationVersion":{"visualization":"7.8.0"},"references":[],"type":"visualization","updated_at":"2021-08-07T23:30:40.150Z","version":"WzYsMV0="} -{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}"},"title":"Pod-to-External Filter","uiStateJSON":"{}","version":1,"visState":"{\"type\":\"input_control_vis\",\"aggs\":[],\"params\":{\"updateFiltersOnChange\":true,\"useTimeFilter\":true,\"pinFilters\":true,\"controls\":[{\"id\":\"1526108909005\",\"fieldName\":\"ipfix.sourcePodNamespace.keyword\",\"label\":\"Source Pod Namespace\",\"type\":\"list\",\"options\":{\"type\":\"terms\",\"multiselect\":true,\"size\":1000,\"order\":\"desc\",\"dynamicOptions\":false},\"indexPatternRefName\":\"control_0_index_pattern\"},{\"id\":\"1526107640219\",\"fieldName\":\"ipfix.sourcePodName.keyword\",\"label\":\"Source Pod Name\",\"type\":\"list\",\"options\":{\"type\":\"terms\",\"multiselect\":true,\"size\":1000,\"order\":\"desc\",\"dynamicOptions\":false},\"indexPatternRefName\":\"control_1_index_pattern\"},{\"id\":\"1594408631049\",\"fieldName\":\"ipfix.sourceNodeName.keyword\",\"parent\":\"\",\"label\":\"Source Pod Node\",\"type\":\"list\",\"options\":{\"type\":\"terms\",\"multiselect\":true,\"dynamicOptions\":false,\"size\":1000,\"order\":\"desc\"},\"indexPatternRefName\":\"control_2_index_pattern\"},{\"id\":\"1526108883717\",\"fieldName\":\"ipfix.destinationIP.keyword\",\"label\":\"Destination IP\",\"type\":\"list\",\"options\":{\"type\":\"terms\",\"multiselect\":true,\"size\":1000,\"order\":\"desc\",\"dynamicOptions\":false},\"indexPatternRefName\":\"control_3_index_pattern\"},{\"id\":\"1609999080958\",\"parent\":\"\",\"type\":\"list\",\"options\":{\"type\":\"terms\",\"multiselect\":true,\"dynamicOptions\":false,\"size\":1000,\"order\":\"desc\"},\"fieldName\":\"ipfix.flowKeyPodToExternal.keyword\",\"label\":\"Flow Key (Pod-to-External)\",\"indexPatternRefName\":\"control_4_index_pattern\"}]},\"title\":\"Pod-to-External Filter\"}"},"id":"1ec263c0-a93c-11eb-a7ef-5dcb53008c10","migrationVersion":{"visualization":"7.8.0"},"references":[{"id":"e2ab2c50-b981-11ea-b16e-fb06687c3589","name":"control_0_index_pattern","type":"index-pattern"},{"id":"e2ab2c50-b981-11ea-b16e-fb06687c3589","name":"control_1_index_pattern","type":"index-pattern"},{"id":"e2ab2c50-b981-11ea-b16e-fb06687c3589","name":"control_2_index_pattern","type":"index-pattern"},{"id":"e2ab2c50-b981-11ea-b16e-fb06687c3589","name":"control_3_index_pattern","type":"index-pattern"},{"id":"e2ab2c50-b981-11ea-b16e-fb06687c3589","name":"control_4_index_pattern","type":"index-pattern"}],"type":"visualization","updated_at":"2021-08-07T23:30:40.150Z","version":"WzcsMV0="} -{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"language\":\"kuery\",\"query\":\"\"},\"filter\":[]}"},"title":"Rx Mbps by Pod-to-Service Flow","uiStateJSON":"{}","version":1,"visState":"{\"type\":\"metrics\",\"aggs\":[],\"params\":{\"id\":\"61ca57f0-469d-11e7-af02-69e470af7417\",\"type\":\"timeseries\",\"axis_position\":\"left\",\"axis_formatter\":\"number\",\"show_legend\":1,\"show_grid\":1,\"axis_min\":\"0\",\"filter\":\"\",\"axis_scale\":\"normal\",\"default_index_pattern\":\"flow-*\",\"default_timefield\":\"@timestamp\",\"isModelInvalid\":false,\"index_pattern\":\"flow-*\",\"interval\":\"1m\",\"time_field\":\"ipfix.flowEndSeconds\",\"background_color_rules\":[{\"id\":\"4010d970-50b9-11eb-8f30-87baf4f5ad91\"}],\"series\":[{\"id\":\"61ca57f1-469d-11e7-af02-69e470af7417\",\"color\":\"rgba(144,201,227,1)\",\"split_mode\":\"terms\",\"metrics\":[{\"id\":\"a1ba0060-b9a7-11ea-9740-552c943910e4\",\"type\":\"sum\",\"field\":\"ipfix.reverseThroughput\"},{\"script\":\"params.bytes * 8 \",\"id\":\"dd0b81d0-b9a6-11ea-9740-552c943910e4\",\"type\":\"calculation\",\"variables\":[{\"id\":\"e1f87e50-b9a6-11ea-9740-552c943910e4\",\"name\":\"bytes\",\"field\":\"a1ba0060-b9a7-11ea-9740-552c943910e4\"}]}],\"separate_axis\":0,\"axis_position\":\"right\",\"formatter\":\"bytes\",\"chart_type\":\"line\",\"line_width\":1,\"point_size\":\"0\",\"fill\":\"0.6\",\"stacked\":\"none\",\"split_color_mode\":\"rainbow\",\"label\":\"Bytes\",\"terms_field\":\"ipfix.flowKeyPodToService.keyword\",\"terms_size\":\"30\",\"terms_order_by\":\"a1ba0060-b9a7-11ea-9740-552c943910e4\",\"value_template\":\"{{value}}it/s\",\"type\":\"timeseries\",\"terms_exclude\":\"\",\"filter\":{\"query\":\"\",\"language\":\"kuery\"}}]},\"title\":\"Rx Mbps by Pod-to-Service Flow\"}"},"id":"20dfae20-520b-11eb-8385-698d3cd613b0","migrationVersion":{"visualization":"7.8.0"},"references":[],"type":"visualization","updated_at":"2021-08-07T23:30:40.150Z","version":"WzgsMV0="} -{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"lucene\"},\"filter\":[]}"},"title":"Node Reverse Cumulative Bytes","uiStateJSON":"{}","version":1,"visState":"{\"type\":\"vega\",\"aggs\":[],\"params\":{\"spec\":\"{\\n \\\"$schema\\\": \\\"https://vega.github.io/schema/vega/v3.0.json\\\",\\n \\\"data\\\": [\\n {\\n \\\"name\\\": \\\"rawData\\\",\\n \\\"url\\\": {\\n \\\"%context%\\\": true,\\n \\\"%timefield%\\\": \\\"@timestamp\\\",\\n \\\"index\\\": \\\"flow-*\\\",\\n \\\"body\\\": {\\n \\\"size\\\": 0,\\n \\\"aggs\\\": {\\n \\\"table\\\": {\\n \\\"composite\\\": {\\n \\\"size\\\": 1000,\\n \\\"sources\\\": [\\n {\\\"stk1\\\": {\\\"terms\\\": {\\\"field\\\": \\\"ipfix.sourceNodeName.keyword\\\"}}},\\n {\\\"stk2\\\": {\\\"terms\\\": {\\\"field\\\": \\\"ipfix.destinationNodeName.keyword\\\"}}},\\n {\\\"stk3\\\": {\\\"terms\\\": {\\\"field\\\": \\\"ipfix.sourceIP.keyword\\\"}}},\\n {\\\"stk4\\\": {\\\"terms\\\": {\\\"field\\\": \\\"ipfix.destinationIP.keyword\\\"}}}\\n ]\\n },\\n \\t\\t\\t\\\"aggs\\\": {\\n \\t\\t\\t\\t\\\"bytes\\\": {\\n \\t\\t\\t\\t\\t\\\"sum\\\": {\\n \\t\\t\\t\\t\\t\\t\\\"field\\\": \\\"ipfix.reverseOctetDeltaCountFromSourceNode\\\"\\n \\t\\t\\t\\t\\t}\\n \\t\\t\\t\\t}\\n \\t\\t\\t}\\n }\\n }\\n }\\n },\\n \\\"format\\\": {\\\"property\\\": \\\"aggregations.table.buckets\\\"},\\n \\\"transform\\\": [\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"(datum.key.stk1==''?datum.key.stk3:datum.key.stk1)\\\", \\\"as\\\": \\\"stk1\\\"},\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"(datum.key.stk2==''?datum.key.stk4:datum.key.stk2)\\\", \\\"as\\\": \\\"stk2\\\"},\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"datum.key.stk3\\\", \\\"as\\\": \\\"stk3\\\"},\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"datum.key.stk4\\\", \\\"as\\\": \\\"stk4\\\"},\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"datum.bytes.value\\\", \\\"as\\\": \\\"size\\\"}\\n ]\\n },\\n {\\n \\\"name\\\": \\\"nodes\\\",\\n \\\"source\\\": \\\"rawData\\\",\\n \\\"transform\\\": [\\n {\\n \\\"type\\\": \\\"filter\\\",\\n \\\"expr\\\": \\\"!groupSelector || groupSelector.stk1 == datum.stk1 || groupSelector.stk2 == datum.stk2\\\"\\n },\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"datum.stk1+datum.stk2+datum.stk3+datum.stk4\\\", \\\"as\\\": \\\"key\\\"},\\n {\\\"type\\\": \\\"fold\\\", \\\"fields\\\": [\\\"stk1\\\", \\\"stk2\\\"], \\\"as\\\": [\\\"stack\\\", \\\"grpId\\\"]},\\n {\\n \\\"type\\\": \\\"formula\\\",\\n \\\"expr\\\": \\\"datum.stack == 'stk1' ? datum.stk1+datum.stk2 : datum.stk2+datum.stk1\\\",\\n \\\"as\\\": \\\"sortField\\\"\\n },\\n {\\n \\\"type\\\": \\\"stack\\\",\\n \\\"groupby\\\": [\\\"stack\\\"],\\n \\\"sort\\\": {\\\"field\\\": \\\"sortField\\\", \\\"order\\\": \\\"descending\\\"},\\n \\\"field\\\": \\\"size\\\"\\n },\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"(datum.y0+datum.y1)/2\\\", \\\"as\\\": \\\"yc\\\"}\\n ]\\n },\\n {\\n \\\"name\\\": \\\"groups\\\",\\n \\\"source\\\": \\\"nodes\\\",\\n \\\"transform\\\": [\\n {\\n \\\"type\\\": \\\"aggregate\\\",\\n \\\"groupby\\\": [\\\"stack\\\", \\\"grpId\\\"],\\n \\\"fields\\\": [\\\"size\\\"],\\n \\\"ops\\\": [\\\"sum\\\"],\\n \\\"as\\\": [\\\"total\\\"]\\n },\\n {\\n \\\"type\\\": \\\"stack\\\",\\n \\\"groupby\\\": [\\\"stack\\\"],\\n \\\"sort\\\": {\\\"field\\\": \\\"grpId\\\", \\\"order\\\": \\\"descending\\\"},\\n \\\"field\\\": \\\"total\\\"\\n },\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"scale('y', datum.y0)\\\", \\\"as\\\": \\\"scaledY0\\\"},\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"scale('y', datum.y1)\\\", \\\"as\\\": \\\"scaledY1\\\"},\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"datum.stack == 'stk1'\\\", \\\"as\\\": \\\"rightLabel\\\"},\\n {\\n \\\"type\\\": \\\"formula\\\",\\n \\\"expr\\\": \\\"datum.total/domain('y')[1]\\\",\\n \\\"as\\\": \\\"percentage\\\"\\n }\\n ]\\n },\\n {\\n \\\"name\\\": \\\"destinationNodes\\\",\\n \\\"source\\\": \\\"nodes\\\",\\n \\\"transform\\\": [{\\\"type\\\": \\\"filter\\\", \\\"expr\\\": \\\"datum.stack == 'stk2'\\\"}]\\n },\\n {\\n \\\"name\\\": \\\"edges\\\",\\n \\\"source\\\": \\\"nodes\\\",\\n \\\"transform\\\": [\\n {\\\"type\\\": \\\"filter\\\", \\\"expr\\\": \\\"datum.stack == 'stk1'\\\"},\\n {\\n \\\"type\\\": \\\"lookup\\\",\\n \\\"from\\\": \\\"destinationNodes\\\",\\n \\\"key\\\": \\\"key\\\",\\n \\\"fields\\\": [\\\"key\\\"],\\n \\\"as\\\": [\\\"target\\\"]\\n },\\n {\\n \\\"type\\\": \\\"linkpath\\\",\\n \\\"orient\\\": \\\"horizontal\\\",\\n \\\"shape\\\": \\\"diagonal\\\",\\n \\\"sourceY\\\": {\\\"expr\\\": \\\"scale('y', datum.yc)\\\"},\\n \\\"sourceX\\\": {\\\"expr\\\": \\\"scale('x', 'stk1') + bandwidth('x')\\\"},\\n \\\"targetY\\\": {\\\"expr\\\": \\\"scale('y', datum.target.yc)\\\"},\\n \\\"targetX\\\": {\\\"expr\\\": \\\"scale('x', 'stk2')\\\"}\\n },\\n {\\n \\\"type\\\": \\\"formula\\\",\\n \\\"expr\\\": \\\"range('y')[0]-scale('y', datum.size)\\\",\\n \\\"as\\\": \\\"strokeWidth\\\"\\n },\\n {\\n \\\"type\\\": \\\"formula\\\",\\n \\\"expr\\\": \\\"datum.size/domain('y')[1]\\\",\\n \\\"as\\\": \\\"percentage\\\"\\n }\\n ]\\n }\\n ],\\n \\\"scales\\\": [\\n {\\n \\\"name\\\": \\\"x\\\",\\n \\\"type\\\": \\\"band\\\",\\n \\\"range\\\": \\\"width\\\",\\n \\\"domain\\\": [\\\"stk1\\\", \\\"stk2\\\"],\\n \\\"paddingOuter\\\": 0.01,\\n \\\"paddingInner\\\": 0.98\\n },\\n {\\n \\\"name\\\": \\\"y\\\",\\n \\\"type\\\": \\\"linear\\\",\\n \\\"range\\\": \\\"height\\\",\\n \\\"domain\\\": {\\\"data\\\": \\\"nodes\\\", \\\"field\\\": \\\"y1\\\"}\\n },\\n {\\n \\\"name\\\": \\\"color\\\",\\n \\\"type\\\": \\\"ordinal\\\",\\n \\\"range\\\": \\\"category\\\",\\n \\\"domain\\\": {\\\"data\\\": \\\"rawData\\\", \\\"fields\\\": [\\\"stk1\\\",\\\"stk2\\\"]}\\n },\\n {\\n \\\"name\\\": \\\"stackNames\\\",\\n \\\"type\\\": \\\"ordinal\\\",\\n \\\"range\\\": [\\\"Source\\\", \\\"Destination\\\"],\\n \\\"domain\\\": [\\\"stk1\\\", \\\"stk2\\\"]\\n }\\n ],\\n \\\"axes\\\": [\\n {\\n \\\"orient\\\": \\\"bottom\\\",\\n \\\"scale\\\": \\\"x\\\",\\n \\\"labelColor\\\": {\\n \\\"value\\\": \\\"#888888\\\"\\n },\\n \\\"encode\\\": {\\n \\\"labels\\\": {\\n \\\"update\\\": {\\n \\\"text\\\": {\\\"scale\\\": \\\"stackNames\\\", \\\"field\\\": \\\"value\\\"},\\n \\\"fontSize\\\": {\\\"value\\\": 14}\\n }\\n }\\n }\\n },\\n {\\n \\\"orient\\\": \\\"left\\\",\\n \\\"scale\\\": \\\"y\\\",\\n \\\"labelColor\\\": {\\n \\\"value\\\": \\\"#888888\\\"\\n },\\n \\\"encode\\\": {\\n \\\"labels\\\": {\\n \\\"update\\\": {\\n \\\"text\\\": {\\\"signal\\\": \\\"format(datum.value, '.2s') + 'B'\\\"},\\n \\\"fontSize\\\": {\\\"value\\\": 12}\\n }\\n }\\n }\\n }\\n ],\\n \\\"marks\\\": [\\n {\\n \\\"type\\\": \\\"path\\\",\\n \\\"name\\\": \\\"edgeMark\\\",\\n \\\"from\\\": {\\\"data\\\": \\\"edges\\\"},\\n \\\"clip\\\": true,\\n \\\"encode\\\": {\\n \\\"update\\\": {\\n \\\"stroke\\\": [\\n {\\n \\\"test\\\": \\\"groupSelector && groupSelector.stack=='stk1'\\\",\\n \\\"scale\\\": \\\"color\\\",\\n \\\"field\\\": \\\"stk2\\\"\\n },\\n {\\\"scale\\\": \\\"color\\\", \\\"field\\\": \\\"stk1\\\"}\\n ],\\n \\\"strokeWidth\\\": {\\\"field\\\": \\\"strokeWidth\\\"},\\n \\\"path\\\": {\\\"field\\\": \\\"path\\\"},\\n \\\"strokeOpacity\\\": {\\n \\\"signal\\\": \\\"!groupSelector && (groupHover.stk1 == datum.stk1 || groupHover.stk2 == datum.stk2) ? 0.75 : 0.3\\\"\\n },\\n \\\"zindex\\\": {\\n \\\"signal\\\": \\\"!groupSelector && (groupHover.stk1 == datum.stk1 || groupHover.stk2 == datum.stk2) ? 1 : 0\\\"\\n },\\n \\\"tooltip\\\": {\\n \\\"signal\\\": \\\"{'title': datum.stk1 + ' → ' + datum.stk2 + ' ' + format(datum.size, '.2s') + 'B (' + format(datum.percentage, '.1%') + ')', 'IP Address': datum.stk3 +' → ' + datum.stk4 }\\\"\\n }\\n },\\n \\\"hover\\\": {\\\"strokeOpacity\\\": {\\\"value\\\": 0.75}}\\n }\\n },\\n {\\n \\\"type\\\": \\\"rect\\\",\\n \\\"name\\\": \\\"groupMark\\\",\\n \\\"from\\\": {\\\"data\\\": \\\"groups\\\"},\\n \\\"encode\\\": {\\n \\\"enter\\\": {\\n \\\"fill\\\": {\\\"scale\\\": \\\"color\\\", \\\"field\\\": \\\"grpId\\\"},\\n \\\"width\\\": {\\\"scale\\\": \\\"x\\\", \\\"band\\\": 1}\\n },\\n \\\"update\\\": {\\n \\\"x\\\": {\\\"scale\\\": \\\"x\\\", \\\"field\\\": \\\"stack\\\"},\\n \\\"y\\\": {\\\"field\\\": \\\"scaledY0\\\"},\\n \\\"y2\\\": {\\\"field\\\": \\\"scaledY1\\\"},\\n \\\"fillOpacity\\\": {\\\"value\\\": 0.7},\\n \\\"tooltip\\\": {\\n \\\"signal\\\": \\\"datum.grpId + ' ' + format(datum.total, '.2s') + 'B (' + format(datum.percentage, '.1%') + ')'\\\"\\n }\\n },\\n \\\"hover\\\": {\\\"fillOpacity\\\": {\\\"value\\\": 1}}\\n }\\n },\\n {\\n \\\"type\\\": \\\"text\\\",\\n \\\"from\\\": {\\\"data\\\": \\\"groups\\\"},\\n \\\"interactive\\\": false,\\n \\\"encode\\\": {\\n \\\"update\\\": {\\n \\\"x\\\": {\\n \\\"signal\\\": \\\"scale('x', datum.stack) + (datum.rightLabel ? bandwidth('x') + 8 : -8)\\\"\\n },\\n \\\"yc\\\": {\\\"signal\\\": \\\"(datum.scaledY0 + datum.scaledY1)/2\\\"},\\n \\\"align\\\": {\\\"signal\\\": \\\"datum.rightLabel ? 'left' : 'right'\\\"},\\n \\\"baseline\\\": {\\\"value\\\": \\\"middle\\\"},\\n \\\"fontWeight\\\": {\\\"value\\\": \\\"bold\\\"},\\n \\\"fontSize\\\": {\\\"value\\\": 12},\\n \\\"text\\\": {\\n \\\"signal\\\": \\\"abs(datum.scaledY0-datum.scaledY1) > 10 ? datum.grpId : ''\\\"\\n }\\n }\\n }\\n },\\n {\\n \\\"type\\\": \\\"group\\\",\\n \\\"data\\\": [\\n {\\n \\\"name\\\": \\\"dataForShowAll\\\",\\n \\\"values\\\": [{}],\\n \\\"transform\\\": [{\\\"type\\\": \\\"filter\\\", \\\"expr\\\": \\\"groupSelector\\\"}]\\n }\\n ],\\n \\\"encode\\\": {\\n \\\"enter\\\": {\\n \\\"xc\\\": {\\\"signal\\\": \\\"width/2\\\"},\\n \\\"y\\\": {\\\"value\\\": 30},\\n \\\"width\\\": {\\\"value\\\": 100},\\n \\\"height\\\": {\\\"value\\\": 36}\\n }\\n },\\n \\\"marks\\\": [\\n {\\n \\\"type\\\": \\\"group\\\",\\n \\\"name\\\": \\\"groupReset\\\",\\n \\\"from\\\": {\\\"data\\\": \\\"dataForShowAll\\\"},\\n \\\"encode\\\": {\\n \\\"enter\\\": {\\n \\\"cornerRadius\\\": {\\\"value\\\": 3.5},\\n \\\"fill\\\": {\\\"value\\\": \\\"#666666\\\"},\\n \\\"height\\\": {\\\"field\\\": {\\\"group\\\": \\\"height\\\"}},\\n \\\"width\\\": {\\\"field\\\": {\\\"group\\\": \\\"width\\\"}}\\n },\\n \\\"update\\\": {\\\"opacity\\\": {\\\"value\\\": 1}},\\n \\\"hover\\\": {\\\"fill\\\": {\\\"value\\\": \\\"#444444\\\"}}\\n },\\n \\\"marks\\\": [\\n {\\n \\\"type\\\": \\\"text\\\",\\n \\\"interactive\\\": false,\\n \\\"encode\\\": {\\n \\\"enter\\\": {\\n \\\"xc\\\": {\\\"field\\\": {\\\"group\\\": \\\"width\\\"}, \\\"mult\\\": 0.5},\\n \\\"yc\\\": {\\\"field\\\": {\\\"group\\\": \\\"height\\\"}, \\\"mult\\\": 0.5, \\\"offset\\\": 1},\\n \\\"align\\\": {\\\"value\\\": \\\"center\\\"},\\n \\\"baseline\\\": {\\\"value\\\": \\\"middle\\\"},\\n \\\"text\\\": {\\\"value\\\": \\\"Show All\\\"},\\n \\\"fontSize\\\": {\\\"value\\\": 14},\\n \\\"stroke\\\": {\\\"value\\\": \\\"#ecf0f1\\\"}\\n }\\n }\\n }\\n ]\\n }\\n ]\\n }\\n ],\\n \\\"signals\\\": [\\n {\\n \\\"name\\\": \\\"groupHover\\\",\\n \\\"value\\\": {},\\n \\\"on\\\": [\\n {\\n \\\"events\\\": \\\"@groupMark:mouseover\\\",\\n \\\"update\\\": \\\"{stk1:datum.stack=='stk1' && datum.grpId, stk2:datum.stack=='stk2' && datum.grpId}\\\"\\n },\\n {\\\"events\\\": \\\"mouseout\\\", \\\"update\\\": \\\"{}\\\"}\\n ]\\n },\\n {\\n \\\"name\\\": \\\"groupSelector\\\",\\n \\\"value\\\": false,\\n \\\"on\\\": [\\n {\\n \\\"events\\\": \\\"@groupMark:click!\\\",\\n \\\"update\\\": \\\"{stack:datum.stack, stk1:datum.stack=='stk1' && datum.grpId, stk2:datum.stack=='stk2' && datum.grpId}\\\"\\n },\\n {\\n \\\"events\\\": [\\n {\\\"type\\\": \\\"click\\\", \\\"markname\\\": \\\"groupReset\\\"},\\n {\\\"type\\\": \\\"dblclick\\\"}\\n ],\\n \\\"update\\\": \\\"false\\\"\\n }\\n ]\\n }\\n ]\\n}\"},\"title\":\"Node Reverse Cumulative Bytes\"}"},"id":"211178f0-cd37-11ea-8911-87da3aad0324","migrationVersion":{"visualization":"7.8.0"},"references":[],"type":"visualization","updated_at":"2021-08-07T23:30:40.150Z","version":"WzksMV0="} -{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}"},"title":"Aggregated Tx Mbps by Node Acting as Source","uiStateJSON":"{}","version":1,"visState":"{\"type\":\"metrics\",\"aggs\":[],\"params\":{\"id\":\"61ca57f0-469d-11e7-af02-69e470af7417\",\"type\":\"timeseries\",\"axis_position\":\"left\",\"axis_formatter\":\"number\",\"show_legend\":1,\"show_grid\":1,\"axis_min\":\"0\",\"filter\":\"\",\"axis_scale\":\"normal\",\"default_index_pattern\":\"flow-*\",\"default_timefield\":\"@timestamp\",\"isModelInvalid\":false,\"index_pattern\":\"flow-*\",\"interval\":\"1m\",\"time_field\":\"ipfix.flowEndSeconds\",\"series\":[{\"id\":\"61ca57f1-469d-11e7-af02-69e470af7417\",\"color\":\"rgba(144,201,227,1)\",\"split_mode\":\"terms\",\"metrics\":[{\"id\":\"673aaae0-d084-11ea-9bdd-3d70b41d215d\",\"type\":\"sum\",\"field\":\"ipfix.throughput\"},{\"script\":\"params.bytes * 8 \",\"id\":\"dd0b81d0-b9a6-11ea-9740-552c943910e4\",\"type\":\"calculation\",\"variables\":[{\"id\":\"e1f87e50-b9a6-11ea-9740-552c943910e4\",\"name\":\"bytes\",\"field\":\"673aaae0-d084-11ea-9bdd-3d70b41d215d\"}]}],\"separate_axis\":0,\"axis_position\":\"right\",\"formatter\":\"bytes\",\"chart_type\":\"line\",\"line_width\":\"2\",\"point_size\":\"0\",\"fill\":\"0.6\",\"stacked\":\"none\",\"split_color_mode\":\"rainbow\",\"label\":\"Bytes\",\"terms_field\":\"ipfix.sourceNodeName.keyword\",\"terms_size\":\"30\",\"terms_order_by\":\"673aaae0-d084-11ea-9bdd-3d70b41d215d\",\"value_template\":\"{{value}}its/s\",\"type\":\"timeseries\"}]},\"title\":\"Aggregated Tx Mbps by Node Acting as Source\"}"},"id":"226c4040-cd32-11ea-8911-87da3aad0324","migrationVersion":{"visualization":"7.8.0"},"references":[],"type":"visualization","updated_at":"2021-08-07T23:30:40.150Z","version":"WzEwLDFd"} -{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"lucene\"},\"filter\":[]}"},"title":"Flow Record Nav","uiStateJSON":"{}","version":1,"visState":"{\"type\":\"metrics\",\"aggs\":[],\"params\":{\"id\":\"61ca57f0-469d-11e7-af02-69e470af7417\",\"type\":\"markdown\",\"series\":[{\"id\":\"61ca57f1-469d-11e7-af02-69e470af7417\",\"color\":\"#68BC00\",\"split_mode\":\"everything\",\"metrics\":[{\"id\":\"61ca57f2-469d-11e7-af02-69e470af7417\",\"type\":\"count\"}],\"separate_axis\":0,\"axis_position\":\"right\",\"formatter\":\"number\",\"chart_type\":\"line\",\"line_width\":1,\"point_size\":1,\"fill\":0.5,\"stacked\":\"none\",\"offset_time\":\"-5y\",\"split_color_mode\":\"gradient\"}],\"interval\":\"auto\",\"axis_position\":\"left\",\"axis_formatter\":\"number\",\"axis_scale\":\"normal\",\"show_legend\":1,\"show_grid\":1,\"markdown_vertical_align\":\"top\",\"default_index_pattern\":\"flow-*\",\"default_timefield\":\"@timestamp\",\"isModelInvalid\":false,\"time_field\":null,\"index_pattern\":\"flow-*\",\"markdown_css\":\"#markdown-61ca57f0-469d-11e7-af02-69e470af7417 p{color:#cccccc;margin-top:0;margin-bottom:8px;text-align:right}#markdown-61ca57f0-469d-11e7-af02-69e470af7417 p a{color:#1eadbd;font-size:17px;font-weight:bold;text-decoration:none}#markdown-61ca57f0-469d-11e7-af02-69e470af7417 p a strong{color:#ffac12;font-weight:bold}#markdown-61ca57f0-469d-11e7-af02-69e470af7417 hr{background-color:#cccccc;margin:0;height:1px}\",\"markdown_less\":\"p {\\n color: #cccccc;\\n margin-top: 0px;\\n margin-bottom: 8px;\\n text-align: right;\\n}\\np a {\\n color: #1eadbd;\\n\\tfont-size: 17px;\\n\\tfont-weight: bold;\\n\\ttext-decoration: none;\\n}\\np a strong {\\n color: #ffac12;\\n\\tfont-weight: bold;\\n}\\nhr {\\n background-color: #cccccc;\\n margin: 0px;\\n height: 1px;\\n}\",\"markdown\":\"[Overview](#/dashboard/3b331b30-b987-11ea-b16e-fb06687c3589) | [Pod-to-Pod Flow](#/dashboard/c2b15fb0-b9a8-11ea-b16e-fb06687c3589) | [Pod-to-External Flow](#/dashboard/3ed71e80-a92d-11eb-a7ef-5dcb53008c10) | [Pod-to-Service Flow](#/dashboard/6d77e8a0-513a-11eb-a19a-05e08a82dcf8) | [Node](#/dashboard/5400cdf0-cd2e-11ea-8911-87da3aad0324) | [Network Policy](#/dashboard/c5af6850-23b2-11eb-90d2-a7a4de48218a) | [**Flow Records**](#/dashboard/2ab9c220-b984-11ea-b16e-fb06687c3589)\\n\"},\"title\":\"Flow Record Nav\"}"},"id":"a96b21c0-b9ae-11ea-b16e-fb06687c3589","migrationVersion":{"visualization":"7.8.0"},"references":[],"type":"visualization","updated_at":"2021-08-07T23:30:40.150Z","version":"WzExLDFd"} -{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}"},"title":"Flow Record Count","uiStateJSON":"{}","version":1,"visState":"{\"type\":\"metrics\",\"aggs\":[],\"params\":{\"id\":\"61ca57f0-469d-11e7-af02-69e470af7417\",\"type\":\"metric\",\"series\":[{\"id\":\"61ca57f1-469d-11e7-af02-69e470af7417\",\"color\":\"rgba(144,201,227,1)\",\"split_mode\":\"everything\",\"metrics\":[{\"id\":\"61ca57f2-469d-11e7-af02-69e470af7417\",\"type\":\"count\"},{\"id\":\"bdd65820-55db-11e8-a230-6b3654bd4d61\",\"type\":\"cumulative_sum\",\"field\":\"61ca57f2-469d-11e7-af02-69e470af7417\"}],\"separate_axis\":0,\"axis_position\":\"right\",\"formatter\":\"number\",\"chart_type\":\"bar\",\"line_width\":1,\"point_size\":\"0\",\"fill\":\"0.6\",\"stacked\":\"stacked\",\"split_color_mode\":\"gradient\",\"label\":\"Flow Records\",\"terms_field\":\"event.type\",\"terms_size\":\"25\",\"filter\":\"\"}],\"interval\":\">=1m\",\"axis_position\":\"left\",\"axis_formatter\":\"number\",\"show_legend\":1,\"show_grid\":1,\"axis_min\":\"0\",\"background_color_rules\":[{\"id\":\"c5d26960-55db-11e8-a230-6b3654bd4d61\"}],\"axis_scale\":\"normal\",\"default_index_pattern\":\"flow-*\",\"default_timefield\":\"@timestamp\",\"isModelInvalid\":false,\"index_pattern\":\"flow-*\",\"time_field\":\"@timestamp\"},\"title\":\"Flow Record Count\"}"},"id":"5eef9cb0-b982-11ea-b16e-fb06687c3589","migrationVersion":{"visualization":"7.8.0"},"references":[],"type":"visualization","updated_at":"2021-08-07T23:30:40.150Z","version":"WzEyLDFd"} -{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}"},"title":"Filter","uiStateJSON":"{}","version":1,"visState":"{\"type\":\"input_control_vis\",\"aggs\":[],\"params\":{\"updateFiltersOnChange\":true,\"useTimeFilter\":true,\"pinFilters\":true,\"controls\":[{\"id\":\"1526108909005\",\"fieldName\":\"ipfix.sourcePodNamespace.keyword\",\"label\":\"Source Pod Namespace\",\"type\":\"list\",\"options\":{\"type\":\"terms\",\"multiselect\":true,\"size\":1000,\"order\":\"desc\",\"dynamicOptions\":false},\"indexPatternRefName\":\"control_0_index_pattern\"},{\"id\":\"1526107640219\",\"fieldName\":\"ipfix.sourcePodName.keyword\",\"label\":\"Source Pod Name\",\"type\":\"list\",\"options\":{\"type\":\"terms\",\"multiselect\":true,\"size\":1000,\"order\":\"desc\",\"dynamicOptions\":false},\"indexPatternRefName\":\"control_1_index_pattern\"},{\"id\":\"1594408631049\",\"fieldName\":\"ipfix.sourceNodeName.keyword\",\"parent\":\"\",\"label\":\"Source Pod Node\",\"type\":\"list\",\"options\":{\"type\":\"terms\",\"multiselect\":true,\"dynamicOptions\":false,\"size\":1000,\"order\":\"desc\"},\"indexPatternRefName\":\"control_2_index_pattern\"},{\"id\":\"1592936602245\",\"fieldName\":\"ipfix.destinationPodNamespace.keyword\",\"parent\":\"\",\"label\":\"Destination Pod Namespace\",\"type\":\"list\",\"options\":{\"type\":\"terms\",\"multiselect\":true,\"dynamicOptions\":false,\"size\":1000,\"order\":\"desc\"},\"indexPatternRefName\":\"control_3_index_pattern\"},{\"id\":\"1526108883717\",\"fieldName\":\"ipfix.destinationPodName.keyword\",\"label\":\"Destination Pod Name\",\"type\":\"list\",\"options\":{\"type\":\"terms\",\"multiselect\":true,\"size\":1000,\"order\":\"desc\",\"dynamicOptions\":false},\"indexPatternRefName\":\"control_4_index_pattern\"},{\"id\":\"1594408650442\",\"fieldName\":\"ipfix.destinationNodeName.keyword\",\"parent\":\"\",\"label\":\"Destination Pod Node\",\"type\":\"list\",\"options\":{\"type\":\"terms\",\"multiselect\":true,\"dynamicOptions\":false,\"size\":1000,\"order\":\"desc\"},\"indexPatternRefName\":\"control_5_index_pattern\"},{\"id\":\"1595904313889\",\"fieldName\":\"ipfix.destinationServicePortName.keyword\",\"parent\":\"\",\"label\":\"Destination Service Name\",\"type\":\"list\",\"options\":{\"type\":\"terms\",\"multiselect\":true,\"dynamicOptions\":false,\"size\":1000,\"order\":\"desc\"},\"indexPatternRefName\":\"control_6_index_pattern\"},{\"id\":\"1609999080958\",\"parent\":\"\",\"type\":\"list\",\"options\":{\"type\":\"terms\",\"multiselect\":true,\"dynamicOptions\":false,\"size\":1000,\"order\":\"desc\"},\"fieldName\":\"ipfix.flowKey.keyword\",\"label\":\"Flow Key\",\"indexPatternRefName\":\"control_7_index_pattern\"},{\"id\":\"1618607047867\",\"fieldName\":\"ipfix.flowTypeStr.keyword\",\"parent\":\"\",\"label\":\"Flow Type\",\"type\":\"list\",\"options\":{\"type\":\"terms\",\"multiselect\":true,\"dynamicOptions\":false,\"size\":1000,\"order\":\"desc\"},\"indexPatternRefName\":\"control_8_index_pattern\"}]},\"title\":\"Filter\"}"},"id":"df9ec4c0-b983-11ea-b16e-fb06687c3589","migrationVersion":{"visualization":"7.8.0"},"references":[{"id":"e2ab2c50-b981-11ea-b16e-fb06687c3589","name":"control_0_index_pattern","type":"index-pattern"},{"id":"e2ab2c50-b981-11ea-b16e-fb06687c3589","name":"control_1_index_pattern","type":"index-pattern"},{"id":"e2ab2c50-b981-11ea-b16e-fb06687c3589","name":"control_2_index_pattern","type":"index-pattern"},{"id":"e2ab2c50-b981-11ea-b16e-fb06687c3589","name":"control_3_index_pattern","type":"index-pattern"},{"id":"e2ab2c50-b981-11ea-b16e-fb06687c3589","name":"control_4_index_pattern","type":"index-pattern"},{"id":"e2ab2c50-b981-11ea-b16e-fb06687c3589","name":"control_5_index_pattern","type":"index-pattern"},{"id":"e2ab2c50-b981-11ea-b16e-fb06687c3589","name":"control_6_index_pattern","type":"index-pattern"},{"id":"e2ab2c50-b981-11ea-b16e-fb06687c3589","name":"control_7_index_pattern","type":"index-pattern"},{"id":"e2ab2c50-b981-11ea-b16e-fb06687c3589","name":"control_8_index_pattern","type":"index-pattern"}],"type":"visualization","updated_at":"2021-08-07T23:30:40.150Z","version":"WzEzLDFd"} -{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}"},"title":"Flow Record Graph","uiStateJSON":"{}","version":1,"visState":"{\"type\":\"metrics\",\"aggs\":[],\"params\":{\"id\":\"61ca57f0-469d-11e7-af02-69e470af7417\",\"type\":\"timeseries\",\"interval\":\">=1m\",\"axis_position\":\"left\",\"axis_formatter\":\"number\",\"show_legend\":1,\"show_grid\":1,\"axis_min\":\"0\",\"axis_scale\":\"normal\",\"default_index_pattern\":\"flow-*\",\"default_timefield\":\"@timestamp\",\"isModelInvalid\":false,\"index_pattern\":\"flow-*\",\"time_field\":\"@timestamp\",\"series\":[{\"id\":\"61ca57f1-469d-11e7-af02-69e470af7417\",\"color\":\"rgba(144,201,227,1)\",\"split_mode\":\"terms\",\"metrics\":[{\"id\":\"61ca57f2-469d-11e7-af02-69e470af7417\",\"type\":\"count\"}],\"separate_axis\":0,\"axis_position\":\"right\",\"formatter\":\"number\",\"chart_type\":\"bar\",\"line_width\":1,\"point_size\":\"0\",\"fill\":\"0.6\",\"stacked\":\"stacked\",\"split_color_mode\":\"gradient\",\"label\":\"Flows\",\"terms_field\":null,\"terms_size\":\"50\",\"filter\":\"\"}]},\"title\":\"Flow Record Graph\"}"},"id":"5fc91750-b983-11ea-b16e-fb06687c3589","migrationVersion":{"visualization":"7.8.0"},"references":[],"type":"visualization","updated_at":"2021-08-07T23:30:40.150Z","version":"WzE0LDFd"} -{"attributes":{"columns":["ipfix.sourceIP","ipfix.destinationIP","ipfix.sourcePodName","ipfix.destinationPodName","ipfix.bytes","ipfix.packets"],"description":"","hits":0,"kibanaSavedObjectMeta":{"searchSourceJSON":"{\"highlightAll\":true,\"version\":true,\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\",\"filter\":[]}"},"sort":[["@timestamp","desc"]],"title":"Antrea: Flow Record Table","version":1},"id":"adeb7dc0-b982-11ea-b16e-fb06687c3589","migrationVersion":{"search":"7.4.0"},"references":[{"id":"e2ab2c50-b981-11ea-b16e-fb06687c3589","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"}],"type":"search","updated_at":"2021-08-07T23:30:40.150Z","version":"WzE1LDFd"} -{"attributes":{"description":"","hits":0,"kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"language\":\"kuery\",\"query\":\"\"},\"filter\":[]}"},"optionsJSON":"{\"hidePanelTitles\":false,\"useMargins\":true}","panelsJSON":"[{\"embeddableConfig\":{\"title\":\"\"},\"gridData\":{\"h\":3,\"i\":\"fef76e06-bf55-4447-bd27-bb06afa1a590\",\"w\":48,\"x\":0,\"y\":0},\"panelIndex\":\"fef76e06-bf55-4447-bd27-bb06afa1a590\",\"version\":\"7.8.0\",\"panelRefName\":\"panel_0\"},{\"embeddableConfig\":{},\"gridData\":{\"h\":10,\"i\":\"9540e56c-70eb-498e-a587-6fc4b4fa2d98\",\"w\":11,\"x\":0,\"y\":3},\"panelIndex\":\"9540e56c-70eb-498e-a587-6fc4b4fa2d98\",\"version\":\"7.8.0\",\"panelRefName\":\"panel_1\"},{\"embeddableConfig\":{\"title\":\"\"},\"gridData\":{\"h\":10,\"i\":\"69a239b5-0a27-4108-937f-2e8396f7ee61\",\"w\":37,\"x\":11,\"y\":3},\"panelIndex\":\"69a239b5-0a27-4108-937f-2e8396f7ee61\",\"version\":\"7.8.0\",\"panelRefName\":\"panel_2\"},{\"embeddableConfig\":{},\"gridData\":{\"h\":10,\"i\":\"f98c36a9-f87b-45c2-85ed-f2d8782f9404\",\"w\":48,\"x\":0,\"y\":13},\"panelIndex\":\"f98c36a9-f87b-45c2-85ed-f2d8782f9404\",\"version\":\"7.8.0\",\"panelRefName\":\"panel_3\"},{\"embeddableConfig\":{},\"gridData\":{\"h\":65,\"i\":\"9eb3e16c-8161-4d9d-bb5c-431d3b622890\",\"w\":48,\"x\":0,\"y\":23},\"panelIndex\":\"9eb3e16c-8161-4d9d-bb5c-431d3b622890\",\"version\":\"7.8.0\",\"panelRefName\":\"panel_4\"}]","timeRestore":false,"title":"Flow Record Dashboard","version":1},"id":"2ab9c220-b984-11ea-b16e-fb06687c3589","migrationVersion":{"dashboard":"7.3.0"},"references":[{"id":"a96b21c0-b9ae-11ea-b16e-fb06687c3589","name":"panel_0","type":"visualization"},{"id":"5eef9cb0-b982-11ea-b16e-fb06687c3589","name":"panel_1","type":"visualization"},{"id":"df9ec4c0-b983-11ea-b16e-fb06687c3589","name":"panel_2","type":"visualization"},{"id":"5fc91750-b983-11ea-b16e-fb06687c3589","name":"panel_3","type":"visualization"},{"id":"adeb7dc0-b982-11ea-b16e-fb06687c3589","name":"panel_4","type":"search"}],"type":"dashboard","updated_at":"2021-08-07T23:30:40.150Z","version":"WzE2LDFd"} -{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"lucene\"},\"filter\":[]}"},"title":"Pod-to-Pod Traffic Reverse Cumulative Bytes","uiStateJSON":"{}","version":1,"visState":"{\"type\":\"vega\",\"aggs\":[],\"params\":{\"spec\":\"{\\n \\\"$schema\\\": \\\"https://vega.github.io/schema/vega/v3.0.json\\\",\\n \\\"data\\\": [\\n {\\n \\\"name\\\": \\\"rawData\\\",\\n \\\"url\\\": {\\n \\\"%context%\\\": true,\\n \\\"%timefield%\\\": \\\"@timestamp\\\",\\n \\\"index\\\": \\\"flow-*\\\",\\n \\\"body\\\": {\\n \\\"size\\\": 0,\\n \\\"aggs\\\": {\\n \\\"table\\\": {\\n \\\"composite\\\": {\\n \\\"size\\\": 1000,\\n \\\"sources\\\": [\\n {\\\"stk1\\\": {\\\"terms\\\": {\\\"field\\\": \\\"ipfix.sourcePodName.keyword\\\"}}},\\n {\\\"stk1ns\\\": {\\\"terms\\\": {\\\"field\\\": \\\"ipfix.sourcePodNamespace.keyword\\\"}}},\\n {\\\"stk2\\\": {\\\"terms\\\": {\\\"field\\\": \\\"ipfix.destinationPodName.keyword\\\"}}},\\n {\\\"stk2ns\\\": {\\\"terms\\\": {\\\"field\\\": \\\"ipfix.destinationPodNamespace.keyword\\\"}}},\\n {\\\"stk3\\\": {\\\"terms\\\": {\\\"field\\\": \\\"ipfix.sourceIP.keyword\\\"}}},\\n {\\\"stk4\\\": {\\\"terms\\\": {\\\"field\\\": \\\"ipfix.destinationIP.keyword\\\"}}}\\n {\\\"stk5\\\": {\\\"terms\\\": {\\\"field\\\": \\\"ipfix.flowTypeStr.keyword\\\"}}}\\n ]\\n },\\n \\t\\t\\t\\\"aggs\\\": {\\n \\t\\t\\t\\t\\\"bytes\\\": {\\n \\t\\t\\t\\t\\t\\\"sum\\\": {\\n \\t\\t\\t\\t\\t\\t\\\"field\\\": \\\"ipfix.reverseOctetDeltaCountFromSourceNode\\\"\\n \\t\\t\\t\\t\\t}\\n \\t\\t\\t\\t}\\n \\t\\t\\t}\\n }\\n }\\n }\\n },\\n \\\"format\\\": {\\\"property\\\": \\\"aggregations.table.buckets\\\"},\\n \\\"transform\\\": [\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"datum.key.stk1ns +'/'+ datum.key.stk1\\\", \\\"as\\\": \\\"stk1s\\\"},\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"(datum.key.stk1==''?datum.key.stk3:datum.stk1s)\\\", \\\"as\\\": \\\"stk1\\\"},\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"datum.key.stk2ns +'/'+ datum.key.stk2\\\", \\\"as\\\": \\\"stk2s\\\"},\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"(datum.key.stk2==''?datum.key.stk4:datum.stk2s)\\\", \\\"as\\\": \\\"stk2\\\"},\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"datum.key.stk3\\\", \\\"as\\\": \\\"stk3\\\"},\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"datum.key.stk4\\\", \\\"as\\\": \\\"stk4\\\"},\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"datum.key.stk5\\\", \\\"as\\\": \\\"stk5\\\"},\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"datum.bytes.value\\\", \\\"as\\\": \\\"size\\\"}\\n ]\\n },\\n {\\n \\\"name\\\": \\\"nodes\\\",\\n \\\"source\\\": \\\"rawData\\\",\\n \\\"transform\\\": [\\n {\\n \\\"type\\\": \\\"filter\\\",\\n \\\"expr\\\": \\\"(datum.stk5 == 'Inter-Node' || datum.stk5 == 'Intra-Node') && !groupSelector || groupSelector.stk1 == datum.stk1 || groupSelector.stk2 == datum.stk2\\\"\\n },\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"datum.stk1+datum.stk2\\\", \\\"as\\\": \\\"key\\\"},\\n {\\\"type\\\": \\\"fold\\\", \\\"fields\\\": [\\\"stk1\\\", \\\"stk2\\\"], \\\"as\\\": [\\\"stack\\\", \\\"grpId\\\"]},\\n {\\n \\\"type\\\": \\\"formula\\\",\\n \\\"expr\\\": \\\"datum.stack == 'stk1' ? datum.stk1+datum.stk2 : datum.stk2+datum.stk1\\\",\\n \\\"as\\\": \\\"sortField\\\"\\n },\\n {\\n \\\"type\\\": \\\"stack\\\",\\n \\\"groupby\\\": [\\\"stack\\\"],\\n \\\"sort\\\": {\\\"field\\\": \\\"sortField\\\", \\\"order\\\": \\\"descending\\\"},\\n \\\"field\\\": \\\"size\\\"\\n },\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"(datum.y0+datum.y1)/2\\\", \\\"as\\\": \\\"yc\\\"}\\n ]\\n },\\n {\\n \\\"name\\\": \\\"groups\\\",\\n \\\"source\\\": \\\"nodes\\\",\\n \\\"transform\\\": [\\n {\\n \\\"type\\\": \\\"aggregate\\\",\\n \\\"groupby\\\": [\\\"stack\\\", \\\"grpId\\\"],\\n \\\"fields\\\": [\\\"size\\\"],\\n \\\"ops\\\": [\\\"sum\\\"],\\n \\\"as\\\": [\\\"total\\\"]\\n },\\n {\\n \\\"type\\\": \\\"stack\\\",\\n \\\"groupby\\\": [\\\"stack\\\"],\\n \\\"sort\\\": {\\\"field\\\": \\\"grpId\\\", \\\"order\\\": \\\"descending\\\"},\\n \\\"field\\\": \\\"total\\\"\\n },\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"scale('y', datum.y0)\\\", \\\"as\\\": \\\"scaledY0\\\"},\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"scale('y', datum.y1)\\\", \\\"as\\\": \\\"scaledY1\\\"},\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"datum.stack == 'stk1'\\\", \\\"as\\\": \\\"rightLabel\\\"},\\n {\\n \\\"type\\\": \\\"formula\\\",\\n \\\"expr\\\": \\\"datum.total/domain('y')[1]\\\",\\n \\\"as\\\": \\\"percentage\\\"\\n }\\n ]\\n },\\n {\\n \\\"name\\\": \\\"destinationNodes\\\",\\n \\\"source\\\": \\\"nodes\\\",\\n \\\"transform\\\": [{\\\"type\\\": \\\"filter\\\", \\\"expr\\\": \\\"datum.stack == 'stk2'\\\"}]\\n },\\n {\\n \\\"name\\\": \\\"edges\\\",\\n \\\"source\\\": \\\"nodes\\\",\\n \\\"transform\\\": [\\n {\\\"type\\\": \\\"filter\\\", \\\"expr\\\": \\\"datum.stack == 'stk1'\\\"},\\n {\\n \\\"type\\\": \\\"lookup\\\",\\n \\\"from\\\": \\\"destinationNodes\\\",\\n \\\"key\\\": \\\"key\\\",\\n \\\"fields\\\": [\\\"key\\\"],\\n \\\"as\\\": [\\\"target\\\"]\\n },\\n {\\n \\\"type\\\": \\\"linkpath\\\",\\n \\\"orient\\\": \\\"horizontal\\\",\\n \\\"shape\\\": \\\"diagonal\\\",\\n \\\"sourceY\\\": {\\\"expr\\\": \\\"scale('y', datum.yc)\\\"},\\n \\\"sourceX\\\": {\\\"expr\\\": \\\"scale('x', 'stk1') + bandwidth('x')\\\"},\\n \\\"targetY\\\": {\\\"expr\\\": \\\"scale('y', datum.target.yc)\\\"},\\n \\\"targetX\\\": {\\\"expr\\\": \\\"scale('x', 'stk2')\\\"}\\n },\\n {\\n \\\"type\\\": \\\"formula\\\",\\n \\\"expr\\\": \\\"range('y')[0]-scale('y', datum.size)\\\",\\n \\\"as\\\": \\\"strokeWidth\\\"\\n },\\n {\\n \\\"type\\\": \\\"formula\\\",\\n \\\"expr\\\": \\\"datum.size/domain('y')[1]\\\",\\n \\\"as\\\": \\\"percentage\\\"\\n }\\n ]\\n }\\n ],\\n \\\"scales\\\": [\\n {\\n \\\"name\\\": \\\"x\\\",\\n \\\"type\\\": \\\"band\\\",\\n \\\"range\\\": \\\"width\\\",\\n \\\"domain\\\": [\\\"stk1\\\", \\\"stk2\\\"],\\n \\\"paddingOuter\\\": 0.01,\\n \\\"paddingInner\\\": 0.98\\n },\\n {\\n \\\"name\\\": \\\"y\\\",\\n \\\"type\\\": \\\"linear\\\",\\n \\\"range\\\": \\\"height\\\",\\n \\\"domain\\\": {\\\"data\\\": \\\"nodes\\\", \\\"field\\\": \\\"y1\\\"}\\n },\\n {\\n \\\"name\\\": \\\"color\\\",\\n \\\"type\\\": \\\"ordinal\\\",\\n \\\"range\\\": \\\"category\\\",\\n \\\"domain\\\": {\\\"data\\\": \\\"rawData\\\", \\\"fields\\\": [\\\"stk1\\\",\\\"stk2\\\"]}\\n },\\n {\\n \\\"name\\\": \\\"stackNames\\\",\\n \\\"type\\\": \\\"ordinal\\\",\\n \\\"range\\\": [\\\"Source Pod\\\", \\\"Destination Pod\\\"],\\n \\\"domain\\\": [\\\"stk1\\\", \\\"stk2\\\"]\\n }\\n ],\\n \\\"axes\\\": [\\n {\\n \\\"orient\\\": \\\"bottom\\\",\\n \\\"scale\\\": \\\"x\\\",\\n \\\"labelColor\\\": {\\n \\\"value\\\": \\\"#888888\\\"\\n },\\n \\\"encode\\\": {\\n \\\"labels\\\": {\\n \\\"update\\\": {\\n \\\"text\\\": {\\\"scale\\\": \\\"stackNames\\\", \\\"field\\\": \\\"value\\\"},\\n \\\"fontSize\\\": {\\\"value\\\": 14}\\n }\\n }\\n }\\n },\\n {\\n \\\"orient\\\": \\\"left\\\",\\n \\\"scale\\\": \\\"y\\\",\\n \\\"labelColor\\\": {\\n \\\"value\\\": \\\"#888888\\\"\\n },\\n \\\"encode\\\": {\\n \\\"labels\\\": {\\n \\\"update\\\": {\\n \\\"text\\\": {\\\"signal\\\": \\\"format(datum.value, '.2s') + 'B'\\\"},\\n \\\"fontSize\\\": {\\\"value\\\": 12}\\n }\\n }\\n }\\n }\\n ],\\n \\\"marks\\\": [\\n {\\n \\\"type\\\": \\\"path\\\",\\n \\\"name\\\": \\\"edgeMark\\\",\\n \\\"from\\\": {\\\"data\\\": \\\"edges\\\"},\\n \\\"clip\\\": true,\\n \\\"encode\\\": {\\n \\\"update\\\": {\\n \\\"stroke\\\": [\\n {\\n \\\"test\\\": \\\"groupSelector && groupSelector.stack=='stk1'\\\",\\n \\\"scale\\\": \\\"color\\\",\\n \\\"field\\\": \\\"stk2\\\"\\n },\\n {\\\"scale\\\": \\\"color\\\", \\\"field\\\": \\\"stk1\\\"}\\n ],\\n \\\"strokeWidth\\\": {\\\"field\\\": \\\"strokeWidth\\\"},\\n \\\"path\\\": {\\\"field\\\": \\\"path\\\"},\\n \\\"strokeOpacity\\\": {\\n \\\"signal\\\": \\\"!groupSelector && (groupHover.stk1 == datum.stk1 || groupHover.stk2 == datum.stk2) ? 0.75 : 0.3\\\"\\n },\\n \\\"zindex\\\": {\\n \\\"signal\\\": \\\"!groupSelector && (groupHover.stk1 == datum.stk1 || groupHover.stk2 == datum.stk2) ? 1 : 0\\\"\\n },\\n \\\"tooltip\\\": {\\n \\\"signal\\\": \\\"{'title': datum.stk1 + ' → ' + datum.stk2 + ' ' + format(datum.size, '.2s') + 'B (' + format(datum.percentage, '.1%') + ')', 'IP Address': datum.stk3 + ' → ' + datum.stk4}\\\"\\n }\\n },\\n \\\"hover\\\": {\\\"strokeOpacity\\\": {\\\"value\\\": 0.75}}\\n }\\n },\\n {\\n \\\"type\\\": \\\"rect\\\",\\n \\\"name\\\": \\\"groupMark\\\",\\n \\\"from\\\": {\\\"data\\\": \\\"groups\\\"},\\n \\\"encode\\\": {\\n \\\"enter\\\": {\\n \\\"fill\\\": {\\\"scale\\\": \\\"color\\\", \\\"field\\\": \\\"grpId\\\"},\\n \\\"width\\\": {\\\"scale\\\": \\\"x\\\", \\\"band\\\": 1}\\n },\\n \\\"update\\\": {\\n \\\"x\\\": {\\\"scale\\\": \\\"x\\\", \\\"field\\\": \\\"stack\\\"},\\n \\\"y\\\": {\\\"field\\\": \\\"scaledY0\\\"},\\n \\\"y2\\\": {\\\"field\\\": \\\"scaledY1\\\"},\\n \\\"fillOpacity\\\": {\\\"value\\\": 0.7},\\n \\\"tooltip\\\": {\\n \\\"signal\\\": \\\"datum.grpId + ' ' + format(datum.total, '.2s') + 'B (' + format(datum.percentage, '.1%') + ')'\\\"\\n }\\n },\\n \\\"hover\\\": {\\\"fillOpacity\\\": {\\\"value\\\": 1}}\\n }\\n },\\n {\\n \\\"type\\\": \\\"text\\\",\\n \\\"from\\\": {\\\"data\\\": \\\"groups\\\"},\\n \\\"interactive\\\": false,\\n \\\"encode\\\": {\\n \\\"update\\\": {\\n \\\"x\\\": {\\n \\\"signal\\\": \\\"scale('x', datum.stack) + (datum.rightLabel ? bandwidth('x') + 8 : -8)\\\"\\n },\\n \\\"yc\\\": {\\\"signal\\\": \\\"(datum.scaledY0 + datum.scaledY1)/2\\\"},\\n \\\"align\\\": {\\\"signal\\\": \\\"datum.rightLabel ? 'left' : 'right'\\\"},\\n \\\"baseline\\\": {\\\"value\\\": \\\"middle\\\"},\\n \\\"fontWeight\\\": {\\\"value\\\": \\\"bold\\\"},\\n \\\"fontSize\\\": {\\\"value\\\": 12},\\n \\\"text\\\": {\\n \\\"signal\\\": \\\"abs(datum.scaledY0-datum.scaledY1) > 10 ? datum.grpId : ''\\\"\\n }\\n }\\n }\\n },\\n {\\n \\\"type\\\": \\\"group\\\",\\n \\\"data\\\": [\\n {\\n \\\"name\\\": \\\"dataForShowAll\\\",\\n \\\"values\\\": [{}],\\n \\\"transform\\\": [{\\\"type\\\": \\\"filter\\\", \\\"expr\\\": \\\"groupSelector\\\"}]\\n }\\n ],\\n \\\"encode\\\": {\\n \\\"enter\\\": {\\n \\\"xc\\\": {\\\"signal\\\": \\\"width/2\\\"},\\n \\\"y\\\": {\\\"value\\\": 30},\\n \\\"width\\\": {\\\"value\\\": 100},\\n \\\"height\\\": {\\\"value\\\": 36}\\n }\\n },\\n \\\"marks\\\": [\\n {\\n \\\"type\\\": \\\"group\\\",\\n \\\"name\\\": \\\"groupReset\\\",\\n \\\"from\\\": {\\\"data\\\": \\\"dataForShowAll\\\"},\\n \\\"encode\\\": {\\n \\\"enter\\\": {\\n \\\"cornerRadius\\\": {\\\"value\\\": 3.5},\\n \\\"fill\\\": {\\\"value\\\": \\\"#666666\\\"},\\n \\\"height\\\": {\\\"field\\\": {\\\"group\\\": \\\"height\\\"}},\\n \\\"width\\\": {\\\"field\\\": {\\\"group\\\": \\\"width\\\"}}\\n },\\n \\\"update\\\": {\\\"opacity\\\": {\\\"value\\\": 1}},\\n \\\"hover\\\": {\\\"fill\\\": {\\\"value\\\": \\\"#444444\\\"}}\\n },\\n \\\"marks\\\": [\\n {\\n \\\"type\\\": \\\"text\\\",\\n \\\"interactive\\\": false,\\n \\\"encode\\\": {\\n \\\"enter\\\": {\\n \\\"xc\\\": {\\\"field\\\": {\\\"group\\\": \\\"width\\\"}, \\\"mult\\\": 0.5},\\n \\\"yc\\\": {\\\"field\\\": {\\\"group\\\": \\\"height\\\"}, \\\"mult\\\": 0.5, \\\"offset\\\": 1},\\n \\\"align\\\": {\\\"value\\\": \\\"center\\\"},\\n \\\"baseline\\\": {\\\"value\\\": \\\"middle\\\"},\\n \\\"text\\\": {\\\"value\\\": \\\"Show All\\\"},\\n \\\"fontSize\\\": {\\\"value\\\": 14},\\n \\\"stroke\\\": {\\\"value\\\": \\\"#ecf0f1\\\"}\\n }\\n }\\n }\\n ]\\n }\\n ]\\n }\\n ],\\n \\\"signals\\\": [\\n {\\n \\\"name\\\": \\\"groupHover\\\",\\n \\\"value\\\": {},\\n \\\"on\\\": [\\n {\\n \\\"events\\\": \\\"@groupMark:mouseover\\\",\\n \\\"update\\\": \\\"{stk1:datum.stack=='stk1' && datum.grpId, stk2:datum.stack=='stk2' && datum.grpId}\\\"\\n },\\n {\\\"events\\\": \\\"mouseout\\\", \\\"update\\\": \\\"{}\\\"}\\n ]\\n },\\n {\\n \\\"name\\\": \\\"groupSelector\\\",\\n \\\"value\\\": false,\\n \\\"on\\\": [\\n {\\n \\\"events\\\": \\\"@groupMark:click!\\\",\\n \\\"update\\\": \\\"{stack:datum.stack, stk1:datum.stack=='stk1' && datum.grpId, stk2:datum.stack=='stk2' && datum.grpId}\\\"\\n },\\n {\\n \\\"events\\\": [\\n {\\\"type\\\": \\\"click\\\", \\\"markname\\\": \\\"groupReset\\\"},\\n {\\\"type\\\": \\\"dblclick\\\"}\\n ],\\n \\\"update\\\": \\\"false\\\"\\n }\\n ]\\n }\\n ]\\n}\"},\"title\":\"Pod-to-Pod Traffic Reverse Cumulative Bytes\"}"},"id":"2bd8fe60-c243-11ea-873e-8f9a9a3cbdc1","migrationVersion":{"visualization":"7.8.0"},"references":[],"type":"visualization","updated_at":"2021-08-07T23:30:40.150Z","version":"WzE3LDFd"} -{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}"},"title":"Aggregated Rx Mbps by Service Acting as Destination","uiStateJSON":"{}","version":1,"visState":"{\"type\":\"metrics\",\"aggs\":[],\"params\":{\"id\":\"61ca57f0-469d-11e7-af02-69e470af7417\",\"type\":\"timeseries\",\"axis_position\":\"left\",\"axis_formatter\":\"number\",\"show_legend\":1,\"show_grid\":1,\"axis_min\":\"0\",\"filter\":\"\",\"axis_scale\":\"normal\",\"default_index_pattern\":\"flow-*\",\"default_timefield\":\"@timestamp\",\"isModelInvalid\":false,\"index_pattern\":\"flow-*\",\"interval\":\"1m\",\"time_field\":\"ipfix.flowEndSeconds\",\"series\":[{\"id\":\"61ca57f1-469d-11e7-af02-69e470af7417\",\"color\":\"rgba(144,201,227,1)\",\"split_mode\":\"terms\",\"metrics\":[{\"id\":\"a1ba0060-b9a7-11ea-9740-552c943910e4\",\"type\":\"sum\",\"field\":\"ipfix.throughput\"},{\"script\":\"params.bytes * 8 \",\"id\":\"dd0b81d0-b9a6-11ea-9740-552c943910e4\",\"type\":\"calculation\",\"variables\":[{\"id\":\"e1f87e50-b9a6-11ea-9740-552c943910e4\",\"name\":\"bytes\",\"field\":\"a1ba0060-b9a7-11ea-9740-552c943910e4\"}]}],\"separate_axis\":0,\"axis_position\":\"right\",\"formatter\":\"bytes\",\"chart_type\":\"line\",\"line_width\":\"2\",\"point_size\":\"0\",\"fill\":\"0.6\",\"stacked\":\"none\",\"split_color_mode\":\"rainbow\",\"label\":\"Bytes\",\"terms_field\":\"ipfix.destinationServicePortName.keyword\",\"terms_size\":\"30\",\"terms_order_by\":\"a1ba0060-b9a7-11ea-9740-552c943910e4\",\"value_template\":\"{{value}}its/s\",\"type\":\"timeseries\"}]},\"title\":\"Aggregated Rx Mbps by Service Acting as Destination\"}"},"id":"2fb72bf0-d086-11ea-a734-57fc7859997d","migrationVersion":{"visualization":"7.8.0"},"references":[],"type":"visualization","updated_at":"2021-08-07T23:30:40.150Z","version":"WzE4LDFd"} -{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"lucene\"},\"filter\":[]}"},"title":"Overview Nav","uiStateJSON":"{}","version":1,"visState":"{\"type\":\"metrics\",\"aggs\":[],\"params\":{\"id\":\"61ca57f0-469d-11e7-af02-69e470af7417\",\"type\":\"markdown\",\"series\":[{\"id\":\"61ca57f1-469d-11e7-af02-69e470af7417\",\"color\":\"#68BC00\",\"split_mode\":\"everything\",\"metrics\":[{\"id\":\"61ca57f2-469d-11e7-af02-69e470af7417\",\"type\":\"count\"}],\"separate_axis\":0,\"axis_position\":\"right\",\"formatter\":\"number\",\"chart_type\":\"line\",\"line_width\":1,\"point_size\":1,\"fill\":0.5,\"stacked\":\"none\",\"offset_time\":\"-5y\",\"split_color_mode\":\"gradient\"}],\"interval\":\"auto\",\"axis_position\":\"left\",\"axis_formatter\":\"number\",\"axis_scale\":\"normal\",\"show_legend\":1,\"show_grid\":1,\"markdown_vertical_align\":\"top\",\"default_index_pattern\":\"flow-*\",\"default_timefield\":\"@timestamp\",\"isModelInvalid\":false,\"time_field\":null,\"index_pattern\":\"flow-*\",\"markdown_css\":\"#markdown-61ca57f0-469d-11e7-af02-69e470af7417 p{color:#cccccc;margin-top:0;margin-bottom:8px;text-align:right}#markdown-61ca57f0-469d-11e7-af02-69e470af7417 p a{color:#1eadbd;font-size:17px;font-weight:bold;text-decoration:none}#markdown-61ca57f0-469d-11e7-af02-69e470af7417 p a strong{color:#ffac12;font-weight:bold}#markdown-61ca57f0-469d-11e7-af02-69e470af7417 hr{background-color:#cccccc;margin:0;height:1px}\",\"markdown_less\":\"p {\\n color: #cccccc;\\n margin-top: 0px;\\n margin-bottom: 8px;\\n text-align: right;\\n}\\np a {\\n color: #1eadbd;\\n\\tfont-size: 17px;\\n\\tfont-weight: bold;\\n\\ttext-decoration: none;\\n}\\np a strong {\\n color: #ffac12;\\n\\tfont-weight: bold;\\n}\\nhr {\\n background-color: #cccccc;\\n margin: 0px;\\n height: 1px;\\n}\",\"markdown\":\"[**Overview**](#/dashboard/3b331b30-b987-11ea-b16e-fb06687c3589) | [Pod-to-Pod Flow](#/dashboard/c2b15fb0-b9a8-11ea-b16e-fb06687c3589) | [Pod-to-External Flow](#/dashboard/3ed71e80-a92d-11eb-a7ef-5dcb53008c10) | [Pod-to-Service Flow](#/dashboard/6d77e8a0-513a-11eb-a19a-05e08a82dcf8) | [Node](#/dashboard/5400cdf0-cd2e-11ea-8911-87da3aad0324) | [Network Policy](#/dashboard/c5af6850-23b2-11eb-90d2-a7a4de48218a) | [Flow Records](#/dashboard/2ab9c220-b984-11ea-b16e-fb06687c3589)\"},\"title\":\"Overview Nav\"}"},"id":"b990e3f0-b9ae-11ea-b16e-fb06687c3589","migrationVersion":{"visualization":"7.8.0"},"references":[],"type":"visualization","updated_at":"2021-08-07T23:30:40.150Z","version":"WzE5LDFd"} -{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\",\"filter\":[]}"},"title":"Source Pod Bytes","uiStateJSON":"{}","version":1,"visState":"{\"type\":\"pie\",\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"sum\",\"schema\":\"metric\",\"params\":{\"field\":\"ipfix.bytes\"}},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"segment\",\"params\":{\"field\":\"ipfix.sourcePodName.keyword\",\"orderBy\":\"1\",\"order\":\"desc\",\"size\":30,\"otherBucket\":true,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\",\"customLabel\":\"Client\"}}],\"params\":{\"type\":\"pie\",\"addTooltip\":true,\"addLegend\":true,\"legendPosition\":\"right\",\"isDonut\":true,\"labels\":{\"show\":false,\"values\":true,\"last_level\":true,\"truncate\":100},\"dimensions\":{\"metric\":{\"accessor\":1,\"format\":{\"id\":\"number\"},\"params\":{},\"aggType\":\"sum\"},\"buckets\":[{\"accessor\":0,\"format\":{\"id\":\"terms\",\"params\":{\"id\":\"string\",\"otherBucketLabel\":\"Other\",\"missingBucketLabel\":\"Missing\"}},\"params\":{},\"aggType\":\"terms\"},{\"accessor\":2,\"format\":{\"id\":\"terms\",\"params\":{\"id\":\"string\",\"otherBucketLabel\":\"Other\",\"missingBucketLabel\":\"Missing\"}},\"params\":{},\"aggType\":\"terms\"}]}},\"title\":\"Source Pod Bytes\"}"},"id":"b265b3e0-b985-11ea-b16e-fb06687c3589","migrationVersion":{"visualization":"7.8.0"},"references":[{"id":"e2ab2c50-b981-11ea-b16e-fb06687c3589","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"}],"type":"visualization","updated_at":"2021-08-07T23:30:40.150Z","version":"WzIwLDFd"} -{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\",\"filter\":[]}"},"title":"Source Pod Packets","uiStateJSON":"{}","version":1,"visState":"{\"type\":\"pie\",\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"sum\",\"schema\":\"metric\",\"params\":{\"field\":\"ipfix.packets\"}},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"segment\",\"params\":{\"field\":\"ipfix.sourcePodName.keyword\",\"orderBy\":\"1\",\"order\":\"desc\",\"size\":30,\"otherBucket\":true,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\",\"customLabel\":\"Client\"}}],\"params\":{\"type\":\"pie\",\"addTooltip\":true,\"addLegend\":true,\"legendPosition\":\"right\",\"isDonut\":true,\"labels\":{\"show\":false,\"values\":true,\"last_level\":true,\"truncate\":100},\"dimensions\":{\"metric\":{\"accessor\":0,\"format\":{\"id\":\"number\"},\"params\":{},\"aggType\":\"count\"}}},\"title\":\"Source Pod Packets\"}"},"id":"3efa51d0-b986-11ea-b16e-fb06687c3589","migrationVersion":{"visualization":"7.8.0"},"references":[{"id":"e2ab2c50-b981-11ea-b16e-fb06687c3589","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"}],"type":"visualization","updated_at":"2021-08-07T23:30:40.150Z","version":"WzIxLDFd"} -{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\",\"filter\":[]}"},"title":"Destination Pod Packets","uiStateJSON":"{}","version":1,"visState":"{\"type\":\"pie\",\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"sum\",\"schema\":\"metric\",\"params\":{\"field\":\"ipfix.packets\"}},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"segment\",\"params\":{\"field\":\"ipfix.destinationPodName.keyword\",\"orderBy\":\"1\",\"order\":\"desc\",\"size\":30,\"otherBucket\":true,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\",\"customLabel\":\"Server\"}}],\"params\":{\"type\":\"pie\",\"addTooltip\":true,\"addLegend\":true,\"legendPosition\":\"right\",\"isDonut\":true,\"labels\":{\"show\":false,\"values\":true,\"last_level\":true,\"truncate\":100},\"dimensions\":{\"metric\":{\"accessor\":0,\"format\":{\"id\":\"number\"},\"params\":{},\"aggType\":\"count\"}}},\"title\":\"Destination Pod Packets\"}"},"id":"6ac7d9e0-b986-11ea-b16e-fb06687c3589","migrationVersion":{"visualization":"7.8.0"},"references":[{"id":"e2ab2c50-b981-11ea-b16e-fb06687c3589","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"}],"type":"visualization","updated_at":"2021-08-07T23:30:40.150Z","version":"WzIyLDFd"} -{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\",\"filter\":[]}"},"title":"Source Pod Bytes (IP)","uiStateJSON":"{}","version":1,"visState":"{\"type\":\"pie\",\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"sum\",\"schema\":\"metric\",\"params\":{\"field\":\"ipfix.bytes\"}},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"segment\",\"params\":{\"field\":\"ipfix.sourceIP.keyword\",\"orderBy\":\"1\",\"order\":\"desc\",\"size\":20,\"otherBucket\":true,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\"}}],\"params\":{\"type\":\"pie\",\"addTooltip\":true,\"addLegend\":true,\"legendPosition\":\"right\",\"isDonut\":true,\"labels\":{\"show\":false,\"values\":true,\"last_level\":true,\"truncate\":100},\"dimensions\":{\"metric\":{\"accessor\":1,\"format\":{\"id\":\"number\"},\"params\":{},\"aggType\":\"sum\"},\"buckets\":[{\"accessor\":0,\"format\":{\"id\":\"terms\",\"params\":{\"id\":\"string\",\"otherBucketLabel\":\"Other\",\"missingBucketLabel\":\"Missing\"}},\"params\":{},\"aggType\":\"terms\"}]}},\"title\":\"Source Pod Bytes (IP)\"}"},"id":"a33e14e0-b992-11ea-b16e-fb06687c3589","migrationVersion":{"visualization":"7.8.0"},"references":[{"id":"e2ab2c50-b981-11ea-b16e-fb06687c3589","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"}],"type":"visualization","updated_at":"2021-08-07T23:30:40.150Z","version":"WzIzLDFd"} -{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\",\"filter\":[]}"},"title":"Source Pod Packets (IP)","uiStateJSON":"{}","version":1,"visState":"{\"type\":\"pie\",\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"sum\",\"schema\":\"metric\",\"params\":{\"field\":\"ipfix.packets\"}},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"segment\",\"params\":{\"field\":\"ipfix.sourceIP.keyword\",\"orderBy\":\"1\",\"order\":\"desc\",\"size\":20,\"otherBucket\":true,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\"}}],\"params\":{\"type\":\"pie\",\"addTooltip\":true,\"addLegend\":true,\"legendPosition\":\"right\",\"isDonut\":true,\"labels\":{\"show\":false,\"values\":true,\"last_level\":true,\"truncate\":100},\"dimensions\":{\"metric\":{\"accessor\":1,\"format\":{\"id\":\"number\"},\"params\":{},\"aggType\":\"sum\"},\"buckets\":[{\"accessor\":0,\"format\":{\"id\":\"terms\",\"params\":{\"id\":\"string\",\"otherBucketLabel\":\"Other\",\"missingBucketLabel\":\"Missing\"}},\"params\":{},\"aggType\":\"terms\"}]}},\"title\":\"Source Pod Packets (IP)\"}"},"id":"b14081e0-b992-11ea-b16e-fb06687c3589","migrationVersion":{"visualization":"7.8.0"},"references":[{"id":"e2ab2c50-b981-11ea-b16e-fb06687c3589","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"}],"type":"visualization","updated_at":"2021-08-07T23:30:40.150Z","version":"WzI0LDFd"} -{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\",\"filter\":[]}"},"title":"Destination Pod Bytes (IP)","uiStateJSON":"{}","version":1,"visState":"{\"type\":\"pie\",\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"sum\",\"schema\":\"metric\",\"params\":{\"field\":\"ipfix.bytes\"}},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"segment\",\"params\":{\"field\":\"ipfix.destinationIP.keyword\",\"orderBy\":\"1\",\"order\":\"desc\",\"size\":20,\"otherBucket\":true,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\"}}],\"params\":{\"type\":\"pie\",\"addTooltip\":true,\"addLegend\":true,\"legendPosition\":\"right\",\"isDonut\":true,\"labels\":{\"show\":false,\"values\":true,\"last_level\":true,\"truncate\":100},\"dimensions\":{\"metric\":{\"accessor\":0,\"format\":{\"id\":\"number\"},\"params\":{},\"aggType\":\"count\"}}},\"title\":\"Destination Pod Bytes (IP)\"}"},"id":"910eee20-b992-11ea-b16e-fb06687c3589","migrationVersion":{"visualization":"7.8.0"},"references":[{"id":"e2ab2c50-b981-11ea-b16e-fb06687c3589","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"}],"type":"visualization","updated_at":"2021-08-07T23:30:40.150Z","version":"WzI1LDFd"} -{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\",\"filter\":[]}"},"title":"Destination Pod Packets (IP)","uiStateJSON":"{}","version":1,"visState":"{\"type\":\"pie\",\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"sum\",\"schema\":\"metric\",\"params\":{\"field\":\"ipfix.packets\"}},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"segment\",\"params\":{\"field\":\"ipfix.destinationIP.keyword\",\"orderBy\":\"1\",\"order\":\"desc\",\"size\":20,\"otherBucket\":true,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\"}}],\"params\":{\"type\":\"pie\",\"addTooltip\":true,\"addLegend\":true,\"legendPosition\":\"right\",\"isDonut\":true,\"labels\":{\"show\":false,\"values\":true,\"last_level\":true,\"truncate\":100},\"dimensions\":{\"metric\":{\"accessor\":1,\"format\":{\"id\":\"number\"},\"params\":{},\"aggType\":\"sum\"},\"buckets\":[{\"accessor\":0,\"format\":{\"id\":\"terms\",\"params\":{\"id\":\"string\",\"otherBucketLabel\":\"Other\",\"missingBucketLabel\":\"Missing\"}},\"params\":{},\"aggType\":\"terms\"}]}},\"title\":\"Destination Pod Packets (IP)\"}"},"id":"c74e1b50-b992-11ea-b16e-fb06687c3589","migrationVersion":{"visualization":"7.8.0"},"references":[{"id":"e2ab2c50-b981-11ea-b16e-fb06687c3589","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"}],"type":"visualization","updated_at":"2021-08-07T23:30:40.150Z","version":"WzI2LDFd"} -{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\",\"filter\":[]}"},"title":"Source Pod Flow Count","uiStateJSON":"{\"vis\":{\"legendOpen\":true}}","version":1,"visState":"{\"type\":\"horizontal_bar\",\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{\"customLabel\":\"Record Count\"}},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"group\",\"params\":{\"field\":\"ipfix.sourcePodName.keyword\",\"orderBy\":\"1\",\"order\":\"desc\",\"size\":20,\"otherBucket\":true,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\",\"customLabel\":\"Client\"}}],\"params\":{\"type\":\"histogram\",\"grid\":{\"categoryLines\":false,\"valueAxis\":\"ValueAxis-1\"},\"categoryAxes\":[{\"id\":\"CategoryAxis-1\",\"type\":\"category\",\"position\":\"left\",\"show\":true,\"style\":{},\"scale\":{\"type\":\"linear\"},\"labels\":{\"show\":true,\"rotate\":0,\"filter\":false,\"truncate\":200},\"title\":{}}],\"valueAxes\":[{\"id\":\"ValueAxis-1\",\"name\":\"LeftAxis-1\",\"type\":\"value\",\"position\":\"bottom\",\"show\":true,\"style\":{},\"scale\":{\"type\":\"linear\",\"mode\":\"normal\"},\"labels\":{\"show\":true,\"rotate\":75,\"filter\":true,\"truncate\":100},\"title\":{\"text\":\"Record Count\"}}],\"seriesParams\":[{\"show\":true,\"type\":\"histogram\",\"mode\":\"normal\",\"valueAxis\":\"ValueAxis-1\",\"drawLinesBetweenPoints\":true,\"lineWidth\":2,\"showCircles\":true,\"data\":{\"id\":\"1\",\"label\":\"Record Count\"}}],\"addTooltip\":true,\"addLegend\":true,\"legendPosition\":\"top\",\"times\":[],\"addTimeMarker\":false,\"labels\":{\"show\":true},\"thresholdLine\":{\"show\":false,\"value\":10,\"width\":1,\"style\":\"full\",\"color\":\"#34130C\"},\"dimensions\":{\"x\":null,\"y\":[{\"accessor\":1,\"format\":{\"id\":\"number\"},\"params\":{},\"aggType\":\"count\"}],\"series\":[{\"accessor\":0,\"format\":{\"id\":\"terms\",\"params\":{\"id\":\"string\",\"otherBucketLabel\":\"Other\",\"missingBucketLabel\":\"Missing\"}},\"params\":{},\"aggType\":\"terms\"}]}},\"title\":\"Source Pod Flow Count\"}"},"id":"d3760780-b988-11ea-b16e-fb06687c3589","migrationVersion":{"visualization":"7.8.0"},"references":[{"id":"e2ab2c50-b981-11ea-b16e-fb06687c3589","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"}],"type":"visualization","updated_at":"2021-08-07T23:30:40.150Z","version":"WzI3LDFd"} -{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\",\"filter\":[]}"},"title":"Destination Pod Flow Count","uiStateJSON":"{}","version":1,"visState":"{\"type\":\"histogram\",\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{\"customLabel\":\"Record Count\"}},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"group\",\"params\":{\"field\":\"ipfix.destinationPodName.keyword\",\"orderBy\":\"1\",\"order\":\"desc\",\"size\":20,\"otherBucket\":true,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\"}}],\"params\":{\"type\":\"histogram\",\"grid\":{\"categoryLines\":false,\"valueAxis\":\"ValueAxis-1\"},\"categoryAxes\":[{\"id\":\"CategoryAxis-1\",\"type\":\"category\",\"position\":\"left\",\"show\":true,\"style\":{},\"scale\":{\"type\":\"linear\"},\"labels\":{\"show\":true,\"rotate\":0,\"filter\":false,\"truncate\":200},\"title\":{}}],\"valueAxes\":[{\"id\":\"ValueAxis-1\",\"name\":\"LeftAxis-1\",\"type\":\"value\",\"position\":\"bottom\",\"show\":true,\"style\":{},\"scale\":{\"type\":\"linear\",\"mode\":\"normal\"},\"labels\":{\"show\":true,\"rotate\":75,\"filter\":true,\"truncate\":100},\"title\":{\"text\":\"Record Count\"}}],\"seriesParams\":[{\"show\":true,\"type\":\"histogram\",\"mode\":\"normal\",\"valueAxis\":\"ValueAxis-1\",\"drawLinesBetweenPoints\":true,\"lineWidth\":2,\"showCircles\":true,\"data\":{\"label\":\"Record Count\",\"id\":\"1\"}}],\"addTooltip\":true,\"addLegend\":true,\"legendPosition\":\"top\",\"times\":[],\"addTimeMarker\":false,\"labels\":{\"show\":true},\"thresholdLine\":{\"show\":false,\"value\":10,\"width\":1,\"style\":\"full\",\"color\":\"#34130C\"},\"dimensions\":{\"x\":null,\"y\":[{\"accessor\":1,\"format\":{\"id\":\"number\"},\"params\":{},\"aggType\":\"count\"}],\"series\":[{\"accessor\":0,\"format\":{\"id\":\"terms\",\"params\":{\"id\":\"string\",\"otherBucketLabel\":\"Other\",\"missingBucketLabel\":\"Missing\"}},\"params\":{},\"aggType\":\"terms\"}]}},\"title\":\"Destination Pod Flow Count\"}"},"id":"766c7960-b989-11ea-b16e-fb06687c3589","migrationVersion":{"visualization":"7.8.0"},"references":[{"id":"e2ab2c50-b981-11ea-b16e-fb06687c3589","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"}],"type":"visualization","updated_at":"2021-08-07T23:30:40.150Z","version":"WzI4LDFd"} -{"attributes":{"description":"","hits":0,"kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"language\":\"kuery\",\"query\":\"\"},\"filter\":[]}"},"optionsJSON":"{\"hidePanelTitles\":false,\"useMargins\":true}","panelsJSON":"[{\"embeddableConfig\":{\"title\":\"\"},\"gridData\":{\"h\":3,\"i\":\"611b0a9e-2dd7-40b9-ab13-a388e16ab1f0\",\"w\":47,\"x\":0,\"y\":0},\"panelIndex\":\"611b0a9e-2dd7-40b9-ab13-a388e16ab1f0\",\"version\":\"7.8.0\",\"panelRefName\":\"panel_0\"},{\"embeddableConfig\":{\"title\":\"\"},\"gridData\":{\"h\":8,\"i\":\"6b959c34-c8dd-4587-985e-f005036d5c19\",\"w\":47,\"x\":0,\"y\":3},\"panelIndex\":\"6b959c34-c8dd-4587-985e-f005036d5c19\",\"version\":\"7.8.0\",\"panelRefName\":\"panel_1\"},{\"embeddableConfig\":{},\"gridData\":{\"h\":10,\"i\":\"d0bcb363-e35c-4eda-8bc1-3bde850ff7cf\",\"w\":12,\"x\":0,\"y\":11},\"panelIndex\":\"d0bcb363-e35c-4eda-8bc1-3bde850ff7cf\",\"version\":\"7.8.0\",\"panelRefName\":\"panel_2\"},{\"embeddableConfig\":{},\"gridData\":{\"h\":10,\"i\":\"34ae553a-89a9-48c7-be20-aed5378f047f\",\"w\":12,\"x\":12,\"y\":11},\"panelIndex\":\"34ae553a-89a9-48c7-be20-aed5378f047f\",\"version\":\"7.8.0\",\"panelRefName\":\"panel_3\"},{\"embeddableConfig\":{},\"gridData\":{\"h\":10,\"i\":\"688aaf07-3775-4eea-8b89-dd21a3105983\",\"w\":12,\"x\":24,\"y\":11},\"panelIndex\":\"688aaf07-3775-4eea-8b89-dd21a3105983\",\"version\":\"7.8.0\",\"panelRefName\":\"panel_4\"},{\"embeddableConfig\":{},\"gridData\":{\"h\":10,\"i\":\"f772179d-9071-4f66-b658-11b29d42893a\",\"w\":11,\"x\":36,\"y\":11},\"panelIndex\":\"f772179d-9071-4f66-b658-11b29d42893a\",\"version\":\"7.8.0\",\"panelRefName\":\"panel_5\"},{\"embeddableConfig\":{},\"gridData\":{\"h\":9,\"i\":\"65de1d73-69b3-418a-a087-87c6c3fa03aa\",\"w\":12,\"x\":0,\"y\":21},\"panelIndex\":\"65de1d73-69b3-418a-a087-87c6c3fa03aa\",\"version\":\"7.8.0\",\"panelRefName\":\"panel_6\"},{\"embeddableConfig\":{},\"gridData\":{\"h\":9,\"i\":\"99310550-57db-4649-b384-7034750f0fa5\",\"w\":12,\"x\":12,\"y\":21},\"panelIndex\":\"99310550-57db-4649-b384-7034750f0fa5\",\"version\":\"7.8.0\",\"panelRefName\":\"panel_7\"},{\"embeddableConfig\":{},\"gridData\":{\"h\":9,\"i\":\"e70a5b6d-195b-4ead-b413-5ebc0ca91f8b\",\"w\":12,\"x\":24,\"y\":21},\"panelIndex\":\"e70a5b6d-195b-4ead-b413-5ebc0ca91f8b\",\"version\":\"7.8.0\",\"panelRefName\":\"panel_8\"},{\"embeddableConfig\":{},\"gridData\":{\"h\":9,\"i\":\"df8ade74-a938-473c-adda-b3c0ac35b9ce\",\"w\":11,\"x\":36,\"y\":21},\"panelIndex\":\"df8ade74-a938-473c-adda-b3c0ac35b9ce\",\"version\":\"7.8.0\",\"panelRefName\":\"panel_9\"},{\"embeddableConfig\":{},\"gridData\":{\"h\":12,\"i\":\"c8b1671d-c6aa-4b68-9ca7-0fd6613fbeea\",\"w\":24,\"x\":0,\"y\":30},\"panelIndex\":\"c8b1671d-c6aa-4b68-9ca7-0fd6613fbeea\",\"version\":\"7.8.0\",\"panelRefName\":\"panel_10\"},{\"embeddableConfig\":{},\"gridData\":{\"h\":12,\"i\":\"cafff520-4093-43a8-b6e9-8585e21ce179\",\"w\":23,\"x\":24,\"y\":30},\"panelIndex\":\"cafff520-4093-43a8-b6e9-8585e21ce179\",\"version\":\"7.8.0\",\"panelRefName\":\"panel_11\"}]","timeRestore":false,"title":"Overview Dashboard","version":1},"id":"3b331b30-b987-11ea-b16e-fb06687c3589","migrationVersion":{"dashboard":"7.3.0"},"references":[{"id":"b990e3f0-b9ae-11ea-b16e-fb06687c3589","name":"panel_0","type":"visualization"},{"id":"df9ec4c0-b983-11ea-b16e-fb06687c3589","name":"panel_1","type":"visualization"},{"id":"b265b3e0-b985-11ea-b16e-fb06687c3589","name":"panel_2","type":"visualization"},{"id":"3efa51d0-b986-11ea-b16e-fb06687c3589","name":"panel_3","type":"visualization"},{"id":"051d3d60-b986-11ea-b16e-fb06687c3589","name":"panel_4","type":"visualization"},{"id":"6ac7d9e0-b986-11ea-b16e-fb06687c3589","name":"panel_5","type":"visualization"},{"id":"a33e14e0-b992-11ea-b16e-fb06687c3589","name":"panel_6","type":"visualization"},{"id":"b14081e0-b992-11ea-b16e-fb06687c3589","name":"panel_7","type":"visualization"},{"id":"910eee20-b992-11ea-b16e-fb06687c3589","name":"panel_8","type":"visualization"},{"id":"c74e1b50-b992-11ea-b16e-fb06687c3589","name":"panel_9","type":"visualization"},{"id":"d3760780-b988-11ea-b16e-fb06687c3589","name":"panel_10","type":"visualization"},{"id":"766c7960-b989-11ea-b16e-fb06687c3589","name":"panel_11","type":"visualization"}],"type":"dashboard","updated_at":"2021-08-07T23:30:40.150Z","version":"WzI5LDFd"} -{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}"},"title":"Aggregated Tx Mbps by Service Acting as Destination","uiStateJSON":"{}","version":1,"visState":"{\"type\":\"metrics\",\"aggs\":[],\"params\":{\"id\":\"61ca57f0-469d-11e7-af02-69e470af7417\",\"type\":\"timeseries\",\"axis_position\":\"left\",\"axis_formatter\":\"number\",\"show_legend\":1,\"show_grid\":1,\"axis_min\":\"0\",\"filter\":\"\",\"axis_scale\":\"normal\",\"default_index_pattern\":\"flow-*\",\"default_timefield\":\"@timestamp\",\"isModelInvalid\":false,\"index_pattern\":\"flow-*\",\"interval\":\"1m\",\"time_field\":\"ipfix.flowEndSeconds\",\"series\":[{\"id\":\"61ca57f1-469d-11e7-af02-69e470af7417\",\"color\":\"rgba(144,201,227,1)\",\"split_mode\":\"terms\",\"metrics\":[{\"id\":\"a1ba0060-b9a7-11ea-9740-552c943910e4\",\"type\":\"sum\",\"field\":\"ipfix.reverseThroughput\"},{\"script\":\"params.bytes * 8\",\"id\":\"dd0b81d0-b9a6-11ea-9740-552c943910e4\",\"type\":\"calculation\",\"variables\":[{\"id\":\"e1f87e50-b9a6-11ea-9740-552c943910e4\",\"name\":\"bytes\",\"field\":\"a1ba0060-b9a7-11ea-9740-552c943910e4\"}]}],\"separate_axis\":0,\"axis_position\":\"right\",\"formatter\":\"bytes\",\"chart_type\":\"line\",\"line_width\":\"2\",\"point_size\":\"0\",\"fill\":\"0.6\",\"stacked\":\"none\",\"split_color_mode\":\"rainbow\",\"label\":\"Bytes\",\"terms_field\":\"ipfix.destinationServicePortName.keyword\",\"terms_size\":\"30\",\"terms_order_by\":\"a1ba0060-b9a7-11ea-9740-552c943910e4\",\"value_template\":\"{{value}}its/s\",\"type\":\"timeseries\"}]},\"title\":\"Aggregated Tx Mbps by Service Acting as Destination\"}"},"id":"3ccd6430-d086-11ea-a734-57fc7859997d","migrationVersion":{"visualization":"7.8.0"},"references":[],"type":"visualization","updated_at":"2021-08-07T23:30:40.150Z","version":"WzMwLDFd"} -{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"language\":\"lucene\",\"query\":\"\"},\"filter\":[]}"},"title":"Pod-to-External Flow Nav","uiStateJSON":"{}","version":1,"visState":"{\"type\":\"metrics\",\"aggs\":[],\"params\":{\"axis_formatter\":\"number\",\"axis_position\":\"left\",\"axis_scale\":\"normal\",\"default_index_pattern\":\"flow-*\",\"default_timefield\":\"@timestamp\",\"id\":\"61ca57f0-469d-11e7-af02-69e470af7417\",\"index_pattern\":\"flow-*\",\"interval\":\"auto\",\"isModelInvalid\":false,\"markdown_css\":\"#markdown-61ca57f0-469d-11e7-af02-69e470af7417 p{color:#cccccc;margin-top:0;margin-bottom:8px;text-align:right}#markdown-61ca57f0-469d-11e7-af02-69e470af7417 p a{color:#1eadbd;font-size:17px;font-weight:bold;text-decoration:none}#markdown-61ca57f0-469d-11e7-af02-69e470af7417 p a strong{color:#ffac12;font-weight:bold}#markdown-61ca57f0-469d-11e7-af02-69e470af7417 hr{background-color:#cccccc;margin:0;height:1px}\",\"markdown_less\":\"p {\\n color: #cccccc;\\n margin-top: 0px;\\n margin-bottom: 8px;\\n text-align: right;\\n}\\np a {\\n color: #1eadbd;\\n\\tfont-size: 17px;\\n\\tfont-weight: bold;\\n\\ttext-decoration: none;\\n}\\np a strong {\\n color: #ffac12;\\n\\tfont-weight: bold;\\n}\\nhr {\\n background-color: #cccccc;\\n margin: 0px;\\n height: 1px;\\n}\",\"markdown_vertical_align\":\"top\",\"series\":[{\"axis_position\":\"right\",\"chart_type\":\"line\",\"color\":\"#68BC00\",\"fill\":0.5,\"formatter\":\"number\",\"id\":\"61ca57f1-469d-11e7-af02-69e470af7417\",\"line_width\":1,\"metrics\":[{\"id\":\"61ca57f2-469d-11e7-af02-69e470af7417\",\"type\":\"count\"}],\"offset_time\":\"-5y\",\"point_size\":1,\"separate_axis\":0,\"split_color_mode\":\"gradient\",\"split_mode\":\"everything\",\"stacked\":\"none\"}],\"show_grid\":1,\"show_legend\":1,\"time_field\":null,\"type\":\"markdown\",\"markdown\":\"[Overview](#/dashboard/3b331b30-b987-11ea-b16e-fb06687c3589) | [Pod-to-Pod Flow](#/dashboard/c2b15fb0-b9a8-11ea-b16e-fb06687c3589) | [**Pod-to-External Flow**](#/dashboard/3ed71e80-a92d-11eb-a7ef-5dcb53008c10) | [Pod-to-Service Flow](#/dashboard/6d77e8a0-513a-11eb-a19a-05e08a82dcf8) | [Node](#/dashboard/5400cdf0-cd2e-11ea-8911-87da3aad0324) | [Network Policy](#/dashboard/c5af6850-23b2-11eb-90d2-a7a4de48218a) | [Flow Records](#/dashboard/2ab9c220-b984-11ea-b16e-fb06687c3589)\"},\"title\":\"Pod-to-External Flow Nav\"}"},"id":"af8f70b0-a93b-11eb-a7ef-5dcb53008c10","migrationVersion":{"visualization":"7.8.0"},"references":[],"type":"visualization","updated_at":"2021-08-07T23:30:40.150Z","version":"WzMxLDFd"} -{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"lucene\"},\"filter\":[]}"},"title":"Pod-to-External Traffic Cumulative Bytes","uiStateJSON":"{}","version":1,"visState":"{\"type\":\"vega\",\"aggs\":[],\"params\":{\"spec\":\"{\\n \\\"$schema\\\": \\\"https://vega.github.io/schema/vega/v3.0.json\\\",\\n \\\"data\\\": [\\n {\\n \\\"name\\\": \\\"rawData\\\",\\n \\\"url\\\": {\\n \\\"%context%\\\": true,\\n \\\"%timefield%\\\": \\\"@timestamp\\\",\\n \\\"index\\\": \\\"flow-*\\\",\\n \\\"body\\\": {\\n \\\"size\\\": 0,\\n \\\"aggs\\\": {\\n \\\"table\\\": {\\n \\\"composite\\\": {\\n \\\"size\\\": 1000,\\n \\\"sources\\\": [\\n {\\\"stk1\\\": {\\\"terms\\\": {\\\"field\\\": \\\"ipfix.sourcePodName.keyword\\\"}}},\\n {\\\"stk1ns\\\": {\\\"terms\\\": {\\\"field\\\": \\\"ipfix.sourcePodNamespace.keyword\\\"}}},\\n {\\\"stk2\\\": {\\\"terms\\\": {\\\"field\\\": \\\"ipfix.destinationIP.keyword\\\"}}},\\n {\\\"stk3\\\": {\\\"terms\\\": {\\\"field\\\": \\\"ipfix.sourceIP.keyword\\\"}}},\\n {\\\"stk4\\\": {\\\"terms\\\": {\\\"field\\\": \\\"ipfix.flowTypeStr.keyword\\\"}}},\\n ]\\n },\\n \\t\\t\\t\\\"aggs\\\": {\\n \\t\\t\\t\\t\\\"bytes\\\": {\\n \\t\\t\\t\\t\\t\\\"sum\\\": {\\n \\t\\t\\t\\t\\t\\t\\\"field\\\": \\\"ipfix.octetDeltaCountFromSourceNode\\\"\\n \\t\\t\\t\\t\\t}\\n \\t\\t\\t\\t}\\n \\t\\t\\t}\\n }\\n }\\n }\\n },\\n \\\"format\\\": {\\\"property\\\": \\\"aggregations.table.buckets\\\"},\\n \\\"transform\\\": [\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"datum.key.stk1ns +'/'+ datum.key.stk1\\\", \\\"as\\\": \\\"stk1s\\\"},\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"(datum.key.stk1==''?datum.key.stk3:datum.stk1s)\\\", \\\"as\\\": \\\"stk1\\\"},\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"datum.key.stk2\\\", \\\"as\\\": \\\"stk2\\\"},\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"datum.key.stk3\\\", \\\"as\\\": \\\"stk3\\\"},\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"datum.key.stk4\\\", \\\"as\\\": \\\"stk4\\\"},\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"datum.bytes.value\\\", \\\"as\\\": \\\"size\\\"}\\n ]\\n },\\n {\\n \\\"name\\\": \\\"nodes\\\",\\n \\\"source\\\": \\\"rawData\\\",\\n \\\"transform\\\": [\\n {\\n \\\"type\\\": \\\"filter\\\",\\n \\\"expr\\\": \\\"datum.stk4 =='To External' && !groupSelector || groupSelector.stk1 == datum.stk1 || groupSelector.stk2 == datum.stk2\\\"\\n },\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"datum.stk1+datum.stk2\\\", \\\"as\\\": \\\"key\\\"},\\n {\\\"type\\\": \\\"fold\\\", \\\"fields\\\": [\\\"stk1\\\", \\\"stk2\\\"], \\\"as\\\": [\\\"stack\\\", \\\"grpId\\\"]},\\n {\\n \\\"type\\\": \\\"formula\\\",\\n \\\"expr\\\": \\\"datum.stack == 'stk1' ? datum.stk1+datum.stk2 : datum.stk2+datum.stk1\\\",\\n \\\"as\\\": \\\"sortField\\\"\\n },\\n {\\n \\\"type\\\": \\\"stack\\\",\\n \\\"groupby\\\": [\\\"stack\\\"],\\n \\\"sort\\\": {\\\"field\\\": \\\"sortField\\\", \\\"order\\\": \\\"descending\\\"},\\n \\\"field\\\": \\\"size\\\"\\n },\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"(datum.y0+datum.y1)/2\\\", \\\"as\\\": \\\"yc\\\"}\\n ]\\n },\\n {\\n \\\"name\\\": \\\"groups\\\",\\n \\\"source\\\": \\\"nodes\\\",\\n \\\"transform\\\": [\\n {\\n \\\"type\\\": \\\"aggregate\\\",\\n \\\"groupby\\\": [\\\"stack\\\", \\\"grpId\\\"],\\n \\\"fields\\\": [\\\"size\\\"],\\n \\\"ops\\\": [\\\"sum\\\"],\\n \\\"as\\\": [\\\"total\\\"]\\n },\\n {\\n \\\"type\\\": \\\"stack\\\",\\n \\\"groupby\\\": [\\\"stack\\\"],\\n \\\"sort\\\": {\\\"field\\\": \\\"grpId\\\", \\\"order\\\": \\\"descending\\\"},\\n \\\"field\\\": \\\"total\\\"\\n },\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"scale('y', datum.y0)\\\", \\\"as\\\": \\\"scaledY0\\\"},\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"scale('y', datum.y1)\\\", \\\"as\\\": \\\"scaledY1\\\"},\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"datum.stack == 'stk1'\\\", \\\"as\\\": \\\"rightLabel\\\"},\\n {\\n \\\"type\\\": \\\"formula\\\",\\n \\\"expr\\\": \\\"datum.total/domain('y')[1]\\\",\\n \\\"as\\\": \\\"percentage\\\"\\n }\\n ]\\n },\\n {\\n \\\"name\\\": \\\"destinationNodes\\\",\\n \\\"source\\\": \\\"nodes\\\",\\n \\\"transform\\\": [{\\\"type\\\": \\\"filter\\\", \\\"expr\\\": \\\"datum.stack == 'stk2'\\\"}]\\n },\\n {\\n \\\"name\\\": \\\"edges\\\",\\n \\\"source\\\": \\\"nodes\\\",\\n \\\"transform\\\": [\\n {\\\"type\\\": \\\"filter\\\", \\\"expr\\\": \\\"datum.stack == 'stk1'\\\"},\\n {\\n \\\"type\\\": \\\"lookup\\\",\\n \\\"from\\\": \\\"destinationNodes\\\",\\n \\\"key\\\": \\\"key\\\",\\n \\\"fields\\\": [\\\"key\\\"],\\n \\\"as\\\": [\\\"target\\\"]\\n },\\n {\\n \\\"type\\\": \\\"linkpath\\\",\\n \\\"orient\\\": \\\"horizontal\\\",\\n \\\"shape\\\": \\\"diagonal\\\",\\n \\\"sourceY\\\": {\\\"expr\\\": \\\"scale('y', datum.yc)\\\"},\\n \\\"sourceX\\\": {\\\"expr\\\": \\\"scale('x', 'stk1') + bandwidth('x')\\\"},\\n \\\"targetY\\\": {\\\"expr\\\": \\\"scale('y', datum.target.yc)\\\"},\\n \\\"targetX\\\": {\\\"expr\\\": \\\"scale('x', 'stk2')\\\"}\\n },\\n {\\n \\\"type\\\": \\\"formula\\\",\\n \\\"expr\\\": \\\"range('y')[0]-scale('y', datum.size)\\\",\\n \\\"as\\\": \\\"strokeWidth\\\"\\n },\\n {\\n \\\"type\\\": \\\"formula\\\",\\n \\\"expr\\\": \\\"datum.size/domain('y')[1]\\\",\\n \\\"as\\\": \\\"percentage\\\"\\n }\\n ]\\n }\\n ],\\n \\\"scales\\\": [\\n {\\n \\\"name\\\": \\\"x\\\",\\n \\\"type\\\": \\\"band\\\",\\n \\\"range\\\": \\\"width\\\",\\n \\\"domain\\\": [\\\"stk1\\\", \\\"stk2\\\"],\\n \\\"paddingOuter\\\": 0.01,\\n \\\"paddingInner\\\": 0.98\\n },\\n {\\n \\\"name\\\": \\\"y\\\",\\n \\\"type\\\": \\\"linear\\\",\\n \\\"range\\\": \\\"height\\\",\\n \\\"domain\\\": {\\\"data\\\": \\\"nodes\\\", \\\"field\\\": \\\"y1\\\"}\\n },\\n {\\n \\\"name\\\": \\\"color\\\",\\n \\\"type\\\": \\\"ordinal\\\",\\n \\\"range\\\": \\\"category\\\",\\n \\\"domain\\\": {\\\"data\\\": \\\"rawData\\\", \\\"fields\\\": [\\\"stk1\\\",\\\"stk2\\\"]}\\n },\\n {\\n \\\"name\\\": \\\"stackNames\\\",\\n \\\"type\\\": \\\"ordinal\\\",\\n \\\"range\\\": [\\\"Source Pod\\\", \\\"Destination IP\\\"],\\n \\\"domain\\\": [\\\"stk1\\\", \\\"stk2\\\"]\\n }\\n ],\\n \\\"axes\\\": [\\n {\\n \\\"orient\\\": \\\"bottom\\\",\\n \\\"scale\\\": \\\"x\\\",\\n \\\"labelColor\\\": {\\n \\\"value\\\": \\\"#888888\\\"\\n },\\n \\\"encode\\\": {\\n \\\"labels\\\": {\\n \\\"update\\\": {\\n \\\"text\\\": {\\\"scale\\\": \\\"stackNames\\\", \\\"field\\\": \\\"value\\\"},\\n \\\"fontSize\\\": {\\\"value\\\": 14}\\n }\\n }\\n }\\n },\\n {\\n \\\"orient\\\": \\\"left\\\",\\n \\\"scale\\\": \\\"y\\\",\\n \\\"labelColor\\\": {\\n \\\"value\\\": \\\"#888888\\\"\\n },\\n \\\"encode\\\": {\\n \\\"labels\\\": {\\n \\\"update\\\": {\\n \\\"text\\\": {\\\"signal\\\": \\\"format(datum.value, '.2s') + 'B'\\\"},\\n \\\"fontSize\\\": {\\\"value\\\": 12}\\n }\\n }\\n }\\n }\\n ],\\n \\\"marks\\\": [\\n {\\n \\\"type\\\": \\\"path\\\",\\n \\\"name\\\": \\\"edgeMark\\\",\\n \\\"from\\\": {\\\"data\\\": \\\"edges\\\"},\\n \\\"clip\\\": true,\\n \\\"encode\\\": {\\n \\\"update\\\": {\\n \\\"stroke\\\": [\\n {\\n \\\"test\\\": \\\"groupSelector && groupSelector.stack=='stk1'\\\",\\n \\\"scale\\\": \\\"color\\\",\\n \\\"field\\\": \\\"stk2\\\"\\n },\\n {\\\"scale\\\": \\\"color\\\", \\\"field\\\": \\\"stk1\\\"}\\n ],\\n \\\"strokeWidth\\\": {\\\"field\\\": \\\"strokeWidth\\\"},\\n \\\"path\\\": {\\\"field\\\": \\\"path\\\"},\\n \\\"strokeOpacity\\\": {\\n \\\"signal\\\": \\\"!groupSelector && (groupHover.stk1 == datum.stk1 || groupHover.stk2 == datum.stk2) ? 0.75 : 0.3\\\"\\n },\\n \\\"zindex\\\": {\\n \\\"signal\\\": \\\"!groupSelector && (groupHover.stk1 == datum.stk1 || groupHover.stk2 == datum.stk2) ? 1 : 0\\\"\\n },\\n \\\"tooltip\\\": {\\n \\\"signal\\\": \\\"{'title': datum.stk1 + ' → ' + datum.stk2 + ' ' + format(datum.size, '.2s') + 'B (' + format(datum.percentage, '.1%') + ')', 'IP Address': datum.stk3 +' → ' + datum.stk2 }\\\"\\n }\\n },\\n \\\"hover\\\": {\\\"strokeOpacity\\\": {\\\"value\\\": 0.75}}\\n }\\n },\\n {\\n \\\"type\\\": \\\"rect\\\",\\n \\\"name\\\": \\\"groupMark\\\",\\n \\\"from\\\": {\\\"data\\\": \\\"groups\\\"},\\n \\\"encode\\\": {\\n \\\"enter\\\": {\\n \\\"fill\\\": {\\\"scale\\\": \\\"color\\\", \\\"field\\\": \\\"grpId\\\"},\\n \\\"width\\\": {\\\"scale\\\": \\\"x\\\", \\\"band\\\": 1}\\n },\\n \\\"update\\\": {\\n \\\"x\\\": {\\\"scale\\\": \\\"x\\\", \\\"field\\\": \\\"stack\\\"},\\n \\\"y\\\": {\\\"field\\\": \\\"scaledY0\\\"},\\n \\\"y2\\\": {\\\"field\\\": \\\"scaledY1\\\"},\\n \\\"fillOpacity\\\": {\\\"value\\\": 0.7},\\n \\\"tooltip\\\": {\\n \\\"signal\\\": \\\"datum.grpId + ' ' + format(datum.total, '.2s') + 'B (' + format(datum.percentage, '.1%') + ')'\\\"\\n }\\n },\\n \\\"hover\\\": {\\\"fillOpacity\\\": {\\\"value\\\": 1}}\\n }\\n },\\n {\\n \\\"type\\\": \\\"text\\\",\\n \\\"from\\\": {\\\"data\\\": \\\"groups\\\"},\\n \\\"interactive\\\": false,\\n \\\"encode\\\": {\\n \\\"update\\\": {\\n \\\"x\\\": {\\n \\\"signal\\\": \\\"scale('x', datum.stack) + (datum.rightLabel ? bandwidth('x') + 8 : -8)\\\"\\n },\\n \\\"yc\\\": {\\\"signal\\\": \\\"(datum.scaledY0 + datum.scaledY1)/2\\\"},\\n \\\"align\\\": {\\\"signal\\\": \\\"datum.rightLabel ? 'left' : 'right'\\\"},\\n \\\"baseline\\\": {\\\"value\\\": \\\"middle\\\"},\\n \\\"fontWeight\\\": {\\\"value\\\": \\\"bold\\\"},\\n \\\"fontSize\\\": {\\\"value\\\": 12},\\n \\\"text\\\": {\\n \\\"signal\\\": \\\"abs(datum.scaledY0-datum.scaledY1) > 10 ? datum.grpId : ''\\\"\\n }\\n }\\n }\\n },\\n {\\n \\\"type\\\": \\\"group\\\",\\n \\\"data\\\": [\\n {\\n \\\"name\\\": \\\"dataForShowAll\\\",\\n \\\"values\\\": [{}],\\n \\\"transform\\\": [{\\\"type\\\": \\\"filter\\\", \\\"expr\\\": \\\"groupSelector\\\"}]\\n }\\n ],\\n \\\"encode\\\": {\\n \\\"enter\\\": {\\n \\\"xc\\\": {\\\"signal\\\": \\\"width/2\\\"},\\n \\\"y\\\": {\\\"value\\\": 30},\\n \\\"width\\\": {\\\"value\\\": 100},\\n \\\"height\\\": {\\\"value\\\": 36}\\n }\\n },\\n \\\"marks\\\": [\\n {\\n \\\"type\\\": \\\"group\\\",\\n \\\"name\\\": \\\"groupReset\\\",\\n \\\"from\\\": {\\\"data\\\": \\\"dataForShowAll\\\"},\\n \\\"encode\\\": {\\n \\\"enter\\\": {\\n \\\"cornerRadius\\\": {\\\"value\\\": 3.5},\\n \\\"fill\\\": {\\\"value\\\": \\\"#666666\\\"},\\n \\\"height\\\": {\\\"field\\\": {\\\"group\\\": \\\"height\\\"}},\\n \\\"width\\\": {\\\"field\\\": {\\\"group\\\": \\\"width\\\"}}\\n },\\n \\\"update\\\": {\\\"opacity\\\": {\\\"value\\\": 1}},\\n \\\"hover\\\": {\\\"fill\\\": {\\\"value\\\": \\\"#444444\\\"}}\\n },\\n \\\"marks\\\": [\\n {\\n \\\"type\\\": \\\"text\\\",\\n \\\"interactive\\\": false,\\n \\\"encode\\\": {\\n \\\"enter\\\": {\\n \\\"xc\\\": {\\\"field\\\": {\\\"group\\\": \\\"width\\\"}, \\\"mult\\\": 0.5},\\n \\\"yc\\\": {\\\"field\\\": {\\\"group\\\": \\\"height\\\"}, \\\"mult\\\": 0.5, \\\"offset\\\": 1},\\n \\\"align\\\": {\\\"value\\\": \\\"center\\\"},\\n \\\"baseline\\\": {\\\"value\\\": \\\"middle\\\"},\\n \\\"text\\\": {\\\"value\\\": \\\"Show All\\\"},\\n \\\"fontSize\\\": {\\\"value\\\": 14},\\n \\\"stroke\\\": {\\\"value\\\": \\\"#ecf0f1\\\"}\\n }\\n }\\n }\\n ]\\n }\\n ]\\n }\\n ],\\n \\\"signals\\\": [\\n {\\n \\\"name\\\": \\\"groupHover\\\",\\n \\\"value\\\": {},\\n \\\"on\\\": [\\n {\\n \\\"events\\\": \\\"@groupMark:mouseover\\\",\\n \\\"update\\\": \\\"{stk1:datum.stack=='stk1' && datum.grpId, stk2:datum.stack=='stk2' && datum.grpId}\\\"\\n },\\n {\\\"events\\\": \\\"mouseout\\\", \\\"update\\\": \\\"{}\\\"}\\n ]\\n },\\n {\\n \\\"name\\\": \\\"groupSelector\\\",\\n \\\"value\\\": false,\\n \\\"on\\\": [\\n {\\n \\\"events\\\": \\\"@groupMark:click!\\\",\\n \\\"update\\\": \\\"{stack:datum.stack, stk1:datum.stack=='stk1' && datum.grpId, stk2:datum.stack=='stk2' && datum.grpId}\\\"\\n },\\n {\\n \\\"events\\\": [\\n {\\\"type\\\": \\\"click\\\", \\\"markname\\\": \\\"groupReset\\\"},\\n {\\\"type\\\": \\\"dblclick\\\"}\\n ],\\n \\\"update\\\": \\\"false\\\"\\n }\\n ]\\n }\\n ]\\n}\"},\"title\":\"Pod-to-External Traffic Cumulative Bytes\"}"},"id":"7a428f90-a937-11eb-a7ef-5dcb53008c10","migrationVersion":{"visualization":"7.8.0"},"references":[],"type":"visualization","updated_at":"2021-08-07T23:30:40.150Z","version":"WzMyLDFd"} -{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}"},"title":"Tx Mbps by Pod-to-External Flow","uiStateJSON":"{}","version":1,"visState":"{\"type\":\"metrics\",\"aggs\":[],\"params\":{\"id\":\"61ca57f0-469d-11e7-af02-69e470af7417\",\"type\":\"timeseries\",\"axis_position\":\"left\",\"axis_formatter\":\"number\",\"show_legend\":1,\"show_grid\":1,\"axis_min\":\"0\",\"filter\":\"\",\"axis_scale\":\"normal\",\"default_index_pattern\":\"flow-*\",\"default_timefield\":\"@timestamp\",\"isModelInvalid\":false,\"index_pattern\":\"flow-*\",\"interval\":\"1m\",\"time_field\":\"ipfix.flowEndSeconds\",\"background_color_rules\":[{\"id\":\"4010d970-50b9-11eb-8f30-87baf4f5ad91\"}],\"series\":[{\"id\":\"61ca57f1-469d-11e7-af02-69e470af7417\",\"color\":\"rgba(144,201,227,1)\",\"split_mode\":\"terms\",\"metrics\":[{\"id\":\"a1ba0060-b9a7-11ea-9740-552c943910e4\",\"type\":\"sum\",\"field\":\"ipfix.throughput\"},{\"script\":\"params.bytes * 8 \",\"id\":\"dd0b81d0-b9a6-11ea-9740-552c943910e4\",\"type\":\"calculation\",\"variables\":[{\"id\":\"e1f87e50-b9a6-11ea-9740-552c943910e4\",\"name\":\"bytes\",\"field\":\"a1ba0060-b9a7-11ea-9740-552c943910e4\"}]}],\"separate_axis\":0,\"axis_position\":\"right\",\"formatter\":\"bytes\",\"chart_type\":\"line\",\"line_width\":\"2\",\"point_size\":\"0\",\"fill\":\"0.6\",\"stacked\":\"none\",\"split_color_mode\":\"rainbow\",\"label\":\"Bytes\",\"terms_field\":\"ipfix.flowKeyPodToExternal.keyword\",\"terms_size\":\"30\",\"terms_order_by\":\"a1ba0060-b9a7-11ea-9740-552c943910e4\",\"value_template\":\"{{value}}it/s\",\"type\":\"timeseries\",\"terms_exclude\":\"\",\"filter\":{\"query\":\"\",\"language\":\"kuery\"}}]},\"title\":\"Tx Mbps by Pod-to-External Flow\"}"},"id":"4a9b7d30-a93f-11eb-a7ef-5dcb53008c10","migrationVersion":{"visualization":"7.8.0"},"references":[],"type":"visualization","updated_at":"2021-08-07T23:30:40.150Z","version":"WzMzLDFd"} -{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}"},"title":"Cumulative Bandwidth by Pod-to-External Flow","uiStateJSON":"{}","version":1,"visState":"{\"type\":\"metrics\",\"aggs\":[],\"params\":{\"id\":\"61ca57f0-469d-11e7-af02-69e470af7417\",\"type\":\"timeseries\",\"axis_position\":\"left\",\"axis_formatter\":\"number\",\"show_legend\":1,\"show_grid\":1,\"axis_min\":\"0\",\"filter\":\"\",\"axis_scale\":\"normal\",\"default_index_pattern\":\"flow-*\",\"default_timefield\":\"@timestamp\",\"isModelInvalid\":false,\"index_pattern\":\"flow-*\",\"interval\":\"1m\",\"time_field\":\"ipfix.flowEndSeconds\",\"series\":[{\"id\":\"61ca57f1-469d-11e7-af02-69e470af7417\",\"color\":\"rgba(144,201,227,1)\",\"split_mode\":\"terms\",\"metrics\":[{\"id\":\"a1ba0060-b9a7-11ea-9740-552c943910e4\",\"type\":\"sum\",\"field\":\"ipfix.octetTotalCountFromSourceNode\"},{\"script\":\"params.bytes * 8\",\"id\":\"dd0b81d0-b9a6-11ea-9740-552c943910e4\",\"type\":\"calculation\",\"variables\":[{\"id\":\"e1f87e50-b9a6-11ea-9740-552c943910e4\",\"name\":\"bytes\",\"field\":\"a1ba0060-b9a7-11ea-9740-552c943910e4\"}]}],\"separate_axis\":0,\"axis_position\":\"right\",\"formatter\":\"bytes\",\"chart_type\":\"line\",\"line_width\":\"2\",\"point_size\":\"0\",\"fill\":\"0.6\",\"stacked\":\"none\",\"split_color_mode\":\"rainbow\",\"label\":\"Bytes\",\"terms_field\":\"ipfix.flowKeyPodToExternal.keyword\",\"terms_size\":\"30\",\"terms_order_by\":\"a1ba0060-b9a7-11ea-9740-552c943910e4\",\"value_template\":\"{{value}}\",\"type\":\"timeseries\"}]},\"title\":\"Cumulative Bandwidth by Pod-to-External Flow\"}"},"id":"73518c10-a93f-11eb-a7ef-5dcb53008c10","migrationVersion":{"visualization":"7.8.0"},"references":[],"type":"visualization","updated_at":"2021-08-07T23:30:40.150Z","version":"WzM0LDFd"} -{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}"},"title":"Rx Mbps by Pod-to-External Flow","uiStateJSON":"{}","version":1,"visState":"{\"type\":\"metrics\",\"aggs\":[],\"params\":{\"id\":\"61ca57f0-469d-11e7-af02-69e470af7417\",\"type\":\"timeseries\",\"axis_position\":\"left\",\"axis_formatter\":\"number\",\"show_legend\":1,\"show_grid\":1,\"axis_min\":\"0\",\"filter\":\"\",\"axis_scale\":\"normal\",\"default_index_pattern\":\"flow-*\",\"default_timefield\":\"@timestamp\",\"isModelInvalid\":false,\"index_pattern\":\"flow-*\",\"interval\":\"1m\",\"time_field\":\"ipfix.flowEndSeconds\",\"legend_position\":\"right\",\"series\":[{\"id\":\"61ca57f1-469d-11e7-af02-69e470af7417\",\"color\":\"rgba(144,201,227,1)\",\"split_mode\":\"terms\",\"metrics\":[{\"id\":\"a1ba0060-b9a7-11ea-9740-552c943910e4\",\"type\":\"sum\",\"field\":\"ipfix.reverseThroughput\"},{\"script\":\"params.bytes * 8 \",\"id\":\"dd0b81d0-b9a6-11ea-9740-552c943910e4\",\"type\":\"calculation\",\"variables\":[{\"id\":\"e1f87e50-b9a6-11ea-9740-552c943910e4\",\"name\":\"bytes\",\"field\":\"a1ba0060-b9a7-11ea-9740-552c943910e4\"}]}],\"separate_axis\":0,\"axis_position\":\"right\",\"formatter\":\"bytes\",\"chart_type\":\"line\",\"line_width\":\"2\",\"point_size\":\"0\",\"fill\":\"0.6\",\"stacked\":\"none\",\"split_color_mode\":\"rainbow\",\"label\":\"Bytes\",\"terms_field\":\"ipfix.flowKeyPodToExternal.keyword\",\"terms_size\":\"30\",\"terms_order_by\":\"a1ba0060-b9a7-11ea-9740-552c943910e4\",\"value_template\":\"{{value}}it/s\",\"type\":\"timeseries\",\"terms_exclude\":\"\"}]},\"title\":\"Rx Mbps by Pod-to-External Flow\"}"},"id":"857d7e80-a93f-11eb-a7ef-5dcb53008c10","migrationVersion":{"visualization":"7.8.0"},"references":[],"type":"visualization","updated_at":"2021-08-07T23:30:40.150Z","version":"WzM1LDFd"} -{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}"},"title":"Aggregated Rx Mbps by Pod Acting as Source","uiStateJSON":"{}","version":1,"visState":"{\"type\":\"metrics\",\"aggs\":[],\"params\":{\"id\":\"61ca57f0-469d-11e7-af02-69e470af7417\",\"type\":\"timeseries\",\"axis_position\":\"left\",\"axis_formatter\":\"number\",\"show_legend\":1,\"show_grid\":1,\"axis_min\":\"0\",\"filter\":\"\",\"axis_scale\":\"normal\",\"default_index_pattern\":\"flow-*\",\"default_timefield\":\"@timestamp\",\"isModelInvalid\":false,\"index_pattern\":\"flow-*\",\"interval\":\"1m\",\"time_field\":\"ipfix.flowEndSeconds\",\"series\":[{\"id\":\"61ca57f1-469d-11e7-af02-69e470af7417\",\"color\":\"rgba(144,201,227,1)\",\"split_mode\":\"terms\",\"metrics\":[{\"id\":\"a1ba0060-b9a7-11ea-9740-552c943910e4\",\"type\":\"sum\",\"field\":\"ipfix.reverseThroughput\"},{\"script\":\"params.bytes * 8\",\"id\":\"dd0b81d0-b9a6-11ea-9740-552c943910e4\",\"type\":\"calculation\",\"variables\":[{\"id\":\"e1f87e50-b9a6-11ea-9740-552c943910e4\",\"name\":\"bytes\",\"field\":\"a1ba0060-b9a7-11ea-9740-552c943910e4\"}]}],\"separate_axis\":0,\"axis_position\":\"right\",\"formatter\":\"bytes\",\"chart_type\":\"line\",\"line_width\":\"2\",\"point_size\":\"0\",\"fill\":\"0.6\",\"stacked\":\"none\",\"split_color_mode\":\"rainbow\",\"label\":\"Bytes\",\"terms_field\":\"ipfix.sourcePodName.keyword\",\"terms_size\":\"30\",\"terms_order_by\":\"a1ba0060-b9a7-11ea-9740-552c943910e4\",\"value_template\":\"{{value}}its/s\",\"type\":\"timeseries\"}]},\"title\":\"Aggregated Rx Mbps by Pod Acting as Source\"}"},"id":"68f05640-c243-11ea-873e-8f9a9a3cbdc1","migrationVersion":{"visualization":"7.8.0"},"references":[],"type":"visualization","updated_at":"2021-08-07T23:30:40.150Z","version":"WzM2LDFd"} -{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"language\":\"lucene\",\"query\":\"\"},\"filter\":[]}"},"title":"Title: From Source Node","uiStateJSON":"{}","version":1,"visState":"{\"type\":\"metrics\",\"aggs\":[],\"params\":{\"axis_formatter\":\"number\",\"axis_position\":\"left\",\"axis_scale\":\"normal\",\"default_index_pattern\":\"flow-*\",\"default_timefield\":\"@timestamp\",\"id\":\"61ca57f0-469d-11e7-af02-69e470af7417\",\"index_pattern\":\"flow-*\",\"interval\":\"auto\",\"isModelInvalid\":false,\"markdown_vertical_align\":\"top\",\"series\":[{\"axis_position\":\"right\",\"chart_type\":\"line\",\"color\":\"#68BC00\",\"fill\":0.5,\"formatter\":\"number\",\"id\":\"61ca57f1-469d-11e7-af02-69e470af7417\",\"line_width\":1,\"metrics\":[{\"id\":\"61ca57f2-469d-11e7-af02-69e470af7417\",\"type\":\"count\"}],\"offset_time\":\"-5y\",\"point_size\":1,\"separate_axis\":0,\"split_color_mode\":\"gradient\",\"split_mode\":\"everything\",\"stacked\":\"none\"}],\"show_grid\":1,\"show_legend\":1,\"time_field\":null,\"type\":\"markdown\",\"markdown_css\":\"#markdown-61ca57f0-469d-11e7-af02-69e470af7417 p{font-size:8pt;margin-top:0;margin-bottom:8px;text-align:left}\",\"markdown_less\":\"p {\\n font-size: 8pt;\\n margin-top: 0px;\\n margin-bottom: 8px;\\n text-align: left;\\n}\",\"markdown\":\"**\\\\*All stats are from source Node if the flow is in between two Nodes (inter-Node flows). This distinction is not applicable for intra-Node flows.**\"},\"title\":\"Title: From Source Node\"}"},"id":"f8323bc0-514f-11eb-a19a-05e08a82dcf8","migrationVersion":{"visualization":"7.8.0"},"references":[],"type":"visualization","updated_at":"2021-08-07T23:30:40.150Z","version":"WzM3LDFd"} -{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}"},"title":"Reverse Cumulative Bandwidth by Pod-to-External Flow","uiStateJSON":"{}","version":1,"visState":"{\"type\":\"metrics\",\"aggs\":[],\"params\":{\"id\":\"61ca57f0-469d-11e7-af02-69e470af7417\",\"type\":\"timeseries\",\"axis_position\":\"left\",\"axis_formatter\":\"number\",\"show_legend\":1,\"show_grid\":1,\"axis_min\":\"0\",\"filter\":\"\",\"axis_scale\":\"normal\",\"default_index_pattern\":\"flow-*\",\"default_timefield\":\"@timestamp\",\"isModelInvalid\":false,\"index_pattern\":\"flow-*\",\"interval\":\"1m\",\"time_field\":\"ipfix.flowEndSeconds\",\"series\":[{\"id\":\"61ca57f1-469d-11e7-af02-69e470af7417\",\"color\":\"rgba(144,201,227,1)\",\"split_mode\":\"terms\",\"metrics\":[{\"id\":\"a1ba0060-b9a7-11ea-9740-552c943910e4\",\"type\":\"sum\",\"field\":\"ipfix.reverseOctetTotalCountFromSourceNode\"},{\"script\":\"params.bytes * 8\",\"id\":\"dd0b81d0-b9a6-11ea-9740-552c943910e4\",\"type\":\"calculation\",\"variables\":[{\"id\":\"e1f87e50-b9a6-11ea-9740-552c943910e4\",\"name\":\"bytes\",\"field\":\"a1ba0060-b9a7-11ea-9740-552c943910e4\"}]}],\"separate_axis\":0,\"axis_position\":\"right\",\"formatter\":\"bytes\",\"chart_type\":\"line\",\"line_width\":\"2\",\"point_size\":\"0\",\"fill\":\"0.6\",\"stacked\":\"none\",\"split_color_mode\":\"rainbow\",\"label\":\"Bytes\",\"terms_field\":\"ipfix.flowKeyPodToExternal.keyword\",\"terms_size\":\"30\",\"terms_order_by\":\"a1ba0060-b9a7-11ea-9740-552c943910e4\",\"value_template\":\"{{value}}\",\"type\":\"timeseries\"}]},\"title\":\"Reverse Cumulative Bandwidth by Pod-to-External Flow\"}"},"id":"94adbd20-a93f-11eb-a7ef-5dcb53008c10","migrationVersion":{"visualization":"7.8.0"},"references":[],"type":"visualization","updated_at":"2021-08-07T23:30:40.150Z","version":"WzM4LDFd"} -{"attributes":{"description":"","hits":0,"kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"language\":\"kuery\",\"query\":\"\"},\"filter\":[]}"},"optionsJSON":"{\"hidePanelTitles\":false,\"useMargins\":true}","panelsJSON":"[{\"embeddableConfig\":{\"title\":\"\"},\"gridData\":{\"h\":3,\"i\":\"13e1880c-a00d-42e2-bbaa-9f3dcaddbb18\",\"w\":48,\"x\":0,\"y\":0},\"panelIndex\":\"13e1880c-a00d-42e2-bbaa-9f3dcaddbb18\",\"version\":\"7.8.0\",\"panelRefName\":\"panel_0\"},{\"embeddableConfig\":{\"title\":\"\"},\"gridData\":{\"h\":5,\"i\":\"f5f6c39c-9514-4025-a240-250cfbfc1ab6\",\"w\":48,\"x\":0,\"y\":3},\"panelIndex\":\"f5f6c39c-9514-4025-a240-250cfbfc1ab6\",\"version\":\"7.8.0\",\"panelRefName\":\"panel_1\"},{\"embeddableConfig\":{},\"gridData\":{\"h\":27,\"i\":\"ea45ecd2-c2f9-4973-b999-93f4ba1d3e19\",\"w\":24,\"x\":0,\"y\":8},\"panelIndex\":\"ea45ecd2-c2f9-4973-b999-93f4ba1d3e19\",\"version\":\"7.8.0\",\"panelRefName\":\"panel_2\"},{\"embeddableConfig\":{},\"gridData\":{\"h\":27,\"i\":\"a3fb9b2d-6839-49dc-b1fb-b00a10f02bb6\",\"w\":24,\"x\":24,\"y\":8},\"panelIndex\":\"a3fb9b2d-6839-49dc-b1fb-b00a10f02bb6\",\"version\":\"7.8.0\",\"panelRefName\":\"panel_3\"},{\"embeddableConfig\":{},\"gridData\":{\"h\":15,\"i\":\"84015a09-6cef-47c2-9ff8-422816d286ca\",\"w\":24,\"x\":0,\"y\":35},\"panelIndex\":\"84015a09-6cef-47c2-9ff8-422816d286ca\",\"version\":\"7.8.0\",\"panelRefName\":\"panel_4\"},{\"embeddableConfig\":{},\"gridData\":{\"h\":15,\"i\":\"735892b3-e4d8-4f75-b858-7464477a7adf\",\"w\":24,\"x\":24,\"y\":35},\"panelIndex\":\"735892b3-e4d8-4f75-b858-7464477a7adf\",\"version\":\"7.8.0\",\"panelRefName\":\"panel_5\"},{\"embeddableConfig\":{},\"gridData\":{\"h\":15,\"i\":\"d83090d2-4aa6-4e62-957e-135412ff1c7e\",\"w\":24,\"x\":0,\"y\":50},\"panelIndex\":\"d83090d2-4aa6-4e62-957e-135412ff1c7e\",\"version\":\"7.8.0\",\"panelRefName\":\"panel_6\"},{\"embeddableConfig\":{},\"gridData\":{\"h\":15,\"i\":\"d3a735b0-e1e7-4751-89f4-f69be3d341c5\",\"w\":24,\"x\":24,\"y\":65},\"panelIndex\":\"d3a735b0-e1e7-4751-89f4-f69be3d341c5\",\"version\":\"7.8.0\",\"panelRefName\":\"panel_7\"},{\"embeddableConfig\":{\"title\":\"Aggregated Tx Mbps by Pod Acting as Source\"},\"gridData\":{\"h\":15,\"i\":\"94c135b5-ab6b-41db-831e-7adb96282635\",\"w\":24,\"x\":0,\"y\":65},\"panelIndex\":\"94c135b5-ab6b-41db-831e-7adb96282635\",\"title\":\"Aggregated Tx Mbps by Pod Acting as Source\",\"version\":\"7.8.0\",\"panelRefName\":\"panel_8\"},{\"embeddableConfig\":{\"title\":\"\"},\"gridData\":{\"h\":2,\"i\":\"3b5dd519-11fe-41d0-9379-d6d8576fb688\",\"w\":48,\"x\":0,\"y\":80},\"panelIndex\":\"3b5dd519-11fe-41d0-9379-d6d8576fb688\",\"version\":\"7.8.0\",\"panelRefName\":\"panel_9\"},{\"embeddableConfig\":{},\"gridData\":{\"h\":15,\"i\":\"0d9793b3-945a-48f9-9260-139776553b25\",\"w\":24,\"x\":24,\"y\":50},\"panelIndex\":\"0d9793b3-945a-48f9-9260-139776553b25\",\"version\":\"7.8.0\",\"panelRefName\":\"panel_10\"}]","timeRestore":false,"title":"Pod-to-External Flow Dashboard","version":1},"id":"3ed71e80-a92d-11eb-a7ef-5dcb53008c10","migrationVersion":{"dashboard":"7.3.0"},"references":[{"id":"af8f70b0-a93b-11eb-a7ef-5dcb53008c10","name":"panel_0","type":"visualization"},{"id":"1ec263c0-a93c-11eb-a7ef-5dcb53008c10","name":"panel_1","type":"visualization"},{"id":"7a428f90-a937-11eb-a7ef-5dcb53008c10","name":"panel_2","type":"visualization"},{"id":"0d0aac60-a93b-11eb-a7ef-5dcb53008c10","name":"panel_3","type":"visualization"},{"id":"4a9b7d30-a93f-11eb-a7ef-5dcb53008c10","name":"panel_4","type":"visualization"},{"id":"73518c10-a93f-11eb-a7ef-5dcb53008c10","name":"panel_5","type":"visualization"},{"id":"857d7e80-a93f-11eb-a7ef-5dcb53008c10","name":"panel_6","type":"visualization"},{"id":"68f05640-c243-11ea-873e-8f9a9a3cbdc1","name":"panel_7","type":"visualization"},{"id":"114eba40-55d4-11e8-a695-171fb712da36","name":"panel_8","type":"visualization"},{"id":"f8323bc0-514f-11eb-a19a-05e08a82dcf8","name":"panel_9","type":"visualization"},{"id":"94adbd20-a93f-11eb-a7ef-5dcb53008c10","name":"panel_10","type":"visualization"}],"type":"dashboard","updated_at":"2021-08-07T23:30:40.150Z","version":"WzM5LDFd"} -{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\",\"filter\":[]}"},"title":"Egress Network Policy Packets","uiStateJSON":"{\"vis\":{\"colors\":{\"default\":\"#F2C96D\"}}}","version":1,"visState":"{\"type\":\"pie\",\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"sum\",\"schema\":\"metric\",\"params\":{\"field\":\"ipfix.packets\"}},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"segment\",\"params\":{\"field\":\"ipfix.egressNetworkPolicyNamespace.keyword\",\"orderBy\":\"1\",\"order\":\"desc\",\"size\":30,\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\",\"exclude\":\"\",\"customLabel\":\"Namespace\"}},{\"id\":\"3\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"segment\",\"params\":{\"field\":\"ipfix.egressNetworkPolicyName.keyword\",\"orderBy\":\"1\",\"order\":\"desc\",\"size\":5,\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\",\"customLabel\":\"Network Policy Name\"}}],\"params\":{\"type\":\"pie\",\"addTooltip\":true,\"addLegend\":true,\"legendPosition\":\"right\",\"isDonut\":true,\"labels\":{\"show\":false,\"values\":true,\"last_level\":true,\"truncate\":100},\"dimensions\":{\"metric\":{\"accessor\":0,\"format\":{\"id\":\"number\"},\"params\":{},\"aggType\":\"count\"}}},\"title\":\"Egress Network Policy Packets\"}"},"id":"40e05390-23b8-11eb-90d2-a7a4de48218a","migrationVersion":{"visualization":"7.8.0"},"references":[{"id":"e2ab2c50-b981-11ea-b16e-fb06687c3589","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"}],"type":"visualization","updated_at":"2021-08-07T23:30:40.150Z","version":"WzQwLDFd"} -{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}"},"title":"Network Policy Filter","uiStateJSON":"{}","version":1,"visState":"{\"type\":\"input_control_vis\",\"aggs\":[],\"params\":{\"controls\":[{\"id\":\"1526108883717\",\"fieldName\":\"ipfix.egressNetworkPolicyNamespace.keyword\",\"label\":\"Egress Network Policy Namespace\",\"type\":\"list\",\"options\":{\"type\":\"terms\",\"multiselect\":true,\"size\":1000,\"order\":\"desc\",\"dynamicOptions\":false},\"indexPatternRefName\":\"control_0_index_pattern\"},{\"id\":\"1526107640219\",\"fieldName\":\"ipfix.egressNetworkPolicyName.keyword\",\"label\":\"Egress Network Policy Name\",\"type\":\"list\",\"options\":{\"type\":\"terms\",\"multiselect\":true,\"size\":1000,\"order\":\"desc\",\"dynamicOptions\":false},\"indexPatternRefName\":\"control_1_index_pattern\"},{\"id\":\"1592936602245\",\"fieldName\":\"ipfix.ingressNetworkPolicyNamespace.keyword\",\"parent\":\"\",\"label\":\"Ingress Network Policy Namespace\",\"type\":\"list\",\"options\":{\"type\":\"terms\",\"multiselect\":true,\"dynamicOptions\":false,\"size\":1000,\"order\":\"desc\"},\"indexPatternRefName\":\"control_2_index_pattern\"},{\"id\":\"1526108909005\",\"fieldName\":\"ipfix.ingressNetworkPolicyName.keyword\",\"label\":\"Ingress Network Policy Name\",\"type\":\"list\",\"options\":{\"type\":\"terms\",\"multiselect\":true,\"size\":1000,\"order\":\"desc\",\"dynamicOptions\":false},\"indexPatternRefName\":\"control_3_index_pattern\"}],\"updateFiltersOnChange\":true,\"useTimeFilter\":true,\"pinFilters\":true},\"title\":\"Network Policy Filter\"}"},"id":"4b5a40a0-23b9-11eb-90d2-a7a4de48218a","migrationVersion":{"visualization":"7.8.0"},"references":[{"id":"e2ab2c50-b981-11ea-b16e-fb06687c3589","name":"control_0_index_pattern","type":"index-pattern"},{"id":"e2ab2c50-b981-11ea-b16e-fb06687c3589","name":"control_1_index_pattern","type":"index-pattern"},{"id":"e2ab2c50-b981-11ea-b16e-fb06687c3589","name":"control_2_index_pattern","type":"index-pattern"},{"id":"e2ab2c50-b981-11ea-b16e-fb06687c3589","name":"control_3_index_pattern","type":"index-pattern"}],"type":"visualization","updated_at":"2021-08-07T23:30:40.150Z","version":"WzQxLDFd"} -{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}"},"title":"Aggregated Tx Mbps by Pod Acting as Destination","uiStateJSON":"{}","version":1,"visState":"{\"type\":\"metrics\",\"aggs\":[],\"params\":{\"id\":\"61ca57f0-469d-11e7-af02-69e470af7417\",\"type\":\"timeseries\",\"axis_position\":\"left\",\"axis_formatter\":\"number\",\"show_legend\":1,\"show_grid\":1,\"axis_min\":\"0\",\"filter\":\"\",\"axis_scale\":\"normal\",\"default_index_pattern\":\"flow-*\",\"default_timefield\":\"@timestamp\",\"isModelInvalid\":false,\"index_pattern\":\"flow-*\",\"time_field\":\"@timestamp\",\"interval\":\"1m\",\"series\":[{\"id\":\"61ca57f1-469d-11e7-af02-69e470af7417\",\"color\":\"rgba(144,201,227,1)\",\"split_mode\":\"terms\",\"metrics\":[{\"id\":\"a1ba0060-b9a7-11ea-9740-552c943910e4\",\"type\":\"sum\",\"field\":\"ipfix.reverseOctetDeltaCount\"},{\"id\":\"071b3440-50b8-11eb-8f30-87baf4f5ad91\",\"type\":\"avg\",\"field\":\"ipfix.interval\"},{\"script\":\"params.bytes * 8 / params.interval\",\"id\":\"dd0b81d0-b9a6-11ea-9740-552c943910e4\",\"type\":\"calculation\",\"variables\":[{\"id\":\"e1f87e50-b9a6-11ea-9740-552c943910e4\",\"name\":\"bytes\",\"field\":\"a1ba0060-b9a7-11ea-9740-552c943910e4\"},{\"id\":\"0e3aa120-50b8-11eb-8f30-87baf4f5ad91\",\"name\":\"interval\",\"field\":\"071b3440-50b8-11eb-8f30-87baf4f5ad91\"}]}],\"separate_axis\":0,\"axis_position\":\"right\",\"formatter\":\"bytes\",\"chart_type\":\"line\",\"line_width\":1,\"point_size\":\"0\",\"fill\":\"0.6\",\"stacked\":\"stacked\",\"split_color_mode\":\"rainbow\",\"label\":\"Bytes\",\"terms_field\":\"ipfix.destinationPodName.keyword\",\"terms_size\":\"30\",\"terms_order_by\":\"a1ba0060-b9a7-11ea-9740-552c943910e4\",\"value_template\":\"{{value}}its/s\",\"type\":\"timeseries\"}]},\"title\":\"Aggregated Tx Mbps by Pod Acting as Destination\"}"},"id":"4dde25b0-b9a8-11ea-b16e-fb06687c3589","migrationVersion":{"visualization":"7.8.0"},"references":[],"type":"visualization","updated_at":"2021-08-07T23:30:40.150Z","version":"WzQyLDFd"} -{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"lucene\"},\"filter\":[]}"},"title":"Node Nav","uiStateJSON":"{}","version":1,"visState":"{\"type\":\"metrics\",\"aggs\":[],\"params\":{\"id\":\"61ca57f0-469d-11e7-af02-69e470af7417\",\"type\":\"markdown\",\"series\":[{\"id\":\"61ca57f1-469d-11e7-af02-69e470af7417\",\"color\":\"#68BC00\",\"split_mode\":\"everything\",\"metrics\":[{\"id\":\"61ca57f2-469d-11e7-af02-69e470af7417\",\"type\":\"count\"}],\"separate_axis\":0,\"axis_position\":\"right\",\"formatter\":\"number\",\"chart_type\":\"line\",\"line_width\":1,\"point_size\":1,\"fill\":0.5,\"stacked\":\"none\",\"offset_time\":\"-5y\",\"split_color_mode\":\"gradient\"}],\"interval\":\"auto\",\"axis_position\":\"left\",\"axis_formatter\":\"number\",\"axis_scale\":\"normal\",\"show_legend\":1,\"show_grid\":1,\"markdown_vertical_align\":\"top\",\"default_index_pattern\":\"flow-*\",\"default_timefield\":\"@timestamp\",\"isModelInvalid\":false,\"time_field\":null,\"index_pattern\":\"flow-*\",\"markdown_css\":\"#markdown-61ca57f0-469d-11e7-af02-69e470af7417 p{color:#cccccc;margin-top:0;margin-bottom:8px;text-align:right}#markdown-61ca57f0-469d-11e7-af02-69e470af7417 p a{color:#1eadbd;font-size:17px;font-weight:bold;text-decoration:none}#markdown-61ca57f0-469d-11e7-af02-69e470af7417 p a strong{color:#ffac12;font-weight:bold}#markdown-61ca57f0-469d-11e7-af02-69e470af7417 hr{background-color:#cccccc;margin:0;height:1px}\",\"markdown_less\":\"p {\\n color: #cccccc;\\n margin-top: 0px;\\n margin-bottom: 8px;\\n text-align: right;\\n}\\np a {\\n color: #1eadbd;\\n\\tfont-size: 17px;\\n\\tfont-weight: bold;\\n\\ttext-decoration: none;\\n}\\np a strong {\\n color: #ffac12;\\n\\tfont-weight: bold;\\n}\\nhr {\\n background-color: #cccccc;\\n margin: 0px;\\n height: 1px;\\n}\",\"markdown\":\"[Overview](#/dashboard/3b331b30-b987-11ea-b16e-fb06687c3589) | [Pod-to-Pod Flow](#/dashboard/c2b15fb0-b9a8-11ea-b16e-fb06687c3589) | [Pod-to-External Flow](#/dashboard/3ed71e80-a92d-11eb-a7ef-5dcb53008c10) | [Pod-to-Service Flow](#/dashboard/6d77e8a0-513a-11eb-a19a-05e08a82dcf8) | [**Node**](#/dashboard/5400cdf0-cd2e-11ea-8911-87da3aad0324) | [Network Policy](#/dashboard/c5af6850-23b2-11eb-90d2-a7a4de48218a) | [Flow Records](#/dashboard/2ab9c220-b984-11ea-b16e-fb06687c3589)\\n\"},\"title\":\"Node Nav\"}"},"id":"c0940350-cd43-11ea-8911-87da3aad0324","migrationVersion":{"visualization":"7.8.0"},"references":[],"type":"visualization","updated_at":"2021-08-07T23:30:40.150Z","version":"WzQzLDFd"} -{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"lucene\"},\"filter\":[]}"},"title":"Node Cumulative Bytes","uiStateJSON":"{}","version":1,"visState":"{\"type\":\"vega\",\"aggs\":[],\"params\":{\"spec\":\"{\\n \\\"$schema\\\": \\\"https://vega.github.io/schema/vega/v3.0.json\\\",\\n \\\"data\\\": [\\n {\\n \\\"name\\\": \\\"rawData\\\",\\n \\\"url\\\": {\\n \\\"%context%\\\": true,\\n \\\"%timefield%\\\": \\\"@timestamp\\\",\\n \\\"index\\\": \\\"flow-*\\\",\\n \\\"body\\\": {\\n \\\"size\\\": 0,\\n \\\"aggs\\\": {\\n \\\"table\\\": {\\n \\\"composite\\\": {\\n \\\"size\\\": 1000,\\n \\\"sources\\\": [\\n {\\\"stk1\\\": {\\\"terms\\\": {\\\"field\\\": \\\"ipfix.sourceNodeName.keyword\\\"}}},\\n {\\\"stk2\\\": {\\\"terms\\\": {\\\"field\\\": \\\"ipfix.destinationNodeName.keyword\\\"}}},\\n {\\\"stk3\\\": {\\\"terms\\\": {\\\"field\\\": \\\"ipfix.sourceIP.keyword\\\"}}},\\n {\\\"stk4\\\": {\\\"terms\\\": {\\\"field\\\": \\\"ipfix.destinationIP.keyword\\\"}}}\\n ]\\n },\\n \\t\\t\\t\\\"aggs\\\": {\\n \\t\\t\\t\\t\\\"bytes\\\": {\\n \\t\\t\\t\\t\\t\\\"sum\\\": {\\n \\t\\t\\t\\t\\t\\t\\\"field\\\": \\\"ipfix.octetDeltaCountFromSourceNode\\\"\\n \\t\\t\\t\\t\\t}\\n \\t\\t\\t\\t}\\n \\t\\t\\t}\\n }\\n }\\n }\\n },\\n \\\"format\\\": {\\\"property\\\": \\\"aggregations.table.buckets\\\"},\\n \\\"transform\\\": [\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"(datum.key.stk1==''?datum.key.stk3:datum.key.stk1)\\\", \\\"as\\\": \\\"stk1\\\"},\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"(datum.key.stk2==''?datum.key.stk4:datum.key.stk2)\\\", \\\"as\\\": \\\"stk2\\\"},\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"datum.key.stk3\\\", \\\"as\\\": \\\"stk3\\\"},\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"datum.key.stk4\\\", \\\"as\\\": \\\"stk4\\\"},\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"datum.bytes.value\\\", \\\"as\\\": \\\"size\\\"}\\n ]\\n },\\n {\\n \\\"name\\\": \\\"nodes\\\",\\n \\\"source\\\": \\\"rawData\\\",\\n \\\"transform\\\": [\\n {\\n \\\"type\\\": \\\"filter\\\",\\n \\\"expr\\\": \\\"!groupSelector || groupSelector.stk1 == datum.stk1 || groupSelector.stk2 == datum.stk2\\\"\\n },\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"datum.stk1+datum.stk2+datum.stk3+datum.stk4\\\", \\\"as\\\": \\\"key\\\"},\\n {\\\"type\\\": \\\"fold\\\", \\\"fields\\\": [\\\"stk1\\\", \\\"stk2\\\"], \\\"as\\\": [\\\"stack\\\", \\\"grpId\\\"]},\\n {\\n \\\"type\\\": \\\"formula\\\",\\n \\\"expr\\\": \\\"datum.stack == 'stk1' ? datum.stk1+datum.stk2 : datum.stk2+datum.stk1\\\",\\n \\\"as\\\": \\\"sortField\\\"\\n },\\n {\\n \\\"type\\\": \\\"stack\\\",\\n \\\"groupby\\\": [\\\"stack\\\"],\\n \\\"sort\\\": {\\\"field\\\": \\\"sortField\\\", \\\"order\\\": \\\"descending\\\"},\\n \\\"field\\\": \\\"size\\\"\\n },\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"(datum.y0+datum.y1)/2\\\", \\\"as\\\": \\\"yc\\\"}\\n ]\\n },\\n {\\n \\\"name\\\": \\\"groups\\\",\\n \\\"source\\\": \\\"nodes\\\",\\n \\\"transform\\\": [\\n {\\n \\\"type\\\": \\\"aggregate\\\",\\n \\\"groupby\\\": [\\\"stack\\\", \\\"grpId\\\"],\\n \\\"fields\\\": [\\\"size\\\"],\\n \\\"ops\\\": [\\\"sum\\\"],\\n \\\"as\\\": [\\\"total\\\"]\\n },\\n {\\n \\\"type\\\": \\\"stack\\\",\\n \\\"groupby\\\": [\\\"stack\\\"],\\n \\\"sort\\\": {\\\"field\\\": \\\"grpId\\\", \\\"order\\\": \\\"descending\\\"},\\n \\\"field\\\": \\\"total\\\"\\n },\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"scale('y', datum.y0)\\\", \\\"as\\\": \\\"scaledY0\\\"},\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"scale('y', datum.y1)\\\", \\\"as\\\": \\\"scaledY1\\\"},\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"datum.stack == 'stk1'\\\", \\\"as\\\": \\\"rightLabel\\\"},\\n {\\n \\\"type\\\": \\\"formula\\\",\\n \\\"expr\\\": \\\"datum.total/domain('y')[1]\\\",\\n \\\"as\\\": \\\"percentage\\\"\\n }\\n ]\\n },\\n {\\n \\\"name\\\": \\\"destinationNodes\\\",\\n \\\"source\\\": \\\"nodes\\\",\\n \\\"transform\\\": [{\\\"type\\\": \\\"filter\\\", \\\"expr\\\": \\\"datum.stack == 'stk2'\\\"}]\\n },\\n {\\n \\\"name\\\": \\\"edges\\\",\\n \\\"source\\\": \\\"nodes\\\",\\n \\\"transform\\\": [\\n {\\\"type\\\": \\\"filter\\\", \\\"expr\\\": \\\"datum.stack == 'stk1'\\\"},\\n {\\n \\\"type\\\": \\\"lookup\\\",\\n \\\"from\\\": \\\"destinationNodes\\\",\\n \\\"key\\\": \\\"key\\\",\\n \\\"fields\\\": [\\\"key\\\"],\\n \\\"as\\\": [\\\"target\\\"]\\n },\\n {\\n \\\"type\\\": \\\"linkpath\\\",\\n \\\"orient\\\": \\\"horizontal\\\",\\n \\\"shape\\\": \\\"diagonal\\\",\\n \\\"sourceY\\\": {\\\"expr\\\": \\\"scale('y', datum.yc)\\\"},\\n \\\"sourceX\\\": {\\\"expr\\\": \\\"scale('x', 'stk1') + bandwidth('x')\\\"},\\n \\\"targetY\\\": {\\\"expr\\\": \\\"scale('y', datum.target.yc)\\\"},\\n \\\"targetX\\\": {\\\"expr\\\": \\\"scale('x', 'stk2')\\\"}\\n },\\n {\\n \\\"type\\\": \\\"formula\\\",\\n \\\"expr\\\": \\\"range('y')[0]-scale('y', datum.size)\\\",\\n \\\"as\\\": \\\"strokeWidth\\\"\\n },\\n {\\n \\\"type\\\": \\\"formula\\\",\\n \\\"expr\\\": \\\"datum.size/domain('y')[1]\\\",\\n \\\"as\\\": \\\"percentage\\\"\\n }\\n ]\\n }\\n ],\\n \\\"scales\\\": [\\n {\\n \\\"name\\\": \\\"x\\\",\\n \\\"type\\\": \\\"band\\\",\\n \\\"range\\\": \\\"width\\\",\\n \\\"domain\\\": [\\\"stk1\\\", \\\"stk2\\\"],\\n \\\"paddingOuter\\\": 0.01,\\n \\\"paddingInner\\\": 0.98\\n },\\n {\\n \\\"name\\\": \\\"y\\\",\\n \\\"type\\\": \\\"linear\\\",\\n \\\"range\\\": \\\"height\\\",\\n \\\"domain\\\": {\\\"data\\\": \\\"nodes\\\", \\\"field\\\": \\\"y1\\\"}\\n },\\n {\\n \\\"name\\\": \\\"color\\\",\\n \\\"type\\\": \\\"ordinal\\\",\\n \\\"range\\\": \\\"category\\\",\\n \\\"domain\\\": {\\\"data\\\": \\\"rawData\\\", \\\"fields\\\": [\\\"stk1\\\",\\\"stk2\\\"]}\\n },\\n {\\n \\\"name\\\": \\\"stackNames\\\",\\n \\\"type\\\": \\\"ordinal\\\",\\n \\\"range\\\": [\\\"Source\\\", \\\"Destination\\\"],\\n \\\"domain\\\": [\\\"stk1\\\", \\\"stk2\\\"]\\n }\\n ],\\n \\\"axes\\\": [\\n {\\n \\\"orient\\\": \\\"bottom\\\",\\n \\\"scale\\\": \\\"x\\\",\\n \\\"labelColor\\\": {\\n \\\"value\\\": \\\"#888888\\\"\\n },\\n \\\"encode\\\": {\\n \\\"labels\\\": {\\n \\\"update\\\": {\\n \\\"text\\\": {\\\"scale\\\": \\\"stackNames\\\", \\\"field\\\": \\\"value\\\"},\\n \\\"fontSize\\\": {\\\"value\\\": 14}\\n }\\n }\\n }\\n },\\n {\\n \\\"orient\\\": \\\"left\\\",\\n \\\"scale\\\": \\\"y\\\",\\n \\\"labelColor\\\": {\\n \\\"value\\\": \\\"#888888\\\"\\n },\\n \\\"encode\\\": {\\n \\\"labels\\\": {\\n \\\"update\\\": {\\n \\\"text\\\": {\\\"signal\\\": \\\"format(datum.value, '.2s') + 'B'\\\"},\\n \\\"fontSize\\\": {\\\"value\\\": 12}\\n }\\n }\\n }\\n }\\n ],\\n \\\"marks\\\": [\\n {\\n \\\"type\\\": \\\"path\\\",\\n \\\"name\\\": \\\"edgeMark\\\",\\n \\\"from\\\": {\\\"data\\\": \\\"edges\\\"},\\n \\\"clip\\\": true,\\n \\\"encode\\\": {\\n \\\"update\\\": {\\n \\\"stroke\\\": [\\n {\\n \\\"test\\\": \\\"groupSelector && groupSelector.stack=='stk1'\\\",\\n \\\"scale\\\": \\\"color\\\",\\n \\\"field\\\": \\\"stk2\\\"\\n },\\n {\\\"scale\\\": \\\"color\\\", \\\"field\\\": \\\"stk1\\\"}\\n ],\\n \\\"strokeWidth\\\": {\\\"field\\\": \\\"strokeWidth\\\"},\\n \\\"path\\\": {\\\"field\\\": \\\"path\\\"},\\n \\\"strokeOpacity\\\": {\\n \\\"signal\\\": \\\"!groupSelector && (groupHover.stk1 == datum.stk1 || groupHover.stk2 == datum.stk2) ? 0.75 : 0.3\\\"\\n },\\n \\\"zindex\\\": {\\n \\\"signal\\\": \\\"!groupSelector && (groupHover.stk1 == datum.stk1 || groupHover.stk2 == datum.stk2) ? 1 : 0\\\"\\n },\\n \\\"tooltip\\\": {\\n \\\"signal\\\": \\\"{'title': datum.stk1 + ' → ' + datum.stk2 + ' ' + format(datum.size, '.2s') + 'B (' + format(datum.percentage, '.1%') + ')', 'IP Address': datum.stk3 +' → ' + datum.stk4 }\\\"\\n }\\n },\\n \\\"hover\\\": {\\\"strokeOpacity\\\": {\\\"value\\\": 0.75}}\\n }\\n },\\n {\\n \\\"type\\\": \\\"rect\\\",\\n \\\"name\\\": \\\"groupMark\\\",\\n \\\"from\\\": {\\\"data\\\": \\\"groups\\\"},\\n \\\"encode\\\": {\\n \\\"enter\\\": {\\n \\\"fill\\\": {\\\"scale\\\": \\\"color\\\", \\\"field\\\": \\\"grpId\\\"},\\n \\\"width\\\": {\\\"scale\\\": \\\"x\\\", \\\"band\\\": 1}\\n },\\n \\\"update\\\": {\\n \\\"x\\\": {\\\"scale\\\": \\\"x\\\", \\\"field\\\": \\\"stack\\\"},\\n \\\"y\\\": {\\\"field\\\": \\\"scaledY0\\\"},\\n \\\"y2\\\": {\\\"field\\\": \\\"scaledY1\\\"},\\n \\\"fillOpacity\\\": {\\\"value\\\": 0.7},\\n \\\"tooltip\\\": {\\n \\\"signal\\\": \\\"datum.grpId + ' ' + format(datum.total, '.2s') + 'B (' + format(datum.percentage, '.1%') + ')'\\\"\\n }\\n },\\n \\\"hover\\\": {\\\"fillOpacity\\\": {\\\"value\\\": 1}}\\n }\\n },\\n {\\n \\\"type\\\": \\\"text\\\",\\n \\\"from\\\": {\\\"data\\\": \\\"groups\\\"},\\n \\\"interactive\\\": false,\\n \\\"encode\\\": {\\n \\\"update\\\": {\\n \\\"x\\\": {\\n \\\"signal\\\": \\\"scale('x', datum.stack) + (datum.rightLabel ? bandwidth('x') + 8 : -8)\\\"\\n },\\n \\\"yc\\\": {\\\"signal\\\": \\\"(datum.scaledY0 + datum.scaledY1)/2\\\"},\\n \\\"align\\\": {\\\"signal\\\": \\\"datum.rightLabel ? 'left' : 'right'\\\"},\\n \\\"baseline\\\": {\\\"value\\\": \\\"middle\\\"},\\n \\\"fontWeight\\\": {\\\"value\\\": \\\"bold\\\"},\\n \\\"fontSize\\\": {\\\"value\\\": 12},\\n \\\"text\\\": {\\n \\\"signal\\\": \\\"abs(datum.scaledY0-datum.scaledY1) > 10 ? datum.grpId : ''\\\"\\n }\\n }\\n }\\n },\\n {\\n \\\"type\\\": \\\"group\\\",\\n \\\"data\\\": [\\n {\\n \\\"name\\\": \\\"dataForShowAll\\\",\\n \\\"values\\\": [{}],\\n \\\"transform\\\": [{\\\"type\\\": \\\"filter\\\", \\\"expr\\\": \\\"groupSelector\\\"}]\\n }\\n ],\\n \\\"encode\\\": {\\n \\\"enter\\\": {\\n \\\"xc\\\": {\\\"signal\\\": \\\"width/2\\\"},\\n \\\"y\\\": {\\\"value\\\": 30},\\n \\\"width\\\": {\\\"value\\\": 100},\\n \\\"height\\\": {\\\"value\\\": 36}\\n }\\n },\\n \\\"marks\\\": [\\n {\\n \\\"type\\\": \\\"group\\\",\\n \\\"name\\\": \\\"groupReset\\\",\\n \\\"from\\\": {\\\"data\\\": \\\"dataForShowAll\\\"},\\n \\\"encode\\\": {\\n \\\"enter\\\": {\\n \\\"cornerRadius\\\": {\\\"value\\\": 3.5},\\n \\\"fill\\\": {\\\"value\\\": \\\"#666666\\\"},\\n \\\"height\\\": {\\\"field\\\": {\\\"group\\\": \\\"height\\\"}},\\n \\\"width\\\": {\\\"field\\\": {\\\"group\\\": \\\"width\\\"}}\\n },\\n \\\"update\\\": {\\\"opacity\\\": {\\\"value\\\": 1}},\\n \\\"hover\\\": {\\\"fill\\\": {\\\"value\\\": \\\"#444444\\\"}}\\n },\\n \\\"marks\\\": [\\n {\\n \\\"type\\\": \\\"text\\\",\\n \\\"interactive\\\": false,\\n \\\"encode\\\": {\\n \\\"enter\\\": {\\n \\\"xc\\\": {\\\"field\\\": {\\\"group\\\": \\\"width\\\"}, \\\"mult\\\": 0.5},\\n \\\"yc\\\": {\\\"field\\\": {\\\"group\\\": \\\"height\\\"}, \\\"mult\\\": 0.5, \\\"offset\\\": 1},\\n \\\"align\\\": {\\\"value\\\": \\\"center\\\"},\\n \\\"baseline\\\": {\\\"value\\\": \\\"middle\\\"},\\n \\\"text\\\": {\\\"value\\\": \\\"Show All\\\"},\\n \\\"fontSize\\\": {\\\"value\\\": 14},\\n \\\"stroke\\\": {\\\"value\\\": \\\"#ecf0f1\\\"}\\n }\\n }\\n }\\n ]\\n }\\n ]\\n }\\n ],\\n \\\"signals\\\": [\\n {\\n \\\"name\\\": \\\"groupHover\\\",\\n \\\"value\\\": {},\\n \\\"on\\\": [\\n {\\n \\\"events\\\": \\\"@groupMark:mouseover\\\",\\n \\\"update\\\": \\\"{stk1:datum.stack=='stk1' && datum.grpId, stk2:datum.stack=='stk2' && datum.grpId}\\\"\\n },\\n {\\\"events\\\": \\\"mouseout\\\", \\\"update\\\": \\\"{}\\\"}\\n ]\\n },\\n {\\n \\\"name\\\": \\\"groupSelector\\\",\\n \\\"value\\\": false,\\n \\\"on\\\": [\\n {\\n \\\"events\\\": \\\"@groupMark:click!\\\",\\n \\\"update\\\": \\\"{stack:datum.stack, stk1:datum.stack=='stk1' && datum.grpId, stk2:datum.stack=='stk2' && datum.grpId}\\\"\\n },\\n {\\n \\\"events\\\": [\\n {\\\"type\\\": \\\"click\\\", \\\"markname\\\": \\\"groupReset\\\"},\\n {\\\"type\\\": \\\"dblclick\\\"}\\n ],\\n \\\"update\\\": \\\"false\\\"\\n }\\n ]\\n }\\n ]\\n}\"},\"title\":\"Node Cumulative Bytes\"}"},"id":"5b165620-cd36-11ea-8911-87da3aad0324","migrationVersion":{"visualization":"7.8.0"},"references":[],"type":"visualization","updated_at":"2021-08-07T23:30:40.150Z","version":"WzQ0LDFd"} -{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\",\"filter\":[]}"},"title":"Aggregated Tx Mbps by Node Acting as Source (Heatmap)","uiStateJSON":"{}","version":1,"visState":"{\"type\":\"heatmap\",\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"sum\",\"schema\":\"metric\",\"params\":{\"field\":\"ipfix.throughput\",\"json\":\"{ \\n \\\"script\\\" : \\\"_value / 1024/1024\\\" \\n}\",\"customLabel\":\"Node Throughput\"}},{\"id\":\"2\",\"enabled\":true,\"type\":\"date_histogram\",\"schema\":\"segment\",\"params\":{\"field\":\"ipfix.flowEndSeconds\",\"timeRange\":{\"from\":\"now-1h\",\"to\":\"now\"},\"useNormalizedEsInterval\":true,\"scaleMetricValues\":false,\"interval\":\"1m\",\"drop_partials\":false,\"min_doc_count\":1,\"extended_bounds\":{},\"customLabel\":\"Time\"}},{\"id\":\"3\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"group\",\"params\":{\"field\":\"ipfix.sourceNodeName.keyword\",\"orderBy\":\"1\",\"order\":\"desc\",\"size\":10,\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\",\"exclude\":\"\\\"\\\"\",\"customLabel\":\"Source Node Name\"}}],\"params\":{\"type\":\"heatmap\",\"addTooltip\":true,\"addLegend\":true,\"enableHover\":false,\"legendPosition\":\"right\",\"times\":[],\"colorsNumber\":10,\"colorSchema\":\"Greens\",\"setColorRange\":false,\"colorsRange\":[],\"invertColors\":false,\"percentageMode\":false,\"valueAxes\":[{\"show\":false,\"id\":\"ValueAxis-1\",\"type\":\"value\",\"scale\":{\"type\":\"linear\",\"defaultYExtents\":false},\"labels\":{\"show\":false,\"rotate\":0,\"overwriteColor\":false,\"color\":\"black\"}}]},\"title\":\"Aggregated Tx Mbps by Node Acting as Source (Heatmap)\"}"},"id":"e4855250-612c-11eb-aaaf-792dd02d0158","migrationVersion":{"visualization":"7.8.0"},"references":[{"id":"e2ab2c50-b981-11ea-b16e-fb06687c3589","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"}],"type":"visualization","updated_at":"2021-08-07T23:30:40.150Z","version":"WzQ1LDFd"} -{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"language\":\"kuery\",\"query\":\"\"},\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\",\"filter\":[]}"},"title":"Aggregated Rx Mbps by Node Acting as Source (Heatmap)","uiStateJSON":"{}","version":1,"visState":"{\"type\":\"heatmap\",\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"sum\",\"schema\":\"metric\",\"params\":{\"field\":\"ipfix.reverseThroughput\",\"json\":\"{ \\n \\\"script\\\" : \\\"_value / 1024/1024\\\" \\n}\",\"customLabel\":\"Node Throughput (Reverse)\"}},{\"id\":\"2\",\"enabled\":true,\"type\":\"date_histogram\",\"schema\":\"segment\",\"params\":{\"field\":\"ipfix.flowEndSeconds\",\"timeRange\":{\"from\":\"now-1h\",\"to\":\"now\"},\"useNormalizedEsInterval\":true,\"scaleMetricValues\":false,\"interval\":\"1m\",\"drop_partials\":false,\"min_doc_count\":1,\"extended_bounds\":{},\"customLabel\":\"Time\"}},{\"id\":\"3\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"group\",\"params\":{\"field\":\"ipfix.sourceNodeName.keyword\",\"orderBy\":\"1\",\"order\":\"desc\",\"size\":10,\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\",\"exclude\":\"\\\"\\\"\",\"customLabel\":\"Source Node Name\"}}],\"params\":{\"type\":\"heatmap\",\"addTooltip\":true,\"addLegend\":true,\"enableHover\":false,\"legendPosition\":\"right\",\"times\":[],\"colorsNumber\":10,\"colorSchema\":\"Greens\",\"setColorRange\":false,\"colorsRange\":[],\"invertColors\":false,\"percentageMode\":false,\"valueAxes\":[{\"show\":false,\"id\":\"ValueAxis-1\",\"type\":\"value\",\"scale\":{\"type\":\"linear\",\"defaultYExtents\":false},\"labels\":{\"show\":false,\"rotate\":0,\"overwriteColor\":false,\"color\":\"black\"}}]},\"title\":\"Aggregated Rx Mbps by Node Acting as Source (Heatmap)\"}"},"id":"f9b2c4f0-612c-11eb-aaaf-792dd02d0158","migrationVersion":{"visualization":"7.8.0"},"references":[{"id":"e2ab2c50-b981-11ea-b16e-fb06687c3589","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"}],"type":"visualization","updated_at":"2021-08-07T23:30:40.150Z","version":"WzQ2LDFd"} -{"attributes":{"description":"","hits":0,"kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"language\":\"kuery\",\"query\":\"\"},\"filter\":[]}"},"optionsJSON":"{\"hidePanelTitles\":false,\"useMargins\":true}","panelsJSON":"[{\"embeddableConfig\":{\"title\":\"\"},\"gridData\":{\"h\":3,\"i\":\"bf65a47f-1490-4143-8b39-b4c58cb7e035\",\"w\":48,\"x\":0,\"y\":0},\"panelIndex\":\"bf65a47f-1490-4143-8b39-b4c58cb7e035\",\"version\":\"7.8.0\",\"panelRefName\":\"panel_0\"},{\"embeddableConfig\":{},\"gridData\":{\"h\":23,\"i\":\"74fca433-a353-4042-83c4-5f39ca49309f\",\"w\":24,\"x\":0,\"y\":3},\"panelIndex\":\"74fca433-a353-4042-83c4-5f39ca49309f\",\"version\":\"7.8.0\",\"panelRefName\":\"panel_1\"},{\"embeddableConfig\":{},\"gridData\":{\"h\":23,\"i\":\"0cb5399f-d965-4dd6-9b4f-6b09f138fa48\",\"w\":24,\"x\":24,\"y\":3},\"panelIndex\":\"0cb5399f-d965-4dd6-9b4f-6b09f138fa48\",\"version\":\"7.8.0\",\"panelRefName\":\"panel_2\"},{\"embeddableConfig\":{},\"gridData\":{\"h\":11,\"i\":\"d5b1b4df-a268-44fc-82a7-74fd370cb6a8\",\"w\":24,\"x\":0,\"y\":26},\"panelIndex\":\"d5b1b4df-a268-44fc-82a7-74fd370cb6a8\",\"version\":\"7.8.0\",\"panelRefName\":\"panel_3\"},{\"embeddableConfig\":{},\"gridData\":{\"h\":11,\"i\":\"de83b6b5-b7d3-46a8-af90-6ddc85897c6e\",\"w\":24,\"x\":24,\"y\":26},\"panelIndex\":\"de83b6b5-b7d3-46a8-af90-6ddc85897c6e\",\"version\":\"7.8.0\",\"panelRefName\":\"panel_4\"},{\"embeddableConfig\":{\"title\":\"Aggregated Tx Mbps by Node Acting as Source (MBit/s)\",\"vis\":null},\"gridData\":{\"h\":15,\"i\":\"898f3b90-9f29-487b-8c15-7160c5e9909f\",\"w\":24,\"x\":0,\"y\":37},\"panelIndex\":\"898f3b90-9f29-487b-8c15-7160c5e9909f\",\"title\":\"Aggregated Tx Mbps by Node Acting as Source (MBit/s)\",\"version\":\"7.8.0\",\"panelRefName\":\"panel_5\"},{\"embeddableConfig\":{\"title\":\"Aggregated Rx Mbps by Node Acting as Source (MBit/s)\",\"vis\":null},\"gridData\":{\"h\":15,\"i\":\"a551f0c9-a9f2-4909-b0ef-7d60f98484f3\",\"w\":24,\"x\":24,\"y\":37},\"panelIndex\":\"a551f0c9-a9f2-4909-b0ef-7d60f98484f3\",\"title\":\"Aggregated Rx Mbps by Node Acting as Source (MBit/s)\",\"version\":\"7.8.0\",\"panelRefName\":\"panel_6\"}]","timeRestore":false,"title":"Node Throughput Dashboard","version":1},"id":"5400cdf0-cd2e-11ea-8911-87da3aad0324","migrationVersion":{"dashboard":"7.3.0"},"references":[{"id":"c0940350-cd43-11ea-8911-87da3aad0324","name":"panel_0","type":"visualization"},{"id":"5b165620-cd36-11ea-8911-87da3aad0324","name":"panel_1","type":"visualization"},{"id":"211178f0-cd37-11ea-8911-87da3aad0324","name":"panel_2","type":"visualization"},{"id":"226c4040-cd32-11ea-8911-87da3aad0324","name":"panel_3","type":"visualization"},{"id":"089a7d70-cd33-11ea-8911-87da3aad0324","name":"panel_4","type":"visualization"},{"id":"e4855250-612c-11eb-aaaf-792dd02d0158","name":"panel_5","type":"visualization"},{"id":"f9b2c4f0-612c-11eb-aaaf-792dd02d0158","name":"panel_6","type":"visualization"}],"type":"dashboard","updated_at":"2021-08-07T23:30:40.150Z","version":"WzQ3LDFd"} -{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"lucene\"},\"filter\":[]}"},"title":"Pod-to-Pod Traffic Cumulative Bytes","uiStateJSON":"{}","version":1,"visState":"{\"type\":\"vega\",\"aggs\":[],\"params\":{\"spec\":\"{\\n \\\"$schema\\\": \\\"https://vega.github.io/schema/vega/v3.0.json\\\",\\n \\\"data\\\": [\\n {\\n \\\"name\\\": \\\"rawData\\\",\\n \\\"url\\\": {\\n \\\"%context%\\\": true,\\n \\\"%timefield%\\\": \\\"@timestamp\\\",\\n \\\"index\\\": \\\"flow-*\\\",\\n \\\"body\\\": {\\n \\\"size\\\": 0,\\n \\\"aggs\\\": {\\n \\\"table\\\": {\\n \\\"composite\\\": {\\n \\\"size\\\": 1000,\\n \\\"sources\\\": [\\n {\\\"stk1\\\": {\\\"terms\\\": {\\\"field\\\": \\\"ipfix.sourcePodName.keyword\\\"}}},\\n {\\\"stk1ns\\\": {\\\"terms\\\": {\\\"field\\\": \\\"ipfix.sourcePodNamespace.keyword\\\"}}},\\n {\\\"stk2\\\": {\\\"terms\\\": {\\\"field\\\": \\\"ipfix.destinationPodName.keyword\\\"}}},\\n {\\\"stk2ns\\\": {\\\"terms\\\": {\\\"field\\\": \\\"ipfix.destinationPodNamespace.keyword\\\"}}},\\n {\\\"stk3\\\": {\\\"terms\\\": {\\\"field\\\": \\\"ipfix.sourceIP.keyword\\\"}}},\\n {\\\"stk4\\\": {\\\"terms\\\": {\\\"field\\\": \\\"ipfix.destinationIP.keyword\\\"}}},\\n {\\\"stk5\\\": {\\\"terms\\\": {\\\"field\\\": \\\"ipfix.flowTypeStr.keyword\\\"}}},\\n ]\\n },\\n \\t\\t\\t\\\"aggs\\\": {\\n \\t\\t\\t\\t\\\"bytes\\\": {\\n \\t\\t\\t\\t\\t\\\"sum\\\": {\\n \\t\\t\\t\\t\\t\\t\\\"field\\\": \\\"ipfix.octetDeltaCountFromSourceNode\\\"\\n \\t\\t\\t\\t\\t}\\n \\t\\t\\t\\t}\\n \\t\\t\\t}\\n }\\n }\\n }\\n },\\n \\\"format\\\": {\\\"property\\\": \\\"aggregations.table.buckets\\\"},\\n \\\"transform\\\": [\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"datum.key.stk1ns +'/'+ datum.key.stk1\\\", \\\"as\\\": \\\"stk1s\\\"},\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"(datum.key.stk1==''?datum.key.stk3:datum.stk1s)\\\", \\\"as\\\": \\\"stk1\\\"},\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"datum.key.stk2ns +'/'+ datum.key.stk2\\\", \\\"as\\\": \\\"stk2s\\\"},\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"(datum.key.stk2==''?datum.key.stk4:datum.stk2s)\\\", \\\"as\\\": \\\"stk2\\\"},\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"datum.key.stk3\\\", \\\"as\\\": \\\"stk3\\\"},\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"datum.key.stk4\\\", \\\"as\\\": \\\"stk4\\\"},\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"datum.key.stk5\\\", \\\"as\\\": \\\"stk5\\\"},\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"datum.bytes.value\\\", \\\"as\\\": \\\"size\\\"}\\n ]\\n },\\n {\\n \\\"name\\\": \\\"nodes\\\",\\n \\\"source\\\": \\\"rawData\\\",\\n \\\"transform\\\": [\\n {\\n \\\"type\\\": \\\"filter\\\",\\n \\\"expr\\\": \\\"(datum.stk5=='Inter-Node' || datum.stk5 == 'Intra-Node') && !groupSelector || groupSelector.stk1 == datum.stk1 || groupSelector.stk2 == datum.stk2\\\"\\n },\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"datum.stk1+datum.stk2\\\", \\\"as\\\": \\\"key\\\"},\\n {\\\"type\\\": \\\"fold\\\", \\\"fields\\\": [\\\"stk1\\\", \\\"stk2\\\"], \\\"as\\\": [\\\"stack\\\", \\\"grpId\\\"]},\\n {\\n \\\"type\\\": \\\"formula\\\",\\n \\\"expr\\\": \\\"datum.stack == 'stk1' ? datum.stk1+datum.stk2 : datum.stk2+datum.stk1\\\",\\n \\\"as\\\": \\\"sortField\\\"\\n },\\n {\\n \\\"type\\\": \\\"stack\\\",\\n \\\"groupby\\\": [\\\"stack\\\"],\\n \\\"sort\\\": {\\\"field\\\": \\\"sortField\\\", \\\"order\\\": \\\"descending\\\"},\\n \\\"field\\\": \\\"size\\\"\\n },\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"(datum.y0+datum.y1)/2\\\", \\\"as\\\": \\\"yc\\\"}\\n ]\\n },\\n {\\n \\\"name\\\": \\\"groups\\\",\\n \\\"source\\\": \\\"nodes\\\",\\n \\\"transform\\\": [\\n {\\n \\\"type\\\": \\\"aggregate\\\",\\n \\\"groupby\\\": [\\\"stack\\\", \\\"grpId\\\"],\\n \\\"fields\\\": [\\\"size\\\"],\\n \\\"ops\\\": [\\\"sum\\\"],\\n \\\"as\\\": [\\\"total\\\"]\\n },\\n {\\n \\\"type\\\": \\\"stack\\\",\\n \\\"groupby\\\": [\\\"stack\\\"],\\n \\\"sort\\\": {\\\"field\\\": \\\"grpId\\\", \\\"order\\\": \\\"descending\\\"},\\n \\\"field\\\": \\\"total\\\"\\n },\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"scale('y', datum.y0)\\\", \\\"as\\\": \\\"scaledY0\\\"},\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"scale('y', datum.y1)\\\", \\\"as\\\": \\\"scaledY1\\\"},\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"datum.stack == 'stk1'\\\", \\\"as\\\": \\\"rightLabel\\\"},\\n {\\n \\\"type\\\": \\\"formula\\\",\\n \\\"expr\\\": \\\"datum.total/domain('y')[1]\\\",\\n \\\"as\\\": \\\"percentage\\\"\\n }\\n ]\\n },\\n {\\n \\\"name\\\": \\\"destinationNodes\\\",\\n \\\"source\\\": \\\"nodes\\\",\\n \\\"transform\\\": [{\\\"type\\\": \\\"filter\\\", \\\"expr\\\": \\\"datum.stack == 'stk2'\\\"}]\\n },\\n {\\n \\\"name\\\": \\\"edges\\\",\\n \\\"source\\\": \\\"nodes\\\",\\n \\\"transform\\\": [\\n {\\\"type\\\": \\\"filter\\\", \\\"expr\\\": \\\"datum.stack == 'stk1'\\\"},\\n {\\n \\\"type\\\": \\\"lookup\\\",\\n \\\"from\\\": \\\"destinationNodes\\\",\\n \\\"key\\\": \\\"key\\\",\\n \\\"fields\\\": [\\\"key\\\"],\\n \\\"as\\\": [\\\"target\\\"]\\n },\\n {\\n \\\"type\\\": \\\"linkpath\\\",\\n \\\"orient\\\": \\\"horizontal\\\",\\n \\\"shape\\\": \\\"diagonal\\\",\\n \\\"sourceY\\\": {\\\"expr\\\": \\\"scale('y', datum.yc)\\\"},\\n \\\"sourceX\\\": {\\\"expr\\\": \\\"scale('x', 'stk1') + bandwidth('x')\\\"},\\n \\\"targetY\\\": {\\\"expr\\\": \\\"scale('y', datum.target.yc)\\\"},\\n \\\"targetX\\\": {\\\"expr\\\": \\\"scale('x', 'stk2')\\\"}\\n },\\n {\\n \\\"type\\\": \\\"formula\\\",\\n \\\"expr\\\": \\\"range('y')[0]-scale('y', datum.size)\\\",\\n \\\"as\\\": \\\"strokeWidth\\\"\\n },\\n {\\n \\\"type\\\": \\\"formula\\\",\\n \\\"expr\\\": \\\"datum.size/domain('y')[1]\\\",\\n \\\"as\\\": \\\"percentage\\\"\\n }\\n ]\\n }\\n ],\\n \\\"scales\\\": [\\n {\\n \\\"name\\\": \\\"x\\\",\\n \\\"type\\\": \\\"band\\\",\\n \\\"range\\\": \\\"width\\\",\\n \\\"domain\\\": [\\\"stk1\\\", \\\"stk2\\\"],\\n \\\"paddingOuter\\\": 0.01,\\n \\\"paddingInner\\\": 0.98\\n },\\n {\\n \\\"name\\\": \\\"y\\\",\\n \\\"type\\\": \\\"linear\\\",\\n \\\"range\\\": \\\"height\\\",\\n \\\"domain\\\": {\\\"data\\\": \\\"nodes\\\", \\\"field\\\": \\\"y1\\\"}\\n },\\n {\\n \\\"name\\\": \\\"color\\\",\\n \\\"type\\\": \\\"ordinal\\\",\\n \\\"range\\\": \\\"category\\\",\\n \\\"domain\\\": {\\\"data\\\": \\\"rawData\\\", \\\"fields\\\": [\\\"stk1\\\",\\\"stk2\\\"]}\\n },\\n {\\n \\\"name\\\": \\\"stackNames\\\",\\n \\\"type\\\": \\\"ordinal\\\",\\n \\\"range\\\": [\\\"Source Pod\\\", \\\"Destination Pod\\\"],\\n \\\"domain\\\": [\\\"stk1\\\", \\\"stk2\\\"]\\n }\\n ],\\n \\\"axes\\\": [\\n {\\n \\\"orient\\\": \\\"bottom\\\",\\n \\\"scale\\\": \\\"x\\\",\\n \\\"labelColor\\\": {\\n \\\"value\\\": \\\"#888888\\\"\\n },\\n \\\"encode\\\": {\\n \\\"labels\\\": {\\n \\\"update\\\": {\\n \\\"text\\\": {\\\"scale\\\": \\\"stackNames\\\", \\\"field\\\": \\\"value\\\"},\\n \\\"fontSize\\\": {\\\"value\\\": 14}\\n }\\n }\\n }\\n },\\n {\\n \\\"orient\\\": \\\"left\\\",\\n \\\"scale\\\": \\\"y\\\",\\n \\\"labelColor\\\": {\\n \\\"value\\\": \\\"#888888\\\"\\n },\\n \\\"encode\\\": {\\n \\\"labels\\\": {\\n \\\"update\\\": {\\n \\\"text\\\": {\\\"signal\\\": \\\"format(datum.value, '.2s') + 'B'\\\"},\\n \\\"fontSize\\\": {\\\"value\\\": 12}\\n }\\n }\\n }\\n }\\n ],\\n \\\"marks\\\": [\\n {\\n \\\"type\\\": \\\"path\\\",\\n \\\"name\\\": \\\"edgeMark\\\",\\n \\\"from\\\": {\\\"data\\\": \\\"edges\\\"},\\n \\\"clip\\\": true,\\n \\\"encode\\\": {\\n \\\"update\\\": {\\n \\\"stroke\\\": [\\n {\\n \\\"test\\\": \\\"groupSelector && groupSelector.stack=='stk1'\\\",\\n \\\"scale\\\": \\\"color\\\",\\n \\\"field\\\": \\\"stk2\\\"\\n },\\n {\\\"scale\\\": \\\"color\\\", \\\"field\\\": \\\"stk1\\\"}\\n ],\\n \\\"strokeWidth\\\": {\\\"field\\\": \\\"strokeWidth\\\"},\\n \\\"path\\\": {\\\"field\\\": \\\"path\\\"},\\n \\\"strokeOpacity\\\": {\\n \\\"signal\\\": \\\"!groupSelector && (groupHover.stk1 == datum.stk1 || groupHover.stk2 == datum.stk2) ? 0.75 : 0.3\\\"\\n },\\n \\\"zindex\\\": {\\n \\\"signal\\\": \\\"!groupSelector && (groupHover.stk1 == datum.stk1 || groupHover.stk2 == datum.stk2) ? 1 : 0\\\"\\n },\\n \\\"tooltip\\\": {\\n \\\"signal\\\": \\\"{'title': datum.stk1 + ' → ' + datum.stk2 + ' ' + format(datum.size, '.2s') + 'B (' + format(datum.percentage, '.1%') + ')', 'IP Address': datum.stk3 +' → ' + datum.stk4 }\\\"\\n }\\n },\\n \\\"hover\\\": {\\\"strokeOpacity\\\": {\\\"value\\\": 0.75}}\\n }\\n },\\n {\\n \\\"type\\\": \\\"rect\\\",\\n \\\"name\\\": \\\"groupMark\\\",\\n \\\"from\\\": {\\\"data\\\": \\\"groups\\\"},\\n \\\"encode\\\": {\\n \\\"enter\\\": {\\n \\\"fill\\\": {\\\"scale\\\": \\\"color\\\", \\\"field\\\": \\\"grpId\\\"},\\n \\\"width\\\": {\\\"scale\\\": \\\"x\\\", \\\"band\\\": 1}\\n },\\n \\\"update\\\": {\\n \\\"x\\\": {\\\"scale\\\": \\\"x\\\", \\\"field\\\": \\\"stack\\\"},\\n \\\"y\\\": {\\\"field\\\": \\\"scaledY0\\\"},\\n \\\"y2\\\": {\\\"field\\\": \\\"scaledY1\\\"},\\n \\\"fillOpacity\\\": {\\\"value\\\": 0.7},\\n \\\"tooltip\\\": {\\n \\\"signal\\\": \\\"datum.grpId + ' ' + format(datum.total, '.2s') + 'B (' + format(datum.percentage, '.1%') + ')'\\\"\\n }\\n },\\n \\\"hover\\\": {\\\"fillOpacity\\\": {\\\"value\\\": 1}}\\n }\\n },\\n {\\n \\\"type\\\": \\\"text\\\",\\n \\\"from\\\": {\\\"data\\\": \\\"groups\\\"},\\n \\\"interactive\\\": false,\\n \\\"encode\\\": {\\n \\\"update\\\": {\\n \\\"x\\\": {\\n \\\"signal\\\": \\\"scale('x', datum.stack) + (datum.rightLabel ? bandwidth('x') + 8 : -8)\\\"\\n },\\n \\\"yc\\\": {\\\"signal\\\": \\\"(datum.scaledY0 + datum.scaledY1)/2\\\"},\\n \\\"align\\\": {\\\"signal\\\": \\\"datum.rightLabel ? 'left' : 'right'\\\"},\\n \\\"baseline\\\": {\\\"value\\\": \\\"middle\\\"},\\n \\\"fontWeight\\\": {\\\"value\\\": \\\"bold\\\"},\\n \\\"fontSize\\\": {\\\"value\\\": 12},\\n \\\"text\\\": {\\n \\\"signal\\\": \\\"abs(datum.scaledY0-datum.scaledY1) > 10 ? datum.grpId : ''\\\"\\n }\\n }\\n }\\n },\\n {\\n \\\"type\\\": \\\"group\\\",\\n \\\"data\\\": [\\n {\\n \\\"name\\\": \\\"dataForShowAll\\\",\\n \\\"values\\\": [{}],\\n \\\"transform\\\": [{\\\"type\\\": \\\"filter\\\", \\\"expr\\\": \\\"groupSelector\\\"}]\\n }\\n ],\\n \\\"encode\\\": {\\n \\\"enter\\\": {\\n \\\"xc\\\": {\\\"signal\\\": \\\"width/2\\\"},\\n \\\"y\\\": {\\\"value\\\": 30},\\n \\\"width\\\": {\\\"value\\\": 100},\\n \\\"height\\\": {\\\"value\\\": 36}\\n }\\n },\\n \\\"marks\\\": [\\n {\\n \\\"type\\\": \\\"group\\\",\\n \\\"name\\\": \\\"groupReset\\\",\\n \\\"from\\\": {\\\"data\\\": \\\"dataForShowAll\\\"},\\n \\\"encode\\\": {\\n \\\"enter\\\": {\\n \\\"cornerRadius\\\": {\\\"value\\\": 3.5},\\n \\\"fill\\\": {\\\"value\\\": \\\"#666666\\\"},\\n \\\"height\\\": {\\\"field\\\": {\\\"group\\\": \\\"height\\\"}},\\n \\\"width\\\": {\\\"field\\\": {\\\"group\\\": \\\"width\\\"}}\\n },\\n \\\"update\\\": {\\\"opacity\\\": {\\\"value\\\": 1}},\\n \\\"hover\\\": {\\\"fill\\\": {\\\"value\\\": \\\"#444444\\\"}}\\n },\\n \\\"marks\\\": [\\n {\\n \\\"type\\\": \\\"text\\\",\\n \\\"interactive\\\": false,\\n \\\"encode\\\": {\\n \\\"enter\\\": {\\n \\\"xc\\\": {\\\"field\\\": {\\\"group\\\": \\\"width\\\"}, \\\"mult\\\": 0.5},\\n \\\"yc\\\": {\\\"field\\\": {\\\"group\\\": \\\"height\\\"}, \\\"mult\\\": 0.5, \\\"offset\\\": 1},\\n \\\"align\\\": {\\\"value\\\": \\\"center\\\"},\\n \\\"baseline\\\": {\\\"value\\\": \\\"middle\\\"},\\n \\\"text\\\": {\\\"value\\\": \\\"Show All\\\"},\\n \\\"fontSize\\\": {\\\"value\\\": 14},\\n \\\"stroke\\\": {\\\"value\\\": \\\"#ecf0f1\\\"}\\n }\\n }\\n }\\n ]\\n }\\n ]\\n }\\n ],\\n \\\"signals\\\": [\\n {\\n \\\"name\\\": \\\"groupHover\\\",\\n \\\"value\\\": {},\\n \\\"on\\\": [\\n {\\n \\\"events\\\": \\\"@groupMark:mouseover\\\",\\n \\\"update\\\": \\\"{stk1:datum.stack=='stk1' && datum.grpId, stk2:datum.stack=='stk2' && datum.grpId}\\\"\\n },\\n {\\\"events\\\": \\\"mouseout\\\", \\\"update\\\": \\\"{}\\\"}\\n ]\\n },\\n {\\n \\\"name\\\": \\\"groupSelector\\\",\\n \\\"value\\\": false,\\n \\\"on\\\": [\\n {\\n \\\"events\\\": \\\"@groupMark:click!\\\",\\n \\\"update\\\": \\\"{stack:datum.stack, stk1:datum.stack=='stk1' && datum.grpId, stk2:datum.stack=='stk2' && datum.grpId}\\\"\\n },\\n {\\n \\\"events\\\": [\\n {\\\"type\\\": \\\"click\\\", \\\"markname\\\": \\\"groupReset\\\"},\\n {\\\"type\\\": \\\"dblclick\\\"}\\n ],\\n \\\"update\\\": \\\"false\\\"\\n }\\n ]\\n }\\n ]\\n}\"},\"title\":\"Pod-to-Pod Traffic Cumulative Bytes\"}"},"id":"54525bd0-3373-11e9-aec0-c1d93190f676","migrationVersion":{"visualization":"7.8.0"},"references":[],"type":"visualization","updated_at":"2021-08-07T23:30:40.150Z","version":"WzQ4LDFd"} -{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\",\"filter\":[]}"},"title":"Ingress Network Policy Packets","uiStateJSON":"{\"vis\":{\"colors\":{\"default\":\"#F2C96D\"}}}","version":1,"visState":"{\"type\":\"pie\",\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"sum\",\"schema\":\"metric\",\"params\":{\"field\":\"ipfix.packets\"}},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"segment\",\"params\":{\"field\":\"ipfix.ingressNetworkPolicyNamespace.keyword\",\"orderBy\":\"1\",\"order\":\"desc\",\"size\":30,\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\",\"exclude\":\"\",\"customLabel\":\"Namespace\"}},{\"id\":\"3\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"segment\",\"params\":{\"field\":\"ipfix.ingressNetworkPolicyName.keyword\",\"orderBy\":\"1\",\"order\":\"desc\",\"size\":5,\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\",\"customLabel\":\"Network Policy Name\"}}],\"params\":{\"type\":\"pie\",\"addTooltip\":true,\"addLegend\":true,\"legendPosition\":\"right\",\"isDonut\":true,\"labels\":{\"show\":false,\"values\":true,\"last_level\":true,\"truncate\":100},\"dimensions\":{\"metric\":{\"accessor\":0,\"format\":{\"id\":\"number\"},\"params\":{},\"aggType\":\"count\"}}},\"title\":\"Ingress Network Policy Packets\"}"},"id":"56535ab0-23b8-11eb-90d2-a7a4de48218a","migrationVersion":{"visualization":"7.8.0"},"references":[{"id":"e2ab2c50-b981-11ea-b16e-fb06687c3589","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"}],"type":"visualization","updated_at":"2021-08-07T23:30:40.150Z","version":"WzQ5LDFd"} -{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}"},"title":"Cumulative Bandwidth by Pod-to-Pod Flow","uiStateJSON":"{}","version":1,"visState":"{\"type\":\"metrics\",\"aggs\":[],\"params\":{\"id\":\"61ca57f0-469d-11e7-af02-69e470af7417\",\"type\":\"timeseries\",\"axis_position\":\"left\",\"axis_formatter\":\"number\",\"show_legend\":1,\"show_grid\":1,\"axis_min\":\"0\",\"filter\":\"\",\"axis_scale\":\"normal\",\"default_index_pattern\":\"flow-*\",\"default_timefield\":\"@timestamp\",\"isModelInvalid\":false,\"index_pattern\":\"flow-*\",\"interval\":\"1m\",\"time_field\":\"ipfix.flowEndSeconds\",\"series\":[{\"id\":\"61ca57f1-469d-11e7-af02-69e470af7417\",\"color\":\"rgba(144,201,227,1)\",\"split_mode\":\"terms\",\"metrics\":[{\"id\":\"a1ba0060-b9a7-11ea-9740-552c943910e4\",\"type\":\"sum\",\"field\":\"ipfix.octetTotalCountFromSourceNode\"},{\"script\":\"params.bytes * 8\",\"id\":\"dd0b81d0-b9a6-11ea-9740-552c943910e4\",\"type\":\"calculation\",\"variables\":[{\"id\":\"e1f87e50-b9a6-11ea-9740-552c943910e4\",\"name\":\"bytes\",\"field\":\"a1ba0060-b9a7-11ea-9740-552c943910e4\"}]}],\"separate_axis\":0,\"axis_position\":\"right\",\"formatter\":\"bytes\",\"chart_type\":\"line\",\"line_width\":\"2\",\"point_size\":\"0\",\"fill\":\"0.6\",\"stacked\":\"none\",\"split_color_mode\":\"rainbow\",\"label\":\"Bytes\",\"terms_field\":\"ipfix.flowKeyPodToPod.keyword\",\"terms_size\":\"30\",\"terms_order_by\":\"a1ba0060-b9a7-11ea-9740-552c943910e4\",\"value_template\":\"{{value}}\",\"type\":\"timeseries\"}]},\"title\":\"Cumulative Bandwidth by Pod-to-Pod Flow\"}"},"id":"5d8d7b90-4ee6-11eb-b841-6bf6243fda88","migrationVersion":{"visualization":"7.8.0"},"references":[],"type":"visualization","updated_at":"2021-08-07T23:30:40.150Z","version":"WzUwLDFd"} -{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"lucene\"},\"filter\":[]}"},"title":"Pod-to-Service Flow Cumulative Bytes","uiStateJSON":"{}","version":1,"visState":"{\"type\":\"vega\",\"aggs\":[],\"params\":{\"spec\":\"{\\n \\\"$schema\\\": \\\"https://vega.github.io/schema/vega/v3.0.json\\\",\\n \\\"data\\\": [\\n {\\n \\\"name\\\": \\\"rawData\\\",\\n \\\"url\\\": {\\n \\\"%context%\\\": true,\\n \\\"%timefield%\\\": \\\"@timestamp\\\",\\n \\\"index\\\": \\\"flow-*\\\",\\n \\\"body\\\": {\\n \\\"size\\\": 0,\\n \\\"aggs\\\": {\\n \\\"table\\\": {\\n \\\"composite\\\": {\\n \\\"size\\\": 1000,\\n \\\"sources\\\": [\\n {\\\"stk1\\\": {\\\"terms\\\": {\\\"field\\\": \\\"ipfix.sourcePodName.keyword\\\"}}},\\n {\\\"stk1ns\\\": {\\\"terms\\\": {\\\"field\\\": \\\"ipfix.sourcePodNamespace.keyword\\\"}}},\\n {\\\"stk2\\\": {\\\"terms\\\": {\\\"field\\\": \\\"ipfix.destinationServicePortName.keyword\\\"}}},\\n {\\\"stk2p\\\": {\\\"terms\\\": {\\\"field\\\": \\\"ipfix.destinationServicePort\\\"}}},\\n {\\\"stk3\\\": {\\\"terms\\\": {\\\"field\\\": \\\"ipfix.sourceIP.keyword\\\"}}},\\n {\\\"stk4\\\": {\\\"terms\\\": {\\\"field\\\": \\\"ipfix.destinationIP.keyword\\\"}}}\\n ]\\n },\\n \\t\\t\\t\\\"aggs\\\": {\\n \\t\\t\\t\\t\\\"bytes\\\": {\\n \\t\\t\\t\\t\\t\\\"sum\\\": {\\n \\t\\t\\t\\t\\t\\t\\\"field\\\": \\\"ipfix.octetDeltaCountFromSourceNode\\\"\\n \\t\\t\\t\\t\\t}\\n \\t\\t\\t\\t}\\n \\t\\t\\t}\\n }\\n }\\n }\\n },\\n \\\"format\\\": {\\\"property\\\": \\\"aggregations.table.buckets\\\"},\\n \\\"transform\\\": [\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"datum.key.stk1ns +'/'+ datum.key.stk1\\\", \\\"as\\\": \\\"stk1s\\\"},\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"(datum.key.stk1==''?datum.key.stk3:datum.stk1s)\\\", \\\"as\\\": \\\"stk1\\\"},\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"datum.key.stk2 + datum.key.stk2p\\\", \\\"as\\\": \\\"stk2p\\\"},\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"(datum.key.stk2==''?datum.key.stk4:datum.stk2p)\\\", \\\"as\\\": \\\"stk2\\\"},\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"datum.key.stk3\\\", \\\"as\\\": \\\"stk3\\\"},\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"datum.key.stk4\\\", \\\"as\\\": \\\"stk4\\\"},\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"datum.bytes.value\\\", \\\"as\\\": \\\"size\\\"}\\n ]\\n },\\n {\\n \\\"name\\\": \\\"nodes\\\",\\n \\\"source\\\": \\\"rawData\\\",\\n \\\"transform\\\": [\\n {\\n \\\"type\\\": \\\"filter\\\",\\n \\\"expr\\\": \\\"!groupSelector || groupSelector.stk1 == datum.stk1 || groupSelector.stk2 == datum.stk2\\\"\\n },\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"datum.stk1+datum.stk2+datum.stk3+datum.stk4\\\", \\\"as\\\": \\\"key\\\"},\\n {\\\"type\\\": \\\"fold\\\", \\\"fields\\\": [\\\"stk1\\\", \\\"stk2\\\"], \\\"as\\\": [\\\"stack\\\", \\\"grpId\\\"]},\\n {\\n \\\"type\\\": \\\"formula\\\",\\n \\\"expr\\\": \\\"datum.stack == 'stk1' ? datum.stk1+datum.stk2 : datum.stk2+datum.stk1\\\",\\n \\\"as\\\": \\\"sortField\\\"\\n },\\n {\\n \\\"type\\\": \\\"stack\\\",\\n \\\"groupby\\\": [\\\"stack\\\"],\\n \\\"sort\\\": {\\\"field\\\": \\\"sortField\\\", \\\"order\\\": \\\"descending\\\"},\\n \\\"field\\\": \\\"size\\\"\\n },\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"(datum.y0+datum.y1)/2\\\", \\\"as\\\": \\\"yc\\\"}\\n ]\\n },\\n {\\n \\\"name\\\": \\\"groups\\\",\\n \\\"source\\\": \\\"nodes\\\",\\n \\\"transform\\\": [\\n {\\n \\\"type\\\": \\\"aggregate\\\",\\n \\\"groupby\\\": [\\\"stack\\\", \\\"grpId\\\"],\\n \\\"fields\\\": [\\\"size\\\"],\\n \\\"ops\\\": [\\\"sum\\\"],\\n \\\"as\\\": [\\\"total\\\"]\\n },\\n {\\n \\\"type\\\": \\\"stack\\\",\\n \\\"groupby\\\": [\\\"stack\\\"],\\n \\\"sort\\\": {\\\"field\\\": \\\"grpId\\\", \\\"order\\\": \\\"descending\\\"},\\n \\\"field\\\": \\\"total\\\"\\n },\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"scale('y', datum.y0)\\\", \\\"as\\\": \\\"scaledY0\\\"},\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"scale('y', datum.y1)\\\", \\\"as\\\": \\\"scaledY1\\\"},\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"datum.stack == 'stk1'\\\", \\\"as\\\": \\\"rightLabel\\\"},\\n {\\n \\\"type\\\": \\\"formula\\\",\\n \\\"expr\\\": \\\"datum.total/domain('y')[1]\\\",\\n \\\"as\\\": \\\"percentage\\\"\\n }\\n ]\\n },\\n {\\n \\\"name\\\": \\\"destinationNodes\\\",\\n \\\"source\\\": \\\"nodes\\\",\\n \\\"transform\\\": [{\\\"type\\\": \\\"filter\\\", \\\"expr\\\": \\\"datum.stack == 'stk2'\\\"}]\\n },\\n {\\n \\\"name\\\": \\\"edges\\\",\\n \\\"source\\\": \\\"nodes\\\",\\n \\\"transform\\\": [\\n {\\\"type\\\": \\\"filter\\\", \\\"expr\\\": \\\"datum.stack == 'stk1'\\\"},\\n {\\n \\\"type\\\": \\\"lookup\\\",\\n \\\"from\\\": \\\"destinationNodes\\\",\\n \\\"key\\\": \\\"key\\\",\\n \\\"fields\\\": [\\\"key\\\"],\\n \\\"as\\\": [\\\"target\\\"]\\n },\\n {\\n \\\"type\\\": \\\"linkpath\\\",\\n \\\"orient\\\": \\\"horizontal\\\",\\n \\\"shape\\\": \\\"diagonal\\\",\\n \\\"sourceY\\\": {\\\"expr\\\": \\\"scale('y', datum.yc)\\\"},\\n \\\"sourceX\\\": {\\\"expr\\\": \\\"scale('x', 'stk1') + bandwidth('x')\\\"},\\n \\\"targetY\\\": {\\\"expr\\\": \\\"scale('y', datum.target.yc)\\\"},\\n \\\"targetX\\\": {\\\"expr\\\": \\\"scale('x', 'stk2')\\\"}\\n },\\n {\\n \\\"type\\\": \\\"formula\\\",\\n \\\"expr\\\": \\\"range('y')[0]-scale('y', datum.size)\\\",\\n \\\"as\\\": \\\"strokeWidth\\\"\\n },\\n {\\n \\\"type\\\": \\\"formula\\\",\\n \\\"expr\\\": \\\"datum.size/domain('y')[1]\\\",\\n \\\"as\\\": \\\"percentage\\\"\\n }\\n ]\\n }\\n ],\\n \\\"scales\\\": [\\n {\\n \\\"name\\\": \\\"x\\\",\\n \\\"type\\\": \\\"band\\\",\\n \\\"range\\\": \\\"width\\\",\\n \\\"domain\\\": [\\\"stk1\\\", \\\"stk2\\\"],\\n \\\"paddingOuter\\\": 0.01,\\n \\\"paddingInner\\\": 0.98\\n },\\n {\\n \\\"name\\\": \\\"y\\\",\\n \\\"type\\\": \\\"linear\\\",\\n \\\"range\\\": \\\"height\\\",\\n \\\"domain\\\": {\\\"data\\\": \\\"nodes\\\", \\\"field\\\": \\\"y1\\\"}\\n },\\n {\\n \\\"name\\\": \\\"color\\\",\\n \\\"type\\\": \\\"ordinal\\\",\\n \\\"range\\\": \\\"category\\\",\\n \\\"domain\\\": {\\\"data\\\": \\\"rawData\\\", \\\"fields\\\": [\\\"stk1\\\",\\\"stk2\\\"]}\\n },\\n {\\n \\\"name\\\": \\\"stackNames\\\",\\n \\\"type\\\": \\\"ordinal\\\",\\n \\\"range\\\": [\\\"Source Pod\\\", \\\"Destination Service\\\"],\\n \\\"domain\\\": [\\\"stk1\\\", \\\"stk2\\\"]\\n }\\n ],\\n \\\"axes\\\": [\\n {\\n \\\"orient\\\": \\\"bottom\\\",\\n \\\"scale\\\": \\\"x\\\",\\n \\\"labelColor\\\": {\\n \\\"value\\\": \\\"#888888\\\"\\n },\\n \\\"encode\\\": {\\n \\\"labels\\\": {\\n \\\"update\\\": {\\n \\\"text\\\": {\\\"scale\\\": \\\"stackNames\\\", \\\"field\\\": \\\"value\\\"},\\n \\\"fontSize\\\": {\\\"value\\\": 14}\\n }\\n }\\n }\\n },\\n {\\n \\\"orient\\\": \\\"left\\\",\\n \\\"scale\\\": \\\"y\\\",\\n \\\"labelColor\\\": {\\n \\\"value\\\": \\\"#888888\\\"\\n },\\n \\\"encode\\\": {\\n \\\"labels\\\": {\\n \\\"update\\\": {\\n \\\"text\\\": {\\\"signal\\\": \\\"format(datum.value, '.2s') + 'B'\\\"},\\n \\\"fontSize\\\": {\\\"value\\\": 12}\\n }\\n }\\n }\\n }\\n ],\\n \\\"marks\\\": [\\n {\\n \\\"type\\\": \\\"path\\\",\\n \\\"name\\\": \\\"edgeMark\\\",\\n \\\"from\\\": {\\\"data\\\": \\\"edges\\\"},\\n \\\"clip\\\": true,\\n \\\"encode\\\": {\\n \\\"update\\\": {\\n \\\"stroke\\\": [\\n {\\n \\\"test\\\": \\\"groupSelector && groupSelector.stack=='stk1'\\\",\\n \\\"scale\\\": \\\"color\\\",\\n \\\"field\\\": \\\"stk2\\\"\\n },\\n {\\\"scale\\\": \\\"color\\\", \\\"field\\\": \\\"stk1\\\"}\\n ],\\n \\\"strokeWidth\\\": {\\\"field\\\": \\\"strokeWidth\\\"},\\n \\\"path\\\": {\\\"field\\\": \\\"path\\\"},\\n \\\"strokeOpacity\\\": {\\n \\\"signal\\\": \\\"!groupSelector && (groupHover.stk1 == datum.stk1 || groupHover.stk2 == datum.stk2) ? 0.75 : 0.3\\\"\\n },\\n \\\"zindex\\\": {\\n \\\"signal\\\": \\\"!groupSelector && (groupHover.stk1 == datum.stk1 || groupHover.stk2 == datum.stk2) ? 1 : 0\\\"\\n },\\n \\\"tooltip\\\": {\\n \\\"signal\\\": \\\"{'title': datum.stk1 + ' → ' + datum.stk2 + ' ' + format(datum.size, '.2s') + 'B (' + format(datum.percentage, '.1%') + ')', 'IP Address': datum.stk3 +' → ' + datum.stk4 }\\\"\\n }\\n },\\n \\\"hover\\\": {\\\"strokeOpacity\\\": {\\\"value\\\": 0.75}}\\n }\\n },\\n {\\n \\\"type\\\": \\\"rect\\\",\\n \\\"name\\\": \\\"groupMark\\\",\\n \\\"from\\\": {\\\"data\\\": \\\"groups\\\"},\\n \\\"encode\\\": {\\n \\\"enter\\\": {\\n \\\"fill\\\": {\\\"scale\\\": \\\"color\\\", \\\"field\\\": \\\"grpId\\\"},\\n \\\"width\\\": {\\\"scale\\\": \\\"x\\\", \\\"band\\\": 1}\\n },\\n \\\"update\\\": {\\n \\\"x\\\": {\\\"scale\\\": \\\"x\\\", \\\"field\\\": \\\"stack\\\"},\\n \\\"y\\\": {\\\"field\\\": \\\"scaledY0\\\"},\\n \\\"y2\\\": {\\\"field\\\": \\\"scaledY1\\\"},\\n \\\"fillOpacity\\\": {\\\"value\\\": 0.7},\\n \\\"tooltip\\\": {\\n \\\"signal\\\": \\\"datum.grpId + ' ' + format(datum.total, '.2s') + 'B (' + format(datum.percentage, '.1%') + ')'\\\"\\n }\\n },\\n \\\"hover\\\": {\\\"fillOpacity\\\": {\\\"value\\\": 1}}\\n }\\n },\\n {\\n \\\"type\\\": \\\"text\\\",\\n \\\"from\\\": {\\\"data\\\": \\\"groups\\\"},\\n \\\"interactive\\\": false,\\n \\\"encode\\\": {\\n \\\"update\\\": {\\n \\\"x\\\": {\\n \\\"signal\\\": \\\"scale('x', datum.stack) + (datum.rightLabel ? bandwidth('x') + 8 : -8)\\\"\\n },\\n \\\"yc\\\": {\\\"signal\\\": \\\"(datum.scaledY0 + datum.scaledY1)/2\\\"},\\n \\\"align\\\": {\\\"signal\\\": \\\"datum.rightLabel ? 'left' : 'right'\\\"},\\n \\\"baseline\\\": {\\\"value\\\": \\\"middle\\\"},\\n \\\"fontWeight\\\": {\\\"value\\\": \\\"bold\\\"},\\n \\\"fontSize\\\": {\\\"value\\\": 12},\\n \\\"text\\\": {\\n \\\"signal\\\": \\\"abs(datum.scaledY0-datum.scaledY1) > 10 ? datum.grpId : ''\\\"\\n }\\n }\\n }\\n },\\n {\\n \\\"type\\\": \\\"group\\\",\\n \\\"data\\\": [\\n {\\n \\\"name\\\": \\\"dataForShowAll\\\",\\n \\\"values\\\": [{}],\\n \\\"transform\\\": [{\\\"type\\\": \\\"filter\\\", \\\"expr\\\": \\\"groupSelector\\\"}]\\n }\\n ],\\n \\\"encode\\\": {\\n \\\"enter\\\": {\\n \\\"xc\\\": {\\\"signal\\\": \\\"width/2\\\"},\\n \\\"y\\\": {\\\"value\\\": 30},\\n \\\"width\\\": {\\\"value\\\": 100},\\n \\\"height\\\": {\\\"value\\\": 36}\\n }\\n },\\n \\\"marks\\\": [\\n {\\n \\\"type\\\": \\\"group\\\",\\n \\\"name\\\": \\\"groupReset\\\",\\n \\\"from\\\": {\\\"data\\\": \\\"dataForShowAll\\\"},\\n \\\"encode\\\": {\\n \\\"enter\\\": {\\n \\\"cornerRadius\\\": {\\\"value\\\": 3.5},\\n \\\"fill\\\": {\\\"value\\\": \\\"#666666\\\"},\\n \\\"height\\\": {\\\"field\\\": {\\\"group\\\": \\\"height\\\"}},\\n \\\"width\\\": {\\\"field\\\": {\\\"group\\\": \\\"width\\\"}}\\n },\\n \\\"update\\\": {\\\"opacity\\\": {\\\"value\\\": 1}},\\n \\\"hover\\\": {\\\"fill\\\": {\\\"value\\\": \\\"#444444\\\"}}\\n },\\n \\\"marks\\\": [\\n {\\n \\\"type\\\": \\\"text\\\",\\n \\\"interactive\\\": false,\\n \\\"encode\\\": {\\n \\\"enter\\\": {\\n \\\"xc\\\": {\\\"field\\\": {\\\"group\\\": \\\"width\\\"}, \\\"mult\\\": 0.5},\\n \\\"yc\\\": {\\\"field\\\": {\\\"group\\\": \\\"height\\\"}, \\\"mult\\\": 0.5, \\\"offset\\\": 1},\\n \\\"align\\\": {\\\"value\\\": \\\"center\\\"},\\n \\\"baseline\\\": {\\\"value\\\": \\\"middle\\\"},\\n \\\"text\\\": {\\\"value\\\": \\\"Show All\\\"},\\n \\\"fontSize\\\": {\\\"value\\\": 14},\\n \\\"stroke\\\": {\\\"value\\\": \\\"#ecf0f1\\\"}\\n }\\n }\\n }\\n ]\\n }\\n ]\\n }\\n ],\\n \\\"signals\\\": [\\n {\\n \\\"name\\\": \\\"groupHover\\\",\\n \\\"value\\\": {},\\n \\\"on\\\": [\\n {\\n \\\"events\\\": \\\"@groupMark:mouseover\\\",\\n \\\"update\\\": \\\"{stk1:datum.stack=='stk1' && datum.grpId, stk2:datum.stack=='stk2' && datum.grpId}\\\"\\n },\\n {\\\"events\\\": \\\"mouseout\\\", \\\"update\\\": \\\"{}\\\"}\\n ]\\n },\\n {\\n \\\"name\\\": \\\"groupSelector\\\",\\n \\\"value\\\": false,\\n \\\"on\\\": [\\n {\\n \\\"events\\\": \\\"@groupMark:click!\\\",\\n \\\"update\\\": \\\"{stack:datum.stack, stk1:datum.stack=='stk1' && datum.grpId, stk2:datum.stack=='stk2' && datum.grpId}\\\"\\n },\\n {\\n \\\"events\\\": [\\n {\\\"type\\\": \\\"click\\\", \\\"markname\\\": \\\"groupReset\\\"},\\n {\\\"type\\\": \\\"dblclick\\\"}\\n ],\\n \\\"update\\\": \\\"false\\\"\\n }\\n ]\\n }\\n ]\\n}\"},\"title\":\"Pod-to-Service Flow Cumulative Bytes\"}"},"id":"67f0ca90-d07b-11ea-a734-57fc7859997d","migrationVersion":{"visualization":"7.8.0"},"references":[],"type":"visualization","updated_at":"2021-08-07T23:30:40.150Z","version":"WzUxLDFd"} -{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"language\":\"lucene\",\"query\":\"\"},\"filter\":[]}"},"title":"Pod-to-Service Flow Nav","uiStateJSON":"{}","version":1,"visState":"{\"type\":\"metrics\",\"aggs\":[],\"params\":{\"axis_formatter\":\"number\",\"axis_position\":\"left\",\"axis_scale\":\"normal\",\"default_index_pattern\":\"flow-*\",\"default_timefield\":\"@timestamp\",\"id\":\"61ca57f0-469d-11e7-af02-69e470af7417\",\"index_pattern\":\"flow-*\",\"interval\":\"auto\",\"isModelInvalid\":false,\"markdown_css\":\"#markdown-61ca57f0-469d-11e7-af02-69e470af7417 p{color:#cccccc;margin-top:0;margin-bottom:8px;text-align:right}#markdown-61ca57f0-469d-11e7-af02-69e470af7417 p a{color:#1eadbd;font-size:17px;font-weight:bold;text-decoration:none}#markdown-61ca57f0-469d-11e7-af02-69e470af7417 p a strong{color:#ffac12;font-weight:bold}#markdown-61ca57f0-469d-11e7-af02-69e470af7417 hr{background-color:#cccccc;margin:0;height:1px}\",\"markdown_less\":\"p {\\n color: #cccccc;\\n margin-top: 0px;\\n margin-bottom: 8px;\\n text-align: right;\\n}\\np a {\\n color: #1eadbd;\\n\\tfont-size: 17px;\\n\\tfont-weight: bold;\\n\\ttext-decoration: none;\\n}\\np a strong {\\n color: #ffac12;\\n\\tfont-weight: bold;\\n}\\nhr {\\n background-color: #cccccc;\\n margin: 0px;\\n height: 1px;\\n}\",\"markdown_vertical_align\":\"top\",\"series\":[{\"axis_position\":\"right\",\"chart_type\":\"line\",\"color\":\"#68BC00\",\"fill\":0.5,\"formatter\":\"number\",\"id\":\"61ca57f1-469d-11e7-af02-69e470af7417\",\"line_width\":1,\"metrics\":[{\"id\":\"61ca57f2-469d-11e7-af02-69e470af7417\",\"type\":\"count\"}],\"offset_time\":\"-5y\",\"point_size\":1,\"separate_axis\":0,\"split_color_mode\":\"gradient\",\"split_mode\":\"everything\",\"stacked\":\"none\"}],\"show_grid\":1,\"show_legend\":1,\"time_field\":null,\"type\":\"markdown\",\"markdown\":\"[Overview](#/dashboard/3b331b30-b987-11ea-b16e-fb06687c3589) | [Pod-to-Pod Flow](#/dashboard/c2b15fb0-b9a8-11ea-b16e-fb06687c3589) | [Pod-to-External Flow](#/dashboard/3ed71e80-a92d-11eb-a7ef-5dcb53008c10) | [**Pod-to-Service Flow**](#/dashboard/6d77e8a0-513a-11eb-a19a-05e08a82dcf8) | [Node](#/dashboard/5400cdf0-cd2e-11ea-8911-87da3aad0324) | [Network Policy](#/dashboard/c5af6850-23b2-11eb-90d2-a7a4de48218a) | [Flow Records](#/dashboard/2ab9c220-b984-11ea-b16e-fb06687c3589)\"},\"title\":\"Pod-to-Service Flow Nav\"}"},"id":"c4e1b7c0-b9a9-11ea-b16e-fb06687c3589","migrationVersion":{"visualization":"7.8.0"},"references":[],"type":"visualization","updated_at":"2021-08-07T23:30:40.150Z","version":"WzUyLDFd"} -{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}"},"title":"Pod-to-Service Filter","uiStateJSON":"{}","version":1,"visState":"{\"type\":\"input_control_vis\",\"aggs\":[],\"params\":{\"updateFiltersOnChange\":true,\"useTimeFilter\":true,\"pinFilters\":true,\"controls\":[{\"id\":\"1610147114234\",\"fieldName\":\"ipfix.sourcePodNamespace.keyword\",\"parent\":\"\",\"label\":\"Source Pod Namespace\",\"type\":\"list\",\"options\":{\"type\":\"terms\",\"multiselect\":true,\"dynamicOptions\":false,\"size\":1000,\"order\":\"desc\"},\"indexPatternRefName\":\"control_0_index_pattern\"},{\"id\":\"1610147099400\",\"fieldName\":\"ipfix.sourcePodName.keyword\",\"parent\":\"\",\"label\":\"Source Pod Name\",\"type\":\"list\",\"options\":{\"type\":\"terms\",\"multiselect\":true,\"dynamicOptions\":false,\"size\":1000,\"order\":\"desc\"},\"indexPatternRefName\":\"control_1_index_pattern\"},{\"id\":\"1610427679127\",\"fieldName\":\"ipfix.destinationPodNamespace.keyword\",\"parent\":\"\",\"label\":\"Destination Service Namespace\",\"type\":\"list\",\"options\":{\"type\":\"terms\",\"multiselect\":true,\"dynamicOptions\":false,\"size\":1000,\"order\":\"desc\"},\"indexPatternRefName\":\"control_2_index_pattern\"},{\"id\":\"1595904313889\",\"fieldName\":\"ipfix.destinationServicePortName.keyword\",\"parent\":\"\",\"label\":\"Destination Service Name\",\"type\":\"list\",\"options\":{\"type\":\"terms\",\"multiselect\":true,\"dynamicOptions\":false,\"size\":1000,\"order\":\"desc\"},\"indexPatternRefName\":\"control_3_index_pattern\"},{\"id\":\"1610067847339\",\"parent\":\"\",\"type\":\"list\",\"label\":\"Destination Service Port\",\"fieldName\":\"ipfix.destinationServicePort\",\"options\":{\"type\":\"terms\",\"multiselect\":true,\"dynamicOptions\":true,\"order\":\"desc\",\"size\":1000},\"indexPatternRefName\":\"control_4_index_pattern\"},{\"id\":\"1610147131444\",\"parent\":\"\",\"label\":\"Flow Key (Pod-to-Service)\",\"type\":\"list\",\"options\":{\"type\":\"terms\",\"multiselect\":true,\"dynamicOptions\":false,\"size\":1000,\"order\":\"desc\"},\"fieldName\":\"ipfix.flowKeyPodToService.keyword\",\"indexPatternRefName\":\"control_5_index_pattern\"},{\"id\":\"1618607115393\",\"fieldName\":\"ipfix.flowTypeStr.keyword\",\"parent\":\"\",\"label\":\"Flow Type\",\"type\":\"list\",\"options\":{\"type\":\"terms\",\"multiselect\":true,\"dynamicOptions\":false,\"size\":1000,\"order\":\"desc\"},\"indexPatternRefName\":\"control_6_index_pattern\"}]},\"title\":\"Pod-to-Service Filter\"}"},"id":"804d18c0-514d-11eb-a19a-05e08a82dcf8","migrationVersion":{"visualization":"7.8.0"},"references":[{"id":"e2ab2c50-b981-11ea-b16e-fb06687c3589","name":"control_0_index_pattern","type":"index-pattern"},{"id":"e2ab2c50-b981-11ea-b16e-fb06687c3589","name":"control_1_index_pattern","type":"index-pattern"},{"id":"e2ab2c50-b981-11ea-b16e-fb06687c3589","name":"control_2_index_pattern","type":"index-pattern"},{"id":"e2ab2c50-b981-11ea-b16e-fb06687c3589","name":"control_3_index_pattern","type":"index-pattern"},{"id":"e2ab2c50-b981-11ea-b16e-fb06687c3589","name":"control_4_index_pattern","type":"index-pattern"},{"id":"e2ab2c50-b981-11ea-b16e-fb06687c3589","name":"control_5_index_pattern","type":"index-pattern"},{"id":"e2ab2c50-b981-11ea-b16e-fb06687c3589","name":"control_6_index_pattern","type":"index-pattern"}],"type":"visualization","updated_at":"2021-08-07T23:30:40.150Z","version":"WzUzLDFd"} -{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"lucene\"},\"filter\":[]}"},"title":"Pod-to-Service Flow Reverse Cumulative Bytes","uiStateJSON":"{}","version":1,"visState":"{\"type\":\"vega\",\"aggs\":[],\"params\":{\"spec\":\"{\\n \\\"$schema\\\": \\\"https://vega.github.io/schema/vega/v3.0.json\\\",\\n \\\"data\\\": [\\n {\\n \\\"name\\\": \\\"rawData\\\",\\n \\\"url\\\": {\\n \\\"%context%\\\": true,\\n \\\"%timefield%\\\": \\\"@timestamp\\\",\\n \\\"index\\\": \\\"flow-*\\\",\\n \\\"body\\\": {\\n \\\"size\\\": 0,\\n \\\"aggs\\\": {\\n \\\"table\\\": {\\n \\\"composite\\\": {\\n \\\"size\\\": 1000,\\n \\\"sources\\\": [\\n {\\\"stk1\\\": {\\\"terms\\\": {\\\"field\\\": \\\"ipfix.sourcePodName.keyword\\\"}}},\\n {\\\"stk1ns\\\": {\\\"terms\\\": {\\\"field\\\": \\\"ipfix.sourcePodNamespace.keyword\\\"}}},\\n {\\\"stk2\\\": {\\\"terms\\\": {\\\"field\\\": \\\"ipfix.destinationServicePortName.keyword\\\"}}},\\n {\\\"stk2p\\\": {\\\"terms\\\": {\\\"field\\\": \\\"ipfix.destinationServicePort\\\"}}},\\n {\\\"stk3\\\": {\\\"terms\\\": {\\\"field\\\": \\\"ipfix.sourceIP.keyword\\\"}}},\\n {\\\"stk4\\\": {\\\"terms\\\": {\\\"field\\\": \\\"ipfix.destinationIP.keyword\\\"}}}\\n ]\\n },\\n \\t\\t\\t\\\"aggs\\\": {\\n \\t\\t\\t\\t\\\"bytes\\\": {\\n \\t\\t\\t\\t\\t\\\"sum\\\": {\\n \\t\\t\\t\\t\\t\\t\\\"field\\\": \\\"ipfix.reverseOctetDeltaCountFromSourceNode\\\"\\n \\t\\t\\t\\t\\t}\\n \\t\\t\\t\\t}\\n \\t\\t\\t}\\n }\\n }\\n }\\n },\\n \\\"format\\\": {\\\"property\\\": \\\"aggregations.table.buckets\\\"},\\n \\\"transform\\\": [\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"datum.key.stk1ns +'/'+ datum.key.stk1\\\", \\\"as\\\": \\\"stk1s\\\"},\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"(datum.key.stk1==''?datum.key.stk3:datum.stk1s)\\\", \\\"as\\\": \\\"stk1\\\"},\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"datum.key.stk2 + datum.key.stk2p\\\", \\\"as\\\": \\\"stk2p\\\"},\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"(datum.key.stk2==''?datum.key.stk4:datum.stk2p)\\\", \\\"as\\\": \\\"stk2\\\"},\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"datum.key.stk3\\\", \\\"as\\\": \\\"stk3\\\"},\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"datum.key.stk4\\\", \\\"as\\\": \\\"stk4\\\"},\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"datum.bytes.value\\\", \\\"as\\\": \\\"size\\\"}\\n ]\\n },\\n {\\n \\\"name\\\": \\\"nodes\\\",\\n \\\"source\\\": \\\"rawData\\\",\\n \\\"transform\\\": [\\n {\\n \\\"type\\\": \\\"filter\\\",\\n \\\"expr\\\": \\\"!groupSelector || groupSelector.stk1 == datum.stk1 || groupSelector.stk2 == datum.stk2\\\"\\n },\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"datum.stk1+datum.stk2+datum.stk3+datum.stk4\\\", \\\"as\\\": \\\"key\\\"},\\n {\\\"type\\\": \\\"fold\\\", \\\"fields\\\": [\\\"stk1\\\", \\\"stk2\\\"], \\\"as\\\": [\\\"stack\\\", \\\"grpId\\\"]},\\n {\\n \\\"type\\\": \\\"formula\\\",\\n \\\"expr\\\": \\\"datum.stack == 'stk1' ? datum.stk1+datum.stk2 : datum.stk2+datum.stk1\\\",\\n \\\"as\\\": \\\"sortField\\\"\\n },\\n {\\n \\\"type\\\": \\\"stack\\\",\\n \\\"groupby\\\": [\\\"stack\\\"],\\n \\\"sort\\\": {\\\"field\\\": \\\"sortField\\\", \\\"order\\\": \\\"descending\\\"},\\n \\\"field\\\": \\\"size\\\"\\n },\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"(datum.y0+datum.y1)/2\\\", \\\"as\\\": \\\"yc\\\"}\\n ]\\n },\\n {\\n \\\"name\\\": \\\"groups\\\",\\n \\\"source\\\": \\\"nodes\\\",\\n \\\"transform\\\": [\\n {\\n \\\"type\\\": \\\"aggregate\\\",\\n \\\"groupby\\\": [\\\"stack\\\", \\\"grpId\\\"],\\n \\\"fields\\\": [\\\"size\\\"],\\n \\\"ops\\\": [\\\"sum\\\"],\\n \\\"as\\\": [\\\"total\\\"]\\n },\\n {\\n \\\"type\\\": \\\"stack\\\",\\n \\\"groupby\\\": [\\\"stack\\\"],\\n \\\"sort\\\": {\\\"field\\\": \\\"grpId\\\", \\\"order\\\": \\\"descending\\\"},\\n \\\"field\\\": \\\"total\\\"\\n },\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"scale('y', datum.y0)\\\", \\\"as\\\": \\\"scaledY0\\\"},\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"scale('y', datum.y1)\\\", \\\"as\\\": \\\"scaledY1\\\"},\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"datum.stack == 'stk1'\\\", \\\"as\\\": \\\"rightLabel\\\"},\\n {\\n \\\"type\\\": \\\"formula\\\",\\n \\\"expr\\\": \\\"datum.total/domain('y')[1]\\\",\\n \\\"as\\\": \\\"percentage\\\"\\n }\\n ]\\n },\\n {\\n \\\"name\\\": \\\"destinationNodes\\\",\\n \\\"source\\\": \\\"nodes\\\",\\n \\\"transform\\\": [{\\\"type\\\": \\\"filter\\\", \\\"expr\\\": \\\"datum.stack == 'stk2'\\\"}]\\n },\\n {\\n \\\"name\\\": \\\"edges\\\",\\n \\\"source\\\": \\\"nodes\\\",\\n \\\"transform\\\": [\\n {\\\"type\\\": \\\"filter\\\", \\\"expr\\\": \\\"datum.stack == 'stk1'\\\"},\\n {\\n \\\"type\\\": \\\"lookup\\\",\\n \\\"from\\\": \\\"destinationNodes\\\",\\n \\\"key\\\": \\\"key\\\",\\n \\\"fields\\\": [\\\"key\\\"],\\n \\\"as\\\": [\\\"target\\\"]\\n },\\n {\\n \\\"type\\\": \\\"linkpath\\\",\\n \\\"orient\\\": \\\"horizontal\\\",\\n \\\"shape\\\": \\\"diagonal\\\",\\n \\\"sourceY\\\": {\\\"expr\\\": \\\"scale('y', datum.yc)\\\"},\\n \\\"sourceX\\\": {\\\"expr\\\": \\\"scale('x', 'stk1') + bandwidth('x')\\\"},\\n \\\"targetY\\\": {\\\"expr\\\": \\\"scale('y', datum.target.yc)\\\"},\\n \\\"targetX\\\": {\\\"expr\\\": \\\"scale('x', 'stk2')\\\"}\\n },\\n {\\n \\\"type\\\": \\\"formula\\\",\\n \\\"expr\\\": \\\"range('y')[0]-scale('y', datum.size)\\\",\\n \\\"as\\\": \\\"strokeWidth\\\"\\n },\\n {\\n \\\"type\\\": \\\"formula\\\",\\n \\\"expr\\\": \\\"datum.size/domain('y')[1]\\\",\\n \\\"as\\\": \\\"percentage\\\"\\n }\\n ]\\n }\\n ],\\n \\\"scales\\\": [\\n {\\n \\\"name\\\": \\\"x\\\",\\n \\\"type\\\": \\\"band\\\",\\n \\\"range\\\": \\\"width\\\",\\n \\\"domain\\\": [\\\"stk1\\\", \\\"stk2\\\"],\\n \\\"paddingOuter\\\": 0.01,\\n \\\"paddingInner\\\": 0.98\\n },\\n {\\n \\\"name\\\": \\\"y\\\",\\n \\\"type\\\": \\\"linear\\\",\\n \\\"range\\\": \\\"height\\\",\\n \\\"domain\\\": {\\\"data\\\": \\\"nodes\\\", \\\"field\\\": \\\"y1\\\"}\\n },\\n {\\n \\\"name\\\": \\\"color\\\",\\n \\\"type\\\": \\\"ordinal\\\",\\n \\\"range\\\": \\\"category\\\",\\n \\\"domain\\\": {\\\"data\\\": \\\"rawData\\\", \\\"fields\\\": [\\\"stk1\\\",\\\"stk2\\\"]}\\n },\\n {\\n \\\"name\\\": \\\"stackNames\\\",\\n \\\"type\\\": \\\"ordinal\\\",\\n \\\"range\\\": [\\\"Source Pod\\\", \\\"Destination Service\\\"],\\n \\\"domain\\\": [\\\"stk1\\\", \\\"stk2\\\"]\\n }\\n ],\\n \\\"axes\\\": [\\n {\\n \\\"orient\\\": \\\"bottom\\\",\\n \\\"scale\\\": \\\"x\\\",\\n \\\"labelColor\\\": {\\n \\\"value\\\": \\\"#888888\\\"\\n },\\n \\\"encode\\\": {\\n \\\"labels\\\": {\\n \\\"update\\\": {\\n \\\"text\\\": {\\\"scale\\\": \\\"stackNames\\\", \\\"field\\\": \\\"value\\\"},\\n \\\"fontSize\\\": {\\\"value\\\": 14}\\n }\\n }\\n }\\n },\\n {\\n \\\"orient\\\": \\\"left\\\",\\n \\\"scale\\\": \\\"y\\\",\\n \\\"labelColor\\\": {\\n \\\"value\\\": \\\"#888888\\\"\\n },\\n \\\"encode\\\": {\\n \\\"labels\\\": {\\n \\\"update\\\": {\\n \\\"text\\\": {\\\"signal\\\": \\\"format(datum.value, '.2s') + 'B'\\\"},\\n \\\"fontSize\\\": {\\\"value\\\": 12}\\n }\\n }\\n }\\n }\\n ],\\n \\\"marks\\\": [\\n {\\n \\\"type\\\": \\\"path\\\",\\n \\\"name\\\": \\\"edgeMark\\\",\\n \\\"from\\\": {\\\"data\\\": \\\"edges\\\"},\\n \\\"clip\\\": true,\\n \\\"encode\\\": {\\n \\\"update\\\": {\\n \\\"stroke\\\": [\\n {\\n \\\"test\\\": \\\"groupSelector && groupSelector.stack=='stk1'\\\",\\n \\\"scale\\\": \\\"color\\\",\\n \\\"field\\\": \\\"stk2\\\"\\n },\\n {\\\"scale\\\": \\\"color\\\", \\\"field\\\": \\\"stk1\\\"}\\n ],\\n \\\"strokeWidth\\\": {\\\"field\\\": \\\"strokeWidth\\\"},\\n \\\"path\\\": {\\\"field\\\": \\\"path\\\"},\\n \\\"strokeOpacity\\\": {\\n \\\"signal\\\": \\\"!groupSelector && (groupHover.stk1 == datum.stk1 || groupHover.stk2 == datum.stk2) ? 0.75 : 0.3\\\"\\n },\\n \\\"zindex\\\": {\\n \\\"signal\\\": \\\"!groupSelector && (groupHover.stk1 == datum.stk1 || groupHover.stk2 == datum.stk2) ? 1 : 0\\\"\\n },\\n \\\"tooltip\\\": {\\n \\\"signal\\\": \\\"{'title': datum.stk1 + ' → ' + datum.stk2 + ' ' + format(datum.size, '.2s') + 'B (' + format(datum.percentage, '.1%') + ')', 'IP Address': datum.stk3 +' → ' + datum.stk4 }\\\"\\n }\\n },\\n \\\"hover\\\": {\\\"strokeOpacity\\\": {\\\"value\\\": 0.75}}\\n }\\n },\\n {\\n \\\"type\\\": \\\"rect\\\",\\n \\\"name\\\": \\\"groupMark\\\",\\n \\\"from\\\": {\\\"data\\\": \\\"groups\\\"},\\n \\\"encode\\\": {\\n \\\"enter\\\": {\\n \\\"fill\\\": {\\\"scale\\\": \\\"color\\\", \\\"field\\\": \\\"grpId\\\"},\\n \\\"width\\\": {\\\"scale\\\": \\\"x\\\", \\\"band\\\": 1}\\n },\\n \\\"update\\\": {\\n \\\"x\\\": {\\\"scale\\\": \\\"x\\\", \\\"field\\\": \\\"stack\\\"},\\n \\\"y\\\": {\\\"field\\\": \\\"scaledY0\\\"},\\n \\\"y2\\\": {\\\"field\\\": \\\"scaledY1\\\"},\\n \\\"fillOpacity\\\": {\\\"value\\\": 0.7},\\n \\\"tooltip\\\": {\\n \\\"signal\\\": \\\"datum.grpId + ' ' + format(datum.total, '.2s') + 'B (' + format(datum.percentage, '.1%') + ')'\\\"\\n }\\n },\\n \\\"hover\\\": {\\\"fillOpacity\\\": {\\\"value\\\": 1}}\\n }\\n },\\n {\\n \\\"type\\\": \\\"text\\\",\\n \\\"from\\\": {\\\"data\\\": \\\"groups\\\"},\\n \\\"interactive\\\": false,\\n \\\"encode\\\": {\\n \\\"update\\\": {\\n \\\"x\\\": {\\n \\\"signal\\\": \\\"scale('x', datum.stack) + (datum.rightLabel ? bandwidth('x') + 8 : -8)\\\"\\n },\\n \\\"yc\\\": {\\\"signal\\\": \\\"(datum.scaledY0 + datum.scaledY1)/2\\\"},\\n \\\"align\\\": {\\\"signal\\\": \\\"datum.rightLabel ? 'left' : 'right'\\\"},\\n \\\"baseline\\\": {\\\"value\\\": \\\"middle\\\"},\\n \\\"fontWeight\\\": {\\\"value\\\": \\\"bold\\\"},\\n \\\"fontSize\\\": {\\\"value\\\": 12},\\n \\\"text\\\": {\\n \\\"signal\\\": \\\"abs(datum.scaledY0-datum.scaledY1) > 10 ? datum.grpId : ''\\\"\\n }\\n }\\n }\\n },\\n {\\n \\\"type\\\": \\\"group\\\",\\n \\\"data\\\": [\\n {\\n \\\"name\\\": \\\"dataForShowAll\\\",\\n \\\"values\\\": [{}],\\n \\\"transform\\\": [{\\\"type\\\": \\\"filter\\\", \\\"expr\\\": \\\"groupSelector\\\"}]\\n }\\n ],\\n \\\"encode\\\": {\\n \\\"enter\\\": {\\n \\\"xc\\\": {\\\"signal\\\": \\\"width/2\\\"},\\n \\\"y\\\": {\\\"value\\\": 30},\\n \\\"width\\\": {\\\"value\\\": 100},\\n \\\"height\\\": {\\\"value\\\": 36}\\n }\\n },\\n \\\"marks\\\": [\\n {\\n \\\"type\\\": \\\"group\\\",\\n \\\"name\\\": \\\"groupReset\\\",\\n \\\"from\\\": {\\\"data\\\": \\\"dataForShowAll\\\"},\\n \\\"encode\\\": {\\n \\\"enter\\\": {\\n \\\"cornerRadius\\\": {\\\"value\\\": 3.5},\\n \\\"fill\\\": {\\\"value\\\": \\\"#666666\\\"},\\n \\\"height\\\": {\\\"field\\\": {\\\"group\\\": \\\"height\\\"}},\\n \\\"width\\\": {\\\"field\\\": {\\\"group\\\": \\\"width\\\"}}\\n },\\n \\\"update\\\": {\\\"opacity\\\": {\\\"value\\\": 1}},\\n \\\"hover\\\": {\\\"fill\\\": {\\\"value\\\": \\\"#444444\\\"}}\\n },\\n \\\"marks\\\": [\\n {\\n \\\"type\\\": \\\"text\\\",\\n \\\"interactive\\\": false,\\n \\\"encode\\\": {\\n \\\"enter\\\": {\\n \\\"xc\\\": {\\\"field\\\": {\\\"group\\\": \\\"width\\\"}, \\\"mult\\\": 0.5},\\n \\\"yc\\\": {\\\"field\\\": {\\\"group\\\": \\\"height\\\"}, \\\"mult\\\": 0.5, \\\"offset\\\": 1},\\n \\\"align\\\": {\\\"value\\\": \\\"center\\\"},\\n \\\"baseline\\\": {\\\"value\\\": \\\"middle\\\"},\\n \\\"text\\\": {\\\"value\\\": \\\"Show All\\\"},\\n \\\"fontSize\\\": {\\\"value\\\": 14},\\n \\\"stroke\\\": {\\\"value\\\": \\\"#ecf0f1\\\"}\\n }\\n }\\n }\\n ]\\n }\\n ]\\n }\\n ],\\n \\\"signals\\\": [\\n {\\n \\\"name\\\": \\\"groupHover\\\",\\n \\\"value\\\": {},\\n \\\"on\\\": [\\n {\\n \\\"events\\\": \\\"@groupMark:mouseover\\\",\\n \\\"update\\\": \\\"{stk1:datum.stack=='stk1' && datum.grpId, stk2:datum.stack=='stk2' && datum.grpId}\\\"\\n },\\n {\\\"events\\\": \\\"mouseout\\\", \\\"update\\\": \\\"{}\\\"}\\n ]\\n },\\n {\\n \\\"name\\\": \\\"groupSelector\\\",\\n \\\"value\\\": false,\\n \\\"on\\\": [\\n {\\n \\\"events\\\": \\\"@groupMark:click!\\\",\\n \\\"update\\\": \\\"{stack:datum.stack, stk1:datum.stack=='stk1' && datum.grpId, stk2:datum.stack=='stk2' && datum.grpId}\\\"\\n },\\n {\\n \\\"events\\\": [\\n {\\\"type\\\": \\\"click\\\", \\\"markname\\\": \\\"groupReset\\\"},\\n {\\\"type\\\": \\\"dblclick\\\"}\\n ],\\n \\\"update\\\": \\\"false\\\"\\n }\\n ]\\n }\\n ]\\n}\"},\"title\":\"Pod-to-Service Flow Reverse Cumulative Bytes\"}"},"id":"94b0a1e0-d07b-11ea-a734-57fc7859997d","migrationVersion":{"visualization":"7.8.0"},"references":[],"type":"visualization","updated_at":"2021-08-07T23:30:40.150Z","version":"WzU0LDFd"} -{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"language\":\"kuery\",\"query\":\"\"},\"filter\":[]}"},"title":"Tx Mbps by Pod-to-Service Flow","uiStateJSON":"{}","version":1,"visState":"{\"type\":\"metrics\",\"aggs\":[],\"params\":{\"id\":\"61ca57f0-469d-11e7-af02-69e470af7417\",\"type\":\"timeseries\",\"axis_position\":\"left\",\"axis_formatter\":\"number\",\"show_legend\":1,\"show_grid\":1,\"axis_min\":\"0\",\"filter\":\"\",\"axis_scale\":\"normal\",\"default_index_pattern\":\"flow-*\",\"default_timefield\":\"@timestamp\",\"isModelInvalid\":false,\"index_pattern\":\"flow-*\",\"interval\":\"1m\",\"time_field\":\"ipfix.flowEndSeconds\",\"background_color_rules\":[{\"id\":\"4010d970-50b9-11eb-8f30-87baf4f5ad91\"}],\"series\":[{\"id\":\"61ca57f1-469d-11e7-af02-69e470af7417\",\"color\":\"rgba(144,201,227,1)\",\"split_mode\":\"terms\",\"metrics\":[{\"id\":\"a1ba0060-b9a7-11ea-9740-552c943910e4\",\"type\":\"sum\",\"field\":\"ipfix.throughput\"},{\"script\":\"params.bytes * 8 \",\"id\":\"dd0b81d0-b9a6-11ea-9740-552c943910e4\",\"type\":\"calculation\",\"variables\":[{\"id\":\"e1f87e50-b9a6-11ea-9740-552c943910e4\",\"name\":\"bytes\",\"field\":\"a1ba0060-b9a7-11ea-9740-552c943910e4\"}]}],\"separate_axis\":0,\"axis_position\":\"right\",\"formatter\":\"bytes\",\"chart_type\":\"line\",\"line_width\":1,\"point_size\":\"0\",\"fill\":\"0.6\",\"stacked\":\"none\",\"split_color_mode\":\"rainbow\",\"label\":\"Bytes\",\"terms_field\":\"ipfix.flowKeyPodToService.keyword\",\"terms_size\":\"30\",\"terms_order_by\":\"a1ba0060-b9a7-11ea-9740-552c943910e4\",\"value_template\":\"{{value}}it/s\",\"type\":\"timeseries\",\"terms_exclude\":\"\",\"filter\":{\"query\":\"\",\"language\":\"kuery\"}}]},\"title\":\"Tx Mbps by Pod-to-Service Flow\"}"},"id":"f5f29b00-520a-11eb-8385-698d3cd613b0","migrationVersion":{"visualization":"7.8.0"},"references":[],"type":"visualization","updated_at":"2021-08-07T23:30:40.150Z","version":"WzU1LDFd"} -{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}"},"title":"Cumulative Bandwidth by Pod-to-Service Flow","uiStateJSON":"{}","version":1,"visState":"{\"type\":\"metrics\",\"aggs\":[],\"params\":{\"id\":\"61ca57f0-469d-11e7-af02-69e470af7417\",\"type\":\"timeseries\",\"axis_position\":\"left\",\"axis_formatter\":\"number\",\"show_legend\":1,\"show_grid\":1,\"axis_min\":\"0\",\"filter\":\"\",\"axis_scale\":\"normal\",\"default_index_pattern\":\"flow-*\",\"default_timefield\":\"@timestamp\",\"isModelInvalid\":false,\"index_pattern\":\"flow-*\",\"interval\":\"1m\",\"time_field\":\"ipfix.flowEndSeconds\",\"series\":[{\"id\":\"61ca57f1-469d-11e7-af02-69e470af7417\",\"color\":\"rgba(144,201,227,1)\",\"split_mode\":\"terms\",\"metrics\":[{\"id\":\"a1ba0060-b9a7-11ea-9740-552c943910e4\",\"type\":\"sum\",\"field\":\"ipfix.octetTotalCountFromSourceNode\"},{\"script\":\"params.bytes * 8\",\"id\":\"dd0b81d0-b9a6-11ea-9740-552c943910e4\",\"type\":\"calculation\",\"variables\":[{\"id\":\"e1f87e50-b9a6-11ea-9740-552c943910e4\",\"name\":\"bytes\",\"field\":\"a1ba0060-b9a7-11ea-9740-552c943910e4\"}]}],\"separate_axis\":0,\"axis_position\":\"right\",\"formatter\":\"bytes\",\"chart_type\":\"line\",\"line_width\":1,\"point_size\":\"0\",\"fill\":\"0.6\",\"stacked\":\"none\",\"split_color_mode\":\"rainbow\",\"label\":\"Bytes\",\"terms_field\":\"ipfix.flowKeyPodToService.keyword\",\"terms_size\":\"30\",\"terms_order_by\":\"a1ba0060-b9a7-11ea-9740-552c943910e4\",\"value_template\":\"{{value}}\",\"type\":\"timeseries\"}]},\"title\":\"Cumulative Bandwidth by Pod-to-Service Flow\"}"},"id":"d0582e90-520b-11eb-8385-698d3cd613b0","migrationVersion":{"visualization":"7.8.0"},"references":[],"type":"visualization","updated_at":"2021-08-07T23:30:40.150Z","version":"WzU2LDFd"} -{"attributes":{"description":"","hits":0,"kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"language\":\"kuery\",\"query\":\"\"},\"filter\":[]}"},"optionsJSON":"{\"hidePanelTitles\":false,\"useMargins\":true}","panelsJSON":"[{\"embeddableConfig\":{\"title\":\"\"},\"gridData\":{\"h\":3,\"i\":\"027bb966-548e-4c19-84a3-e9e213b0fb70\",\"w\":48,\"x\":0,\"y\":0},\"panelIndex\":\"027bb966-548e-4c19-84a3-e9e213b0fb70\",\"version\":\"7.8.0\",\"panelRefName\":\"panel_0\"},{\"embeddableConfig\":{\"title\":\"\"},\"gridData\":{\"h\":5,\"i\":\"66329618-2ac9-4223-a33d-26cce2e4b455\",\"w\":48,\"x\":0,\"y\":3},\"panelIndex\":\"66329618-2ac9-4223-a33d-26cce2e4b455\",\"version\":\"7.8.0\",\"panelRefName\":\"panel_1\"},{\"embeddableConfig\":{},\"gridData\":{\"h\":29,\"i\":\"2136520e-2f75-45f6-9b38-2469f1ff005b\",\"w\":24,\"x\":0,\"y\":8},\"panelIndex\":\"2136520e-2f75-45f6-9b38-2469f1ff005b\",\"version\":\"7.8.0\",\"panelRefName\":\"panel_2\"},{\"embeddableConfig\":{},\"gridData\":{\"h\":29,\"i\":\"d3671f1d-7a7c-4bf7-95a1-da749654e893\",\"w\":24,\"x\":24,\"y\":8},\"panelIndex\":\"d3671f1d-7a7c-4bf7-95a1-da749654e893\",\"version\":\"7.8.0\",\"panelRefName\":\"panel_3\"},{\"embeddableConfig\":{},\"gridData\":{\"h\":15,\"i\":\"1de71bb0-8f22-4859-9260-a8fea17c3fef\",\"w\":24,\"x\":0,\"y\":37},\"panelIndex\":\"1de71bb0-8f22-4859-9260-a8fea17c3fef\",\"version\":\"7.8.0\",\"panelRefName\":\"panel_4\"},{\"embeddableConfig\":{},\"gridData\":{\"h\":15,\"i\":\"35a3e0b4-822c-4581-bb6c-5583c4473cd7\",\"w\":24,\"x\":24,\"y\":37},\"panelIndex\":\"35a3e0b4-822c-4581-bb6c-5583c4473cd7\",\"version\":\"7.8.0\",\"panelRefName\":\"panel_5\"},{\"embeddableConfig\":{},\"gridData\":{\"h\":15,\"i\":\"e9949d99-56ba-4b45-8064-4ce12f9644ae\",\"w\":24,\"x\":0,\"y\":52},\"panelIndex\":\"e9949d99-56ba-4b45-8064-4ce12f9644ae\",\"version\":\"7.8.0\",\"panelRefName\":\"panel_6\"},{\"embeddableConfig\":{},\"gridData\":{\"h\":15,\"i\":\"ce1167e7-f40a-4b0c-a534-9cbad66fa81b\",\"w\":24,\"x\":24,\"y\":52},\"panelIndex\":\"ce1167e7-f40a-4b0c-a534-9cbad66fa81b\",\"version\":\"7.8.0\",\"panelRefName\":\"panel_7\"},{\"embeddableConfig\":{},\"gridData\":{\"h\":15,\"i\":\"7b627514-6dbc-4b8f-8313-e12c2e44f5c2\",\"w\":24,\"x\":0,\"y\":67},\"panelIndex\":\"7b627514-6dbc-4b8f-8313-e12c2e44f5c2\",\"version\":\"7.8.0\",\"panelRefName\":\"panel_8\"},{\"embeddableConfig\":{},\"gridData\":{\"h\":15,\"i\":\"58600a3f-8de1-4917-bcc0-818a62467c78\",\"w\":24,\"x\":24,\"y\":67},\"panelIndex\":\"58600a3f-8de1-4917-bcc0-818a62467c78\",\"version\":\"7.8.0\",\"panelRefName\":\"panel_9\"},{\"embeddableConfig\":{\"title\":\"\"},\"gridData\":{\"h\":2,\"i\":\"77988700-8d00-4dc7-8ef3-211d8fc1b6e5\",\"w\":48,\"x\":0,\"y\":82},\"panelIndex\":\"77988700-8d00-4dc7-8ef3-211d8fc1b6e5\",\"version\":\"7.8.0\",\"panelRefName\":\"panel_10\"}]","timeRestore":false,"title":"Pod-to-Service Flow Dashboard","version":1},"id":"6d77e8a0-513a-11eb-a19a-05e08a82dcf8","migrationVersion":{"dashboard":"7.3.0"},"references":[{"id":"c4e1b7c0-b9a9-11ea-b16e-fb06687c3589","name":"panel_0","type":"visualization"},{"id":"804d18c0-514d-11eb-a19a-05e08a82dcf8","name":"panel_1","type":"visualization"},{"id":"67f0ca90-d07b-11ea-a734-57fc7859997d","name":"panel_2","type":"visualization"},{"id":"94b0a1e0-d07b-11ea-a734-57fc7859997d","name":"panel_3","type":"visualization"},{"id":"3ccd6430-d086-11ea-a734-57fc7859997d","name":"panel_4","type":"visualization"},{"id":"2fb72bf0-d086-11ea-a734-57fc7859997d","name":"panel_5","type":"visualization"},{"id":"f5f29b00-520a-11eb-8385-698d3cd613b0","name":"panel_6","type":"visualization"},{"id":"20dfae20-520b-11eb-8385-698d3cd613b0","name":"panel_7","type":"visualization"},{"id":"d0582e90-520b-11eb-8385-698d3cd613b0","name":"panel_8","type":"visualization"},{"id":"19374b20-4eea-11eb-b841-6bf6243fda88","name":"panel_9","type":"visualization"},{"id":"f8323bc0-514f-11eb-a19a-05e08a82dcf8","name":"panel_10","type":"visualization"}],"type":"dashboard","updated_at":"2021-08-07T23:30:40.150Z","version":"WzU3LDFd"} -{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}"},"title":"Tx Mbps by Pod-to-Pod Flow","uiStateJSON":"{}","version":1,"visState":"{\"type\":\"metrics\",\"aggs\":[],\"params\":{\"id\":\"61ca57f0-469d-11e7-af02-69e470af7417\",\"type\":\"timeseries\",\"axis_position\":\"left\",\"axis_formatter\":\"number\",\"show_legend\":1,\"show_grid\":1,\"axis_min\":\"0\",\"filter\":\"\",\"axis_scale\":\"normal\",\"default_index_pattern\":\"flow-*\",\"default_timefield\":\"@timestamp\",\"isModelInvalid\":false,\"index_pattern\":\"flow-*\",\"interval\":\"1m\",\"time_field\":\"ipfix.flowEndSeconds\",\"background_color_rules\":[{\"id\":\"4010d970-50b9-11eb-8f30-87baf4f5ad91\"}],\"series\":[{\"id\":\"61ca57f1-469d-11e7-af02-69e470af7417\",\"color\":\"rgba(144,201,227,1)\",\"split_mode\":\"terms\",\"metrics\":[{\"id\":\"a1ba0060-b9a7-11ea-9740-552c943910e4\",\"type\":\"sum\",\"field\":\"ipfix.throughput\"},{\"script\":\"params.bytes * 8 \",\"id\":\"dd0b81d0-b9a6-11ea-9740-552c943910e4\",\"type\":\"calculation\",\"variables\":[{\"id\":\"e1f87e50-b9a6-11ea-9740-552c943910e4\",\"name\":\"bytes\",\"field\":\"a1ba0060-b9a7-11ea-9740-552c943910e4\"}]}],\"separate_axis\":0,\"axis_position\":\"right\",\"formatter\":\"bytes\",\"chart_type\":\"line\",\"line_width\":\"2\",\"point_size\":\"0\",\"fill\":\"0.6\",\"stacked\":\"none\",\"split_color_mode\":\"rainbow\",\"label\":\"Bytes\",\"terms_field\":\"ipfix.flowKeyPodToPod.keyword\",\"terms_size\":\"30\",\"terms_order_by\":\"a1ba0060-b9a7-11ea-9740-552c943910e4\",\"value_template\":\"{{value}}it/s\",\"type\":\"timeseries\",\"terms_exclude\":\"\",\"filter\":{\"query\":\"\",\"language\":\"kuery\"}}]},\"title\":\"Tx Mbps by Pod-to-Pod Flow\"}"},"id":"8f9b2980-4ee5-11eb-b841-6bf6243fda88","migrationVersion":{"visualization":"7.8.0"},"references":[],"type":"visualization","updated_at":"2021-08-07T23:30:40.150Z","version":"WzU5LDFd"} -{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\",\"filter\":[]}"},"title":"Ingress Network Policy Bytes","uiStateJSON":"{\"vis\":{\"colors\":{\"default\":\"#F2C96D\"}}}","version":1,"visState":"{\"type\":\"pie\",\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"sum\",\"schema\":\"metric\",\"params\":{\"field\":\"ipfix.bytes\"}},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"segment\",\"params\":{\"field\":\"ipfix.ingressNetworkPolicyNamespace.keyword\",\"orderBy\":\"1\",\"order\":\"desc\",\"size\":30,\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\",\"exclude\":\"\",\"customLabel\":\"Namespace\"}},{\"id\":\"3\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"segment\",\"params\":{\"field\":\"ipfix.ingressNetworkPolicyName.keyword\",\"orderBy\":\"1\",\"order\":\"desc\",\"size\":5,\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\",\"customLabel\":\"Network Policy Name\"}}],\"params\":{\"addLegend\":true,\"addTooltip\":true,\"dimensions\":{\"metric\":{\"accessor\":0,\"aggType\":\"count\",\"format\":{\"id\":\"number\"},\"params\":{}}},\"isDonut\":true,\"labels\":{\"last_level\":true,\"show\":false,\"truncate\":100,\"values\":true},\"legendPosition\":\"right\",\"type\":\"pie\"},\"title\":\"Ingress Network Policy Bytes\"}"},"id":"9b4db300-23b7-11eb-90d2-a7a4de48218a","migrationVersion":{"visualization":"7.8.0"},"references":[{"id":"e2ab2c50-b981-11ea-b16e-fb06687c3589","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"}],"type":"visualization","updated_at":"2021-08-07T23:30:40.150Z","version":"WzYwLDFd"} -{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}"},"title":"Aggregated Rx Mbps by Pod Acting as Destination","uiStateJSON":"{}","version":1,"visState":"{\"type\":\"metrics\",\"aggs\":[],\"params\":{\"id\":\"61ca57f0-469d-11e7-af02-69e470af7417\",\"type\":\"timeseries\",\"axis_position\":\"left\",\"axis_formatter\":\"number\",\"show_legend\":1,\"show_grid\":1,\"axis_min\":\"0\",\"filter\":\"\",\"axis_scale\":\"normal\",\"default_index_pattern\":\"flow-*\",\"default_timefield\":\"@timestamp\",\"isModelInvalid\":false,\"index_pattern\":\"flow-*\",\"time_field\":\"@timestamp\",\"interval\":\"1m\",\"series\":[{\"id\":\"61ca57f1-469d-11e7-af02-69e470af7417\",\"color\":\"rgba(144,201,227,1)\",\"split_mode\":\"terms\",\"metrics\":[{\"id\":\"a1ba0060-b9a7-11ea-9740-552c943910e4\",\"type\":\"sum\",\"field\":\"ipfix.octetDeltaCount\"},{\"id\":\"390d2760-50b8-11eb-8f30-87baf4f5ad91\",\"type\":\"avg\",\"field\":\"ipfix.interval\"},{\"script\":\"params.bytes * 8 / params.interval\",\"id\":\"dd0b81d0-b9a6-11ea-9740-552c943910e4\",\"type\":\"calculation\",\"variables\":[{\"id\":\"e1f87e50-b9a6-11ea-9740-552c943910e4\",\"name\":\"bytes\",\"field\":\"a1ba0060-b9a7-11ea-9740-552c943910e4\"},{\"id\":\"3df84f20-50b8-11eb-8f30-87baf4f5ad91\",\"name\":\"interval\",\"field\":\"390d2760-50b8-11eb-8f30-87baf4f5ad91\"}]}],\"separate_axis\":0,\"axis_position\":\"right\",\"formatter\":\"bytes\",\"chart_type\":\"line\",\"line_width\":1,\"point_size\":\"0\",\"fill\":\"0.6\",\"stacked\":\"stacked\",\"split_color_mode\":\"rainbow\",\"label\":\"Bytes\",\"terms_field\":\"ipfix.destinationPodName.keyword\",\"terms_size\":\"30\",\"terms_order_by\":\"a1ba0060-b9a7-11ea-9740-552c943910e4\",\"value_template\":\"{{value}}its/s\",\"type\":\"timeseries\"}]},\"title\":\"Aggregated Rx Mbps by Pod Acting as Destination\"}"},"id":"a1b7b4f0-c243-11ea-873e-8f9a9a3cbdc1","migrationVersion":{"visualization":"7.8.0"},"references":[],"type":"visualization","updated_at":"2021-08-07T23:30:40.150Z","version":"WzYxLDFd"} -{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\",\"filter\":[]}"},"title":"Egress Network Policy Bytes","uiStateJSON":"{\"vis\":{\"colors\":{\"default\":\"#F2C96D\"}}}","version":1,"visState":"{\"type\":\"pie\",\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"sum\",\"schema\":\"metric\",\"params\":{\"field\":\"ipfix.bytes\"}},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"segment\",\"params\":{\"field\":\"ipfix.egressNetworkPolicyNamespace.keyword\",\"orderBy\":\"1\",\"order\":\"desc\",\"size\":30,\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\",\"exclude\":\"\",\"customLabel\":\"Namespace\"}},{\"id\":\"3\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"segment\",\"params\":{\"field\":\"ipfix.egressNetworkPolicyName.keyword\",\"orderBy\":\"1\",\"order\":\"desc\",\"size\":5,\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\",\"customLabel\":\"Network Policy Name\"}}],\"params\":{\"type\":\"pie\",\"addTooltip\":true,\"addLegend\":true,\"legendPosition\":\"right\",\"isDonut\":true,\"labels\":{\"show\":false,\"values\":true,\"last_level\":true,\"truncate\":100},\"dimensions\":{\"metric\":{\"accessor\":0,\"format\":{\"id\":\"number\"},\"params\":{},\"aggType\":\"count\"}}},\"title\":\"Egress Network Policy Bytes\"}"},"id":"bc4e0870-23b7-11eb-90d2-a7a4de48218a","migrationVersion":{"visualization":"7.8.0"},"references":[{"id":"e2ab2c50-b981-11ea-b16e-fb06687c3589","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"}],"type":"visualization","updated_at":"2021-08-07T23:30:40.150Z","version":"WzYyLDFd"} -{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}"},"title":"Pod-to-Pod Filter","uiStateJSON":"{}","version":1,"visState":"{\"type\":\"input_control_vis\",\"aggs\":[],\"params\":{\"updateFiltersOnChange\":true,\"useTimeFilter\":true,\"pinFilters\":true,\"controls\":[{\"id\":\"1526108909005\",\"fieldName\":\"ipfix.sourcePodNamespace.keyword\",\"label\":\"Source Pod Namespace\",\"type\":\"list\",\"options\":{\"type\":\"terms\",\"multiselect\":true,\"size\":1000,\"order\":\"desc\",\"dynamicOptions\":false},\"indexPatternRefName\":\"control_0_index_pattern\"},{\"id\":\"1526107640219\",\"fieldName\":\"ipfix.sourcePodName.keyword\",\"label\":\"Source Pod Name\",\"type\":\"list\",\"options\":{\"type\":\"terms\",\"multiselect\":true,\"size\":1000,\"order\":\"desc\",\"dynamicOptions\":false},\"indexPatternRefName\":\"control_1_index_pattern\"},{\"id\":\"1594408631049\",\"fieldName\":\"ipfix.sourceNodeName.keyword\",\"parent\":\"\",\"label\":\"Source Pod Node\",\"type\":\"list\",\"options\":{\"type\":\"terms\",\"multiselect\":true,\"dynamicOptions\":false,\"size\":1000,\"order\":\"desc\"},\"indexPatternRefName\":\"control_2_index_pattern\"},{\"id\":\"1592936602245\",\"fieldName\":\"ipfix.destinationPodNamespace.keyword\",\"parent\":\"\",\"label\":\"Destination Pod Namespace\",\"type\":\"list\",\"options\":{\"type\":\"terms\",\"multiselect\":true,\"dynamicOptions\":false,\"size\":1000,\"order\":\"desc\"},\"indexPatternRefName\":\"control_3_index_pattern\"},{\"id\":\"1526108883717\",\"fieldName\":\"ipfix.destinationPodName.keyword\",\"label\":\"Destination Pod Name\",\"type\":\"list\",\"options\":{\"type\":\"terms\",\"multiselect\":true,\"size\":1000,\"order\":\"desc\",\"dynamicOptions\":false},\"indexPatternRefName\":\"control_4_index_pattern\"},{\"id\":\"1594408650442\",\"fieldName\":\"ipfix.destinationNodeName.keyword\",\"parent\":\"\",\"label\":\"Destination Pod Node\",\"type\":\"list\",\"options\":{\"type\":\"terms\",\"multiselect\":true,\"dynamicOptions\":false,\"size\":1000,\"order\":\"desc\"},\"indexPatternRefName\":\"control_5_index_pattern\"},{\"id\":\"1609999080958\",\"parent\":\"\",\"type\":\"list\",\"options\":{\"type\":\"terms\",\"multiselect\":true,\"dynamicOptions\":false,\"size\":1000,\"order\":\"desc\"},\"fieldName\":\"ipfix.flowKeyPodToPod.keyword\",\"label\":\"Flow Key (Pod-to-Pod)\",\"indexPatternRefName\":\"control_6_index_pattern\"},{\"id\":\"1618607160649\",\"fieldName\":\"ipfix.flowTypeStr.keyword\",\"parent\":\"\",\"label\":\"Flow Type\",\"type\":\"list\",\"options\":{\"type\":\"terms\",\"multiselect\":true,\"dynamicOptions\":false,\"size\":1000,\"order\":\"desc\"},\"indexPatternRefName\":\"control_7_index_pattern\"}]},\"title\":\"Pod-to-Pod Filter\"}"},"id":"bcb98010-514c-11eb-a19a-05e08a82dcf8","migrationVersion":{"visualization":"7.8.0"},"references":[{"id":"e2ab2c50-b981-11ea-b16e-fb06687c3589","name":"control_0_index_pattern","type":"index-pattern"},{"id":"e2ab2c50-b981-11ea-b16e-fb06687c3589","name":"control_1_index_pattern","type":"index-pattern"},{"id":"e2ab2c50-b981-11ea-b16e-fb06687c3589","name":"control_2_index_pattern","type":"index-pattern"},{"id":"e2ab2c50-b981-11ea-b16e-fb06687c3589","name":"control_3_index_pattern","type":"index-pattern"},{"id":"e2ab2c50-b981-11ea-b16e-fb06687c3589","name":"control_4_index_pattern","type":"index-pattern"},{"id":"e2ab2c50-b981-11ea-b16e-fb06687c3589","name":"control_5_index_pattern","type":"index-pattern"},{"id":"e2ab2c50-b981-11ea-b16e-fb06687c3589","name":"control_6_index_pattern","type":"index-pattern"},{"id":"e2ab2c50-b981-11ea-b16e-fb06687c3589","name":"control_7_index_pattern","type":"index-pattern"}],"type":"visualization","updated_at":"2021-08-07T23:30:40.150Z","version":"WzYzLDFd"} -{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"language\":\"lucene\",\"query\":\"\"},\"filter\":[]}"},"title":"Network Policy Flow Throughput Diagram","uiStateJSON":"{}","version":1,"visState":"{\"type\":\"vega\",\"aggs\":[],\"params\":{\"spec\":\"{\\n \\\"$schema\\\": \\\"https://vega.github.io/schema/vega/v3.0.json\\\",\\n \\\"data\\\": [\\n {\\n \\\"name\\\": \\\"rawData\\\",\\n \\\"url\\\": {\\n \\\"%context%\\\": true,\\n \\\"%timefield%\\\": \\\"@timestamp\\\",\\n \\\"index\\\": \\\"flow-*\\\",\\n \\\"body\\\": {\\n \\\"size\\\": 0,\\n \\\"aggs\\\": {\\n \\\"table\\\": {\\n \\\"composite\\\": {\\n \\\"size\\\": 1000,\\n \\\"sources\\\": [\\n {\\\"stk1\\\": {\\\"terms\\\": {\\\"field\\\": \\\"ipfix.egressNetworkPolicyName.keyword\\\"}}},\\n {\\\"stk1ns\\\": {\\\"terms\\\": {\\\"field\\\": \\\"ipfix.egressNetworkPolicyNamespace.keyword\\\"}}},\\n {\\\"stk2\\\": {\\\"terms\\\": {\\\"field\\\": \\\"ipfix.ingressNetworkPolicyName.keyword\\\"}}},\\n {\\\"stk2ns\\\": {\\\"terms\\\": {\\\"field\\\": \\\"ipfix.ingressNetworkPolicyNamespace.keyword\\\"}}},\\n {\\\"stk3\\\": {\\\"terms\\\": {\\\"field\\\": \\\"ipfix.sourceIP.keyword\\\"}}},\\n {\\\"stk4\\\": {\\\"terms\\\": {\\\"field\\\": \\\"ipfix.destinationIP.keyword\\\"}}},\\n {\\\"stk5\\\": {\\\"terms\\\": {\\\"field\\\": \\\"ipfix.sourcePodName.keyword\\\"}}},\\n {\\\"stk5ns\\\": {\\\"terms\\\": {\\\"field\\\": \\\"ipfix.sourcePodNamespace.keyword\\\"}}},\\n {\\\"stk6\\\": {\\\"terms\\\": {\\\"field\\\": \\\"ipfix.destinationPodName.keyword\\\"}}},\\n {\\\"stk6ns\\\": {\\\"terms\\\": {\\\"field\\\": \\\"ipfix.destinationPodNamespace.keyword\\\"}}},\\n ]\\n },\\n \\t\\t\\t\\\"aggs\\\": {\\n \\t\\t\\t\\t\\\"bytes\\\": {\\n \\t\\t\\t\\t\\t\\\"sum\\\": {\\n \\t\\t\\t\\t\\t\\t\\\"field\\\": \\\"ipfix.octetDeltaCountFromSourceNode\\\"\\n \\t\\t\\t\\t\\t}\\n \\t\\t\\t\\t}\\n \\t\\t\\t}\\n }\\n }\\n }\\n },\\n \\\"format\\\": {\\\"property\\\": \\\"aggregations.table.buckets\\\"},\\n \\\"transform\\\": [\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"datum.key.stk1ns +'/'+ datum.key.stk1\\\", \\\"as\\\": \\\"stk1\\\"},\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"datum.key.stk2ns +'/'+ datum.key.stk2\\\", \\\"as\\\": \\\"stk2\\\"},\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"datum.key.stk3\\\", \\\"as\\\": \\\"stk3\\\"},\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"datum.key.stk4\\\", \\\"as\\\": \\\"stk4\\\"},\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"datum.key.stk5ns +'/'+ datum.key.stk5\\\", \\\"as\\\": \\\"stk5s\\\"},\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"(datum.key.stk5==''?datum.key.stk3:datum.stk5s)\\\", \\\"as\\\": \\\"stk5\\\"},\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"datum.key.stk6ns +'/'+ datum.key.stk6\\\", \\\"as\\\": \\\"stk6s\\\"},\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"(datum.key.stk6==''?datum.key.stk4:datum.stk6s)\\\", \\\"as\\\": \\\"stk6\\\"},\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"datum.bytes.value\\\", \\\"as\\\": \\\"size\\\"}\\n ]\\n },\\n {\\n \\\"name\\\": \\\"nodes\\\",\\n \\\"source\\\": \\\"rawData\\\",\\n \\\"transform\\\": [\\n {\\n \\\"type\\\": \\\"filter\\\",\\n \\\"expr\\\": \\\"!groupSelector || groupSelector.stk1 == datum.stk1 || groupSelector.stk2 == datum.stk2\\\"\\n },\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"datum.stk1+datum.stk2+datum.stk5+datum.stk6\\\", \\\"as\\\": \\\"key\\\"},\\n {\\\"type\\\": \\\"fold\\\", \\\"fields\\\": [\\\"stk1\\\", \\\"stk2\\\"], \\\"as\\\": [\\\"stack\\\", \\\"grpId\\\"]},\\n {\\n \\\"type\\\": \\\"formula\\\",\\n \\\"expr\\\": \\\"datum.stack == 'stk1' ? datum.stk1+datum.stk2 : datum.stk2+datum.stk1\\\",\\n \\\"as\\\": \\\"sortField\\\"\\n },\\n {\\n \\\"type\\\": \\\"stack\\\",\\n \\\"groupby\\\": [\\\"stack\\\"],\\n \\\"sort\\\": {\\\"field\\\": \\\"sortField\\\", \\\"order\\\": \\\"ascending\\\"},\\n \\\"field\\\": \\\"size\\\"\\n },\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"(datum.y0+datum.y1)/2\\\", \\\"as\\\": \\\"yc\\\"}\\n ]\\n },\\n {\\n \\\"name\\\": \\\"groups\\\",\\n \\\"source\\\": \\\"nodes\\\",\\n \\\"transform\\\": [\\n {\\n \\\"type\\\": \\\"aggregate\\\",\\n \\\"groupby\\\": [\\\"stack\\\", \\\"grpId\\\"],\\n \\\"fields\\\": [\\\"size\\\"],\\n \\\"ops\\\": [\\\"sum\\\"],\\n \\\"as\\\": [\\\"total\\\"]\\n },\\n {\\n \\\"type\\\": \\\"stack\\\",\\n \\\"groupby\\\": [\\\"stack\\\"],\\n \\\"sort\\\": {\\\"field\\\": \\\"grpId\\\", \\\"order\\\": \\\"ascending\\\"},\\n \\\"field\\\": \\\"total\\\"\\n },\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"scale('y', datum.y0)\\\", \\\"as\\\": \\\"scaledY0\\\"},\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"scale('y', datum.y1)\\\", \\\"as\\\": \\\"scaledY1\\\"},\\n {\\\"type\\\": \\\"formula\\\", \\\"expr\\\": \\\"datum.stack == 'stk1'\\\", \\\"as\\\": \\\"rightLabel\\\"},\\n {\\n \\\"type\\\": \\\"formula\\\",\\n \\\"expr\\\": \\\"datum.total/domain('y')[1]\\\",\\n \\\"as\\\": \\\"percentage\\\"\\n }\\n ]\\n },\\n {\\n \\\"name\\\": \\\"destinationNodes\\\",\\n \\\"source\\\": \\\"nodes\\\",\\n \\\"transform\\\": [{\\\"type\\\": \\\"filter\\\", \\\"expr\\\": \\\"datum.stack == 'stk2'\\\"}]\\n },\\n {\\n \\\"name\\\": \\\"edges\\\",\\n \\\"source\\\": \\\"nodes\\\",\\n \\\"transform\\\": [\\n {\\\"type\\\": \\\"filter\\\", \\\"expr\\\": \\\"datum.stack == 'stk1'\\\"},\\n {\\n \\\"type\\\": \\\"lookup\\\",\\n \\\"from\\\": \\\"destinationNodes\\\",\\n \\\"key\\\": \\\"key\\\",\\n \\\"fields\\\": [\\\"key\\\"],\\n \\\"as\\\": [\\\"target\\\"]\\n },\\n {\\n \\\"type\\\": \\\"linkpath\\\",\\n \\\"orient\\\": \\\"horizontal\\\",\\n \\\"shape\\\": \\\"diagonal\\\",\\n \\\"sourceY\\\": {\\\"expr\\\": \\\"scale('y', datum.yc)\\\"},\\n \\\"sourceX\\\": {\\\"expr\\\": \\\"scale('x', 'stk1') + bandwidth('x')\\\"},\\n \\\"targetY\\\": {\\\"expr\\\": \\\"scale('y', datum.target.yc)\\\"},\\n \\\"targetX\\\": {\\\"expr\\\": \\\"scale('x', 'stk2')\\\"}\\n },\\n {\\n \\\"type\\\": \\\"formula\\\",\\n \\\"expr\\\": \\\"range('y')[0]-scale('y', datum.size)\\\",\\n \\\"as\\\": \\\"strokeWidth\\\"\\n },\\n {\\n \\\"type\\\": \\\"formula\\\",\\n \\\"expr\\\": \\\"datum.size/domain('y')[1]\\\",\\n \\\"as\\\": \\\"percentage\\\"\\n }\\n ]\\n }\\n ],\\n \\\"scales\\\": [\\n {\\n \\\"name\\\": \\\"x\\\",\\n \\\"type\\\": \\\"band\\\",\\n \\\"range\\\": \\\"width\\\",\\n \\\"domain\\\": [\\\"stk1\\\", \\\"stk2\\\"],\\n \\\"paddingOuter\\\": 0.01,\\n \\\"paddingInner\\\": 0.98\\n },\\n {\\n \\\"name\\\": \\\"y\\\",\\n \\\"type\\\": \\\"linear\\\",\\n \\\"range\\\": \\\"height\\\",\\n \\\"domain\\\": {\\\"data\\\": \\\"nodes\\\", \\\"field\\\": \\\"y1\\\"}\\n },\\n {\\n \\\"name\\\": \\\"color\\\",\\n \\\"type\\\": \\\"ordinal\\\",\\n \\\"range\\\": \\\"category\\\",\\n \\\"domain\\\": {\\\"data\\\": \\\"rawData\\\", \\\"fields\\\": [\\\"stk1\\\",\\\"stk2\\\"]}\\n },\\n {\\n \\\"name\\\": \\\"stackNames\\\",\\n \\\"type\\\": \\\"ordinal\\\",\\n \\\"range\\\": [\\\"Egress Network Policy\\\", \\\"Ingress Network Policy\\\"],\\n \\\"domain\\\": [\\\"stk1\\\", \\\"stk2\\\"]\\n }\\n ],\\n \\\"axes\\\": [\\n {\\n \\\"orient\\\": \\\"bottom\\\",\\n \\\"scale\\\": \\\"x\\\",\\n \\\"labelColor\\\": {\\n \\\"value\\\": \\\"#888888\\\"\\n },\\n \\\"encode\\\": {\\n \\\"labels\\\": {\\n \\\"update\\\": {\\n \\\"text\\\": {\\\"scale\\\": \\\"stackNames\\\", \\\"field\\\": \\\"value\\\"},\\n \\\"fontSize\\\": {\\\"value\\\": 14}\\n }\\n }\\n }\\n },\\n {\\n \\\"orient\\\": \\\"left\\\",\\n \\\"scale\\\": \\\"y\\\",\\n \\\"labelColor\\\": {\\n \\\"value\\\": \\\"#888888\\\"\\n },\\n \\\"encode\\\": {\\n \\\"labels\\\": {\\n \\\"update\\\": {\\n \\\"text\\\": {\\\"signal\\\": \\\"format(datum.value, '.2s') + 'B'\\\"},\\n \\\"fontSize\\\": {\\\"value\\\": 12}\\n }\\n }\\n }\\n }\\n ],\\n \\\"marks\\\": [\\n {\\n \\\"type\\\": \\\"path\\\",\\n \\\"name\\\": \\\"edgeMark\\\",\\n \\\"from\\\": {\\\"data\\\": \\\"edges\\\"},\\n \\\"clip\\\": true,\\n \\\"encode\\\": {\\n \\\"update\\\": {\\n \\\"stroke\\\": [\\n {\\n \\\"test\\\": \\\"groupSelector && groupSelector.stack=='stk1'\\\",\\n \\\"scale\\\": \\\"color\\\",\\n \\\"field\\\": \\\"stk2\\\"\\n },\\n {\\\"scale\\\": \\\"color\\\", \\\"field\\\": \\\"stk1\\\"}\\n ],\\n \\\"strokeWidth\\\": {\\\"field\\\": \\\"strokeWidth\\\"},\\n \\\"path\\\": {\\\"field\\\": \\\"path\\\"},\\n \\\"strokeOpacity\\\": {\\n \\\"signal\\\": \\\"!groupSelector && (groupHover.stk1 == datum.stk1 || groupHover.stk2 == datum.stk2) ? 0.75 : 0.3\\\"\\n },\\n \\\"zindex\\\": {\\n \\\"signal\\\": \\\"!groupSelector && (groupHover.stk1 == datum.stk1 || groupHover.stk2 == datum.stk2) ? 1 : 0\\\"\\n },\\n \\\"tooltip\\\": {\\n \\\"signal\\\": \\\"{'title': datum.stk5 + ' → ' + datum.stk6 + ' ' + format(datum.size, '.2s') + 'B (' + format(datum.percentage, '.1%') + ')', 'Egress Policy': datum.stk1, 'Ingress Policy': datum.stk2, 'IP Address': datum.stk3 +' → ' + datum.stk4 }\\\"\\n }\\n },\\n \\\"hover\\\": {\\\"strokeOpacity\\\": {\\\"value\\\": 0.75}}\\n }\\n },\\n {\\n \\\"type\\\": \\\"rect\\\",\\n \\\"name\\\": \\\"groupMark\\\",\\n \\\"from\\\": {\\\"data\\\": \\\"groups\\\"},\\n \\\"encode\\\": {\\n \\\"enter\\\": {\\n \\\"fill\\\": {\\\"scale\\\": \\\"color\\\", \\\"field\\\": \\\"grpId\\\"},\\n \\\"width\\\": {\\\"scale\\\": \\\"x\\\", \\\"band\\\": 1}\\n },\\n \\\"update\\\": {\\n \\\"x\\\": {\\\"scale\\\": \\\"x\\\", \\\"field\\\": \\\"stack\\\"},\\n \\\"y\\\": {\\\"field\\\": \\\"scaledY0\\\"},\\n \\\"y2\\\": {\\\"field\\\": \\\"scaledY1\\\"},\\n \\\"fillOpacity\\\": {\\\"value\\\": 0.7},\\n \\\"tooltip\\\": {\\n \\\"signal\\\": \\\"datum.grpId + ' ' + format(datum.total, '.2s') + 'B (' + format(datum.percentage, '.1%') + ')'\\\"\\n }\\n },\\n \\\"hover\\\": {\\\"fillOpacity\\\": {\\\"value\\\": 1}}\\n }\\n },\\n {\\n \\\"type\\\": \\\"text\\\",\\n \\\"from\\\": {\\\"data\\\": \\\"groups\\\"},\\n \\\"interactive\\\": false,\\n \\\"encode\\\": {\\n \\\"update\\\": {\\n \\\"x\\\": {\\n \\\"signal\\\": \\\"scale('x', datum.stack) + (datum.rightLabel ? bandwidth('x') + 8 : -8)\\\"\\n },\\n \\\"yc\\\": {\\\"signal\\\": \\\"(datum.scaledY0 + datum.scaledY1)/2\\\"},\\n \\\"align\\\": {\\\"signal\\\": \\\"datum.rightLabel ? 'left' : 'right'\\\"},\\n \\\"baseline\\\": {\\\"value\\\": \\\"middle\\\"},\\n \\\"fontWeight\\\": {\\\"value\\\": \\\"bold\\\"},\\n \\\"fontSize\\\": {\\\"value\\\": 12},\\n \\\"text\\\": {\\n \\\"signal\\\": \\\"abs(datum.scaledY0-datum.scaledY1) > 10 ? datum.grpId : ''\\\"\\n }\\n }\\n }\\n },\\n {\\n \\\"type\\\": \\\"group\\\",\\n \\\"data\\\": [\\n {\\n \\\"name\\\": \\\"dataForShowAll\\\",\\n \\\"values\\\": [{}],\\n \\\"transform\\\": [{\\\"type\\\": \\\"filter\\\", \\\"expr\\\": \\\"groupSelector\\\"}]\\n }\\n ],\\n \\\"encode\\\": {\\n \\\"enter\\\": {\\n \\\"xc\\\": {\\\"signal\\\": \\\"width/2\\\"},\\n \\\"y\\\": {\\\"value\\\": 30},\\n \\\"width\\\": {\\\"value\\\": 100},\\n \\\"height\\\": {\\\"value\\\": 36}\\n }\\n },\\n \\\"marks\\\": [\\n {\\n \\\"type\\\": \\\"group\\\",\\n \\\"name\\\": \\\"groupReset\\\",\\n \\\"from\\\": {\\\"data\\\": \\\"dataForShowAll\\\"},\\n \\\"encode\\\": {\\n \\\"enter\\\": {\\n \\\"cornerRadius\\\": {\\\"value\\\": 3.5},\\n \\\"fill\\\": {\\\"value\\\": \\\"#666666\\\"},\\n \\\"height\\\": {\\\"field\\\": {\\\"group\\\": \\\"height\\\"}},\\n \\\"width\\\": {\\\"field\\\": {\\\"group\\\": \\\"width\\\"}}\\n },\\n \\\"update\\\": {\\\"opacity\\\": {\\\"value\\\": 1}},\\n \\\"hover\\\": {\\\"fill\\\": {\\\"value\\\": \\\"#444444\\\"}}\\n },\\n \\\"marks\\\": [\\n {\\n \\\"type\\\": \\\"text\\\",\\n \\\"interactive\\\": false,\\n \\\"encode\\\": {\\n \\\"enter\\\": {\\n \\\"xc\\\": {\\\"field\\\": {\\\"group\\\": \\\"width\\\"}, \\\"mult\\\": 0.5},\\n \\\"yc\\\": {\\\"field\\\": {\\\"group\\\": \\\"height\\\"}, \\\"mult\\\": 0.5, \\\"offset\\\": 1},\\n \\\"align\\\": {\\\"value\\\": \\\"center\\\"},\\n \\\"baseline\\\": {\\\"value\\\": \\\"middle\\\"},\\n \\\"text\\\": {\\\"value\\\": \\\"Show All\\\"},\\n \\\"fontSize\\\": {\\\"value\\\": 14},\\n \\\"stroke\\\": {\\\"value\\\": \\\"#ecf0f1\\\"}\\n }\\n }\\n }\\n ]\\n }\\n ]\\n }\\n ],\\n \\\"signals\\\": [\\n {\\n \\\"name\\\": \\\"groupHover\\\",\\n \\\"value\\\": {},\\n \\\"on\\\": [\\n {\\n \\\"events\\\": \\\"@groupMark:mouseover\\\",\\n \\\"update\\\": \\\"{stk1:datum.stack=='stk1' && datum.grpId, stk2:datum.stack=='stk2' && datum.grpId}\\\"\\n },\\n {\\\"events\\\": \\\"mouseout\\\", \\\"update\\\": \\\"{}\\\"}\\n ]\\n },\\n {\\n \\\"name\\\": \\\"groupSelector\\\",\\n \\\"value\\\": false,\\n \\\"on\\\": [\\n {\\n \\\"events\\\": \\\"@groupMark:click!\\\",\\n \\\"update\\\": \\\"{stack:datum.stack, stk1:datum.stack=='stk1' && datum.grpId, stk2:datum.stack=='stk2' && datum.grpId}\\\"\\n },\\n {\\n \\\"events\\\": [\\n {\\\"type\\\": \\\"click\\\", \\\"markname\\\": \\\"groupReset\\\"},\\n {\\\"type\\\": \\\"dblclick\\\"}\\n ],\\n \\\"update\\\": \\\"false\\\"\\n }\\n ]\\n }\\n ]\\n}\"},\"title\":\"Network Policy Flow Throughput Diagram\"}"},"id":"c08ea960-7a1c-11eb-a325-39e98502337e","migrationVersion":{"visualization":"7.8.0"},"references":[],"type":"visualization","updated_at":"2021-08-07T23:30:40.150Z","version":"WzY0LDFd"} -{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"language\":\"lucene\",\"query\":\"\"},\"filter\":[]}"},"title":"Pod-to-Pod Flow Nav","uiStateJSON":"{}","version":1,"visState":"{\"type\":\"metrics\",\"aggs\":[],\"params\":{\"axis_formatter\":\"number\",\"axis_position\":\"left\",\"axis_scale\":\"normal\",\"default_index_pattern\":\"flow-*\",\"default_timefield\":\"@timestamp\",\"id\":\"61ca57f0-469d-11e7-af02-69e470af7417\",\"index_pattern\":\"flow-*\",\"interval\":\"auto\",\"isModelInvalid\":false,\"markdown_css\":\"#markdown-61ca57f0-469d-11e7-af02-69e470af7417 p{color:#cccccc;margin-top:0;margin-bottom:8px;text-align:right}#markdown-61ca57f0-469d-11e7-af02-69e470af7417 p a{color:#1eadbd;font-size:17px;font-weight:bold;text-decoration:none}#markdown-61ca57f0-469d-11e7-af02-69e470af7417 p a strong{color:#ffac12;font-weight:bold}#markdown-61ca57f0-469d-11e7-af02-69e470af7417 hr{background-color:#cccccc;margin:0;height:1px}\",\"markdown_less\":\"p {\\n color: #cccccc;\\n margin-top: 0px;\\n margin-bottom: 8px;\\n text-align: right;\\n}\\np a {\\n color: #1eadbd;\\n\\tfont-size: 17px;\\n\\tfont-weight: bold;\\n\\ttext-decoration: none;\\n}\\np a strong {\\n color: #ffac12;\\n\\tfont-weight: bold;\\n}\\nhr {\\n background-color: #cccccc;\\n margin: 0px;\\n height: 1px;\\n}\",\"markdown_vertical_align\":\"top\",\"series\":[{\"axis_position\":\"right\",\"chart_type\":\"line\",\"color\":\"#68BC00\",\"fill\":0.5,\"formatter\":\"number\",\"id\":\"61ca57f1-469d-11e7-af02-69e470af7417\",\"line_width\":1,\"metrics\":[{\"id\":\"61ca57f2-469d-11e7-af02-69e470af7417\",\"type\":\"count\"}],\"offset_time\":\"-5y\",\"point_size\":1,\"separate_axis\":0,\"split_color_mode\":\"gradient\",\"split_mode\":\"everything\",\"stacked\":\"none\"}],\"show_grid\":1,\"show_legend\":1,\"time_field\":null,\"type\":\"markdown\",\"markdown\":\"[Overview](#/dashboard/3b331b30-b987-11ea-b16e-fb06687c3589) | [**Pod-to-Pod Flow**](#/dashboard/c2b15fb0-b9a8-11ea-b16e-fb06687c3589) | [Pod-to-External Flow](#/dashboard/3ed71e80-a92d-11eb-a7ef-5dcb53008c10) | [Pod-to-Service Flow](#/dashboard/6d77e8a0-513a-11eb-a19a-05e08a82dcf8) | [Node](#/dashboard/5400cdf0-cd2e-11ea-8911-87da3aad0324) | [Network Policy](#/dashboard/c5af6850-23b2-11eb-90d2-a7a4de48218a) | [Flow Records](#/dashboard/2ab9c220-b984-11ea-b16e-fb06687c3589)\"},\"title\":\"Pod-to-Pod Flow Nav\"}"},"id":"d5de6870-5148-11eb-a19a-05e08a82dcf8","migrationVersion":{"visualization":"7.8.0"},"references":[],"type":"visualization","updated_at":"2021-08-07T23:30:40.150Z","version":"WzY1LDFd"} -{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}"},"title":"Rx Mbps by Pod-to-Pod Flow","uiStateJSON":"{}","version":1,"visState":"{\"type\":\"metrics\",\"aggs\":[],\"params\":{\"id\":\"61ca57f0-469d-11e7-af02-69e470af7417\",\"type\":\"timeseries\",\"axis_position\":\"left\",\"axis_formatter\":\"number\",\"show_legend\":1,\"show_grid\":1,\"axis_min\":\"0\",\"filter\":\"\",\"axis_scale\":\"normal\",\"default_index_pattern\":\"flow-*\",\"default_timefield\":\"@timestamp\",\"isModelInvalid\":false,\"index_pattern\":\"flow-*\",\"interval\":\"1m\",\"time_field\":\"ipfix.flowEndSeconds\",\"legend_position\":\"right\",\"series\":[{\"id\":\"61ca57f1-469d-11e7-af02-69e470af7417\",\"color\":\"rgba(144,201,227,1)\",\"split_mode\":\"terms\",\"metrics\":[{\"id\":\"a1ba0060-b9a7-11ea-9740-552c943910e4\",\"type\":\"sum\",\"field\":\"ipfix.reverseThroughput\"},{\"script\":\"params.bytes * 8 \",\"id\":\"dd0b81d0-b9a6-11ea-9740-552c943910e4\",\"type\":\"calculation\",\"variables\":[{\"id\":\"e1f87e50-b9a6-11ea-9740-552c943910e4\",\"name\":\"bytes\",\"field\":\"a1ba0060-b9a7-11ea-9740-552c943910e4\"}]}],\"separate_axis\":0,\"axis_position\":\"right\",\"formatter\":\"bytes\",\"chart_type\":\"line\",\"line_width\":\"2\",\"point_size\":\"0\",\"fill\":\"0.6\",\"stacked\":\"none\",\"split_color_mode\":\"rainbow\",\"label\":\"Bytes\",\"terms_field\":\"ipfix.flowKeyPodToPod.keyword\",\"terms_size\":\"30\",\"terms_order_by\":\"a1ba0060-b9a7-11ea-9740-552c943910e4\",\"value_template\":\"{{value}}it/s\",\"type\":\"timeseries\",\"terms_exclude\":\"\"}]},\"title\":\"Rx Mbps by Pod-to-Pod Flow\"}"},"id":"c35f47c0-4ee9-11eb-b841-6bf6243fda88","migrationVersion":{"visualization":"7.8.0"},"references":[],"type":"visualization","updated_at":"2021-08-07T23:30:40.150Z","version":"WzY2LDFd"} -{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}"},"title":"Reverse Cumulative Bandwidth by Pod-to-Pod Flow","uiStateJSON":"{}","version":1,"visState":"{\"type\":\"metrics\",\"aggs\":[],\"params\":{\"id\":\"61ca57f0-469d-11e7-af02-69e470af7417\",\"type\":\"timeseries\",\"axis_position\":\"left\",\"axis_formatter\":\"number\",\"show_legend\":1,\"show_grid\":1,\"axis_min\":\"0\",\"filter\":\"\",\"axis_scale\":\"normal\",\"default_index_pattern\":\"flow-*\",\"default_timefield\":\"@timestamp\",\"isModelInvalid\":false,\"index_pattern\":\"flow-*\",\"interval\":\"1m\",\"time_field\":\"ipfix.flowEndSeconds\",\"series\":[{\"id\":\"61ca57f1-469d-11e7-af02-69e470af7417\",\"color\":\"rgba(144,201,227,1)\",\"split_mode\":\"terms\",\"metrics\":[{\"id\":\"a1ba0060-b9a7-11ea-9740-552c943910e4\",\"type\":\"sum\",\"field\":\"ipfix.reverseOctetTotalCountFromSourceNode\"},{\"script\":\"params.bytes * 8\",\"id\":\"dd0b81d0-b9a6-11ea-9740-552c943910e4\",\"type\":\"calculation\",\"variables\":[{\"id\":\"e1f87e50-b9a6-11ea-9740-552c943910e4\",\"name\":\"bytes\",\"field\":\"a1ba0060-b9a7-11ea-9740-552c943910e4\"}]}],\"separate_axis\":0,\"axis_position\":\"right\",\"formatter\":\"bytes\",\"chart_type\":\"line\",\"line_width\":\"2\",\"point_size\":\"0\",\"fill\":\"0.6\",\"stacked\":\"none\",\"split_color_mode\":\"rainbow\",\"label\":\"Bytes\",\"terms_field\":\"ipfix.flowKeyPodToPod.keyword\",\"terms_size\":\"30\",\"terms_order_by\":\"a1ba0060-b9a7-11ea-9740-552c943910e4\",\"value_template\":\"{{value}}\",\"type\":\"timeseries\"}]},\"title\":\"Reverse Cumulative Bandwidth by Pod-to-Pod Flow\"}"},"id":"df090970-4ee9-11eb-b841-6bf6243fda88","migrationVersion":{"visualization":"7.8.0"},"references":[],"type":"visualization","updated_at":"2021-08-07T23:30:40.150Z","version":"WzY3LDFd"} -{"attributes":{"description":"","hits":0,"kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"language\":\"kuery\",\"query\":\"\"},\"filter\":[]}"},"optionsJSON":"{\"hidePanelTitles\":false,\"useMargins\":true}","panelsJSON":"[{\"embeddableConfig\":{\"title\":\"\"},\"gridData\":{\"h\":3,\"i\":\"741ac64c-ca0c-4aba-abdd-f493e7f04820\",\"w\":48,\"x\":0,\"y\":0},\"panelIndex\":\"741ac64c-ca0c-4aba-abdd-f493e7f04820\",\"version\":\"7.8.0\",\"panelRefName\":\"panel_0\"},{\"embeddableConfig\":{\"title\":\"\"},\"gridData\":{\"h\":8,\"i\":\"a878455a-38c2-40ec-b2e8-735cb5d282af\",\"w\":48,\"x\":0,\"y\":3},\"panelIndex\":\"a878455a-38c2-40ec-b2e8-735cb5d282af\",\"version\":\"7.8.0\",\"panelRefName\":\"panel_1\"},{\"embeddableConfig\":{\"title\":\"Pod-to-Pod Traffic Cumulative Bytes\"},\"gridData\":{\"h\":27,\"i\":\"6748bbbb-660f-4598-85fa-bed3130fa167\",\"w\":24,\"x\":0,\"y\":11},\"panelIndex\":\"6748bbbb-660f-4598-85fa-bed3130fa167\",\"title\":\"Pod-to-Pod Traffic Cumulative Bytes\",\"version\":\"7.8.0\",\"panelRefName\":\"panel_2\"},{\"embeddableConfig\":{\"title\":\"Pod-to-Pod Traffic Reverse Cumulative Bytes\"},\"gridData\":{\"h\":27,\"i\":\"62ae0c67-a496-464f-b131-2356316dd07d\",\"w\":24,\"x\":24,\"y\":11},\"panelIndex\":\"62ae0c67-a496-464f-b131-2356316dd07d\",\"title\":\"Pod-to-Pod Traffic Reverse Cumulative Bytes\",\"version\":\"7.8.0\",\"panelRefName\":\"panel_3\"},{\"embeddableConfig\":{\"title\":\"Tx Mbps by Pod-to-Pod Flow\"},\"gridData\":{\"h\":15,\"i\":\"f3d0a648-08c2-4b6a-bac3-502e57aa6491\",\"w\":24,\"x\":0,\"y\":38},\"panelIndex\":\"f3d0a648-08c2-4b6a-bac3-502e57aa6491\",\"title\":\"Tx Mbps by Pod-to-Pod Flow\",\"version\":\"7.8.0\",\"panelRefName\":\"panel_4\"},{\"embeddableConfig\":{\"title\":\"Cumulative Bandwidth by Pod-to-Pod Flow\"},\"gridData\":{\"h\":15,\"i\":\"e00e255f-6ca9-491b-91e9-88bb9743f9d2\",\"w\":24,\"x\":24,\"y\":38},\"panelIndex\":\"e00e255f-6ca9-491b-91e9-88bb9743f9d2\",\"title\":\"Cumulative Bandwidth by Pod-to-Pod Flow\",\"version\":\"7.8.0\",\"panelRefName\":\"panel_5\"},{\"embeddableConfig\":{\"title\":\"Rx Mbps by Pod-to-Pod Flow\"},\"gridData\":{\"h\":15,\"i\":\"552fb687-487d-4896-afa9-c5a4731590c3\",\"w\":24,\"x\":0,\"y\":53},\"panelIndex\":\"552fb687-487d-4896-afa9-c5a4731590c3\",\"title\":\"Rx Mbps by Pod-to-Pod Flow\",\"version\":\"7.8.0\",\"panelRefName\":\"panel_6\"},{\"embeddableConfig\":{\"title\":\"Reverse Cumulative Bandwidth by Pod-to-Pod Flow\"},\"gridData\":{\"h\":15,\"i\":\"17c78f77-6667-413a-b3b2-ae99d0bd276c\",\"w\":24,\"x\":24,\"y\":53},\"panelIndex\":\"17c78f77-6667-413a-b3b2-ae99d0bd276c\",\"title\":\"Reverse Cumulative Bandwidth by Pod-to-Pod Flow\",\"version\":\"7.8.0\",\"panelRefName\":\"panel_7\"},{\"embeddableConfig\":{\"title\":\"Aggregated Tx Mbps by Pod Acting as Source\"},\"gridData\":{\"h\":15,\"i\":\"94c135b5-ab6b-41db-831e-7adb96282635\",\"w\":24,\"x\":0,\"y\":68},\"panelIndex\":\"94c135b5-ab6b-41db-831e-7adb96282635\",\"title\":\"Aggregated Tx Mbps by Pod Acting as Source\",\"version\":\"7.8.0\",\"panelRefName\":\"panel_8\"},{\"embeddableConfig\":{},\"gridData\":{\"h\":15,\"i\":\"d3a735b0-e1e7-4751-89f4-f69be3d341c5\",\"w\":24,\"x\":24,\"y\":68},\"panelIndex\":\"d3a735b0-e1e7-4751-89f4-f69be3d341c5\",\"version\":\"7.8.0\",\"panelRefName\":\"panel_9\"},{\"embeddableConfig\":{\"title\":\"\"},\"gridData\":{\"h\":2,\"i\":\"3b5dd519-11fe-41d0-9379-d6d8576fb688\",\"w\":48,\"x\":0,\"y\":83},\"panelIndex\":\"3b5dd519-11fe-41d0-9379-d6d8576fb688\",\"version\":\"7.8.0\",\"panelRefName\":\"panel_10\"}]","timeRestore":false,"title":"Pod-to-Pod Flow Dashboard","version":1},"id":"c2b15fb0-b9a8-11ea-b16e-fb06687c3589","migrationVersion":{"dashboard":"7.3.0"},"references":[{"id":"d5de6870-5148-11eb-a19a-05e08a82dcf8","name":"panel_0","type":"visualization"},{"id":"bcb98010-514c-11eb-a19a-05e08a82dcf8","name":"panel_1","type":"visualization"},{"id":"54525bd0-3373-11e9-aec0-c1d93190f676","name":"panel_2","type":"visualization"},{"id":"2bd8fe60-c243-11ea-873e-8f9a9a3cbdc1","name":"panel_3","type":"visualization"},{"id":"8f9b2980-4ee5-11eb-b841-6bf6243fda88","name":"panel_4","type":"visualization"},{"id":"5d8d7b90-4ee6-11eb-b841-6bf6243fda88","name":"panel_5","type":"visualization"},{"id":"c35f47c0-4ee9-11eb-b841-6bf6243fda88","name":"panel_6","type":"visualization"},{"id":"df090970-4ee9-11eb-b841-6bf6243fda88","name":"panel_7","type":"visualization"},{"id":"114eba40-55d4-11e8-a695-171fb712da36","name":"panel_8","type":"visualization"},{"id":"68f05640-c243-11ea-873e-8f9a9a3cbdc1","name":"panel_9","type":"visualization"},{"id":"f8323bc0-514f-11eb-a19a-05e08a82dcf8","name":"panel_10","type":"visualization"}],"type":"dashboard","updated_at":"2021-08-07T23:30:40.150Z","version":"WzY4LDFd"} -{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"lucene\"},\"filter\":[]}"},"title":"Network Policy Nav","uiStateJSON":"{}","version":1,"visState":"{\"type\":\"metrics\",\"aggs\":[],\"params\":{\"id\":\"61ca57f0-469d-11e7-af02-69e470af7417\",\"type\":\"markdown\",\"series\":[{\"id\":\"61ca57f1-469d-11e7-af02-69e470af7417\",\"color\":\"#68BC00\",\"split_mode\":\"everything\",\"metrics\":[{\"id\":\"61ca57f2-469d-11e7-af02-69e470af7417\",\"type\":\"count\"}],\"separate_axis\":0,\"axis_position\":\"right\",\"formatter\":\"number\",\"chart_type\":\"line\",\"line_width\":1,\"point_size\":1,\"fill\":0.5,\"stacked\":\"none\",\"offset_time\":\"-5y\",\"split_color_mode\":\"gradient\"}],\"interval\":\"auto\",\"axis_position\":\"left\",\"axis_formatter\":\"number\",\"axis_scale\":\"normal\",\"show_legend\":1,\"show_grid\":1,\"markdown_vertical_align\":\"top\",\"default_index_pattern\":\"flow-*\",\"default_timefield\":\"@timestamp\",\"isModelInvalid\":false,\"time_field\":null,\"index_pattern\":\"flow-*\",\"markdown_css\":\"#markdown-61ca57f0-469d-11e7-af02-69e470af7417 p{color:#cccccc;margin-top:0;margin-bottom:8px;text-align:right}#markdown-61ca57f0-469d-11e7-af02-69e470af7417 p a{color:#1eadbd;font-size:17px;font-weight:bold;text-decoration:none}#markdown-61ca57f0-469d-11e7-af02-69e470af7417 p a strong{color:#ffac12;font-weight:bold}#markdown-61ca57f0-469d-11e7-af02-69e470af7417 hr{background-color:#cccccc;margin:0;height:1px}\",\"markdown_less\":\"p {\\n color: #cccccc;\\n margin-top: 0px;\\n margin-bottom: 8px;\\n text-align: right;\\n}\\np a {\\n color: #1eadbd;\\n\\tfont-size: 17px;\\n\\tfont-weight: bold;\\n\\ttext-decoration: none;\\n}\\np a strong {\\n color: #ffac12;\\n\\tfont-weight: bold;\\n}\\nhr {\\n background-color: #cccccc;\\n margin: 0px;\\n height: 1px;\\n}\",\"markdown\":\"[Overview](#/dashboard/3b331b30-b987-11ea-b16e-fb06687c3589) | [Pod-to-Pod Flow](#/dashboard/c2b15fb0-b9a8-11ea-b16e-fb06687c3589) | [Pod-to-External Flow](#/dashboard/3ed71e80-a92d-11eb-a7ef-5dcb53008c10) | [Pod-to-Service Flow](#/dashboard/6d77e8a0-513a-11eb-a19a-05e08a82dcf8) | [Node](#/dashboard/5400cdf0-cd2e-11ea-8911-87da3aad0324) | [**Network Policy**](#/dashboard/c5af6850-23b2-11eb-90d2-a7a4de48218a) | [Flow Records](#/dashboard/2ab9c220-b984-11ea-b16e-fb06687c3589)\\n\"},\"title\":\"Network Policy Nav\"}"},"id":"d5d25970-23b4-11eb-90d2-a7a4de48218a","migrationVersion":{"visualization":"7.8.0"},"references":[],"type":"visualization","updated_at":"2021-08-07T23:30:40.150Z","version":"WzY5LDFd"} -{"attributes":{"description":"","hits":0,"kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"language\":\"kuery\",\"query\":\"\"},\"filter\":[]}"},"optionsJSON":"{\"hidePanelTitles\":false,\"useMargins\":true}","panelsJSON":"[{\"embeddableConfig\":{\"title\":\"\"},\"gridData\":{\"h\":3,\"i\":\"db9f8c72-9601-41aa-8e29-75e6fb0e900f\",\"w\":48,\"x\":0,\"y\":0},\"panelIndex\":\"db9f8c72-9601-41aa-8e29-75e6fb0e900f\",\"version\":\"7.8.0\",\"panelRefName\":\"panel_0\"},{\"embeddableConfig\":{\"title\":\"\"},\"gridData\":{\"h\":4,\"i\":\"f82e6f3e-2bc5-4331-9496-6e9924fc82ce\",\"w\":48,\"x\":0,\"y\":3},\"panelIndex\":\"f82e6f3e-2bc5-4331-9496-6e9924fc82ce\",\"version\":\"7.8.0\",\"panelRefName\":\"panel_1\"},{\"embeddableConfig\":{},\"gridData\":{\"h\":7,\"i\":\"442c53bd-1458-410d-ba6a-5fd4c69227c8\",\"w\":16,\"x\":0,\"y\":7},\"panelIndex\":\"442c53bd-1458-410d-ba6a-5fd4c69227c8\",\"version\":\"7.8.0\",\"panelRefName\":\"panel_2\"},{\"embeddableConfig\":{},\"gridData\":{\"h\":28,\"i\":\"1bf91279-3ad2-4050-9bc9-cd6ef1a398ab\",\"w\":32,\"x\":16,\"y\":7},\"panelIndex\":\"1bf91279-3ad2-4050-9bc9-cd6ef1a398ab\",\"version\":\"7.8.0\",\"panelRefName\":\"panel_3\"},{\"embeddableConfig\":{\"vis\":{\"colors\":{\"default\":\"#F2C96D\"},\"legendOpen\":true}},\"gridData\":{\"h\":7,\"i\":\"c6c67d51-43bf-4646-98d4-64be3f6f2ab0\",\"w\":16,\"x\":0,\"y\":14},\"panelIndex\":\"c6c67d51-43bf-4646-98d4-64be3f6f2ab0\",\"version\":\"7.8.0\",\"panelRefName\":\"panel_4\"},{\"embeddableConfig\":{},\"gridData\":{\"h\":7,\"i\":\"0304bbb7-21d6-41ea-b750-c582fc141085\",\"w\":16,\"x\":0,\"y\":21},\"panelIndex\":\"0304bbb7-21d6-41ea-b750-c582fc141085\",\"version\":\"7.8.0\",\"panelRefName\":\"panel_5\"},{\"embeddableConfig\":{},\"gridData\":{\"h\":7,\"i\":\"2d0bdde2-b339-4826-8a10-3e1b837fb192\",\"w\":16,\"x\":0,\"y\":28},\"panelIndex\":\"2d0bdde2-b339-4826-8a10-3e1b837fb192\",\"version\":\"7.8.0\",\"panelRefName\":\"panel_6\"}]","timeRestore":false,"title":"Network Policy Dashboard","version":1},"id":"c5af6850-23b2-11eb-90d2-a7a4de48218a","migrationVersion":{"dashboard":"7.3.0"},"references":[{"id":"d5d25970-23b4-11eb-90d2-a7a4de48218a","name":"panel_0","type":"visualization"},{"id":"4b5a40a0-23b9-11eb-90d2-a7a4de48218a","name":"panel_1","type":"visualization"},{"id":"9b4db300-23b7-11eb-90d2-a7a4de48218a","name":"panel_2","type":"visualization"},{"id":"c08ea960-7a1c-11eb-a325-39e98502337e","name":"panel_3","type":"visualization"},{"id":"56535ab0-23b8-11eb-90d2-a7a4de48218a","name":"panel_4","type":"visualization"},{"id":"bc4e0870-23b7-11eb-90d2-a7a4de48218a","name":"panel_5","type":"visualization"},{"id":"40e05390-23b8-11eb-90d2-a7a4de48218a","name":"panel_6","type":"visualization"}],"type":"dashboard","updated_at":"2021-08-07T23:30:40.150Z","version":"WzcwLDFd"} -{"exportedCount":69,"missingRefCount":0,"missingReferences":[]} \ No newline at end of file diff --git a/build/yamls/elk-flow-collector/logstash/filter.rb b/build/yamls/elk-flow-collector/logstash/filter.rb deleted file mode 100644 index fc4947907d0..00000000000 --- a/build/yamls/elk-flow-collector/logstash/filter.rb +++ /dev/null @@ -1,164 +0,0 @@ -require 'date' -# register accepts the hashmap passed to "script_params" -# it runs once at startup -def register(params) - @@time_map = Hash.new -end - -# filter runs for every event -# return the list of events to be passed forward -# returning empty list is equivalent to event.cancel -def filter(event) - event.set("[ipfix][bytes]", event.get("[ipfix][octetTotalCount]").to_i) - event.set("[ipfix][packets]", event.get("[ipfix][packetTotalCount]").to_i) - if event.get("[ipfix][protocolIdentifier]") == 6 - event.remove("[ipfix][protocolIdentifier]") - event.set("[ipfix][protocolIdentifier]", "TCP") - end - if event.get("[ipfix][protocolIdentifier]") == 17 - event.remove("[ipfix][protocolIdentifier]") - event.set("[ipfix][protocolIdentifier]", "UDP") - end - - flowType = event.get("[ipfix][flowType]") - if flowType == 1 - event.set("[ipfix][flowTypeStr]", "Intra-Node") - elsif flowType == 2 - event.set("[ipfix][flowTypeStr]", "Inter-Node") - elsif flowType == 3 - event.set("[ipfix][flowTypeStr]", "To External") - elsif flowType == 4 - event.set("[ipfix][flowTypeStr]", "From External") - end - - ingressRuleAction = event.get("[ipfix][ingressNetworkPolicyRuleAction]") - egressRuleAction = event.get("[ipfix][egressNetworkPolicyRuleAction]") - if ingressRuleAction == 0 - event.set("[ipfix][ingressNetworkPolicyRuleActionStr]", "No Action") - elsif ingressRuleAction == 1 - event.set("[ipfix][ingressNetworkPolicyRuleActionStr]", "Allow") - elsif ingressRuleAction == 2 - event.set("[ipfix][ingressNetworkPolicyRuleActionStr]", "Drop") - elsif ingressRuleAction == 3 - event.set("[ipfix][ingressNetworkPolicyRuleActionStr]", "Reject") - end - if egressRuleAction == 0 - event.set("[ipfix][egressNetworkPolicyRuleActionStr]", "No Action") - elsif egressRuleAction == 1 - event.set("[ipfix][egressNetworkPolicyRuleActionStr]", "Allow") - elsif egressRuleAction == 2 - event.set("[ipfix][egressNetworkPolicyRuleActionStr]", "Drop") - elsif egressRuleAction == 3 - event.set("[ipfix][egressNetworkPolicyRuleActionStr]", "Reject") - end - - if event.get("[ipfix][destinationIPv6Address]").nil? - event.set("[ipfix][destinationIP]", event.get("[ipfix][destinationIPv4Address]")) - else - event.set("[ipfix][destinationIP]", event.get("[ipfix][destinationIPv6Address]")) - end - if event.get("[ipfix][sourceIPv6Address]").nil? - event.set("[ipfix][sourceIP]", event.get("[ipfix][sourceIPv4Address]")) - else - event.set("[ipfix][sourceIP]", event.get("[ipfix][sourceIPv6Address]")) - end - if event.get("[ipfix][sourcePodName]") != "" - if event.get("[ipfix][destinationServicePortName]") != "" - flowkey = "" - flowkey << event.get("[ipfix][sourcePodName]") - flowkey << ":" - flowkey << event.get("[ipfix][sourceTransportPort]").to_s - flowkey << "->" - flowkey << event.get("[ipfix][destinationServicePortName]") - flowkey << event.get("[ipfix][destinationServicePort]").to_s - flowkey << " " - flowkey << event.get("[ipfix][protocolIdentifier]").to_s - event.set("[ipfix][flowKeyPodToService]", flowkey) - end - if event.get("[ipfix][flowType]") != 3 - flowkey = "" - flowkey << event.get("[ipfix][sourcePodName]") - flowkey << ":" - flowkey << event.get("[ipfix][sourceTransportPort]").to_s - flowkey << "->" - flowkey << event.get("[ipfix][destinationPodName]") - flowkey << ":" - flowkey << event.get("[ipfix][destinationTransportPort]").to_s - flowkey << " " - flowkey << event.get("[ipfix][protocolIdentifier]").to_s - event.set("[ipfix][flowKey]", flowkey) - event.set("[ipfix][flowKeyPodToPod]", flowkey) - else - flowkey = "" - flowkey << event.get("[ipfix][sourcePodName]") - flowkey << ":" - flowkey << event.get("[ipfix][sourceTransportPort]").to_s - flowkey << "->" - flowkey << event.get("[ipfix][destinationIP]") - flowkey << ":" - flowkey << event.get("[ipfix][destinationTransportPort]").to_s - flowkey << " " - flowkey << event.get("[ipfix][protocolIdentifier]").to_s - event.set("[ipfix][flowKey]", flowkey) - event.set("[ipfix][flowKeyPodToExternal]", flowkey) - end - end - if event.get("[ipfix][ingressNetworkPolicyName]") == "" - event.remove("[ipfix][ingressNetworkPolicyName]") - event.set("[ipfix][ingressNetworkPolicyName]", "N/A") - end - if event.get("[ipfix][ingressNetworkPolicyNamespace]") == "" - event.remove("[ipfix][ingressNetworkPolicyNamespace]") - event.set("[ipfix][ingressNetworkPolicyNamespace]", "N/A") - end - if event.get("[ipfix][egressNetworkPolicyName]") == "" - event.remove("[ipfix][egressNetworkPolicyName]") - event.set("[ipfix][egressNetworkPolicyName]", "N/A") - end - if event.get("[ipfix][egressNetworkPolicyNamespace]") == "" - event.remove("[ipfix][egressNetworkPolicyNamespace]") - event.set("[ipfix][egressNetworkPolicyNamespace]", "N/A") - end - ingressNetworkPolicyType = event.get("[ipfix][ingressNetworkPolicyType]") - if ingressNetworkPolicyType == 1 - event.set("[ipfix][ingressNetworkPolicyTypeStr]", "K8s NetworkPolicy") - elsif ingressNetworkPolicyType == 2 - event.set("[ipfix][ingressNetworkPolicyTypeStr]", "Antrea NetworkPolicy") - elsif ingressNetworkPolicyType == 3 - event.set("[ipfix][ingressNetworkPolicyTypeStr]", "Antrea ClusterNetworkPolicy") - end - egressNetworkPolicyType = event.get("[ipfix][egressNetworkPolicyType]") - if egressNetworkPolicyType == 1 - event.set("[ipfix][egressNetworkPolicyTypeStr]", "K8s NetworkPolicy") - elsif egressNetworkPolicyType == 2 - event.set("[ipfix][egressNetworkPolicyTypeStr]", "Antrea NetworkPolicy") - elsif egressNetworkPolicyType == 3 - event.set("[ipfix][egressNetworkPolicyTypeStr]", "Antrea ClusterNetworkPolicy") - end - key = event.get("[ipfix][flowKey]") - if @@time_map.has_key?(key) - t = event.get("[ipfix][flowEndSeconds]").to_i - duration = t - @@time_map[key] - # If flowEndSeconds does not change, throughput should be 0. - if duration == 0 - event.set("[ipfix][throughput]", 0) - event.set("[ipfix][reverseThroughput]", 0) - else - event.set("[ipfix][throughput]", event.get("[ipfix][octetDeltaCountFromSourceNode]").to_i / duration.to_i) - event.set("[ipfix][reverseThroughput]", event.get("[ipfix][reverseOctetDeltaCountFromSourceNode]").to_i / duration.to_i) - @@time_map[key] = t - end - else - startTime = event.get("[ipfix][flowStartSeconds]").to_i - endTime = event.get("[ipfix][flowEndSeconds]").to_i - duration = endTime-startTime - # if startTime equals endTime, just set throughput to current octetDeltaCount - if duration == 0 - duration = 1 - end - event.set("[ipfix][throughput]", event.get("[ipfix][octetDeltaCountFromSourceNode]").to_i / duration.to_i) - event.set("[ipfix][reverseThroughput]", event.get("[ipfix][reverseOctetDeltaCountFromSourceNode]").to_i / duration.to_i) - @@time_map[key] = endTime - end - return [event] -end diff --git a/build/yamls/elk-flow-collector/logstash/ipfix.yml b/build/yamls/elk-flow-collector/logstash/ipfix.yml deleted file mode 100644 index fb35cf35ec2..00000000000 --- a/build/yamls/elk-flow-collector/logstash/ipfix.yml +++ /dev/null @@ -1,209 +0,0 @@ -# ipfix fields definition file. Antrea-specific fields are with Enterprise ID 56506 ---- -0: - 0: - - :skip - 1: - - :uint64 - - :octetDeltaCount - 2: - - :uint64 - - :packetDeltaCount - 4: - - :uint8 - - :protocolIdentifier - 7: - - :uint16 - - :sourceTransportPort - 8: - - :ip4_addr - - :sourceIPv4Address - 11: - - :uint16 - - :destinationTransportPort - 12: - - :ip4_addr - - :destinationIPv4Address - 27: - - :ip6_addr - - :sourceIPv6Address - 28: - - :ip6_addr - - :destinationIPv6Address - 85: - - :uint64 - - :octetTotalCount - 86: - - :uint64 - - :packetTotalCount - 136: - - :uint8 - - :flowEndReason - 149: - - :uint32 - - :observationDomainId - 150: - - :uint32 - - :flowStartSeconds - 151: - - :uint32 - - :flowEndSeconds -29305: - 1: - - :uint64 - - :reverseOctetDeltaCount - 2: - - :uint64 - - :reversePacketDeltaCount - 85: - - :uint64 - - :reverseOctetTotalCount - 86: - - :uint64 - - :reversePacketTotalCount -# Antrea -56506: - 100: - - :string - - :sourcePodNamespace - 101: - - :string - - :sourcePodName - 102: - - :string - - :destinationPodNamespace - 103: - - :string - - :destinationPodName - 104: - - :string - - :sourceNodeName - 105: - - :string - - :destinationNodeName - 106: - - :ip4_addr - - :destinationClusterIPv4 - 107: - - :ip6_addr - - :destinationClusterIPv6 - 108: - - :uint16 - - :destinationServicePort - 109: - - :string - - :destinationServicePortName - 110: - - :string - - :ingressNetworkPolicyName - 111: - - :string - - :ingressNetworkPolicyNamespace - 112: - - :string - - :egressNetworkPolicyName - 113: - - :string - - :egressNetworkPolicyNamespace - 115: - - :uint8 - - :ingressNetworkPolicyType - 118: - - :uint8 - - :egressNetworkPolicyType - 120: - - :uint64 - - :packetTotalCountFromSourceNode - 121: - - :uint64 - - :octetTotalCountFromSourceNode - 122: - - :uint64 - - :packetDeltaCountFromSourceNode - 123: - - :uint64 - - :octetDeltaCountFromSourceNode - 124: - - :uint64 - - :reversePacketTotalCountFromSourceNode - 125: - - :uint64 - - :reverseOctetTotalCountFromSourceNode - 126: - - :uint64 - - :reversePacketDeltaCountFromSourceNode - 127: - - :uint64 - - :reverseOctetDeltaCountFromSourceNode - 128: - - :uint64 - - :packetTotalCountFromDestinationNode - 129: - - :uint64 - - :octetTotalCountFromDestinationNode - 130: - - :uint64 - - :packetDeltaCountFromDestinationNode - 131: - - :uint64 - - :octetDeltaCountFromDestinationNode - 132: - - :uint64 - - :reversePacketTotalCountFromDestinationNode - 133: - - :uint64 - - :reverseOctetTotalCountFromDestinationNode - 134: - - :uint64 - - :reversePacketDeltaCountFromDestinationNode - 135: - - :uint64 - - :reverseOctetDeltaCountFromDestinationNode - 136: - - :string - - :tcpState - 137: - - :uint8 - - :flowType - 139: - - :uint8 - - :ingressNetworkPolicyRuleAction - 140: - - :uint8 - - :egressNetworkPolicyRuleAction - 141: - - :string - - :ingressNetworkPolicyRuleName - 142: - - :string - - :egressNetworkPolicyRuleName - 143: - - :string - - :sourcePodLabels - 144: - - :string - - :destinationPodLabels - 145: - - :uint64 - - :throughput - 146: - - :uint64 - - :reverseThroughput - 147: - - :uint64 - - :throughputFromSourceNode - 148: - - :uint64 - - :throughputFromDestinationNode - 149: - - :uint64 - - :reverseThroughputFromSourceNode - 150: - - :uint64 - - :reverseThroughputFromDestinationNode - 151: - - :uint32 - - :flowEndSecondsFromSourceNode - 152: - - :uint32 - - :flowEndSecondsFromDestinationNode diff --git a/build/yamls/elk-flow-collector/logstash/logstash.conf b/build/yamls/elk-flow-collector/logstash/logstash.conf deleted file mode 100644 index 9bcdc326881..00000000000 --- a/build/yamls/elk-flow-collector/logstash/logstash.conf +++ /dev/null @@ -1,63 +0,0 @@ -# The configuration file is for logstash to receive and process flow records -# it will start a udp listener to receive and decode records using definitions in ipfix.yml, -# filter the flow records for bytes & packets and output to elasticsearch. - -input { - udp { - host => "${POD_IP}" - port => "4739" - workers => "4" - queue_size => "2048" - receive_buffer_bytes => "16777216" - codec => netflow { - versions => [10] - target => "ipfix" - include_flowset_id => "true" - cache_ttl => 86400 - ipfix_definitions => "/usr/share/logstash/definitions/ipfix.yml" - } - type => "ipfix" - } - tcp { - host => "${POD_IP}" - port => "4739" - codec => netflow { - versions => [10] - target => "ipfix" - include_flowset_id => "true" - # Set template expiration time to 365 days - cache_ttl => 31536000 - ipfix_definitions => "/usr/share/logstash/definitions/ipfix.yml" - } - type => "ipfix" - } - tcp { - host => "${POD_IP}" - port => "4736" - codec => json - } - udp { - host => "${POD_IP}" - port => "4736" - workers => "4" - queue_size => "2048" - receive_buffer_bytes => "16777216" - codec => json - } -} - -filter { - ruby { - path => "/usr/share/logstash/config/filter.rb" - } -} - -output { - elasticsearch { - hosts => [ "elasticsearch:9200" ] - ssl => "false" - ssl_certificate_verification => "false" - index => "flow-%{+YYYY.MM.dd}" - } - stdout {codec => rubydebug} -} diff --git a/build/yamls/elk-flow-collector/logstash/logstash.yml b/build/yamls/elk-flow-collector/logstash/logstash.yml deleted file mode 100644 index 22cfe5a810b..00000000000 --- a/build/yamls/elk-flow-collector/logstash/logstash.yml +++ /dev/null @@ -1,4 +0,0 @@ -http.host: "${POD_IP}" -path.config: /usr/share/logstash/pipeline -pipeline.workers: 1 -pipeline.batch.size: 125 diff --git a/build/yamls/flow-visibility.yml b/build/yamls/flow-visibility.yml index 7217afb84f7..45ce2850597 100644 --- a/build/yamls/flow-visibility.yml +++ b/build/yamls/flow-visibility.yml @@ -86,26 +86,27 @@ data: UInt64,\n reverseThroughputFromDestinationNode UInt64,\n trusted UInt8 DEFAULT 0\n ) engine=MergeTree\n ORDER BY (timeInserted, flowEndSeconds)\n \ TTL timeInserted + INTERVAL 1 HOUR\n SETTINGS merge_with_ttl_timeout = - 3600;\n\n CREATE MATERIALIZED VIEW flows_pod_view\n ENGINE = SummingMergeTree\n - \ ORDER BY (\n timeInserted,\n flowEndSeconds,\n flowEndSecondsFromSourceNode,\n - \ flowEndSecondsFromDestinationNode,\n sourcePodName,\n destinationPodName,\n - \ destinationIP,\n destinationServicePortName,\n flowType,\n - \ sourcePodNamespace,\n destinationPodNamespace)\n TTL timeInserted - + INTERVAL 1 HOUR\n SETTINGS merge_with_ttl_timeout = 3600\n POPULATE\n - \ AS SELECT\n timeInserted,\n flowEndSeconds,\n flowEndSecondsFromSourceNode,\n - \ flowEndSecondsFromDestinationNode,\n sourcePodName,\n destinationPodName,\n - \ destinationIP,\n destinationServicePortName,\n flowType,\n - \ sourcePodNamespace,\n destinationPodNamespace,\n sum(octetDeltaCount) - AS octetDeltaCount,\n sum(reverseOctetDeltaCount) AS reverseOctetDeltaCount,\n - \ sum(throughput) AS throughput,\n sum(reverseThroughput) AS reverseThroughput,\n - \ sum(throughputFromSourceNode) AS throughputFromSourceNode,\n sum(throughputFromDestinationNode) - AS throughputFromDestinationNode\n FROM flows\n GROUP BY\n timeInserted,\n + 3600;\n\n CREATE MATERIALIZED VIEW IF NOT EXISTS flows_pod_view\n ENGINE + = SummingMergeTree\n ORDER BY (\n timeInserted,\n flowEndSeconds,\n + \ flowEndSecondsFromSourceNode,\n flowEndSecondsFromDestinationNode,\n + \ sourcePodName,\n destinationPodName,\n destinationIP,\n + \ destinationServicePortName,\n flowType,\n sourcePodNamespace,\n + \ destinationPodNamespace)\n TTL timeInserted + INTERVAL 1 HOUR\n SETTINGS + merge_with_ttl_timeout = 3600\n POPULATE\n AS SELECT\n timeInserted,\n \ flowEndSeconds,\n flowEndSecondsFromSourceNode,\n flowEndSecondsFromDestinationNode,\n \ sourcePodName,\n destinationPodName,\n destinationIP,\n \ destinationServicePortName,\n flowType,\n sourcePodNamespace,\n - \ destinationPodNamespace;\n\n CREATE MATERIALIZED VIEW flows_node_view\n - \ ENGINE = SummingMergeTree\n ORDER BY (\n timeInserted,\n flowEndSeconds,\n + \ destinationPodNamespace,\n sum(octetDeltaCount) AS octetDeltaCount,\n + \ sum(reverseOctetDeltaCount) AS reverseOctetDeltaCount,\n sum(throughput) + AS throughput,\n sum(reverseThroughput) AS reverseThroughput,\n sum(throughputFromSourceNode) + AS throughputFromSourceNode,\n sum(throughputFromDestinationNode) AS throughputFromDestinationNode\n + \ FROM flows\n GROUP BY\n timeInserted,\n flowEndSeconds,\n \ flowEndSecondsFromSourceNode,\n flowEndSecondsFromDestinationNode,\n + \ sourcePodName,\n destinationPodName,\n destinationIP,\n + \ destinationServicePortName,\n flowType,\n sourcePodNamespace,\n + \ destinationPodNamespace;\n\n CREATE MATERIALIZED VIEW IF NOT EXISTS + flows_node_view\n ENGINE = SummingMergeTree\n ORDER BY (\n timeInserted,\n + \ flowEndSeconds,\n flowEndSecondsFromSourceNode,\n flowEndSecondsFromDestinationNode,\n \ sourceNodeName,\n destinationNodeName,\n sourcePodNamespace,\n \ destinationPodNamespace)\n TTL timeInserted + INTERVAL 1 HOUR\n SETTINGS merge_with_ttl_timeout = 3600\n POPULATE\n AS SELECT\n timeInserted,\n @@ -120,9 +121,9 @@ data: AS reverseThroughputFromDestinationNode\n FROM flows\n GROUP BY\n timeInserted,\n \ flowEndSeconds,\n flowEndSecondsFromSourceNode,\n flowEndSecondsFromDestinationNode,\n \ sourceNodeName,\n destinationNodeName,\n sourcePodNamespace,\n - \ destinationPodNamespace;\n\n CREATE MATERIALIZED VIEW flows_policy_view\n - \ ENGINE = SummingMergeTree\n ORDER BY (\n timeInserted,\n flowEndSeconds,\n - \ flowEndSecondsFromSourceNode,\n flowEndSecondsFromDestinationNode,\n + \ destinationPodNamespace;\n\n CREATE MATERIALIZED VIEW IF NOT EXISTS + flows_policy_view\n ENGINE = SummingMergeTree\n ORDER BY (\n timeInserted,\n + \ flowEndSeconds,\n flowEndSecondsFromSourceNode,\n flowEndSecondsFromDestinationNode,\n \ egressNetworkPolicyName,\n egressNetworkPolicyRuleAction,\n ingressNetworkPolicyName,\n \ ingressNetworkPolicyRuleAction,\n sourcePodNamespace,\n destinationPodNamespace)\n \ TTL timeInserted + INTERVAL 1 HOUR\n SETTINGS merge_with_ttl_timeout = @@ -145,7 +146,7 @@ data: \ ORDER BY (timeCreated);\n \nEOSQL\n" kind: ConfigMap metadata: - name: clickhouse-mounted-configmap-dkbmg82ctg + name: clickhouse-mounted-configmap-58fkkt9b56 namespace: flow-visibility --- apiVersion: v1 @@ -174,8 +175,8 @@ data: "editable": true, "fiscalYearStartMonth": 0, "graphTooltip": 0, - "id": 2, - "iteration": 1644612871636, + "id": 1, + "iteration": 1652994218341, "links": [], "liveNow": false, "panels": [ @@ -1049,7 +1050,7 @@ data: "query": "SELECT\n $timeSeries as t,\n *\nFROM $table\n\nWHERE $timeFilter\n\nORDER BY t\n", "queryType": "sql", "rawQuery": "SELECT\n (intDiv(toUInt32(flowEndSeconds), 1) * 1) * 1000 as t,\n *\nFROM default.flows\n\nWHERE flowEndSeconds >= toDateTime(1642715797) AND flowEndSeconds <= toDateTime(1642716697)\n\nORDER BY t", - "rawSql": "SELECT * \nFROM flows\nWHERE $__timeFilter(flowEndSeconds)", + "rawSql": "SELECT * \nFROM flows\nWHERE $__timeFilter(flowEndSeconds)\nORDER BY flowEndSeconds DESC\nLIMIT 10000", "refId": "A", "round": "0s", "skip_comments": true, @@ -1129,8 +1130,8 @@ data: "editable": true, "fiscalYearStartMonth": 0, "graphTooltip": 0, - "id": 5, - "iteration": 1644982999763, + "id": 2, + "iteration": 1653420082463, "links": [], "liveNow": false, "panels": [ @@ -1207,7 +1208,7 @@ data: "query": "SELECT SUM(octetDeltaCount), (egressNetworkPolicyName, ingressNetworkPolicyName) AS pair\nFROM $table\nWHERE $timeFilter\nAND (egressNetworkPolicyRuleAction == 1 OR ingressNetworkPolicyRuleAction == 1)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY pair\n", "queryType": "sql", "rawQuery": "SELECT SUM(octetDeltaCount), (egressNetworkPolicyName, ingressNetworkPolicyName) AS pair\nFROM default.flows_policy_view\nWHERE flowEndSeconds >= toDateTime(1642198255) AND flowEndSeconds <= toDateTime(1642200055)\nAND (egressNetworkPolicyRuleAction == 1 OR ingressNetworkPolicyRuleAction == 1)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY pair", - "rawSql": "select SUM(octetDeltaCount) as bytes, egressNetworkPolicyName as source, ingressNetworkPolicyName as destination, ingressNetworkPolicyName as destinationIP\nFrom flows_policy_view\nWHERE $__timeFilter(flowEndSeconds) \nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator') \nAND (egressNetworkPolicyRuleAction == 1 OR ingressNetworkPolicyRuleAction == 1)\nGROUP BY source, destination\nHAVING bytes != 0", + "rawSql": "select SUM(octetDeltaCount) as bytes, egressNetworkPolicyName as source, ingressNetworkPolicyName as destination, ingressNetworkPolicyName as destinationIP\nFrom flows_policy_view\nWHERE $__timeFilter(flowEndSeconds) \nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator') \nAND (egressNetworkPolicyRuleAction == 1 OR ingressNetworkPolicyRuleAction == 1)\nGROUP BY source, destination\nHAVING bytes != 0\nORDER BY bytes DESC\nLIMIT 50", "refId": "A", "round": "0s", "skip_comments": true, @@ -1256,7 +1257,7 @@ data: "query": "SELECT SUM(reverseOctetDeltaCount), (egressNetworkPolicyName, ingressNetworkPolicyName) AS pair\nFROM $table\nWHERE $timeFilter\nAND (egressNetworkPolicyRuleAction == 1 OR ingressNetworkPolicyRuleAction == 1)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY pair\n", "queryType": "randomWalk", "rawQuery": "SELECT SUM(reverseOctetDeltaCount), (egressNetworkPolicyName, ingressNetworkPolicyName) AS pair\nFROM default.flows_policy_view\nWHERE flowEndSeconds >= toDateTime(1642198301) AND flowEndSeconds <= toDateTime(1642200101)\nAND (egressNetworkPolicyRuleAction == 1 OR ingressNetworkPolicyRuleAction == 1)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY pair", - "rawSql": "select SUM(reverseOctetDeltaCount) as bytes, egressNetworkPolicyName as source, ingressNetworkPolicyName as destination, ingressNetworkPolicyName as destinationIP\nFrom flows_policy_view\nWHERE $__timeFilter(flowEndSeconds)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND (egressNetworkPolicyRuleAction == 1 OR ingressNetworkPolicyRuleAction == 1)\nGROUP BY source, destination\nHAVING bytes != 0", + "rawSql": "select SUM(reverseOctetDeltaCount) as bytes, egressNetworkPolicyName as source, ingressNetworkPolicyName as destination, ingressNetworkPolicyName as destinationIP\nFrom flows_policy_view\nWHERE $__timeFilter(flowEndSeconds)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND (egressNetworkPolicyRuleAction == 1 OR ingressNetworkPolicyRuleAction == 1)\nGROUP BY source, destination\nHAVING bytes != 0\nORDER BY bytes DESC\nLIMIT 50", "refId": "A", "round": "0s", "skip_comments": true, @@ -1365,7 +1366,7 @@ data: "query": "SELECT $timeSeries as t, SUM(throughputFromSourceNode), sourcePodName\nFROM $table\nWHERE $timeFilter \nAND flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY sourcePodName, t\nORDER BY t\n", "queryType": "sql", "rawQuery": "SELECT (intDiv(toUInt32(flowEndSeconds), 60) * 60) * 1000 as t, SUM(throughputFromSourceNode), sourcePodName\nFROM default.flows_pod_view\nWHERE flowEndSeconds >= toDateTime(1642532448) AND flowEndSeconds <= toDateTime(1642534248) \nAND flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY sourcePodName, t\nORDER BY t", - "rawSql": "SELECT $__timeInterval(flowEndSeconds) as time, CONCAT(egressNetworkPolicyName, '->', ingressNetworkPolicyName) as pair, SUM(throughput)\nFROM flows_policy_view\nWHERE $__timeFilter(flowEndSeconds) \nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator') \nAND (egressNetworkPolicyRuleAction == 1 OR ingressNetworkPolicyRuleAction == 1)\nGROUP BY time, pair\nHAVING SUM(throughput) != 0\nORDER BY time", + "rawSql": "SELECT $__timeInterval(flowEndSeconds) as time, CONCAT(egressNetworkPolicyName, '->', ingressNetworkPolicyName) as pair, SUM(throughput)\nFROM flows_policy_view\nWHERE $__timeFilter(flowEndSeconds) \nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator') \nAND (egressNetworkPolicyRuleAction == 1 OR ingressNetworkPolicyRuleAction == 1)\nGROUP BY time, pair\nHAVING SUM(throughput) != 0\nORDER BY time\nLIMIT 50", "refId": "A", "round": "0s", "skip_comments": true, @@ -1493,7 +1494,7 @@ data: "query": "SELECT $timeSeries as t, SUM(throughputFromSourceNode), sourcePodName\nFROM $table\nWHERE $timeFilter \nAND flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY sourcePodName, t\nORDER BY t\n", "queryType": "sql", "rawQuery": "SELECT (intDiv(toUInt32(flowEndSeconds), 60) * 60) * 1000 as t, SUM(throughputFromSourceNode), sourcePodName\nFROM default.flows_pod_view\nWHERE flowEndSeconds >= toDateTime(1642532448) AND flowEndSeconds <= toDateTime(1642534248) \nAND flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY sourcePodName, t\nORDER BY t", - "rawSql": "SELECT $__timeInterval(flowEndSeconds) as time, CONCAT(egressNetworkPolicyName, '->', ingressNetworkPolicyName) as pair, SUM(reverseThroughput)\nFROM flows_policy_view\nWHERE $__timeFilter(time)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND (egressNetworkPolicyRuleAction == 1 OR ingressNetworkPolicyRuleAction == 1)\nGROUP BY time, pair\nHAVING SUM(reverseThroughput) != 0\nORDER BY time", + "rawSql": "SELECT $__timeInterval(flowEndSeconds) as time, CONCAT(egressNetworkPolicyName, '->', ingressNetworkPolicyName) as pair, SUM(reverseThroughput)\nFROM flows_policy_view\nWHERE $__timeFilter(time)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND (egressNetworkPolicyRuleAction == 1 OR ingressNetworkPolicyRuleAction == 1)\nGROUP BY time, pair\nHAVING SUM(reverseThroughput) != 0\nORDER BY time\nLIMIT 50", "refId": "A", "round": "0s", "skip_comments": true, @@ -1621,7 +1622,7 @@ data: "query": "SELECT $timeSeries as t, SUM(throughputFromSourceNode), sourcePodName\nFROM $table\nWHERE $timeFilter \nAND flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY sourcePodName, t\nORDER BY t\n", "queryType": "sql", "rawQuery": "SELECT (intDiv(toUInt32(flowEndSeconds), 60) * 60) * 1000 as t, SUM(throughputFromSourceNode), sourcePodName\nFROM default.flows_pod_view\nWHERE flowEndSeconds >= toDateTime(1642532448) AND flowEndSeconds <= toDateTime(1642534248) \nAND flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY sourcePodName, t\nORDER BY t", - "rawSql": "SELECT $__timeInterval(flowEndSeconds) as time, egressNetworkPolicyName, SUM(throughput)\nFROM flows_policy_view\nWHERE sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND egressNetworkPolicyName != ''\nAND egressNetworkPolicyRuleAction == 1\nAND $__timeFilter(time)\nGROUP BY time, egressNetworkPolicyName\nHAVING SUM(throughput) != 0\nORDER BY time", + "rawSql": "SELECT $__timeInterval(flowEndSeconds) as time, egressNetworkPolicyName, SUM(throughput)\nFROM flows_policy_view\nWHERE sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND egressNetworkPolicyName != ''\nAND egressNetworkPolicyRuleAction == 1\nAND $__timeFilter(time)\nGROUP BY time, egressNetworkPolicyName\nHAVING SUM(throughput) != 0\nORDER BY time\nLIMIT 50", "refId": "A", "round": "0s", "skip_comments": true, @@ -1696,6 +1697,7 @@ data: "lastNotNull" ], "fields": "", + "limit": 25, "values": true }, "tooltip": { @@ -1709,7 +1711,7 @@ data: "uid": "PDEE91DDB90597936" }, "format": 1, - "rawSql": "SELECT SUM(octetDeltaCount), egressNetworkPolicyName\nFROM flows_policy_view\nWHERE sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND egressNetworkPolicyName != ''\nAND egressNetworkPolicyRuleAction == 1\nAND $__timeFilter(flowEndSeconds)\nGROUP BY egressNetworkPolicyName\nHAVING SUM(octetDeltaCount) != 0", + "rawSql": "SELECT SUM(octetDeltaCount) as bytes, egressNetworkPolicyName\nFROM flows_policy_view\nWHERE sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND egressNetworkPolicyName != ''\nAND egressNetworkPolicyRuleAction == 1\nAND $__timeFilter(flowEndSeconds)\nGROUP BY egressNetworkPolicyName\nHAVING SUM(octetDeltaCount) != 0\nORDER BY bytes DESC", "refId": "A" } ], @@ -1814,7 +1816,7 @@ data: "query": "SELECT $timeSeries as t, SUM(throughputFromSourceNode), sourcePodName\nFROM $table\nWHERE $timeFilter \nAND flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY sourcePodName, t\nORDER BY t\n", "queryType": "sql", "rawQuery": "SELECT (intDiv(toUInt32(flowEndSeconds), 60) * 60) * 1000 as t, SUM(throughputFromSourceNode), sourcePodName\nFROM default.flows_pod_view\nWHERE flowEndSeconds >= toDateTime(1642532448) AND flowEndSeconds <= toDateTime(1642534248) \nAND flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY sourcePodName, t\nORDER BY t", - "rawSql": "SELECT $__timeInterval(flowEndSeconds) as time, ingressNetworkPolicyName, SUM(throughput)\nFROM flows_policy_view\nWHERE sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND ingressNetworkPolicyName != ''\nAND ingressNetworkPolicyRuleAction == 1\nAND $__timeFilter(time)\nGROUP BY time, ingressNetworkPolicyName\nHAVING SUM(throughput) != 0\nORDER BY time", + "rawSql": "SELECT $__timeInterval(flowEndSeconds) as time, ingressNetworkPolicyName, SUM(throughput)\nFROM flows_policy_view\nWHERE sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND ingressNetworkPolicyName != ''\nAND ingressNetworkPolicyRuleAction == 1\nAND $__timeFilter(time)\nGROUP BY time, ingressNetworkPolicyName\nHAVING SUM(throughput) != 0\nORDER BY time\nLIMIT 50", "refId": "A", "round": "0s", "skip_comments": true, @@ -1889,6 +1891,7 @@ data: "lastNotNull" ], "fields": "", + "limit": 25, "values": true }, "tooltip": { @@ -1902,7 +1905,7 @@ data: "uid": "PDEE91DDB90597936" }, "format": 1, - "rawSql": "SELECT SUM(octetDeltaCount), ingressNetworkPolicyName\nFROM flows_policy_view\nWHERE sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND ingressNetworkPolicyName != ''\nAND ingressNetworkPolicyRuleAction == 1\nAND $__timeFilter(flowEndSeconds)\nGROUP BY ingressNetworkPolicyName\nHAVING SUM(octetDeltaCount) != 0", + "rawSql": "SELECT SUM(octetDeltaCount) as bytes, ingressNetworkPolicyName\nFROM flows_policy_view\nWHERE sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND ingressNetworkPolicyName != ''\nAND ingressNetworkPolicyRuleAction == 1\nAND $__timeFilter(flowEndSeconds)\nGROUP BY ingressNetworkPolicyName\nHAVING SUM(octetDeltaCount) != 0\nORDER BY bytes DESC", "refId": "A" } ], @@ -1972,8 +1975,8 @@ data: "editable": true, "fiscalYearStartMonth": 0, "graphTooltip": 0, - "id": 4, - "iteration": 1644612915701, + "id": 3, + "iteration": 1653419912594, "links": [], "liveNow": false, "panels": [ @@ -2015,7 +2018,7 @@ data: "query": "SELECT SUM(octetDeltaCount), (sourceNodeName, destinationNodeName) as pair\nFROM $table\nWHERE $timeFilter\nAND sourceNodeName != ''\nAND destinationNodeName != ''\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY pair\n", "queryType": "sql", "rawQuery": false, - "rawSql": "select SUM(octetDeltaCount) as bytes, sourceNodeName as source, destinationNodeName as destination\nFrom flows_node_view\nWHERE source != '' AND destination != ''\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationPodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND $__timeFilter(flowEndSeconds)\nGROUP BY source, destination", + "rawSql": "select SUM(octetDeltaCount) as bytes, sourceNodeName as source, destinationNodeName as destination\nFrom flows_node_view\nWHERE source != '' AND destination != ''\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationPodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND $__timeFilter(flowEndSeconds)\nGROUP BY source, destination\nORDER BY bytes DESC\nLIMIT 50", "refId": "A", "round": "0s", "skip_comments": true, @@ -2071,7 +2074,7 @@ data: "query": "SELECT SUM(reverseOctetDeltaCount), (sourceNodeName, destinationNodeName) as pair\nFROM $table\nWHERE $timeFilter\nAND sourceNodeName != ''\nAND destinationNodeName != ''\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY pair\n", "queryType": "randomWalk", "rawQuery": false, - "rawSql": "select SUM(reverseOctetDeltaCount) as bytes, sourceNodeName as source, destinationNodeName as destination\nFrom flows_node_view\nWHERE source != '' AND destination != ''\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND $__timeFilter(flowEndSeconds)\nGROUP BY source, destination", + "rawSql": "select SUM(reverseOctetDeltaCount) as bytes, sourceNodeName as source, destinationNodeName as destination\nFrom flows_node_view\nWHERE source != '' AND destination != ''\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND $__timeFilter(flowEndSeconds)\nGROUP BY source, destination\nORDER BY bytes DESC\nLIMIT 50", "refId": "A", "round": "0s", "skip_comments": true, @@ -2180,7 +2183,7 @@ data: "query": "SELECT $timeSeries as t, SUM(throughputFromDestinationNode), destinationNodeName\nFROM $table\nWHERE $timeFilter\nAND sourceNodeName != ''\nAND destinationNodeName != ''\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY destinationNodeName, t\nORDER BY t\n", "queryType": "sql", "rawQuery": "SELECT (intDiv(toUInt32(flowEndSecondsFromDestinationNode), 60) * 60) * 1000 as t, SUM(throughputFromDestinationNode), destinationNodeName\nFROM default.flows_node_view\nWHERE flowEndSecondsFromDestinationNode >= toDateTime(1642533454) AND flowEndSecondsFromDestinationNode <= toDateTime(1642535254)\nAND sourceNodeName != ''\nAND destinationNodeName != ''\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY destinationNodeName, t\nORDER BY t", - "rawSql": "SELECT $__timeInterval(flowEndSeconds) as time, CONCAT(sourceNodeName, '->', destinationNodeName) as pair, SUM(throughput) as Node\nFROM flows_node_view\nWHERE sourceNodeName != '' AND destinationNodeName != ''\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationPodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND $__timeFilter(time)\nGROUP BY time, pair\nORDER BY time", + "rawSql": "SELECT $__timeInterval(flowEndSeconds) as time, CONCAT(sourceNodeName, '->', destinationNodeName) as pair, SUM(throughput) as Node\nFROM flows_node_view\nWHERE sourceNodeName != '' AND destinationNodeName != ''\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationPodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND $__timeFilter(time)\nGROUP BY time, pair\nORDER BY time\nLIMIT 50", "refId": "A", "round": "0s", "skip_comments": true, @@ -2308,7 +2311,7 @@ data: "query": "SELECT $timeSeries as t, SUM(throughputFromDestinationNode), destinationNodeName\nFROM $table\nWHERE $timeFilter\nAND sourceNodeName != ''\nAND destinationNodeName != ''\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY destinationNodeName, t\nORDER BY t\n", "queryType": "randomWalk", "rawQuery": "SELECT (intDiv(toUInt32(flowEndSecondsFromDestinationNode), 60) * 60) * 1000 as t, SUM(throughputFromDestinationNode), destinationNodeName\nFROM default.flows_node_view\nWHERE flowEndSecondsFromDestinationNode >= toDateTime(1642533454) AND flowEndSecondsFromDestinationNode <= toDateTime(1642535254)\nAND sourceNodeName != ''\nAND destinationNodeName != ''\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY destinationNodeName, t\nORDER BY t", - "rawSql": "SELECT $__timeInterval(flowEndSeconds) as time, CONCAT(sourceNodeName, '->', destinationNodeName) as pair, SUM(reverseThroughput) as Node\nFROM flows_node_view\nWHERE sourceNodeName != '' AND destinationNodeName != ''\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationPodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND $__timeFilter(time)\nGROUP BY time, pair\nORDER BY time", + "rawSql": "SELECT $__timeInterval(flowEndSeconds) as time, CONCAT(sourceNodeName, '->', destinationNodeName) as pair, SUM(reverseThroughput) as Node\nFROM flows_node_view\nWHERE sourceNodeName != '' AND destinationNodeName != ''\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationPodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND $__timeFilter(time)\nGROUP BY time, pair\nORDER BY time\nLIMIT 50", "refId": "A", "round": "0s", "skip_comments": true, @@ -2436,7 +2439,7 @@ data: "query": "SELECT $timeSeries as t, SUM(throughputFromDestinationNode), destinationNodeName\nFROM $table\nWHERE $timeFilter\nAND sourceNodeName != ''\nAND destinationNodeName != ''\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY destinationNodeName, t\nORDER BY t\n", "queryType": "sql", "rawQuery": "SELECT (intDiv(toUInt32(flowEndSecondsFromDestinationNode), 60) * 60) * 1000 as t, SUM(throughputFromDestinationNode), destinationNodeName\nFROM default.flows_node_view\nWHERE flowEndSecondsFromDestinationNode >= toDateTime(1642533454) AND flowEndSecondsFromDestinationNode <= toDateTime(1642535254)\nAND sourceNodeName != ''\nAND destinationNodeName != ''\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY destinationNodeName, t\nORDER BY t", - "rawSql": "SELECT $__timeInterval(flowEndSecondsFromSourceNode) as time, sourceNodeName, SUM(throughputFromSourceNode)\nFROM flows_node_view\nWHERE sourceNodeName != '' \nAND destinationNodeName != ''\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationPodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND $__timeFilter(time)\nGROUP BY time, sourceNodeName\nORDER BY time", + "rawSql": "SELECT $__timeInterval(flowEndSecondsFromSourceNode) as time, sourceNodeName, SUM(throughputFromSourceNode)\nFROM flows_node_view\nWHERE sourceNodeName != '' \nAND destinationNodeName != ''\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationPodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND $__timeFilter(time)\nGROUP BY time, sourceNodeName\nORDER BY time\nLIMIT 50", "refId": "A", "round": "0s", "skip_comments": true, @@ -2513,6 +2516,7 @@ data: "lastNotNull" ], "fields": "", + "limit": 25, "values": true }, "tooltip": { @@ -2526,7 +2530,7 @@ data: "uid": "PDEE91DDB90597936" }, "format": 1, - "rawSql": "SELECT SUM(octetDeltaCount), sourceNodeName\nFROM flows_node_view\nWHERE sourceNodeName != '' AND destinationNodeName != ''\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationPodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND $__timeFilter(flowEndSeconds)\nGROUP BY sourceNodeName", + "rawSql": "SELECT SUM(octetDeltaCount) as bytes, sourceNodeName\nFROM flows_node_view\nWHERE sourceNodeName != '' AND destinationNodeName != ''\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationPodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND $__timeFilter(flowEndSeconds)\nGROUP BY sourceNodeName\nORDER BY bytes DESC", "refId": "A" } ], @@ -2631,7 +2635,7 @@ data: "query": "SELECT $timeSeries as t, SUM(throughputFromDestinationNode), destinationNodeName\nFROM $table\nWHERE $timeFilter\nAND sourceNodeName != ''\nAND destinationNodeName != ''\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY destinationNodeName, t\nORDER BY t\n", "queryType": "sql", "rawQuery": "SELECT (intDiv(toUInt32(flowEndSecondsFromDestinationNode), 60) * 60) * 1000 as t, SUM(throughputFromDestinationNode), destinationNodeName\nFROM default.flows_node_view\nWHERE flowEndSecondsFromDestinationNode >= toDateTime(1642533454) AND flowEndSecondsFromDestinationNode <= toDateTime(1642535254)\nAND sourceNodeName != ''\nAND destinationNodeName != ''\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY destinationNodeName, t\nORDER BY t", - "rawSql": "SELECT $__timeInterval(flowEndSecondsFromDestinationNode) as time, destinationNodeName, SUM(throughputFromDestinationNode)\nFROM flows_node_view\nWHERE sourceNodeName != '' AND destinationNodeName != ''\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationPodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND $__timeFilter(time)\nGROUP BY time, destinationNodeName\nORDER BY time", + "rawSql": "SELECT $__timeInterval(flowEndSecondsFromDestinationNode) as time, destinationNodeName, SUM(throughputFromDestinationNode)\nFROM flows_node_view\nWHERE sourceNodeName != '' AND destinationNodeName != ''\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationPodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND $__timeFilter(time)\nGROUP BY time, destinationNodeName\nORDER BY time\nLIMIT 50", "refId": "A", "round": "0s", "skip_comments": true, @@ -2706,6 +2710,7 @@ data: "lastNotNull" ], "fields": "", + "limit": 25, "values": true }, "tooltip": { @@ -2719,7 +2724,7 @@ data: "uid": "PDEE91DDB90597936" }, "format": 1, - "rawSql": "SELECT SUM(octetDeltaCount), destinationNodeName\nFROM flows_node_view\nWHERE sourceNodeName != '' AND destinationNodeName != ''\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationPodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND $__timeFilter(flowEndSeconds)\nGROUP BY destinationNodeName", + "rawSql": "SELECT SUM(octetDeltaCount) as bytes, destinationNodeName\nFROM flows_node_view\nWHERE sourceNodeName != '' AND destinationNodeName != ''\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationPodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND $__timeFilter(flowEndSeconds)\nGROUP BY destinationNodeName\nORDER BY bytes DESC", "refId": "A" } ], @@ -2762,7 +2767,7 @@ data: "timezone": "", "title": "node_to_node_dashboard", "uid": "1F56RJh7z", - "version": 10, + "version": 5, "weekStart": "" } pod_to_external_dashboard.json: |- @@ -2789,8 +2794,8 @@ data: "editable": true, "fiscalYearStartMonth": 0, "graphTooltip": 0, - "id": 5, - "iteration": 1644612843565, + "id": 4, + "iteration": 1653419876105, "links": [], "liveNow": false, "panels": [ @@ -2831,7 +2836,7 @@ data: "query": "SELECT SUM(octetDeltaCount), (sourcePodName, destinationIP) AS pair\nFROM $table\nWHERE $timeFilter\nAND flowType == 3\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-aggregator', 'flow-visibility')\nGROUP BY pair\n", "queryType": "randomWalk", "rawQuery": "SELECT SUM(octetDeltaCount), (sourcePodName, destinationIP) AS pair\nFROM default.flows_pod_view\nWHERE flowEndSeconds >= toDateTime(1642534343) AND flowEndSeconds <= toDateTime(1642536143)\nAND flowType == 3\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-aggregator', 'flow-visibility')\nGROUP BY pair", - "rawSql": "select SUM(octetDeltaCount) as bytes, sourcePodName as source, destinationIP as destination\nFrom flows_pod_view\nWHERE flowType == 3\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND $__timeFilter(flowEndSeconds)\nGROUP BY source, destination\nHAVING bytes != 0", + "rawSql": "select SUM(octetDeltaCount) as bytes, sourcePodName as source, destinationIP as destination\nFrom flows_pod_view\nWHERE flowType == 3\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND $__timeFilter(flowEndSeconds)\nGROUP BY source, destination\nHAVING bytes != 0\nORDER BY bytes DESC\nLIMIT 50", "refId": "A", "round": "0s", "skip_comments": true, @@ -2880,7 +2885,7 @@ data: "query": "SELECT SUM(reverseOctetDeltaCount), (sourcePodName, destinationIP) AS pair\nFROM $table\nWHERE $timeFilter\nAND flowType == 3\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-aggregator', 'flow-visibility')\nGROUP BY pair\n", "queryType": "randomWalk", "rawQuery": "SELECT SUM(reverseOctetDeltaCount), (sourcePodName, destinationIP) AS pair\nFROM default.flows_pod_view\nWHERE flowEndSeconds >= toDateTime(1642534382) AND flowEndSeconds <= toDateTime(1642536182)\nAND flowType == 3\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-aggregator', 'flow-visibility')\nGROUP BY pair", - "rawSql": "select SUM(reverseOctetDeltaCount) as bytes, sourcePodName as source, destinationIP as destination\nFrom flows_pod_view\nWHERE flowType == 3\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND $__timeFilter(flowEndSeconds)\nGROUP BY source, destination\nHAVING bytes != 0", + "rawSql": "select SUM(reverseOctetDeltaCount) as bytes, sourcePodName as source, destinationIP as destination\nFrom flows_pod_view\nWHERE flowType == 3\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND $__timeFilter(flowEndSeconds)\nGROUP BY source, destination\nHAVING bytes != 0\nORDER BY bytes DESC\nLIMIT 50", "refId": "A", "round": "0s", "skip_comments": true, @@ -2954,7 +2959,7 @@ data: "y": 18 }, "id": 2, - "interval": "60s", + "interval": "1s", "options": { "legend": { "calcs": [ @@ -2988,7 +2993,7 @@ data: "query": "SELECT $timeSeries as t, SUM(octetDeltaCount), (sourcePodName, destinationIP) as pair\nFROM $table\nWHERE $timeFilter\nAND flowType == 3\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY pair,t\nORDER BY t\n", "queryType": "sql", "rawQuery": "SELECT (intDiv(toUInt32(flowEndSeconds), 60) * 60) * 1000 as t, SUM(octetDeltaCount), (sourcePodName, destinationIP) as pair\nFROM default.flows_pod_view\nWHERE flowEndSeconds >= toDateTime(1642534150) AND flowEndSeconds <= toDateTime(1642535950)\nAND flowType == 3\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY pair,t\nORDER BY t", - "rawSql": "SELECT $__timeInterval(flowEndSeconds) as time, CONCAT(sourcePodName, '->', destinationIP) as pair, SUM(throughput)\nFROM flows_pod_view\nWHERE flowType == 3\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND $__timeFilter(time)\nGROUP BY time, pair\nHAVING SUM(throughput) != 0\nORDER BY time", + "rawSql": "SELECT $__timeInterval(flowEndSeconds) as time, CONCAT(sourcePodName, '->', destinationIP) as pair, AVG(throughput)\nFROM flows_pod_view\nWHERE flowType == 3\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND $__timeFilter(time)\nGROUP BY time, pair\nHAVING SUM(throughput) != 0\nORDER BY time\nLIMIT 50", "refId": "A", "round": "0s", "skip_comments": true, @@ -3078,7 +3083,7 @@ data: "y": 18 }, "id": 7, - "interval": "60s", + "interval": "1s", "options": { "legend": { "calcs": [ @@ -3112,7 +3117,7 @@ data: "query": "SELECT $timeSeries as t, SUM(reverseOctetDeltaCount), (sourcePodName, destinationIP) as pair\nFROM $table\nWHERE $timeFilter\nAND flowType == 3\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY pair, t\nORDER BY t", "queryType": "sql", "rawQuery": "SELECT (intDiv(toUInt32(flowEndSeconds), 60) * 60) * 1000 as t, SUM(reverseOctetDeltaCount), (sourcePodName, destinationIP) as pair\nFROM default.flows_pod_view\nWHERE flowEndSeconds >= toDateTime(1642534246) AND flowEndSeconds <= toDateTime(1642536046)\nAND flowType == 3\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY pair, t\nORDER BY t", - "rawSql": "SELECT $__timeInterval(flowEndSeconds) as time, CONCAT(sourcePodName, '->', destinationIP) as pair, SUM(reverseThroughput)\nFROM flows_pod_view\nWHERE flowType == 3\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND $__timeFilter(time)\nGROUP BY time, pair\nHAVING SUM(reverseThroughput) != 0\nORDER BY time", + "rawSql": "SELECT $__timeInterval(flowEndSeconds) as time, CONCAT(sourcePodName, '->', destinationIP) as pair, AVG(reverseThroughput)\nFROM flows_pod_view\nWHERE flowType == 3\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND $__timeFilter(time)\nGROUP BY time, pair\nHAVING SUM(reverseThroughput) != 0\nORDER BY time\nLIMIT 50", "refId": "A", "round": "0s", "skip_comments": true, @@ -3178,7 +3183,7 @@ data: "timezone": "", "title": "pod_to_external_dashboard", "uid": "K9SPrnJ7k", - "version": 3, + "version": 5, "weekStart": "" } pod_to_pod_dashboard.json: |- @@ -3205,8 +3210,8 @@ data: "editable": true, "fiscalYearStartMonth": 0, "graphTooltip": 0, - "id": 1, - "iteration": 1644971511247, + "id": 5, + "iteration": 1653419724493, "links": [], "liveNow": false, "panels": [ @@ -3247,7 +3252,7 @@ data: "query": "SELECT SUM(octetDeltaCount), (sourcePodName, destinationPodName, destinationIP) AS pair\nFROM $table\nWHERE $timeFilter\nAND flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY pair\n", "queryType": "sql", "rawQuery": "SELECT SUM(octetDeltaCount), (sourcePodName, destinationPodName, destinationIP) AS pair\nFROM default.flows_pod_view\nWHERE flowEndSeconds >= toDateTime(1642531723) AND flowEndSeconds <= toDateTime(1642533523)\nAND flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY pair", - "rawSql": "select SUM(octetDeltaCount) as bytes, sourcePodName as source, destinationPodName as destination, destinationIP\nFrom flows_pod_view\nWHERE flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationPodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND $__timeFilter(flowEndSeconds)\nGROUP BY source, destination, destinationIP", + "rawSql": "select SUM(octetDeltaCount) as bytes, sourcePodName as source, destinationPodName as destination, destinationIP\nFrom flows_pod_view\nWHERE flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationPodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND $__timeFilter(flowEndSeconds)\nGROUP BY source, destination, destinationIP\nORDER BY bytes DESC\nLIMIT 50", "refId": "A", "round": "0s", "skip_comments": true, @@ -3296,7 +3301,7 @@ data: "query": "SELECT SUM(reverseOctetDeltaCount), (sourcePodName, destinationPodName, destinationIP) AS pair\nFROM $table\nWHERE $timeFilter\nAND flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY pair\n", "queryType": "randomWalk", "rawQuery": "SELECT SUM(reverseOctetDeltaCount), (sourcePodName, destinationPodName, destinationIP) AS pair\nFROM default.flows_pod_view\nWHERE flowEndSeconds >= toDateTime(1642531743) AND flowEndSeconds <= toDateTime(1642533543)\nAND flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY pair", - "rawSql": "select SUM(reverseOctetDeltaCount) as bytes, sourcePodName as source, destinationPodName as destination, destinationIP\nFrom flows_pod_view\nWHERE flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationPodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND $__timeFilter(flowEndSeconds)\nGROUP BY source, destination, destinationIP", + "rawSql": "select SUM(reverseOctetDeltaCount) as bytes, sourcePodName as source, destinationPodName as destination, destinationIP\nFrom flows_pod_view\nWHERE flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationPodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND $__timeFilter(flowEndSeconds)\nGROUP BY source, destination, destinationIP\nORDER BY bytes DESC\nLIMIT 50", "refId": "A", "round": "0s", "skip_comments": true, @@ -3353,10 +3358,6 @@ data: { "color": "green", "value": null - }, - { - "color": "red", - "value": 80 } ] }, @@ -3371,7 +3372,7 @@ data: "y": 18 }, "id": 21, - "interval": "60s", + "interval": "1s", "options": { "legend": { "calcs": [ @@ -3405,7 +3406,7 @@ data: "query": "SELECT $timeSeries as t, SUM(throughputFromSourceNode), sourcePodName\nFROM $table\nWHERE $timeFilter \nAND flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY sourcePodName, t\nORDER BY t\n", "queryType": "sql", "rawQuery": "SELECT (intDiv(toUInt32(flowEndSeconds), 60) * 60) * 1000 as t, SUM(throughputFromSourceNode), sourcePodName\nFROM default.flows_pod_view\nWHERE flowEndSeconds >= toDateTime(1642532448) AND flowEndSeconds <= toDateTime(1642534248) \nAND flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY sourcePodName, t\nORDER BY t", - "rawSql": "SELECT $__timeInterval(flowEndSeconds) as time, CONCAT(sourcePodName, '->', destinationPodName) as pair, SUM(throughput)\nFROM flows_pod_view\nWHERE flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationPodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND $__timeFilter(time)\nGROUP BY time, pair\nHAVING SUM(throughput) > 0\nORDER BY time", + "rawSql": "SELECT $__timeInterval(flowEndSeconds) as time, CONCAT(sourcePodName, '->', destinationPodName) as pair, AVG(throughput)\nFROM flows_pod_view\nWHERE flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationPodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND $__timeFilter(time)\nGROUP BY time, pair\nHAVING SUM(throughput) > 0\nORDER BY time\nLIMIT 50", "refId": "A", "round": "0s", "skip_comments": true, @@ -3499,7 +3500,7 @@ data: "y": 18 }, "id": 22, - "interval": "60s", + "interval": "1s", "options": { "legend": { "calcs": [ @@ -3533,7 +3534,7 @@ data: "query": "SELECT $timeSeries as t, SUM(throughputFromSourceNode), sourcePodName\nFROM $table\nWHERE $timeFilter \nAND flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY sourcePodName, t\nORDER BY t\n", "queryType": "sql", "rawQuery": "SELECT (intDiv(toUInt32(flowEndSeconds), 60) * 60) * 1000 as t, SUM(throughputFromSourceNode), sourcePodName\nFROM default.flows_pod_view\nWHERE flowEndSeconds >= toDateTime(1642532448) AND flowEndSeconds <= toDateTime(1642534248) \nAND flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY sourcePodName, t\nORDER BY t", - "rawSql": "SELECT $__timeInterval(flowEndSeconds) as time, CONCAT(sourcePodName, '->', destinationPodName) as pair, SUM(reverseThroughput)\nFROM flows_pod_view\nWHERE flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationPodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND $__timeFilter(time)\nGROUP BY time, pair\nHAVING SUM(reverseThroughput) > 0\nORDER BY time", + "rawSql": "SELECT $__timeInterval(flowEndSeconds) as time, CONCAT(sourcePodName, '->', destinationPodName) as pair, AVG(reverseThroughput)\nFROM flows_pod_view\nWHERE flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationPodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND $__timeFilter(time)\nGROUP BY time, pair\nHAVING SUM(reverseThroughput) > 0\nORDER BY time\nLIMIT 50", "refId": "A", "round": "0s", "skip_comments": true, @@ -3609,10 +3610,6 @@ data: { "color": "green", "value": null - }, - { - "color": "red", - "value": 80 } ] }, @@ -3661,7 +3658,7 @@ data: "query": "SELECT $timeSeries as t, SUM(throughputFromSourceNode), sourcePodName\nFROM $table\nWHERE $timeFilter \nAND flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY sourcePodName, t\nORDER BY t\n", "queryType": "sql", "rawQuery": "SELECT (intDiv(toUInt32(flowEndSeconds), 60) * 60) * 1000 as t, SUM(throughputFromSourceNode), sourcePodName\nFROM default.flows_pod_view\nWHERE flowEndSeconds >= toDateTime(1642532448) AND flowEndSeconds <= toDateTime(1642534248) \nAND flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY sourcePodName, t\nORDER BY t", - "rawSql": "SELECT $__timeInterval(flowEndSecondsFromSourceNode) as time, sourcePodName, SUM(throughputFromSourceNode)\nFROM flows_pod_view\nWHERE flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationPodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND $__timeFilter(time)\nGROUP BY time, sourcePodName\nHAVING SUM(throughputFromSourceNode) > 0\nORDER BY time", + "rawSql": "SELECT $__timeInterval(flowEndSecondsFromSourceNode) as time, sourcePodName, SUM(throughputFromSourceNode)\nFROM flows_pod_view\nWHERE flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationPodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND $__timeFilter(time)\nGROUP BY time, sourcePodName\nHAVING SUM(throughputFromSourceNode) > 0\nORDER BY time\nLIMIT 50", "refId": "A", "round": "0s", "skip_comments": true, @@ -3736,6 +3733,7 @@ data: "lastNotNull" ], "fields": "", + "limit": 25, "values": true }, "tooltip": { @@ -3750,7 +3748,7 @@ data: }, "format": 1, "queryType": "sql", - "rawSql": "select SUM(octetDeltaCount) as bytes, sourcePodNamespace\nFrom flows_pod_view\nWHERE flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationPodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND $__timeFilter(flowEndSeconds)\nGROUP BY sourcePodNamespace\nHAVING bytes > 0", + "rawSql": "select SUM(octetDeltaCount) as bytes, sourcePodNamespace\nFrom flows_pod_view\nWHERE flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationPodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND $__timeFilter(flowEndSeconds)\nGROUP BY sourcePodNamespace\nHAVING bytes > 0\nORDER BY bytes DESC", "refId": "A" } ], @@ -3855,7 +3853,7 @@ data: "query": "SELECT $timeSeries as t, SUM(throughputFromDestinationNode), destinationPodName\nFROM $table\nWHERE $timeFilter \nAND flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY destinationPodName, t\nORDER BY t\n", "queryType": "sql", "rawQuery": "SELECT (intDiv(toUInt32(flowEndSecondsFromDestinationNode), 60) * 60) * 1000 as t, SUM(throughputFromDestinationNode), destinationPodName\nFROM default.flows_pod_view\nWHERE flowEndSecondsFromDestinationNode >= toDateTime(1642532702) AND flowEndSecondsFromDestinationNode <= toDateTime(1642534502) \nAND flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY destinationPodName, t\nORDER BY t", - "rawSql": "SELECT $__timeInterval(flowEndSecondsFromDestinationNode) as time, destinationPodName, SUM(throughputFromDestinationNode)\nFROM flows_pod_view\nWHERE flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationPodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND $__timeFilter(time)\nGROUP BY time, destinationPodName\nHAVING SUM(throughputFromDestinationNode) > 0\nORDER BY time", + "rawSql": "SELECT $__timeInterval(flowEndSecondsFromDestinationNode) as time, destinationPodName, SUM(throughputFromDestinationNode)\nFROM flows_pod_view\nWHERE flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationPodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND $__timeFilter(time)\nGROUP BY time, destinationPodName\nHAVING SUM(throughputFromDestinationNode) > 0\nORDER BY time\nLIMIT 50", "refId": "A", "round": "0s", "skip_comments": true, @@ -3943,6 +3941,7 @@ data: "lastNotNull" ], "fields": "", + "limit": 25, "values": true }, "tooltip": { @@ -3956,7 +3955,7 @@ data: "uid": "PDEE91DDB90597936" }, "format": 1, - "rawSql": "select SUM(octetDeltaCount) as bytes, destinationPodNamespace\nFrom flows_pod_view\nWHERE flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationPodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND $__timeFilter(flowEndSeconds)\nGROUP BY destinationPodNamespace", + "rawSql": "select SUM(octetDeltaCount) as bytes, destinationPodNamespace\nFrom flows_pod_view\nWHERE flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationPodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND $__timeFilter(flowEndSeconds)\nGROUP BY destinationPodNamespace\nORDER BY bytes DESC", "refId": "A" } ], @@ -3999,7 +3998,7 @@ data: "timezone": "", "title": "pod_to_pod_dashboard", "uid": "Yxn0Ghh7k", - "version": 9, + "version": 5, "weekStart": "" } pod_to_service_dashboard.json: |- @@ -4026,8 +4025,8 @@ data: "editable": true, "fiscalYearStartMonth": 0, "graphTooltip": 0, - "id": 1, - "iteration": 1644612951629, + "id": 6, + "iteration": 1653420001321, "links": [], "liveNow": false, "panels": [ @@ -4068,7 +4067,7 @@ data: "query": "SELECT SUM(octetDeltaCount), (sourcePodName, destinationServicePortName) AS pair\nFROM $table\nWHERE $timeFilter\nAND destinationServicePortName != ''\nAND flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY pair\n", "queryType": "randomWalk", "rawQuery": "SELECT SUM(octetDeltaCount), (sourcePodName, destinationServicePortName) AS pair\nFROM default.flows_pod_view\nWHERE flowEndSeconds >= toDateTime(1642193285) AND flowEndSeconds <= toDateTime(1642195085)\nAND destinationServicePortName != ''\nAND flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY pair", - "rawSql": "select SUM(octetDeltaCount) as bytes, sourcePodName as source, destinationServicePortName as destination\nFrom flows_pod_view\nWHERE flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationPodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationServicePortName != ''\nAND $__timeFilter(flowEndSeconds)\nGROUP BY source, destination", + "rawSql": "select SUM(octetDeltaCount) as bytes, sourcePodName as source, destinationServicePortName as destination\nFrom flows_pod_view\nWHERE flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationPodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationServicePortName != ''\nAND $__timeFilter(flowEndSeconds)\nGROUP BY source, destination\nORDER BY bytes DESC\nLIMIT 50", "refId": "A", "round": "0s", "skip_comments": true, @@ -4117,7 +4116,7 @@ data: "query": "SELECT SUM(reverseOctetDeltaCount), (sourcePodName, destinationServicePortName) AS pair\nFROM $table\nWHERE $timeFilter\nAND destinationServicePortName != ''\nAND flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY pair\n", "queryType": "randomWalk", "rawQuery": "SELECT SUM(reverseOctetDeltaCount), (sourcePodName, destinationServicePortName) AS pair\nFROM default.flows_pod_view\nWHERE flowEndSeconds >= toDateTime(1642193431) AND flowEndSeconds <= toDateTime(1642195231)\nAND destinationServicePortName != ''\nAND flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY pair", - "rawSql": "select SUM(reverseOctetDeltaCount) as bytes, sourcePodName as source, destinationServicePortName as destination\nFrom flows_pod_view\nWHERE flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationPodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationServicePortName != ''\nAND $__timeFilter(flowEndSeconds)\nGROUP BY source, destination", + "rawSql": "select SUM(reverseOctetDeltaCount) as bytes, sourcePodName as source, destinationServicePortName as destination\nFrom flows_pod_view\nWHERE flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationPodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationServicePortName != ''\nAND $__timeFilter(flowEndSeconds)\nGROUP BY source, destination\nORDER BY bytes DESC\nLIMIT 50", "refId": "A", "round": "0s", "skip_comments": true, @@ -4192,7 +4191,7 @@ data: "y": 18 }, "id": 18, - "interval": "60s", + "interval": "1s", "options": { "legend": { "calcs": [ @@ -4226,7 +4225,7 @@ data: "query": "SELECT $timeSeries as t, SUM(throughputFromSourceNode), sourcePodName\nFROM $table\nWHERE $timeFilter \nAND flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY sourcePodName, t\nORDER BY t\n", "queryType": "sql", "rawQuery": "SELECT (intDiv(toUInt32(flowEndSeconds), 60) * 60) * 1000 as t, SUM(throughputFromSourceNode), sourcePodName\nFROM default.flows_pod_view\nWHERE flowEndSeconds >= toDateTime(1642532448) AND flowEndSeconds <= toDateTime(1642534248) \nAND flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY sourcePodName, t\nORDER BY t", - "rawSql": "SELECT $__timeInterval(flowEndSeconds) as time, CONCAT(sourcePodName, '->', destinationServicePortName) as pair, SUM(throughput) as Pod\nFROM flows_pod_view\nWHERE flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationPodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationServicePortName != ''\nAND $__timeFilter(flowEndSeconds)\nGROUP BY time, pair\nORDER BY time", + "rawSql": "SELECT $__timeInterval(flowEndSeconds) as time, CONCAT(sourcePodName, '->', destinationServicePortName) as pair, AVG(throughput)\nFROM flows_pod_view\nWHERE flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationPodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationServicePortName != ''\nAND $__timeFilter(flowEndSeconds)\nGROUP BY time, pair\nORDER BY time\nLIMIT 50", "refId": "A", "round": "0s", "skip_comments": true, @@ -4320,7 +4319,7 @@ data: "y": 18 }, "id": 19, - "interval": "60s", + "interval": "1s", "options": { "legend": { "calcs": [ @@ -4354,7 +4353,7 @@ data: "query": "SELECT $timeSeries as t, SUM(throughputFromSourceNode), sourcePodName\nFROM $table\nWHERE $timeFilter \nAND flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY sourcePodName, t\nORDER BY t\n", "queryType": "sql", "rawQuery": "SELECT (intDiv(toUInt32(flowEndSeconds), 60) * 60) * 1000 as t, SUM(throughputFromSourceNode), sourcePodName\nFROM default.flows_pod_view\nWHERE flowEndSeconds >= toDateTime(1642532448) AND flowEndSeconds <= toDateTime(1642534248) \nAND flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY sourcePodName, t\nORDER BY t", - "rawSql": "SELECT $__timeInterval(flowEndSeconds) as time, CONCAT(sourcePodName, '->', destinationServicePortName) as pair, SUM(reverseThroughput) as Pod\nFROM flows_pod_view\nWHERE flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationPodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationServicePortName != ''\nAND $__timeFilter(time)\nGROUP BY time, pair\nORDER BY time", + "rawSql": "SELECT $__timeInterval(flowEndSeconds) as time, CONCAT(sourcePodName, '->', destinationServicePortName) as pair, AVG(reverseThroughput)\nFROM flows_pod_view\nWHERE flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationPodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationServicePortName != ''\nAND $__timeFilter(time)\nGROUP BY time, pair\nORDER BY time\nLIMIT 50", "refId": "A", "round": "0s", "skip_comments": true, @@ -4482,7 +4481,7 @@ data: "query": "SELECT $timeSeries as t, SUM(throughputFromSourceNode), sourcePodName\nFROM $table\nWHERE $timeFilter \nAND flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY sourcePodName, t\nORDER BY t\n", "queryType": "sql", "rawQuery": "SELECT (intDiv(toUInt32(flowEndSeconds), 60) * 60) * 1000 as t, SUM(throughputFromSourceNode), sourcePodName\nFROM default.flows_pod_view\nWHERE flowEndSeconds >= toDateTime(1642532448) AND flowEndSeconds <= toDateTime(1642534248) \nAND flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY sourcePodName, t\nORDER BY t", - "rawSql": "SELECT $__timeInterval(flowEndSecondsFromSourceNode) as time, sourcePodName, SUM(throughputFromSourceNode) as Pod\nFROM flows_pod_view\nWHERE flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationPodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationServicePortName != ''\nAND $__timeFilter(time)\nGROUP BY time, sourcePodName\nORDER BY time", + "rawSql": "SELECT $__timeInterval(flowEndSecondsFromSourceNode) as time, sourcePodName, SUM(throughputFromSourceNode) as Pod\nFROM flows_pod_view\nWHERE flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationPodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationServicePortName != ''\nAND $__timeFilter(time)\nGROUP BY time, sourcePodName\nORDER BY time\nLIMIT 50", "refId": "A", "round": "0s", "skip_comments": true, @@ -4610,7 +4609,7 @@ data: "query": "SELECT $timeSeries as t, SUM(throughputFromSourceNode), sourcePodName\nFROM $table\nWHERE $timeFilter \nAND flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY sourcePodName, t\nORDER BY t\n", "queryType": "sql", "rawQuery": "SELECT (intDiv(toUInt32(flowEndSeconds), 60) * 60) * 1000 as t, SUM(throughputFromSourceNode), sourcePodName\nFROM default.flows_pod_view\nWHERE flowEndSeconds >= toDateTime(1642532448) AND flowEndSeconds <= toDateTime(1642534248) \nAND flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY sourcePodName, t\nORDER BY t", - "rawSql": "SELECT $__timeInterval(flowEndSecondsFromDestinationNode) as time, destinationServicePortName, SUM(throughputFromDestinationNode) as Service\nFROM flows_pod_view\nWHERE flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationPodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationServicePortName != ''\nAND $__timeFilter(time)\nGROUP BY time, destinationServicePortName\nORDER BY time", + "rawSql": "SELECT $__timeInterval(flowEndSecondsFromDestinationNode) as time, destinationServicePortName, SUM(throughputFromDestinationNode) as Service\nFROM flows_pod_view\nWHERE flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationPodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationServicePortName != ''\nAND $__timeFilter(time)\nGROUP BY time, destinationServicePortName\nORDER BY time\nLIMIT 50", "refId": "A", "round": "0s", "skip_comments": true, @@ -4676,12 +4675,12 @@ data: "timezone": "", "title": "pod_to_service_dashboard", "uid": "LGdxbW17z", - "version": 8, + "version": 5, "weekStart": "" } kind: ConfigMap metadata: - name: grafana-dashboard-config-gkkgc9d727 + name: grafana-dashboard-config-gb25bt99t9 namespace: flow-visibility --- apiVersion: v1 @@ -4881,7 +4880,7 @@ spec: name: grafana-dashboard-provider-m7d5kfmmc6 name: grafana-dashboard-provider - configMap: - name: grafana-dashboard-config-gkkgc9d727 + name: grafana-dashboard-config-gb25bt99t9 name: grafana-dashboard-config --- apiVersion: clickhouse.altinity.com/v1 @@ -4934,12 +4933,14 @@ spec: value: default.flows - name: MV_NAMES value: default.flows_pod_view default.flows_node_view default.flows_policy_view + - name: STORAGE_SIZE + value: 8Gi image: projects.registry.vmware.com/antrea/flow-visibility-clickhouse-monitor:latest imagePullPolicy: IfNotPresent name: clickhouse-monitor volumes: - configMap: - name: clickhouse-mounted-configmap-dkbmg82ctg + name: clickhouse-mounted-configmap-58fkkt9b56 name: clickhouse-configmap-volume - emptyDir: medium: Memory diff --git a/build/yamls/flow-visibility/base/clickhouse.yml b/build/yamls/flow-visibility/base/clickhouse.yml index 18fe72ee747..cfe35293604 100644 --- a/build/yamls/flow-visibility/base/clickhouse.yml +++ b/build/yamls/flow-visibility/base/clickhouse.yml @@ -45,32 +45,7 @@ spec: volumeMounts: - name: clickhouse-configmap-volume mountPath: /docker-entrypoint-initdb.d - - name: clickhouse-storage-volume - mountPath: /var/lib/clickhouse - - name: clickhouse-monitor - image: flow-visibility-clickhouse-monitor - env: - - name: CLICKHOUSE_USERNAME - valueFrom: - secretKeyRef: - name: clickhouse-secret - key: username - - name: CLICKHOUSE_PASSWORD - valueFrom: - secretKeyRef: - name: clickhouse-secret - key: password - - name: DB_URL - value: "tcp://localhost:9000" - - name: TABLE_NAME - value: "default.flows" - - name: MV_NAMES - value: "default.flows_pod_view default.flows_node_view default.flows_policy_view" volumes: - name: clickhouse-configmap-volume configMap: name: $(CLICKHOUSE_CONFIG_MAP_NAME) - - name: clickhouse-storage-volume - emptyDir: - medium: Memory - sizeLimit: 8Gi diff --git a/build/yamls/flow-visibility/base/kustomization-e2e.yml b/build/yamls/flow-visibility/base/kustomization-e2e.yml new file mode 100644 index 00000000000..2511fbc288b --- /dev/null +++ b/build/yamls/flow-visibility/base/kustomization-e2e.yml @@ -0,0 +1,26 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +namespace: flow-visibility + +resources: + - clickhouse.yml + +configMapGenerator: + - name: clickhouse-mounted-configmap + namespace: flow-visibility + files: + - provisioning/datasources/create_table.sh + +# CLICKHOUSE_CONFIG_MAP_NAME exports the value in `metadata.name` from `ConfigMap` named `clickhouse-mounted-configmap`, +# which is used for inserting the value to a CRD for an object of kind `ClickHouseInstallation` +vars: + - name: CLICKHOUSE_CONFIG_MAP_NAME + objref: + kind: ConfigMap + name: clickhouse-mounted-configmap + apiVersion: v1 + fieldref: + fieldpath: metadata.name + +configurations: + - kustomize-config.yml diff --git a/build/yamls/flow-visibility/base/provisioning/dashboards/flow_records_dashboard.json b/build/yamls/flow-visibility/base/provisioning/dashboards/flow_records_dashboard.json index ef012033b6a..97afb0a1b6f 100644 --- a/build/yamls/flow-visibility/base/provisioning/dashboards/flow_records_dashboard.json +++ b/build/yamls/flow-visibility/base/provisioning/dashboards/flow_records_dashboard.json @@ -21,8 +21,8 @@ "editable": true, "fiscalYearStartMonth": 0, "graphTooltip": 0, - "id": 2, - "iteration": 1644612871636, + "id": 1, + "iteration": 1652994218341, "links": [], "liveNow": false, "panels": [ @@ -896,7 +896,7 @@ "query": "SELECT\n $timeSeries as t,\n *\nFROM $table\n\nWHERE $timeFilter\n\nORDER BY t\n", "queryType": "sql", "rawQuery": "SELECT\n (intDiv(toUInt32(flowEndSeconds), 1) * 1) * 1000 as t,\n *\nFROM default.flows\n\nWHERE flowEndSeconds >= toDateTime(1642715797) AND flowEndSeconds <= toDateTime(1642716697)\n\nORDER BY t", - "rawSql": "SELECT * \nFROM flows\nWHERE $__timeFilter(flowEndSeconds)", + "rawSql": "SELECT * \nFROM flows\nWHERE $__timeFilter(flowEndSeconds)\nORDER BY flowEndSeconds DESC\nLIMIT 10000", "refId": "A", "round": "0s", "skip_comments": true, diff --git a/build/yamls/flow-visibility/base/provisioning/dashboards/networkpolicy_allow_dashboard.json b/build/yamls/flow-visibility/base/provisioning/dashboards/networkpolicy_allow_dashboard.json index f37d8de295b..c63ee1d4bd1 100644 --- a/build/yamls/flow-visibility/base/provisioning/dashboards/networkpolicy_allow_dashboard.json +++ b/build/yamls/flow-visibility/base/provisioning/dashboards/networkpolicy_allow_dashboard.json @@ -21,8 +21,8 @@ "editable": true, "fiscalYearStartMonth": 0, "graphTooltip": 0, - "id": 5, - "iteration": 1644982999763, + "id": 2, + "iteration": 1653420082463, "links": [], "liveNow": false, "panels": [ @@ -99,7 +99,7 @@ "query": "SELECT SUM(octetDeltaCount), (egressNetworkPolicyName, ingressNetworkPolicyName) AS pair\nFROM $table\nWHERE $timeFilter\nAND (egressNetworkPolicyRuleAction == 1 OR ingressNetworkPolicyRuleAction == 1)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY pair\n", "queryType": "sql", "rawQuery": "SELECT SUM(octetDeltaCount), (egressNetworkPolicyName, ingressNetworkPolicyName) AS pair\nFROM default.flows_policy_view\nWHERE flowEndSeconds >= toDateTime(1642198255) AND flowEndSeconds <= toDateTime(1642200055)\nAND (egressNetworkPolicyRuleAction == 1 OR ingressNetworkPolicyRuleAction == 1)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY pair", - "rawSql": "select SUM(octetDeltaCount) as bytes, egressNetworkPolicyName as source, ingressNetworkPolicyName as destination, ingressNetworkPolicyName as destinationIP\nFrom flows_policy_view\nWHERE $__timeFilter(flowEndSeconds) \nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator') \nAND (egressNetworkPolicyRuleAction == 1 OR ingressNetworkPolicyRuleAction == 1)\nGROUP BY source, destination\nHAVING bytes != 0", + "rawSql": "select SUM(octetDeltaCount) as bytes, egressNetworkPolicyName as source, ingressNetworkPolicyName as destination, ingressNetworkPolicyName as destinationIP\nFrom flows_policy_view\nWHERE $__timeFilter(flowEndSeconds) \nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator') \nAND (egressNetworkPolicyRuleAction == 1 OR ingressNetworkPolicyRuleAction == 1)\nGROUP BY source, destination\nHAVING bytes != 0\nORDER BY bytes DESC\nLIMIT 50", "refId": "A", "round": "0s", "skip_comments": true, @@ -148,7 +148,7 @@ "query": "SELECT SUM(reverseOctetDeltaCount), (egressNetworkPolicyName, ingressNetworkPolicyName) AS pair\nFROM $table\nWHERE $timeFilter\nAND (egressNetworkPolicyRuleAction == 1 OR ingressNetworkPolicyRuleAction == 1)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY pair\n", "queryType": "randomWalk", "rawQuery": "SELECT SUM(reverseOctetDeltaCount), (egressNetworkPolicyName, ingressNetworkPolicyName) AS pair\nFROM default.flows_policy_view\nWHERE flowEndSeconds >= toDateTime(1642198301) AND flowEndSeconds <= toDateTime(1642200101)\nAND (egressNetworkPolicyRuleAction == 1 OR ingressNetworkPolicyRuleAction == 1)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY pair", - "rawSql": "select SUM(reverseOctetDeltaCount) as bytes, egressNetworkPolicyName as source, ingressNetworkPolicyName as destination, ingressNetworkPolicyName as destinationIP\nFrom flows_policy_view\nWHERE $__timeFilter(flowEndSeconds)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND (egressNetworkPolicyRuleAction == 1 OR ingressNetworkPolicyRuleAction == 1)\nGROUP BY source, destination\nHAVING bytes != 0", + "rawSql": "select SUM(reverseOctetDeltaCount) as bytes, egressNetworkPolicyName as source, ingressNetworkPolicyName as destination, ingressNetworkPolicyName as destinationIP\nFrom flows_policy_view\nWHERE $__timeFilter(flowEndSeconds)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND (egressNetworkPolicyRuleAction == 1 OR ingressNetworkPolicyRuleAction == 1)\nGROUP BY source, destination\nHAVING bytes != 0\nORDER BY bytes DESC\nLIMIT 50", "refId": "A", "round": "0s", "skip_comments": true, @@ -257,7 +257,7 @@ "query": "SELECT $timeSeries as t, SUM(throughputFromSourceNode), sourcePodName\nFROM $table\nWHERE $timeFilter \nAND flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY sourcePodName, t\nORDER BY t\n", "queryType": "sql", "rawQuery": "SELECT (intDiv(toUInt32(flowEndSeconds), 60) * 60) * 1000 as t, SUM(throughputFromSourceNode), sourcePodName\nFROM default.flows_pod_view\nWHERE flowEndSeconds >= toDateTime(1642532448) AND flowEndSeconds <= toDateTime(1642534248) \nAND flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY sourcePodName, t\nORDER BY t", - "rawSql": "SELECT $__timeInterval(flowEndSeconds) as time, CONCAT(egressNetworkPolicyName, '->', ingressNetworkPolicyName) as pair, SUM(throughput)\nFROM flows_policy_view\nWHERE $__timeFilter(flowEndSeconds) \nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator') \nAND (egressNetworkPolicyRuleAction == 1 OR ingressNetworkPolicyRuleAction == 1)\nGROUP BY time, pair\nHAVING SUM(throughput) != 0\nORDER BY time", + "rawSql": "SELECT $__timeInterval(flowEndSeconds) as time, CONCAT(egressNetworkPolicyName, '->', ingressNetworkPolicyName) as pair, SUM(throughput)\nFROM flows_policy_view\nWHERE $__timeFilter(flowEndSeconds) \nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator') \nAND (egressNetworkPolicyRuleAction == 1 OR ingressNetworkPolicyRuleAction == 1)\nGROUP BY time, pair\nHAVING SUM(throughput) != 0\nORDER BY time\nLIMIT 50", "refId": "A", "round": "0s", "skip_comments": true, @@ -385,7 +385,7 @@ "query": "SELECT $timeSeries as t, SUM(throughputFromSourceNode), sourcePodName\nFROM $table\nWHERE $timeFilter \nAND flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY sourcePodName, t\nORDER BY t\n", "queryType": "sql", "rawQuery": "SELECT (intDiv(toUInt32(flowEndSeconds), 60) * 60) * 1000 as t, SUM(throughputFromSourceNode), sourcePodName\nFROM default.flows_pod_view\nWHERE flowEndSeconds >= toDateTime(1642532448) AND flowEndSeconds <= toDateTime(1642534248) \nAND flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY sourcePodName, t\nORDER BY t", - "rawSql": "SELECT $__timeInterval(flowEndSeconds) as time, CONCAT(egressNetworkPolicyName, '->', ingressNetworkPolicyName) as pair, SUM(reverseThroughput)\nFROM flows_policy_view\nWHERE $__timeFilter(time)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND (egressNetworkPolicyRuleAction == 1 OR ingressNetworkPolicyRuleAction == 1)\nGROUP BY time, pair\nHAVING SUM(reverseThroughput) != 0\nORDER BY time", + "rawSql": "SELECT $__timeInterval(flowEndSeconds) as time, CONCAT(egressNetworkPolicyName, '->', ingressNetworkPolicyName) as pair, SUM(reverseThroughput)\nFROM flows_policy_view\nWHERE $__timeFilter(time)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND (egressNetworkPolicyRuleAction == 1 OR ingressNetworkPolicyRuleAction == 1)\nGROUP BY time, pair\nHAVING SUM(reverseThroughput) != 0\nORDER BY time\nLIMIT 50", "refId": "A", "round": "0s", "skip_comments": true, @@ -513,7 +513,7 @@ "query": "SELECT $timeSeries as t, SUM(throughputFromSourceNode), sourcePodName\nFROM $table\nWHERE $timeFilter \nAND flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY sourcePodName, t\nORDER BY t\n", "queryType": "sql", "rawQuery": "SELECT (intDiv(toUInt32(flowEndSeconds), 60) * 60) * 1000 as t, SUM(throughputFromSourceNode), sourcePodName\nFROM default.flows_pod_view\nWHERE flowEndSeconds >= toDateTime(1642532448) AND flowEndSeconds <= toDateTime(1642534248) \nAND flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY sourcePodName, t\nORDER BY t", - "rawSql": "SELECT $__timeInterval(flowEndSeconds) as time, egressNetworkPolicyName, SUM(throughput)\nFROM flows_policy_view\nWHERE sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND egressNetworkPolicyName != ''\nAND egressNetworkPolicyRuleAction == 1\nAND $__timeFilter(time)\nGROUP BY time, egressNetworkPolicyName\nHAVING SUM(throughput) != 0\nORDER BY time", + "rawSql": "SELECT $__timeInterval(flowEndSeconds) as time, egressNetworkPolicyName, SUM(throughput)\nFROM flows_policy_view\nWHERE sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND egressNetworkPolicyName != ''\nAND egressNetworkPolicyRuleAction == 1\nAND $__timeFilter(time)\nGROUP BY time, egressNetworkPolicyName\nHAVING SUM(throughput) != 0\nORDER BY time\nLIMIT 50", "refId": "A", "round": "0s", "skip_comments": true, @@ -588,6 +588,7 @@ "lastNotNull" ], "fields": "", + "limit": 25, "values": true }, "tooltip": { @@ -601,7 +602,7 @@ "uid": "PDEE91DDB90597936" }, "format": 1, - "rawSql": "SELECT SUM(octetDeltaCount), egressNetworkPolicyName\nFROM flows_policy_view\nWHERE sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND egressNetworkPolicyName != ''\nAND egressNetworkPolicyRuleAction == 1\nAND $__timeFilter(flowEndSeconds)\nGROUP BY egressNetworkPolicyName\nHAVING SUM(octetDeltaCount) != 0", + "rawSql": "SELECT SUM(octetDeltaCount) as bytes, egressNetworkPolicyName\nFROM flows_policy_view\nWHERE sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND egressNetworkPolicyName != ''\nAND egressNetworkPolicyRuleAction == 1\nAND $__timeFilter(flowEndSeconds)\nGROUP BY egressNetworkPolicyName\nHAVING SUM(octetDeltaCount) != 0\nORDER BY bytes DESC", "refId": "A" } ], @@ -706,7 +707,7 @@ "query": "SELECT $timeSeries as t, SUM(throughputFromSourceNode), sourcePodName\nFROM $table\nWHERE $timeFilter \nAND flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY sourcePodName, t\nORDER BY t\n", "queryType": "sql", "rawQuery": "SELECT (intDiv(toUInt32(flowEndSeconds), 60) * 60) * 1000 as t, SUM(throughputFromSourceNode), sourcePodName\nFROM default.flows_pod_view\nWHERE flowEndSeconds >= toDateTime(1642532448) AND flowEndSeconds <= toDateTime(1642534248) \nAND flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY sourcePodName, t\nORDER BY t", - "rawSql": "SELECT $__timeInterval(flowEndSeconds) as time, ingressNetworkPolicyName, SUM(throughput)\nFROM flows_policy_view\nWHERE sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND ingressNetworkPolicyName != ''\nAND ingressNetworkPolicyRuleAction == 1\nAND $__timeFilter(time)\nGROUP BY time, ingressNetworkPolicyName\nHAVING SUM(throughput) != 0\nORDER BY time", + "rawSql": "SELECT $__timeInterval(flowEndSeconds) as time, ingressNetworkPolicyName, SUM(throughput)\nFROM flows_policy_view\nWHERE sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND ingressNetworkPolicyName != ''\nAND ingressNetworkPolicyRuleAction == 1\nAND $__timeFilter(time)\nGROUP BY time, ingressNetworkPolicyName\nHAVING SUM(throughput) != 0\nORDER BY time\nLIMIT 50", "refId": "A", "round": "0s", "skip_comments": true, @@ -781,6 +782,7 @@ "lastNotNull" ], "fields": "", + "limit": 25, "values": true }, "tooltip": { @@ -794,7 +796,7 @@ "uid": "PDEE91DDB90597936" }, "format": 1, - "rawSql": "SELECT SUM(octetDeltaCount), ingressNetworkPolicyName\nFROM flows_policy_view\nWHERE sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND ingressNetworkPolicyName != ''\nAND ingressNetworkPolicyRuleAction == 1\nAND $__timeFilter(flowEndSeconds)\nGROUP BY ingressNetworkPolicyName\nHAVING SUM(octetDeltaCount) != 0", + "rawSql": "SELECT SUM(octetDeltaCount) as bytes, ingressNetworkPolicyName\nFROM flows_policy_view\nWHERE sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND ingressNetworkPolicyName != ''\nAND ingressNetworkPolicyRuleAction == 1\nAND $__timeFilter(flowEndSeconds)\nGROUP BY ingressNetworkPolicyName\nHAVING SUM(octetDeltaCount) != 0\nORDER BY bytes DESC", "refId": "A" } ], diff --git a/build/yamls/flow-visibility/base/provisioning/dashboards/node_to_node_dashboard.json b/build/yamls/flow-visibility/base/provisioning/dashboards/node_to_node_dashboard.json index 1f673af6ce2..33bdbf1f221 100644 --- a/build/yamls/flow-visibility/base/provisioning/dashboards/node_to_node_dashboard.json +++ b/build/yamls/flow-visibility/base/provisioning/dashboards/node_to_node_dashboard.json @@ -21,8 +21,8 @@ "editable": true, "fiscalYearStartMonth": 0, "graphTooltip": 0, - "id": 4, - "iteration": 1644612915701, + "id": 3, + "iteration": 1653419912594, "links": [], "liveNow": false, "panels": [ @@ -64,7 +64,7 @@ "query": "SELECT SUM(octetDeltaCount), (sourceNodeName, destinationNodeName) as pair\nFROM $table\nWHERE $timeFilter\nAND sourceNodeName != ''\nAND destinationNodeName != ''\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY pair\n", "queryType": "sql", "rawQuery": false, - "rawSql": "select SUM(octetDeltaCount) as bytes, sourceNodeName as source, destinationNodeName as destination\nFrom flows_node_view\nWHERE source != '' AND destination != ''\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationPodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND $__timeFilter(flowEndSeconds)\nGROUP BY source, destination", + "rawSql": "select SUM(octetDeltaCount) as bytes, sourceNodeName as source, destinationNodeName as destination\nFrom flows_node_view\nWHERE source != '' AND destination != ''\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationPodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND $__timeFilter(flowEndSeconds)\nGROUP BY source, destination\nORDER BY bytes DESC\nLIMIT 50", "refId": "A", "round": "0s", "skip_comments": true, @@ -120,7 +120,7 @@ "query": "SELECT SUM(reverseOctetDeltaCount), (sourceNodeName, destinationNodeName) as pair\nFROM $table\nWHERE $timeFilter\nAND sourceNodeName != ''\nAND destinationNodeName != ''\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY pair\n", "queryType": "randomWalk", "rawQuery": false, - "rawSql": "select SUM(reverseOctetDeltaCount) as bytes, sourceNodeName as source, destinationNodeName as destination\nFrom flows_node_view\nWHERE source != '' AND destination != ''\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND $__timeFilter(flowEndSeconds)\nGROUP BY source, destination", + "rawSql": "select SUM(reverseOctetDeltaCount) as bytes, sourceNodeName as source, destinationNodeName as destination\nFrom flows_node_view\nWHERE source != '' AND destination != ''\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND $__timeFilter(flowEndSeconds)\nGROUP BY source, destination\nORDER BY bytes DESC\nLIMIT 50", "refId": "A", "round": "0s", "skip_comments": true, @@ -229,7 +229,7 @@ "query": "SELECT $timeSeries as t, SUM(throughputFromDestinationNode), destinationNodeName\nFROM $table\nWHERE $timeFilter\nAND sourceNodeName != ''\nAND destinationNodeName != ''\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY destinationNodeName, t\nORDER BY t\n", "queryType": "sql", "rawQuery": "SELECT (intDiv(toUInt32(flowEndSecondsFromDestinationNode), 60) * 60) * 1000 as t, SUM(throughputFromDestinationNode), destinationNodeName\nFROM default.flows_node_view\nWHERE flowEndSecondsFromDestinationNode >= toDateTime(1642533454) AND flowEndSecondsFromDestinationNode <= toDateTime(1642535254)\nAND sourceNodeName != ''\nAND destinationNodeName != ''\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY destinationNodeName, t\nORDER BY t", - "rawSql": "SELECT $__timeInterval(flowEndSeconds) as time, CONCAT(sourceNodeName, '->', destinationNodeName) as pair, SUM(throughput) as Node\nFROM flows_node_view\nWHERE sourceNodeName != '' AND destinationNodeName != ''\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationPodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND $__timeFilter(time)\nGROUP BY time, pair\nORDER BY time", + "rawSql": "SELECT $__timeInterval(flowEndSeconds) as time, CONCAT(sourceNodeName, '->', destinationNodeName) as pair, SUM(throughput) as Node\nFROM flows_node_view\nWHERE sourceNodeName != '' AND destinationNodeName != ''\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationPodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND $__timeFilter(time)\nGROUP BY time, pair\nORDER BY time\nLIMIT 50", "refId": "A", "round": "0s", "skip_comments": true, @@ -357,7 +357,7 @@ "query": "SELECT $timeSeries as t, SUM(throughputFromDestinationNode), destinationNodeName\nFROM $table\nWHERE $timeFilter\nAND sourceNodeName != ''\nAND destinationNodeName != ''\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY destinationNodeName, t\nORDER BY t\n", "queryType": "randomWalk", "rawQuery": "SELECT (intDiv(toUInt32(flowEndSecondsFromDestinationNode), 60) * 60) * 1000 as t, SUM(throughputFromDestinationNode), destinationNodeName\nFROM default.flows_node_view\nWHERE flowEndSecondsFromDestinationNode >= toDateTime(1642533454) AND flowEndSecondsFromDestinationNode <= toDateTime(1642535254)\nAND sourceNodeName != ''\nAND destinationNodeName != ''\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY destinationNodeName, t\nORDER BY t", - "rawSql": "SELECT $__timeInterval(flowEndSeconds) as time, CONCAT(sourceNodeName, '->', destinationNodeName) as pair, SUM(reverseThroughput) as Node\nFROM flows_node_view\nWHERE sourceNodeName != '' AND destinationNodeName != ''\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationPodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND $__timeFilter(time)\nGROUP BY time, pair\nORDER BY time", + "rawSql": "SELECT $__timeInterval(flowEndSeconds) as time, CONCAT(sourceNodeName, '->', destinationNodeName) as pair, SUM(reverseThroughput) as Node\nFROM flows_node_view\nWHERE sourceNodeName != '' AND destinationNodeName != ''\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationPodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND $__timeFilter(time)\nGROUP BY time, pair\nORDER BY time\nLIMIT 50", "refId": "A", "round": "0s", "skip_comments": true, @@ -485,7 +485,7 @@ "query": "SELECT $timeSeries as t, SUM(throughputFromDestinationNode), destinationNodeName\nFROM $table\nWHERE $timeFilter\nAND sourceNodeName != ''\nAND destinationNodeName != ''\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY destinationNodeName, t\nORDER BY t\n", "queryType": "sql", "rawQuery": "SELECT (intDiv(toUInt32(flowEndSecondsFromDestinationNode), 60) * 60) * 1000 as t, SUM(throughputFromDestinationNode), destinationNodeName\nFROM default.flows_node_view\nWHERE flowEndSecondsFromDestinationNode >= toDateTime(1642533454) AND flowEndSecondsFromDestinationNode <= toDateTime(1642535254)\nAND sourceNodeName != ''\nAND destinationNodeName != ''\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY destinationNodeName, t\nORDER BY t", - "rawSql": "SELECT $__timeInterval(flowEndSecondsFromSourceNode) as time, sourceNodeName, SUM(throughputFromSourceNode)\nFROM flows_node_view\nWHERE sourceNodeName != '' \nAND destinationNodeName != ''\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationPodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND $__timeFilter(time)\nGROUP BY time, sourceNodeName\nORDER BY time", + "rawSql": "SELECT $__timeInterval(flowEndSecondsFromSourceNode) as time, sourceNodeName, SUM(throughputFromSourceNode)\nFROM flows_node_view\nWHERE sourceNodeName != '' \nAND destinationNodeName != ''\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationPodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND $__timeFilter(time)\nGROUP BY time, sourceNodeName\nORDER BY time\nLIMIT 50", "refId": "A", "round": "0s", "skip_comments": true, @@ -562,6 +562,7 @@ "lastNotNull" ], "fields": "", + "limit": 25, "values": true }, "tooltip": { @@ -575,7 +576,7 @@ "uid": "PDEE91DDB90597936" }, "format": 1, - "rawSql": "SELECT SUM(octetDeltaCount), sourceNodeName\nFROM flows_node_view\nWHERE sourceNodeName != '' AND destinationNodeName != ''\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationPodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND $__timeFilter(flowEndSeconds)\nGROUP BY sourceNodeName", + "rawSql": "SELECT SUM(octetDeltaCount) as bytes, sourceNodeName\nFROM flows_node_view\nWHERE sourceNodeName != '' AND destinationNodeName != ''\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationPodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND $__timeFilter(flowEndSeconds)\nGROUP BY sourceNodeName\nORDER BY bytes DESC", "refId": "A" } ], @@ -680,7 +681,7 @@ "query": "SELECT $timeSeries as t, SUM(throughputFromDestinationNode), destinationNodeName\nFROM $table\nWHERE $timeFilter\nAND sourceNodeName != ''\nAND destinationNodeName != ''\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY destinationNodeName, t\nORDER BY t\n", "queryType": "sql", "rawQuery": "SELECT (intDiv(toUInt32(flowEndSecondsFromDestinationNode), 60) * 60) * 1000 as t, SUM(throughputFromDestinationNode), destinationNodeName\nFROM default.flows_node_view\nWHERE flowEndSecondsFromDestinationNode >= toDateTime(1642533454) AND flowEndSecondsFromDestinationNode <= toDateTime(1642535254)\nAND sourceNodeName != ''\nAND destinationNodeName != ''\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY destinationNodeName, t\nORDER BY t", - "rawSql": "SELECT $__timeInterval(flowEndSecondsFromDestinationNode) as time, destinationNodeName, SUM(throughputFromDestinationNode)\nFROM flows_node_view\nWHERE sourceNodeName != '' AND destinationNodeName != ''\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationPodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND $__timeFilter(time)\nGROUP BY time, destinationNodeName\nORDER BY time", + "rawSql": "SELECT $__timeInterval(flowEndSecondsFromDestinationNode) as time, destinationNodeName, SUM(throughputFromDestinationNode)\nFROM flows_node_view\nWHERE sourceNodeName != '' AND destinationNodeName != ''\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationPodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND $__timeFilter(time)\nGROUP BY time, destinationNodeName\nORDER BY time\nLIMIT 50", "refId": "A", "round": "0s", "skip_comments": true, @@ -755,6 +756,7 @@ "lastNotNull" ], "fields": "", + "limit": 25, "values": true }, "tooltip": { @@ -768,7 +770,7 @@ "uid": "PDEE91DDB90597936" }, "format": 1, - "rawSql": "SELECT SUM(octetDeltaCount), destinationNodeName\nFROM flows_node_view\nWHERE sourceNodeName != '' AND destinationNodeName != ''\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationPodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND $__timeFilter(flowEndSeconds)\nGROUP BY destinationNodeName", + "rawSql": "SELECT SUM(octetDeltaCount) as bytes, destinationNodeName\nFROM flows_node_view\nWHERE sourceNodeName != '' AND destinationNodeName != ''\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationPodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND $__timeFilter(flowEndSeconds)\nGROUP BY destinationNodeName\nORDER BY bytes DESC", "refId": "A" } ], @@ -811,6 +813,6 @@ "timezone": "", "title": "node_to_node_dashboard", "uid": "1F56RJh7z", - "version": 10, + "version": 5, "weekStart": "" } \ No newline at end of file diff --git a/build/yamls/flow-visibility/base/provisioning/dashboards/pod_to_external_dashboard.json b/build/yamls/flow-visibility/base/provisioning/dashboards/pod_to_external_dashboard.json index aba49c31421..3c8863d918b 100644 --- a/build/yamls/flow-visibility/base/provisioning/dashboards/pod_to_external_dashboard.json +++ b/build/yamls/flow-visibility/base/provisioning/dashboards/pod_to_external_dashboard.json @@ -21,8 +21,8 @@ "editable": true, "fiscalYearStartMonth": 0, "graphTooltip": 0, - "id": 5, - "iteration": 1644612843565, + "id": 4, + "iteration": 1653419876105, "links": [], "liveNow": false, "panels": [ @@ -63,7 +63,7 @@ "query": "SELECT SUM(octetDeltaCount), (sourcePodName, destinationIP) AS pair\nFROM $table\nWHERE $timeFilter\nAND flowType == 3\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-aggregator', 'flow-visibility')\nGROUP BY pair\n", "queryType": "randomWalk", "rawQuery": "SELECT SUM(octetDeltaCount), (sourcePodName, destinationIP) AS pair\nFROM default.flows_pod_view\nWHERE flowEndSeconds >= toDateTime(1642534343) AND flowEndSeconds <= toDateTime(1642536143)\nAND flowType == 3\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-aggregator', 'flow-visibility')\nGROUP BY pair", - "rawSql": "select SUM(octetDeltaCount) as bytes, sourcePodName as source, destinationIP as destination\nFrom flows_pod_view\nWHERE flowType == 3\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND $__timeFilter(flowEndSeconds)\nGROUP BY source, destination\nHAVING bytes != 0", + "rawSql": "select SUM(octetDeltaCount) as bytes, sourcePodName as source, destinationIP as destination\nFrom flows_pod_view\nWHERE flowType == 3\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND $__timeFilter(flowEndSeconds)\nGROUP BY source, destination\nHAVING bytes != 0\nORDER BY bytes DESC\nLIMIT 50", "refId": "A", "round": "0s", "skip_comments": true, @@ -112,7 +112,7 @@ "query": "SELECT SUM(reverseOctetDeltaCount), (sourcePodName, destinationIP) AS pair\nFROM $table\nWHERE $timeFilter\nAND flowType == 3\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-aggregator', 'flow-visibility')\nGROUP BY pair\n", "queryType": "randomWalk", "rawQuery": "SELECT SUM(reverseOctetDeltaCount), (sourcePodName, destinationIP) AS pair\nFROM default.flows_pod_view\nWHERE flowEndSeconds >= toDateTime(1642534382) AND flowEndSeconds <= toDateTime(1642536182)\nAND flowType == 3\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-aggregator', 'flow-visibility')\nGROUP BY pair", - "rawSql": "select SUM(reverseOctetDeltaCount) as bytes, sourcePodName as source, destinationIP as destination\nFrom flows_pod_view\nWHERE flowType == 3\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND $__timeFilter(flowEndSeconds)\nGROUP BY source, destination\nHAVING bytes != 0", + "rawSql": "select SUM(reverseOctetDeltaCount) as bytes, sourcePodName as source, destinationIP as destination\nFrom flows_pod_view\nWHERE flowType == 3\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND $__timeFilter(flowEndSeconds)\nGROUP BY source, destination\nHAVING bytes != 0\nORDER BY bytes DESC\nLIMIT 50", "refId": "A", "round": "0s", "skip_comments": true, @@ -186,7 +186,7 @@ "y": 18 }, "id": 2, - "interval": "60s", + "interval": "1s", "options": { "legend": { "calcs": [ @@ -220,7 +220,7 @@ "query": "SELECT $timeSeries as t, SUM(octetDeltaCount), (sourcePodName, destinationIP) as pair\nFROM $table\nWHERE $timeFilter\nAND flowType == 3\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY pair,t\nORDER BY t\n", "queryType": "sql", "rawQuery": "SELECT (intDiv(toUInt32(flowEndSeconds), 60) * 60) * 1000 as t, SUM(octetDeltaCount), (sourcePodName, destinationIP) as pair\nFROM default.flows_pod_view\nWHERE flowEndSeconds >= toDateTime(1642534150) AND flowEndSeconds <= toDateTime(1642535950)\nAND flowType == 3\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY pair,t\nORDER BY t", - "rawSql": "SELECT $__timeInterval(flowEndSeconds) as time, CONCAT(sourcePodName, '->', destinationIP) as pair, SUM(throughput)\nFROM flows_pod_view\nWHERE flowType == 3\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND $__timeFilter(time)\nGROUP BY time, pair\nHAVING SUM(throughput) != 0\nORDER BY time", + "rawSql": "SELECT $__timeInterval(flowEndSeconds) as time, CONCAT(sourcePodName, '->', destinationIP) as pair, AVG(throughput)\nFROM flows_pod_view\nWHERE flowType == 3\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND $__timeFilter(time)\nGROUP BY time, pair\nHAVING SUM(throughput) != 0\nORDER BY time\nLIMIT 50", "refId": "A", "round": "0s", "skip_comments": true, @@ -310,7 +310,7 @@ "y": 18 }, "id": 7, - "interval": "60s", + "interval": "1s", "options": { "legend": { "calcs": [ @@ -344,7 +344,7 @@ "query": "SELECT $timeSeries as t, SUM(reverseOctetDeltaCount), (sourcePodName, destinationIP) as pair\nFROM $table\nWHERE $timeFilter\nAND flowType == 3\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY pair, t\nORDER BY t", "queryType": "sql", "rawQuery": "SELECT (intDiv(toUInt32(flowEndSeconds), 60) * 60) * 1000 as t, SUM(reverseOctetDeltaCount), (sourcePodName, destinationIP) as pair\nFROM default.flows_pod_view\nWHERE flowEndSeconds >= toDateTime(1642534246) AND flowEndSeconds <= toDateTime(1642536046)\nAND flowType == 3\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY pair, t\nORDER BY t", - "rawSql": "SELECT $__timeInterval(flowEndSeconds) as time, CONCAT(sourcePodName, '->', destinationIP) as pair, SUM(reverseThroughput)\nFROM flows_pod_view\nWHERE flowType == 3\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND $__timeFilter(time)\nGROUP BY time, pair\nHAVING SUM(reverseThroughput) != 0\nORDER BY time", + "rawSql": "SELECT $__timeInterval(flowEndSeconds) as time, CONCAT(sourcePodName, '->', destinationIP) as pair, AVG(reverseThroughput)\nFROM flows_pod_view\nWHERE flowType == 3\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND $__timeFilter(time)\nGROUP BY time, pair\nHAVING SUM(reverseThroughput) != 0\nORDER BY time\nLIMIT 50", "refId": "A", "round": "0s", "skip_comments": true, @@ -410,6 +410,6 @@ "timezone": "", "title": "pod_to_external_dashboard", "uid": "K9SPrnJ7k", - "version": 3, + "version": 5, "weekStart": "" } \ No newline at end of file diff --git a/build/yamls/flow-visibility/base/provisioning/dashboards/pod_to_pod_dashboard.json b/build/yamls/flow-visibility/base/provisioning/dashboards/pod_to_pod_dashboard.json index fb72c30f08b..cc1ac1074a1 100644 --- a/build/yamls/flow-visibility/base/provisioning/dashboards/pod_to_pod_dashboard.json +++ b/build/yamls/flow-visibility/base/provisioning/dashboards/pod_to_pod_dashboard.json @@ -21,8 +21,8 @@ "editable": true, "fiscalYearStartMonth": 0, "graphTooltip": 0, - "id": 1, - "iteration": 1644971511247, + "id": 5, + "iteration": 1653419724493, "links": [], "liveNow": false, "panels": [ @@ -63,7 +63,7 @@ "query": "SELECT SUM(octetDeltaCount), (sourcePodName, destinationPodName, destinationIP) AS pair\nFROM $table\nWHERE $timeFilter\nAND flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY pair\n", "queryType": "sql", "rawQuery": "SELECT SUM(octetDeltaCount), (sourcePodName, destinationPodName, destinationIP) AS pair\nFROM default.flows_pod_view\nWHERE flowEndSeconds >= toDateTime(1642531723) AND flowEndSeconds <= toDateTime(1642533523)\nAND flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY pair", - "rawSql": "select SUM(octetDeltaCount) as bytes, sourcePodName as source, destinationPodName as destination, destinationIP\nFrom flows_pod_view\nWHERE flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationPodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND $__timeFilter(flowEndSeconds)\nGROUP BY source, destination, destinationIP", + "rawSql": "select SUM(octetDeltaCount) as bytes, sourcePodName as source, destinationPodName as destination, destinationIP\nFrom flows_pod_view\nWHERE flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationPodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND $__timeFilter(flowEndSeconds)\nGROUP BY source, destination, destinationIP\nORDER BY bytes DESC\nLIMIT 50", "refId": "A", "round": "0s", "skip_comments": true, @@ -112,7 +112,7 @@ "query": "SELECT SUM(reverseOctetDeltaCount), (sourcePodName, destinationPodName, destinationIP) AS pair\nFROM $table\nWHERE $timeFilter\nAND flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY pair\n", "queryType": "randomWalk", "rawQuery": "SELECT SUM(reverseOctetDeltaCount), (sourcePodName, destinationPodName, destinationIP) AS pair\nFROM default.flows_pod_view\nWHERE flowEndSeconds >= toDateTime(1642531743) AND flowEndSeconds <= toDateTime(1642533543)\nAND flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY pair", - "rawSql": "select SUM(reverseOctetDeltaCount) as bytes, sourcePodName as source, destinationPodName as destination, destinationIP\nFrom flows_pod_view\nWHERE flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationPodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND $__timeFilter(flowEndSeconds)\nGROUP BY source, destination, destinationIP", + "rawSql": "select SUM(reverseOctetDeltaCount) as bytes, sourcePodName as source, destinationPodName as destination, destinationIP\nFrom flows_pod_view\nWHERE flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationPodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND $__timeFilter(flowEndSeconds)\nGROUP BY source, destination, destinationIP\nORDER BY bytes DESC\nLIMIT 50", "refId": "A", "round": "0s", "skip_comments": true, @@ -169,10 +169,6 @@ { "color": "green", "value": null - }, - { - "color": "red", - "value": 80 } ] }, @@ -187,7 +183,7 @@ "y": 18 }, "id": 21, - "interval": "60s", + "interval": "1s", "options": { "legend": { "calcs": [ @@ -221,7 +217,7 @@ "query": "SELECT $timeSeries as t, SUM(throughputFromSourceNode), sourcePodName\nFROM $table\nWHERE $timeFilter \nAND flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY sourcePodName, t\nORDER BY t\n", "queryType": "sql", "rawQuery": "SELECT (intDiv(toUInt32(flowEndSeconds), 60) * 60) * 1000 as t, SUM(throughputFromSourceNode), sourcePodName\nFROM default.flows_pod_view\nWHERE flowEndSeconds >= toDateTime(1642532448) AND flowEndSeconds <= toDateTime(1642534248) \nAND flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY sourcePodName, t\nORDER BY t", - "rawSql": "SELECT $__timeInterval(flowEndSeconds) as time, CONCAT(sourcePodName, '->', destinationPodName) as pair, SUM(throughput)\nFROM flows_pod_view\nWHERE flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationPodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND $__timeFilter(time)\nGROUP BY time, pair\nHAVING SUM(throughput) > 0\nORDER BY time", + "rawSql": "SELECT $__timeInterval(flowEndSeconds) as time, CONCAT(sourcePodName, '->', destinationPodName) as pair, AVG(throughput)\nFROM flows_pod_view\nWHERE flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationPodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND $__timeFilter(time)\nGROUP BY time, pair\nHAVING SUM(throughput) > 0\nORDER BY time\nLIMIT 50", "refId": "A", "round": "0s", "skip_comments": true, @@ -315,7 +311,7 @@ "y": 18 }, "id": 22, - "interval": "60s", + "interval": "1s", "options": { "legend": { "calcs": [ @@ -349,7 +345,7 @@ "query": "SELECT $timeSeries as t, SUM(throughputFromSourceNode), sourcePodName\nFROM $table\nWHERE $timeFilter \nAND flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY sourcePodName, t\nORDER BY t\n", "queryType": "sql", "rawQuery": "SELECT (intDiv(toUInt32(flowEndSeconds), 60) * 60) * 1000 as t, SUM(throughputFromSourceNode), sourcePodName\nFROM default.flows_pod_view\nWHERE flowEndSeconds >= toDateTime(1642532448) AND flowEndSeconds <= toDateTime(1642534248) \nAND flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY sourcePodName, t\nORDER BY t", - "rawSql": "SELECT $__timeInterval(flowEndSeconds) as time, CONCAT(sourcePodName, '->', destinationPodName) as pair, SUM(reverseThroughput)\nFROM flows_pod_view\nWHERE flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationPodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND $__timeFilter(time)\nGROUP BY time, pair\nHAVING SUM(reverseThroughput) > 0\nORDER BY time", + "rawSql": "SELECT $__timeInterval(flowEndSeconds) as time, CONCAT(sourcePodName, '->', destinationPodName) as pair, AVG(reverseThroughput)\nFROM flows_pod_view\nWHERE flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationPodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND $__timeFilter(time)\nGROUP BY time, pair\nHAVING SUM(reverseThroughput) > 0\nORDER BY time\nLIMIT 50", "refId": "A", "round": "0s", "skip_comments": true, @@ -425,10 +421,6 @@ { "color": "green", "value": null - }, - { - "color": "red", - "value": 80 } ] }, @@ -477,7 +469,7 @@ "query": "SELECT $timeSeries as t, SUM(throughputFromSourceNode), sourcePodName\nFROM $table\nWHERE $timeFilter \nAND flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY sourcePodName, t\nORDER BY t\n", "queryType": "sql", "rawQuery": "SELECT (intDiv(toUInt32(flowEndSeconds), 60) * 60) * 1000 as t, SUM(throughputFromSourceNode), sourcePodName\nFROM default.flows_pod_view\nWHERE flowEndSeconds >= toDateTime(1642532448) AND flowEndSeconds <= toDateTime(1642534248) \nAND flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY sourcePodName, t\nORDER BY t", - "rawSql": "SELECT $__timeInterval(flowEndSecondsFromSourceNode) as time, sourcePodName, SUM(throughputFromSourceNode)\nFROM flows_pod_view\nWHERE flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationPodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND $__timeFilter(time)\nGROUP BY time, sourcePodName\nHAVING SUM(throughputFromSourceNode) > 0\nORDER BY time", + "rawSql": "SELECT $__timeInterval(flowEndSecondsFromSourceNode) as time, sourcePodName, SUM(throughputFromSourceNode)\nFROM flows_pod_view\nWHERE flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationPodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND $__timeFilter(time)\nGROUP BY time, sourcePodName\nHAVING SUM(throughputFromSourceNode) > 0\nORDER BY time\nLIMIT 50", "refId": "A", "round": "0s", "skip_comments": true, @@ -552,6 +544,7 @@ "lastNotNull" ], "fields": "", + "limit": 25, "values": true }, "tooltip": { @@ -566,7 +559,7 @@ }, "format": 1, "queryType": "sql", - "rawSql": "select SUM(octetDeltaCount) as bytes, sourcePodNamespace\nFrom flows_pod_view\nWHERE flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationPodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND $__timeFilter(flowEndSeconds)\nGROUP BY sourcePodNamespace\nHAVING bytes > 0", + "rawSql": "select SUM(octetDeltaCount) as bytes, sourcePodNamespace\nFrom flows_pod_view\nWHERE flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationPodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND $__timeFilter(flowEndSeconds)\nGROUP BY sourcePodNamespace\nHAVING bytes > 0\nORDER BY bytes DESC", "refId": "A" } ], @@ -671,7 +664,7 @@ "query": "SELECT $timeSeries as t, SUM(throughputFromDestinationNode), destinationPodName\nFROM $table\nWHERE $timeFilter \nAND flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY destinationPodName, t\nORDER BY t\n", "queryType": "sql", "rawQuery": "SELECT (intDiv(toUInt32(flowEndSecondsFromDestinationNode), 60) * 60) * 1000 as t, SUM(throughputFromDestinationNode), destinationPodName\nFROM default.flows_pod_view\nWHERE flowEndSecondsFromDestinationNode >= toDateTime(1642532702) AND flowEndSecondsFromDestinationNode <= toDateTime(1642534502) \nAND flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY destinationPodName, t\nORDER BY t", - "rawSql": "SELECT $__timeInterval(flowEndSecondsFromDestinationNode) as time, destinationPodName, SUM(throughputFromDestinationNode)\nFROM flows_pod_view\nWHERE flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationPodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND $__timeFilter(time)\nGROUP BY time, destinationPodName\nHAVING SUM(throughputFromDestinationNode) > 0\nORDER BY time", + "rawSql": "SELECT $__timeInterval(flowEndSecondsFromDestinationNode) as time, destinationPodName, SUM(throughputFromDestinationNode)\nFROM flows_pod_view\nWHERE flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationPodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND $__timeFilter(time)\nGROUP BY time, destinationPodName\nHAVING SUM(throughputFromDestinationNode) > 0\nORDER BY time\nLIMIT 50", "refId": "A", "round": "0s", "skip_comments": true, @@ -759,6 +752,7 @@ "lastNotNull" ], "fields": "", + "limit": 25, "values": true }, "tooltip": { @@ -772,7 +766,7 @@ "uid": "PDEE91DDB90597936" }, "format": 1, - "rawSql": "select SUM(octetDeltaCount) as bytes, destinationPodNamespace\nFrom flows_pod_view\nWHERE flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationPodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND $__timeFilter(flowEndSeconds)\nGROUP BY destinationPodNamespace", + "rawSql": "select SUM(octetDeltaCount) as bytes, destinationPodNamespace\nFrom flows_pod_view\nWHERE flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationPodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND $__timeFilter(flowEndSeconds)\nGROUP BY destinationPodNamespace\nORDER BY bytes DESC", "refId": "A" } ], @@ -815,6 +809,6 @@ "timezone": "", "title": "pod_to_pod_dashboard", "uid": "Yxn0Ghh7k", - "version": 9, + "version": 5, "weekStart": "" } \ No newline at end of file diff --git a/build/yamls/flow-visibility/base/provisioning/dashboards/pod_to_service_dashboard.json b/build/yamls/flow-visibility/base/provisioning/dashboards/pod_to_service_dashboard.json index 6489542c76f..69e8bbd9e38 100644 --- a/build/yamls/flow-visibility/base/provisioning/dashboards/pod_to_service_dashboard.json +++ b/build/yamls/flow-visibility/base/provisioning/dashboards/pod_to_service_dashboard.json @@ -21,8 +21,8 @@ "editable": true, "fiscalYearStartMonth": 0, "graphTooltip": 0, - "id": 1, - "iteration": 1644612951629, + "id": 6, + "iteration": 1653420001321, "links": [], "liveNow": false, "panels": [ @@ -63,7 +63,7 @@ "query": "SELECT SUM(octetDeltaCount), (sourcePodName, destinationServicePortName) AS pair\nFROM $table\nWHERE $timeFilter\nAND destinationServicePortName != ''\nAND flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY pair\n", "queryType": "randomWalk", "rawQuery": "SELECT SUM(octetDeltaCount), (sourcePodName, destinationServicePortName) AS pair\nFROM default.flows_pod_view\nWHERE flowEndSeconds >= toDateTime(1642193285) AND flowEndSeconds <= toDateTime(1642195085)\nAND destinationServicePortName != ''\nAND flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY pair", - "rawSql": "select SUM(octetDeltaCount) as bytes, sourcePodName as source, destinationServicePortName as destination\nFrom flows_pod_view\nWHERE flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationPodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationServicePortName != ''\nAND $__timeFilter(flowEndSeconds)\nGROUP BY source, destination", + "rawSql": "select SUM(octetDeltaCount) as bytes, sourcePodName as source, destinationServicePortName as destination\nFrom flows_pod_view\nWHERE flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationPodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationServicePortName != ''\nAND $__timeFilter(flowEndSeconds)\nGROUP BY source, destination\nORDER BY bytes DESC\nLIMIT 50", "refId": "A", "round": "0s", "skip_comments": true, @@ -112,7 +112,7 @@ "query": "SELECT SUM(reverseOctetDeltaCount), (sourcePodName, destinationServicePortName) AS pair\nFROM $table\nWHERE $timeFilter\nAND destinationServicePortName != ''\nAND flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY pair\n", "queryType": "randomWalk", "rawQuery": "SELECT SUM(reverseOctetDeltaCount), (sourcePodName, destinationServicePortName) AS pair\nFROM default.flows_pod_view\nWHERE flowEndSeconds >= toDateTime(1642193431) AND flowEndSeconds <= toDateTime(1642195231)\nAND destinationServicePortName != ''\nAND flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY pair", - "rawSql": "select SUM(reverseOctetDeltaCount) as bytes, sourcePodName as source, destinationServicePortName as destination\nFrom flows_pod_view\nWHERE flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationPodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationServicePortName != ''\nAND $__timeFilter(flowEndSeconds)\nGROUP BY source, destination", + "rawSql": "select SUM(reverseOctetDeltaCount) as bytes, sourcePodName as source, destinationServicePortName as destination\nFrom flows_pod_view\nWHERE flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationPodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationServicePortName != ''\nAND $__timeFilter(flowEndSeconds)\nGROUP BY source, destination\nORDER BY bytes DESC\nLIMIT 50", "refId": "A", "round": "0s", "skip_comments": true, @@ -187,7 +187,7 @@ "y": 18 }, "id": 18, - "interval": "60s", + "interval": "1s", "options": { "legend": { "calcs": [ @@ -221,7 +221,7 @@ "query": "SELECT $timeSeries as t, SUM(throughputFromSourceNode), sourcePodName\nFROM $table\nWHERE $timeFilter \nAND flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY sourcePodName, t\nORDER BY t\n", "queryType": "sql", "rawQuery": "SELECT (intDiv(toUInt32(flowEndSeconds), 60) * 60) * 1000 as t, SUM(throughputFromSourceNode), sourcePodName\nFROM default.flows_pod_view\nWHERE flowEndSeconds >= toDateTime(1642532448) AND flowEndSeconds <= toDateTime(1642534248) \nAND flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY sourcePodName, t\nORDER BY t", - "rawSql": "SELECT $__timeInterval(flowEndSeconds) as time, CONCAT(sourcePodName, '->', destinationServicePortName) as pair, SUM(throughput) as Pod\nFROM flows_pod_view\nWHERE flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationPodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationServicePortName != ''\nAND $__timeFilter(flowEndSeconds)\nGROUP BY time, pair\nORDER BY time", + "rawSql": "SELECT $__timeInterval(flowEndSeconds) as time, CONCAT(sourcePodName, '->', destinationServicePortName) as pair, AVG(throughput)\nFROM flows_pod_view\nWHERE flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationPodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationServicePortName != ''\nAND $__timeFilter(flowEndSeconds)\nGROUP BY time, pair\nORDER BY time\nLIMIT 50", "refId": "A", "round": "0s", "skip_comments": true, @@ -315,7 +315,7 @@ "y": 18 }, "id": 19, - "interval": "60s", + "interval": "1s", "options": { "legend": { "calcs": [ @@ -349,7 +349,7 @@ "query": "SELECT $timeSeries as t, SUM(throughputFromSourceNode), sourcePodName\nFROM $table\nWHERE $timeFilter \nAND flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY sourcePodName, t\nORDER BY t\n", "queryType": "sql", "rawQuery": "SELECT (intDiv(toUInt32(flowEndSeconds), 60) * 60) * 1000 as t, SUM(throughputFromSourceNode), sourcePodName\nFROM default.flows_pod_view\nWHERE flowEndSeconds >= toDateTime(1642532448) AND flowEndSeconds <= toDateTime(1642534248) \nAND flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY sourcePodName, t\nORDER BY t", - "rawSql": "SELECT $__timeInterval(flowEndSeconds) as time, CONCAT(sourcePodName, '->', destinationServicePortName) as pair, SUM(reverseThroughput) as Pod\nFROM flows_pod_view\nWHERE flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationPodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationServicePortName != ''\nAND $__timeFilter(time)\nGROUP BY time, pair\nORDER BY time", + "rawSql": "SELECT $__timeInterval(flowEndSeconds) as time, CONCAT(sourcePodName, '->', destinationServicePortName) as pair, AVG(reverseThroughput)\nFROM flows_pod_view\nWHERE flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationPodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationServicePortName != ''\nAND $__timeFilter(time)\nGROUP BY time, pair\nORDER BY time\nLIMIT 50", "refId": "A", "round": "0s", "skip_comments": true, @@ -477,7 +477,7 @@ "query": "SELECT $timeSeries as t, SUM(throughputFromSourceNode), sourcePodName\nFROM $table\nWHERE $timeFilter \nAND flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY sourcePodName, t\nORDER BY t\n", "queryType": "sql", "rawQuery": "SELECT (intDiv(toUInt32(flowEndSeconds), 60) * 60) * 1000 as t, SUM(throughputFromSourceNode), sourcePodName\nFROM default.flows_pod_view\nWHERE flowEndSeconds >= toDateTime(1642532448) AND flowEndSeconds <= toDateTime(1642534248) \nAND flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY sourcePodName, t\nORDER BY t", - "rawSql": "SELECT $__timeInterval(flowEndSecondsFromSourceNode) as time, sourcePodName, SUM(throughputFromSourceNode) as Pod\nFROM flows_pod_view\nWHERE flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationPodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationServicePortName != ''\nAND $__timeFilter(time)\nGROUP BY time, sourcePodName\nORDER BY time", + "rawSql": "SELECT $__timeInterval(flowEndSecondsFromSourceNode) as time, sourcePodName, SUM(throughputFromSourceNode) as Pod\nFROM flows_pod_view\nWHERE flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationPodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationServicePortName != ''\nAND $__timeFilter(time)\nGROUP BY time, sourcePodName\nORDER BY time\nLIMIT 50", "refId": "A", "round": "0s", "skip_comments": true, @@ -605,7 +605,7 @@ "query": "SELECT $timeSeries as t, SUM(throughputFromSourceNode), sourcePodName\nFROM $table\nWHERE $timeFilter \nAND flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY sourcePodName, t\nORDER BY t\n", "queryType": "sql", "rawQuery": "SELECT (intDiv(toUInt32(flowEndSeconds), 60) * 60) * 1000 as t, SUM(throughputFromSourceNode), sourcePodName\nFROM default.flows_pod_view\nWHERE flowEndSeconds >= toDateTime(1642532448) AND flowEndSeconds <= toDateTime(1642534248) \nAND flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nGROUP BY sourcePodName, t\nORDER BY t", - "rawSql": "SELECT $__timeInterval(flowEndSecondsFromDestinationNode) as time, destinationServicePortName, SUM(throughputFromDestinationNode) as Service\nFROM flows_pod_view\nWHERE flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationPodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationServicePortName != ''\nAND $__timeFilter(time)\nGROUP BY time, destinationServicePortName\nORDER BY time", + "rawSql": "SELECT $__timeInterval(flowEndSecondsFromDestinationNode) as time, destinationServicePortName, SUM(throughputFromDestinationNode) as Service\nFROM flows_pod_view\nWHERE flowType IN (1, 2)\nAND sourcePodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationPodNamespace NOT IN ('kube-system', 'flow-visibility', 'flow-aggregator')\nAND destinationServicePortName != ''\nAND $__timeFilter(time)\nGROUP BY time, destinationServicePortName\nORDER BY time\nLIMIT 50", "refId": "A", "round": "0s", "skip_comments": true, @@ -671,6 +671,6 @@ "timezone": "", "title": "pod_to_service_dashboard", "uid": "LGdxbW17z", - "version": 8, + "version": 5, "weekStart": "" } \ No newline at end of file diff --git a/build/yamls/flow-visibility/base/provisioning/datasources/create_table.sh b/build/yamls/flow-visibility/base/provisioning/datasources/create_table.sh index 9f135579460..423fa45d00d 100644 --- a/build/yamls/flow-visibility/base/provisioning/datasources/create_table.sh +++ b/build/yamls/flow-visibility/base/provisioning/datasources/create_table.sh @@ -72,7 +72,7 @@ clickhouse client -n -h 127.0.0.1 <<-EOSQL TTL timeInserted + INTERVAL 1 HOUR SETTINGS merge_with_ttl_timeout = 3600; - CREATE MATERIALIZED VIEW flows_pod_view + CREATE MATERIALIZED VIEW IF NOT EXISTS flows_pod_view ENGINE = SummingMergeTree ORDER BY ( timeInserted, @@ -121,7 +121,7 @@ clickhouse client -n -h 127.0.0.1 <<-EOSQL sourcePodNamespace, destinationPodNamespace; - CREATE MATERIALIZED VIEW flows_node_view + CREATE MATERIALIZED VIEW IF NOT EXISTS flows_node_view ENGINE = SummingMergeTree ORDER BY ( timeInserted, @@ -163,7 +163,7 @@ clickhouse client -n -h 127.0.0.1 <<-EOSQL sourcePodNamespace, destinationPodNamespace; - CREATE MATERIALIZED VIEW flows_policy_view + CREATE MATERIALIZED VIEW IF NOT EXISTS flows_policy_view ENGINE = SummingMergeTree ORDER BY ( timeInserted, diff --git a/build/yamls/flow-visibility/patches/chmonitor/chMonitor.yml b/build/yamls/flow-visibility/patches/chmonitor/chMonitor.yml new file mode 100644 index 00000000000..68abcc0bb8a --- /dev/null +++ b/build/yamls/flow-visibility/patches/chmonitor/chMonitor.yml @@ -0,0 +1,24 @@ +- op: add + path: /spec/templates/podTemplates/0/spec/containers/- + value: + name: clickhouse-monitor + image: flow-visibility-clickhouse-monitor + env: + - name: CLICKHOUSE_USERNAME + valueFrom: + secretKeyRef: + name: clickhouse-secret + key: username + - name: CLICKHOUSE_PASSWORD + valueFrom: + secretKeyRef: + name: clickhouse-secret + key: password + - name: DB_URL + value: "tcp://localhost:9000" + - name: TABLE_NAME + value: "default.flows" + - name: MV_NAMES + value: "default.flows_pod_view default.flows_node_view default.flows_policy_view" + - name: STORAGE_SIZE + value: STORAGE_SIZE_VALUE diff --git a/build/yamls/flow-visibility/patches/e2e/imagePullPolicyClickhouse.yml b/build/yamls/flow-visibility/patches/e2e/imagePullPolicyClickhouse.yml new file mode 100644 index 00000000000..b49e451783f --- /dev/null +++ b/build/yamls/flow-visibility/patches/e2e/imagePullPolicyClickhouse.yml @@ -0,0 +1,3 @@ +- op: add + path: /spec/templates/podTemplates/0/spec/containers/0/imagePullPolicy + value: IfNotPresent diff --git a/build/yamls/flow-visibility/patches/pv/createLocalPv.yml b/build/yamls/flow-visibility/patches/pv/createLocalPv.yml new file mode 100644 index 00000000000..bda1ac4e3e2 --- /dev/null +++ b/build/yamls/flow-visibility/patches/pv/createLocalPv.yml @@ -0,0 +1,28 @@ +apiVersion: storage.k8s.io/v1 +kind: StorageClass +metadata: + name: clickhouse-storage +provisioner: kubernetes.io/no-provisioner +volumeBindingMode: WaitForFirstConsumer +reclaimPolicy: Retain +allowVolumeExpansion: True +--- +apiVersion: v1 +kind: PersistentVolume +metadata: + name: clickhouse-pv +spec: + storageClassName: clickhouse-storage + capacity: + storage: STORAGE_SIZE + accessModes: + - ReadWriteOnce + volumeMode: Filesystem + local: + path: LOCAL_PATH + nodeAffinity: + required: + nodeSelectorTerms: + - matchExpressions: + - key: antrea.io/clickhouse-data-node + operator: Exists diff --git a/build/yamls/flow-visibility/patches/pv/createNfsPv.yml b/build/yamls/flow-visibility/patches/pv/createNfsPv.yml new file mode 100644 index 00000000000..2cef3949aae --- /dev/null +++ b/build/yamls/flow-visibility/patches/pv/createNfsPv.yml @@ -0,0 +1,23 @@ +apiVersion: storage.k8s.io/v1 +kind: StorageClass +metadata: + name: clickhouse-storage +provisioner: kubernetes.io/no-provisioner +volumeBindingMode: WaitForFirstConsumer +reclaimPolicy: Retain +allowVolumeExpansion: True +--- +apiVersion: v1 +kind: PersistentVolume +metadata: + name: clickhouse-pv +spec: + storageClassName: clickhouse-storage + capacity: + storage: STORAGE_SIZE + accessModes: + - ReadWriteOnce + volumeMode: Filesystem + nfs: + path: NFS_SERVER_PATH + server: NFS_SERVER_ADDRESS diff --git a/build/yamls/flow-visibility/patches/pv/mountPv.yml b/build/yamls/flow-visibility/patches/pv/mountPv.yml new file mode 100644 index 00000000000..c3d4d898bb4 --- /dev/null +++ b/build/yamls/flow-visibility/patches/pv/mountPv.yml @@ -0,0 +1,14 @@ +- op: add + path: /spec/defaults/templates/dataVolumeClaimTemplate + value: clickhouse-storage-template +- op: add + path: /spec/templates/volumeClaimTemplates + value: + - name: clickhouse-storage-template + spec: + storageClassName: STORAGECLASS_NAME + accessModes: + - ReadWriteOnce + resources: + requests: + storage: STORAGE_SIZE diff --git a/build/yamls/flow-visibility/patches/ram/mountRam.yml b/build/yamls/flow-visibility/patches/ram/mountRam.yml new file mode 100644 index 00000000000..541136de993 --- /dev/null +++ b/build/yamls/flow-visibility/patches/ram/mountRam.yml @@ -0,0 +1,12 @@ +- op: add + path: /spec/templates/podTemplates/0/spec/volumes/- + value: + name: clickhouse-storage-volume + emptyDir: + medium: Memory + sizeLimit: STORAGE_SIZE +- op: add + path: /spec/templates/podTemplates/0/spec/containers/0/volumeMounts/- + value: + name: clickhouse-storage-volume + mountPath: /var/lib/clickhouse diff --git a/build/yamls/patches/chaining/installCni.yml b/build/yamls/patches/chaining/installCni.yml deleted file mode 100644 index 5e353352a19..00000000000 --- a/build/yamls/patches/chaining/installCni.yml +++ /dev/null @@ -1,15 +0,0 @@ -apiVersion: apps/v1 -kind: DaemonSet -metadata: - name: antrea-agent -spec: - template: - spec: - initContainers: - - name: install-cni - command: ["install_cni_chaining"] - securityContext: - capabilities: - add: - # SYS_MODULE is required to load the OVS kernel module. - - SYS_MODULE diff --git a/build/yamls/patches/coverage/startAgentCov.yml b/build/yamls/patches/coverage/startAgentCov.yml deleted file mode 100644 index 39812362b57..00000000000 --- a/build/yamls/patches/coverage/startAgentCov.yml +++ /dev/null @@ -1,14 +0,0 @@ -apiVersion: apps/v1 -kind: DaemonSet -metadata: - name: antrea-agent -spec: - template: - spec: - initContainers: - - name: install-cni - image: antrea/antrea-ubuntu-coverage:latest - containers: - - name: antrea-agent - command: ["/bin/sh"] - args: ["-c", "sleep 2; antrea-agent-coverage -test.run=TestBincoverRunMain -test.coverprofile=antrea-agent.cov.out -args-file=/agent-arg-file; while true; do sleep 5 & wait $!; done"] diff --git a/build/yamls/patches/coverage/startControllerCov.yml b/build/yamls/patches/coverage/startControllerCov.yml deleted file mode 100644 index 8e1f187d60e..00000000000 --- a/build/yamls/patches/coverage/startControllerCov.yml +++ /dev/null @@ -1,11 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: antrea-controller -spec: - template: - spec: - containers: - - command: ["/bin/sh"] - args: ["-c", "antrea-controller-coverage -test.run=TestBincoverRunMain -test.coverprofile=antrea-controller.cov.out -args-file=/controller-arg-file; while true; do sleep 5 & wait $!; done"] - name: antrea-controller diff --git a/build/yamls/patches/dev/agentImagePullPolicy.yml b/build/yamls/patches/dev/agentImagePullPolicy.yml deleted file mode 100644 index 51bf1ea8d98..00000000000 --- a/build/yamls/patches/dev/agentImagePullPolicy.yml +++ /dev/null @@ -1,15 +0,0 @@ -apiVersion: apps/v1 -kind: DaemonSet -metadata: - name: antrea-agent -spec: - template: - spec: - containers: - - name: antrea-agent - imagePullPolicy: IfNotPresent - - name: antrea-ovs - imagePullPolicy: IfNotPresent - initContainers: - - name: install-cni - imagePullPolicy: IfNotPresent diff --git a/build/yamls/patches/dev/agentIpsecImagePullPolicy.yml b/build/yamls/patches/dev/agentIpsecImagePullPolicy.yml deleted file mode 100644 index 50aabfcf2c3..00000000000 --- a/build/yamls/patches/dev/agentIpsecImagePullPolicy.yml +++ /dev/null @@ -1,10 +0,0 @@ -apiVersion: apps/v1 -kind: DaemonSet -metadata: - name: antrea-agent -spec: - template: - spec: - containers: - - name: antrea-ipsec - imagePullPolicy: IfNotPresent diff --git a/build/yamls/patches/dev/agentVerboseLog.yml b/build/yamls/patches/dev/agentVerboseLog.yml deleted file mode 100644 index 4bfaaaeeea7..00000000000 --- a/build/yamls/patches/dev/agentVerboseLog.yml +++ /dev/null @@ -1,11 +0,0 @@ -apiVersion: apps/v1 -kind: DaemonSet -metadata: - name: antrea-agent -spec: - template: - spec: - containers: - - name: antrea-agent - args: ["--config", "/etc/antrea/antrea-agent.conf", "--logtostderr=false", "--log_dir=/var/log/antrea", "--alsologtostderr", "--log_file_max_size=100", "--log_file_max_num=4", "--v=4"] - diff --git a/build/yamls/patches/dev/controllerImagePullPolicy.yml b/build/yamls/patches/dev/controllerImagePullPolicy.yml deleted file mode 100644 index ce6bda61abb..00000000000 --- a/build/yamls/patches/dev/controllerImagePullPolicy.yml +++ /dev/null @@ -1,10 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: antrea-controller -spec: - template: - spec: - containers: - - name: antrea-controller - imagePullPolicy: IfNotPresent diff --git a/build/yamls/patches/dev/controllerVerboseLog.yml b/build/yamls/patches/dev/controllerVerboseLog.yml deleted file mode 100644 index 35f79946478..00000000000 --- a/build/yamls/patches/dev/controllerVerboseLog.yml +++ /dev/null @@ -1,11 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: antrea-controller -spec: - template: - spec: - containers: - - name: antrea-controller - args: ["--config", "/etc/antrea/antrea-controller.conf", "--logtostderr=false", "--log_dir=/var/log/antrea", "--alsologtostderr", "--log_file_max_size=100", "--log_file_max_num=4", "--v=4"] - diff --git a/build/yamls/patches/dev/onDeleteUpdateStrategy.yml b/build/yamls/patches/dev/onDeleteUpdateStrategy.yml deleted file mode 100644 index 4e5d30be341..00000000000 --- a/build/yamls/patches/dev/onDeleteUpdateStrategy.yml +++ /dev/null @@ -1,7 +0,0 @@ -apiVersion: apps/v1 -kind: DaemonSet -metadata: - name: antrea-agent -spec: - updateStrategy: - type: OnDelete diff --git a/build/yamls/patches/eks/eksEnv.yml b/build/yamls/patches/eks/eksEnv.yml deleted file mode 100644 index 5ebae561433..00000000000 --- a/build/yamls/patches/eks/eksEnv.yml +++ /dev/null @@ -1,14 +0,0 @@ -apiVersion: apps/v1 -kind: DaemonSet -metadata: - name: antrea-agent -spec: - template: - spec: - containers: - - name: antrea-agent - env: - # Antrea Agent needs to be aware that it is being used in EKS, as - # additional iptables rules may have to be installed. - - name: ANTREA_CLOUD_EKS - value: "true" diff --git a/build/yamls/patches/gke/cniPath.yml b/build/yamls/patches/gke/cniPath.yml deleted file mode 100644 index 671dbb31087..00000000000 --- a/build/yamls/patches/gke/cniPath.yml +++ /dev/null @@ -1,11 +0,0 @@ -apiVersion: apps/v1 -kind: DaemonSet -metadata: - name: antrea-agent -spec: - template: - spec: - volumes: - - hostPath: - path: /home/kubernetes/bin - name: host-cni-bin diff --git a/build/yamls/patches/hwoffload/hwOffload.yml b/build/yamls/patches/hwoffload/hwOffload.yml deleted file mode 100644 index bed398e1984..00000000000 --- a/build/yamls/patches/hwoffload/hwOffload.yml +++ /dev/null @@ -1,11 +0,0 @@ -apiVersion: apps/v1 -kind: DaemonSet -metadata: - name: antrea-agent -spec: - template: - spec: - containers: - - name: antrea-ovs - command: ["start_ovs", "--hw-offload"] - diff --git a/build/yamls/patches/ipsec/ipsecContainer.yml b/build/yamls/patches/ipsec/ipsecContainer.yml deleted file mode 100644 index a1225abdb54..00000000000 --- a/build/yamls/patches/ipsec/ipsecContainer.yml +++ /dev/null @@ -1,36 +0,0 @@ -apiVersion: apps/v1 -kind: DaemonSet -metadata: - name: antrea-agent -spec: - template: - spec: - containers: - - name: antrea-ipsec - image: antrea - resources: - requests: - cpu: "50m" - command: ["start_ovs_ipsec"] - livenessProbe: - exec: - command: - - /bin/sh - - -c - - timeout 5 container_liveness_probe ovs-ipsec - initialDelaySeconds: 5 - periodSeconds: 5 - securityContext: - capabilities: - add: - - NET_ADMIN - volumeMounts: - - name: host-var-run-antrea - mountPath: /var/run/openvswitch - subPath: openvswitch - - name: host-var-log-antrea - mountPath: /var/log/openvswitch - subPath: openvswitch - - name: host-var-log-antrea - mountPath: /var/log/strongswan - subPath: strongswan diff --git a/build/yamls/patches/ipsec/ipsecSecret.yml b/build/yamls/patches/ipsec/ipsecSecret.yml deleted file mode 100644 index b0bb36a572a..00000000000 --- a/build/yamls/patches/ipsec/ipsecSecret.yml +++ /dev/null @@ -1,10 +0,0 @@ ---- -apiVersion: v1 -kind: Secret -metadata: - name: antrea-ipsec - namespace: kube-system -type: Opaque -stringData: - # Preshared Key used by IKE for authentication with peers. - psk: changeme diff --git a/build/yamls/patches/ipsec/pskEnv.yml b/build/yamls/patches/ipsec/pskEnv.yml deleted file mode 100644 index 48d5fbaa7bb..00000000000 --- a/build/yamls/patches/ipsec/pskEnv.yml +++ /dev/null @@ -1,16 +0,0 @@ -apiVersion: apps/v1 -kind: DaemonSet -metadata: - name: antrea-agent -spec: - template: - spec: - containers: - - name: antrea-agent - env: - # Pre-shared key for IPsec IKE. - - name: ANTREA_IPSEC_PSK - valueFrom: - secretKeyRef: - name: antrea-ipsec - key: psk diff --git a/build/yamls/patches/kustomization.configMap.tpl.yml b/build/yamls/patches/kustomization.configMap.tpl.yml deleted file mode 100644 index 08c34218f0a..00000000000 --- a/build/yamls/patches/kustomization.configMap.tpl.yml +++ /dev/null @@ -1,6 +0,0 @@ -configMapGenerator: -- name: antrea-config - behavior: merge - files: - - - - diff --git a/build/yamls/patches/release/.gitignore b/build/yamls/patches/release/.gitignore deleted file mode 100644 index fdffa2a0fd7..00000000000 --- a/build/yamls/patches/release/.gitignore +++ /dev/null @@ -1 +0,0 @@ -# placeholder diff --git a/build/yamls/patches/simulator/agentNodeAffinity.yml b/build/yamls/patches/simulator/agentNodeAffinity.yml deleted file mode 100644 index 1a922cecd3f..00000000000 --- a/build/yamls/patches/simulator/agentNodeAffinity.yml +++ /dev/null @@ -1,16 +0,0 @@ -apiVersion: apps/v1 -kind: DaemonSet -metadata: - name: antrea-agent -spec: - template: - spec: - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: antrea/instance - operator: NotIn - values: - - simulator diff --git a/build/yamls/patches/simulator/controllerNodeAffinity.yml b/build/yamls/patches/simulator/controllerNodeAffinity.yml deleted file mode 100644 index e88e7e23d7d..00000000000 --- a/build/yamls/patches/simulator/controllerNodeAffinity.yml +++ /dev/null @@ -1,16 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: antrea-controller -spec: - template: - spec: - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: antrea/instance - operator: NotIn - values: - - simulator diff --git a/build/yamls/patches/sriov/sriov.yml b/build/yamls/patches/sriov/sriov.yml deleted file mode 100644 index f56c5466e02..00000000000 --- a/build/yamls/patches/sriov/sriov.yml +++ /dev/null @@ -1,17 +0,0 @@ -apiVersion: apps/v1 -kind: DaemonSet -metadata: - name: antrea-agent -spec: - template: - spec: - containers: - - name: antrea-agent - volumeMounts: - - mountPath: /var/lib/kubelet - name: host-kubelet - readOnly: true - volumes: - - hostPath: - path: /var/lib/kubelet - name: host-kubelet diff --git a/build/yamls/patches/whereabouts/whereabouts-rbac.yml b/build/yamls/patches/whereabouts/whereabouts-rbac.yml deleted file mode 100644 index 6492ac97a96..00000000000 --- a/build/yamls/patches/whereabouts/whereabouts-rbac.yml +++ /dev/null @@ -1,46 +0,0 @@ ---- -apiVersion: v1 -kind: Secret -metadata: - name: whereabouts-cni-secret - annotations: - kubernetes.io/service-account.name: antrea-agent-whereabouts -type: kubernetes.io/service-account-token ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: antrea-agent-whereabouts - namespace: kube-system ---- -kind: ClusterRole -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: antrea-agent-whereabouts -rules: - - apiGroups: - - whereabouts.cni.cncf.io - resources: - - ippools - verbs: - - get - - put - - watch - - list - - update - - patch - - create - - delete ---- -kind: ClusterRoleBinding -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: antrea-agent-whereabouts -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: antrea-agent-whereabouts -subjects: - - kind: ServiceAccount - name: antrea-agent-whereabouts - namespace: kube-system diff --git a/build/yamls/patches/whereabouts/whereabouts.yml b/build/yamls/patches/whereabouts/whereabouts.yml deleted file mode 100644 index 3ada5ac9bae..00000000000 --- a/build/yamls/patches/whereabouts/whereabouts.yml +++ /dev/null @@ -1,33 +0,0 @@ -apiVersion: apps/v1 -kind: DaemonSet -metadata: - name: antrea-agent -spec: - template: - spec: - initContainers: - - name: install-whereabouts-config - image: antrea - resources: - requests: - cpu: "100m" - command: ["install_whereabouts_config"] - volumeMounts: - - name: whereabouts-cni-conf - mountPath: /host/etc/cni/net.d/whereabouts.d - - name: whereabouts-secret - mountPath: /var/run/secrets/whereabouts - containers: - - name: antrea-agent - volumeMounts: - - name: whereabouts-cni-conf - mountPath: /host/etc/cni/net.d/whereabouts.d - - name: whereabouts-secret - mountPath: /var/run/secrets/whereabouts - volumes: - - hostPath: - path: /host/etc/cni/net.d/whereabouts.d - name: whereabouts-cni-conf - - name: whereabouts-secret - secret: - secretName: whereabouts-cni-secret diff --git a/build/yamls/windows/base/agent.yml b/build/yamls/windows/base/agent.yml index dba7d90a85f..b5d9d141295 100644 --- a/build/yamls/windows/base/agent.yml +++ b/build/yamls/windows/base/agent.yml @@ -35,8 +35,6 @@ spec: image: antrea-windows name: antrea-agent volumeMounts: - - mountPath: /host - name: host - mountPath: \\.\pipe\rancher_wins name: wins - mountPath: /etc/antrea @@ -45,6 +43,8 @@ spec: name: antrea-agent-windows - mountPath: /host/k/antrea/ name: host-antrea-home + - mountPath: /var/log/antrea/ + name: var-log-antrea hostNetwork: true initContainers: - command: @@ -64,8 +64,8 @@ spec: name: host-cni-bin - mountPath: /host/k/antrea/ name: host-antrea-home - - mountPath: /host - name: host + - mountPath: /host/var/run/secrets/ + name: host-secrets-path nodeSelector: kubernetes.io/os: windows priorityClassName: system-node-critical @@ -95,12 +95,17 @@ spec: path: /k/antrea type: DirectoryOrCreate name: host-antrea-home - - hostPath: - path: / - name: host - name: wins hostPath: path: \\.\pipe\rancher_wins type: null + - name: var-log-antrea + hostPath: + path: /var/log/antrea/ + type: DirectoryOrCreate + - name: host-secrets-path + hostPath: + path: /var/run/secrets/ + type: DirectoryOrCreate updateStrategy: type: RollingUpdate diff --git a/build/yamls/windows/base/conf/Run-AntreaAgent.ps1 b/build/yamls/windows/base/conf/Run-AntreaAgent.ps1 index 34ca44d9737..948645e2e1b 100644 --- a/build/yamls/windows/base/conf/Run-AntreaAgent.ps1 +++ b/build/yamls/windows/base/conf/Run-AntreaAgent.ps1 @@ -2,4 +2,4 @@ $ErrorActionPreference = "Stop" # wins will rename the binary when executing it. So we need to copy the binary everytime before running it. mkdir -force /host/k/antrea/bin cp /k/antrea/bin/* /host/k/antrea/bin/ -C:/k/antrea/utils/wins.exe cli process run --path /k/antrea/bin/antrea-agent.exe --args "--config=/k/antrea/etc/antrea-agent.conf --logtostderr=false --log_dir=/k/antrea/logs/ --alsologtostderr --log_file_max_size=100 --log_file_max_num=4 --v=0" --envs "KUBERNETES_SERVICE_HOST=$env:KUBERNETES_SERVICE_HOST KUBERNETES_SERVICE_PORT=$env:KUBERNETES_SERVICE_PORT ANTREA_SERVICE_HOST=$env:ANTREA_SERVICE_HOST ANTREA_SERVICE_PORT=$env:ANTREA_SERVICE_PORT NODE_NAME=$env:NODE_NAME KUBE_DNS_SERVICE_HOST=$env:KUBE_DNS_SERVICE_HOST KUBE_DNS_SERVICE_PORT=$env:KUBE_DNS_SERVICE_PORT" +C:/k/antrea/utils/wins.exe cli process run --path /k/antrea/bin/antrea-agent.exe --args "--config=/k/antrea/etc/antrea-agent.conf --logtostderr=false --log_dir=/var/log/antrea/ --alsologtostderr --log_file_max_size=100 --log_file_max_num=4 --v=0" --envs "KUBERNETES_SERVICE_HOST=$env:KUBERNETES_SERVICE_HOST KUBERNETES_SERVICE_PORT=$env:KUBERNETES_SERVICE_PORT ANTREA_SERVICE_HOST=$env:ANTREA_SERVICE_HOST ANTREA_SERVICE_PORT=$env:ANTREA_SERVICE_PORT NODE_NAME=$env:NODE_NAME KUBE_DNS_SERVICE_HOST=$env:KUBE_DNS_SERVICE_HOST KUBE_DNS_SERVICE_PORT=$env:KUBE_DNS_SERVICE_PORT" diff --git a/build/yamls/windows/base/conf/antrea-agent.conf b/build/yamls/windows/base/conf/antrea-agent.conf index 7fbb6952468..ab72ae1e4b6 100644 --- a/build/yamls/windows/base/conf/antrea-agent.conf +++ b/build/yamls/windows/base/conf/antrea-agent.conf @@ -10,6 +10,9 @@ featureGates: # this flag will not take effect. # EndpointSlice: false +# Enable NodePortLocal feature to make the Pods reachable externally through NodePort +# NodePortLocal: true + # Enable flowexporter which exports polled conntrack connections as IPFIX flow records from each agent to a configured collector. # FlowExporter: false @@ -113,3 +116,14 @@ antreaProxy: # Note that this option is experimental. If kube-proxy is removed, option kubeAPIServerOverride must be used to access # apiserver directly. #proxyAll: false + +nodePortLocal: +# Enable NodePortLocal, a feature used to make Pods reachable using port forwarding on the host. To +# enable this feature, you need to set "enable" to true, and ensure that the NodePortLocal feature +# gate is also enabled (which is the default). +# enable: false +# Provide the port range used by NodePortLocal. When the NodePortLocal feature is enabled, a port +# from that range will be assigned whenever a Pod's container defines a specific port to be exposed +# (each container can define a list of ports as pod.spec.containers[].ports), and all Node traffic +# directed to that port will be forwarded to the Pod. +# portRange: 61000-62000 diff --git a/ci/README.md b/ci/README.md index 49092fe283f..fbdcad8f22e 100644 --- a/ci/README.md +++ b/ci/README.md @@ -5,9 +5,8 @@ This directory includes all the scripts required to run CI on Antrea. For information about our Jenkins CI jobs and how to run the same tests locally, see [here](jenkins/README.md). -File [k8s-conformance-image-version](k8s-conformance-image-version) stores the -version number of the K8s conformance container image we currently use to run -tests. +For K8s conformance upstream tests, the version of the K8s conformance container +image will be determined at runtime according to the Kubernetes server's version. ## Antrea test suite @@ -36,8 +35,8 @@ We run 4 different categories of tests as part of CI: components can be deployed successfully, check end-to-end connectivity for different types of traffic (e.g. Pod-to-Pod, Pod-to-Service), validate the implementation of Antrea-speicifc APIs - (e.g. [ClusterNetworkPolicy](/docs/network-policy.md), - [Traceflow](/docs/traceflow-guide.md), ...). + (e.g. [ClusterNetworkPolicy](../docs/antrea-network-policy.md), + [Traceflow](../docs/traceflow-guide.md), ...). * **Kubernetes upstream tests**: our CI relies on Kubernetes community tests to ensure conformance and validate the implementation of the NetworkPolicy API. @@ -78,7 +77,7 @@ You can run the linters locally with `make golangci` from the root of the repository. Some issues can be fixed automatically for you if you run `make golangci-fix`. -See our [golangci-lint configuration file](/.golangci.yml) for more details. +See our [golangci-lint configuration file](../.golangci.yml) for more details. You can also run the `golint` linter with `make lint` to see suggestions about how to improve your code, and we encourage you to do so when submitting a diff --git a/ci/golicense/README.md b/ci/golicense/README.md index 1230a67666f..d34dfb2f147 100644 --- a/ci/golicense/README.md +++ b/ci/golicense/README.md @@ -19,7 +19,7 @@ locally: ## Supported OSS Licenses For a list of the OSS licenses accepted or rejected for Antrea dependencies, -please see [conf.json](conf.json). These lists are not comprehensive and do not +please see [conf.yml](conf.yml). These lists are not comprehensive and do not include all possible OSS licenses - however, they do include the most popular ones. If a patch introduces a new dependency, and the license for that dependency is listed in "deny", the patch will not be merged. If the license is diff --git a/ci/jenkins/README.md b/ci/jenkins/README.md index 6f7a6fcb689..95f96b2db24 100644 --- a/ci/jenkins/README.md +++ b/ci/jenkins/README.md @@ -145,8 +145,9 @@ DOCKER_REGISTRY="$(head -n1 ci/docker-registry)" [ci/jenkins/jobs](/ci/jenkins/jobs). It validates the syntax of the jenkins jobs' configuration. -* Jenkins Windows OVS validator: this job only executes for PRs that include changes to [hack/windows/Install-OVS.ps1](hack/windows/Install-OVS.ps1). It validates - if Windows OVS can be installed correctly. +* Jenkins Windows OVS validator: this job only executes for PRs that include + changes to [hack/windows/Install-OVS.ps1](/hack/windows/Install-OVS.ps1). + It validates if Windows OVS can be installed correctly. ```shell #!/bin/bash @@ -177,11 +178,6 @@ DOCKER_REGISTRY="$(head -n1 ci/docker-registry)" | :------------: | :-----------------: | :-------------: | :------: | | 1.21.7 | Standard_DS2_v2 | Ubuntu 18.04 |[![Build Status](http://jenkins.antrea-ci.rocks/buildStatus/icon?job=cloud-antrea-aks-conformance-net-policy)](http://jenkins.antrea-ci.rocks/view/cloud/job/cloud-antrea-aks-conformance-net-policy/)| -* [daily-elk-flow-collector-validate](https://jenkins.antrea-ci.rocks/job/antrea-daily-elk-flow-collector-validate-for-period/): - [![Build Status](http://jenkins.antrea-ci.rocks/buildStatus/icon?job=antrea-daily-elk-flow-collector-validate-for-period)](http://jenkins.antrea-ci.rocks/view/cloud/job/antrea-daily-elk-flow-collector-validate-for-period/) - daily validation of elk flow collector manifest. If build fails, Jenkins will send an email to - projectantrea-dev@googlegroups.com for notification. - * [daily-flow-visibility-validate](https://jenkins.antrea-ci.rocks/job/antrea-daily-flow-visibility-validate-for-period/): [![Build Status](http://jenkins.antrea-ci.rocks/buildStatus/icon?job=antrea-daily-flow-visibility-validate-for-period)](http://jenkins.antrea-ci.rocks/view/cloud/job/antrea-daily-flow-visibility-validate-for-period/) daily validation of Flow Visibility manifest. If build fails, Jenkins will send an email to diff --git a/ci/jenkins/jobs/macros.yaml b/ci/jenkins/jobs/macros.yaml index 7492aa3184b..bb09de4ffef 100644 --- a/ci/jenkins/jobs/macros.yaml +++ b/ci/jenkins/jobs/macros.yaml @@ -124,23 +124,6 @@ DOCKER_REGISTRY="$(head -n1 ci/docker-registry)" ./ci/jenkins/test-vmc.sh --cluster-name "$BUILD_TAG" --testcase '{conformance_type}' --coverage --codecov-token "${{CODECOV_TOKEN}}" --registry ${{DOCKER_REGISTRY}} --username "${{CAPVC_USERNAME}}" --password "${{CAPVC_PASSWORD}}" -- builder: - name: builder-elk-flow-collector - builders: - - shell: |- - #!/bin/bash - set -ex - ./ci/jenkins/test-vmc.sh --cluster-name "${JOB_NAME}-${BUILD_NUMBER}" --setup-only - ./ci/test-elk-flow-collector.sh --kubeconfig jenkins/out/kubeconfig - ./ci/jenkins/test-vmc.sh --cluster-name "${JOB_NAME}-${BUILD_NUMBER}" --cleanup-only - - if !(test -f TEST_FAILURE); then - echo "=== SUCCESS !!! ===" - exit 0 - fi - echo "=== FAILURE !!! ===" - exit 1 - - builder: name: builder-flow-visibility builders: diff --git a/ci/jenkins/jobs/projects.yaml b/ci/jenkins/jobs/projects.yaml index 32baeb08480..a4c1593d677 100644 --- a/ci/jenkins/jobs/projects.yaml +++ b/ci/jenkins/jobs/projects.yaml @@ -58,21 +58,6 @@ - text: credential-id: RESOURCEPOOLPATH variable: RESOURCEPOOLPATH - - '{name}-{test_name}-for-period': - test_name: daily-elk-flow-collector-validate - node: 'antrea-test-node' - description: 'This is for validating the elk flow collector manifest daily.' - builders: - - builder-elk-flow-collector - branches: - - '*/main' - included_regions: [] - cron: 'H H * * *' - ignore_post_commit_hooks: false - publishers: - - email: - recipients: projectantrea-dev@googlegroups.com - wrappers: [] - '{name}-{test_name}-for-period': test_name: daily-flow-visibility-validate node: 'antrea-test-node' diff --git a/ci/jenkins/test-mc.sh b/ci/jenkins/test-mc.sh index af4cf031042..470c26fd97f 100755 --- a/ci/jenkins/test-mc.sh +++ b/ci/jenkins/test-mc.sh @@ -38,7 +38,7 @@ NGINX_IMAGE=projects.registry.vmware.com/antrea/nginx:1.21.6-alpine CONTROL_PLANE_NODE_ROLE="control-plane,master" multicluster_kubeconfigs=($EAST_CLUSTER_CONFIG $LEADER_CLUSTER_CONFIG $WEST_CLUSTER_CONFIG) -membercluter_kubeconfigs=($EAST_CLUSTER_CONFIG $WEST_CLUSTER_CONFIG) +membercluster_kubeconfigs=($EAST_CLUSTER_CONFIG $WEST_CLUSTER_CONFIG) CLEAN_STALE_IMAGES="docker system prune --force --all --filter until=48h" @@ -104,6 +104,11 @@ function clean_tmp() { find ${WORKDIR} -name "support-bundles*" -mtime +7 -exec rm -rf {} \; 2>&1 | grep -v "Permission denied" || true } +function clean_images() { + docker images | grep -E 'mc-controller|antrea-ubuntu' | awk '{print $3}' | xargs -r docker rmi -f || true + # Clean up dangling images generated in previous builds. + docker image prune -f --filter "until=24h" || true > /dev/null +} function cleanup_multicluster_ns { ns=$1 @@ -127,13 +132,7 @@ function cleanup_multicluster_controller { function cleanup_multicluster_antrea { echo "====== Cleanup Antrea controller and agent ======" kubeconfig=$1 - kubectl get pod -n kube-system -l component=antrea-agent --no-headers=true $kubeconfig | awk '{print $1}' | while read AGENTNAME; do - kubectl exec $AGENTNAME -c antrea-agent -n kube-system ${kubeconfig} -- ovs-vsctl del-port br-int gw0 || true - done - - for antrea_yml in ${WORKDIR}/*.yml; do - kubectl delete -f $antrea_yml --ignore-not-found=true ${kubeconfig} --timeout=30s || true - done + kubectl delete -f build/yamls/antrea.yml --ignore-not-found=true ${kubeconfig} --timeout=30s || true } function clean_multicluster { @@ -174,7 +173,7 @@ function wait_for_multicluster_controller_ready { sed -i 's/antrea-mcs-ns/kube-system/g' ./multicluster/test/yamls/leader-access-token.yml echo "type: Opaque" >>./multicluster/test/yamls/leader-access-token.yml - for config in "${membercluter_kubeconfigs[@]}"; + for config in "${membercluster_kubeconfigs[@]}"; do kubectl apply -f ./multicluster/build/yamls/antrea-multicluster-member.yml ${config} kubectl rollout status deployment/antrea-mc-controller -n kube-system ${config} @@ -195,9 +194,12 @@ function deliver_antrea_multicluster { git show --numstat make clean - ${CLEAN_STALE_IMAGES} - cp -f build/yamls/*.yml $WORKDIR + # Ensure that files in the Docker context have the correct permissions, or Docker caching cannot + # be leveraged successfully + chmod -R g-w build/images/ovs + chmod -R g-w build/images/base + DOCKER_REGISTRY="${DOCKER_REGISTRY}" ./hack/build-antrea-linux-all.sh --pull echo "====== Delivering Antrea to all the Nodes ======" docker save -o ${WORKDIR}/antrea-ubuntu.tar $DOCKER_REGISTRY/antrea/antrea-ubuntu:latest @@ -219,11 +221,10 @@ function deliver_multicluster_controller { export GOROOT=/usr/local/go export PATH=${GOROOT}/bin:$PATH - docker images | grep 'mc-controller' | awk '{print $3}' | xargs -r docker rmi || true export NO_PULL=1;make antrea-mc-controller docker save projects.registry.vmware.com/antrea/antrea-mc-controller:latest -o "${WORKDIR}"/antrea-mcs.tar - ./multicluster/hack/generate-manifest.sh -l antrea-mcs-ns >./multicluster/test/yamls/manifest.yml + ./multicluster/hack/generate-manifest.sh -l antrea-mcs-ns > ./multicluster/test/yamls/manifest.yml for kubeconfig in "${multicluster_kubeconfigs[@]}" do @@ -238,10 +239,13 @@ function deliver_multicluster_controller { sed -i "s||${leader_ip}|" ./multicluster/test/yamls/west-member-cluster.yml rsync -avr --progress --inplace -e "ssh -o StrictHostKeyChecking=no" ./multicluster/test/yamls/test-acnp-copy-span-ns-isolation.yml jenkins@["${leader_ip}"]:"${WORKDIR}"/test-acnp-copy-span-ns-isolation.yml - for kubeconfig in "${membercluter_kubeconfigs[@]}" + for kubeconfig in "${membercluster_kubeconfigs[@]}" do - ip=$(kubectl get nodes -o wide --no-headers=true ${EAST_CLUSTER_CONFIG} | awk -v role="$CONTROL_PLANE_NODE_ROLE" '$3 == role {print $6}') - rsync -avr --progress --inplace -e "ssh -o StrictHostKeyChecking=no" ./multicluster/test/yamls/test-east-serviceexport.yml jenkins@["${ip}"]:"${WORKDIR}"/serviceexport.yml + # Remove the longest matched substring '*/' from a string like '--kubeconfig=/var/lib/jenkins/.kube/east' + # to get the last element which is the cluster name. + cluster=${kubeconfig##*/} + ip=$(kubectl get nodes -o wide --no-headers=true ${kubeconfig} | awk -v role="$CONTROL_PLANE_NODE_ROLE" '$3 == role {print $6}') + rsync -avr --progress --inplace -e "ssh -o StrictHostKeyChecking=no" ./multicluster/test/yamls/test-${cluster}-serviceexport.yml jenkins@["${ip}"]:"${WORKDIR}"/serviceexport.yml done } @@ -266,7 +270,7 @@ function run_multicluster_e2e { docker tag "${DOCKER_REGISTRY}/antrea/agnhost:2.26" "agnhost:2.26" docker save agnhost:2.26 -o "${WORKDIR}"/agnhost.tar - for kubeconfig in "${membercluter_kubeconfigs[@]}" + for kubeconfig in "${membercluster_kubeconfigs[@]}" do kubectl get nodes -o wide --no-headers=true "${kubeconfig}"| awk '{print $6}' | while read IP; do rsync -avr --progress --inplace -e "ssh -o StrictHostKeyChecking=no" "${WORKDIR}"/nginx.tar jenkins@["${IP}"]:"${WORKDIR}"/nginx.tar @@ -289,6 +293,7 @@ function run_multicluster_e2e { trap clean_multicluster EXIT clean_tmp +clean_images if [[ ${TESTCASE} =~ "e2e" ]]; then deliver_antrea_multicluster diff --git a/ci/jenkins/test.sh b/ci/jenkins/test.sh index 02f02def582..02cea304214 100755 --- a/ci/jenkins/test.sh +++ b/ci/jenkins/test.sh @@ -135,9 +135,8 @@ function clean_antrea { clean_up_one_ns "antrea-ipam-test-12" clean_up_one_ns "antrea-ipam-test" clean_up_one_ns "antrea-test" - kubectl get pod -n kube-system -l component=antrea-agent --no-headers=true | awk '{print $1}' | while read AGENTNAME; do - kubectl exec $AGENTNAME -c antrea-agent -n kube-system -- ovs-vsctl del-port br-int gw0 || true - done + # Delete antrea-prometheus first for k8s>=1.22 to avoid Pod stuck in Terminating state. + kubectl delete -f ${WORKDIR}/antrea-prometheus.yml --ignore-not-found=true || true for antrea_yml in ${WORKDIR}/*.yml; do kubectl delete -f $antrea_yml --ignore-not-found=true || true done @@ -145,7 +144,7 @@ function clean_antrea { function clean_for_windows_install_cni { # https://github.com/antrea-io/antrea/issues/1577 - kubectl get nodes -o wide --no-headers=true | awk -v role="$CONTROL_PLANE_NODE_ROLE" '$3 != role && $1 ~ /win/ {print $6}' | while read IP; do + kubectl get nodes -o wide --no-headers=true | awk -v role="$CONTROL_PLANE_NODE_ROLE" '$3 !~ role && $1 ~ /win/ {print $6}' | while read IP; do CLEAN_LIST=("/cygdrive/c/opt/cni/bin/antrea.exe" "/cygdrive/c/opt/cni/bin/host-local.exe" "/cygdrive/c/k/antrea/etc/antrea-agent.conf" "/cygdrive/c/etc/cni/net.d/10-antrea.conflist" "/cygdrive/c/k/antrea/bin/antrea-agent.exe") for file in "${CLEAN_LIST[@]}"; do ssh -o StrictHostKeyChecking=no -n Administrator@${IP} "rm -f ${file}" @@ -185,7 +184,7 @@ function collect_windows_network_info_and_logs { fi done - kubectl get nodes -o wide --no-headers=true | awk -v role="$CONTROL_PLANE_NODE_ROLE" '$3 != role && $1 ~ /win/ {print $1}' | while read NODENAME; do + kubectl get nodes -o wide --no-headers=true | awk -v role="$CONTROL_PLANE_NODE_ROLE" '$3 !~ role && $1 ~ /win/ {print $1}' | while read NODENAME; do IP=$(kubectl get node ${NODENAME} -o json | jq -r '.status.addresses[] | select(.type | test("InternalIP")).address') mkdir "${DEBUG_LOG_PATH}/${NODENAME}" @@ -223,7 +222,7 @@ function wait_for_antrea_windows_pods_ready { if [[ "${PROXY_ALL}" == false ]]; then kubectl rollout status daemonset/kube-proxy-windows -n kube-system fi - kubectl get nodes -o wide --no-headers=true | awk -v role="$CONTROL_PLANE_NODE_ROLE" '$3 != role && $1 ~ /win/ {print $6}' | while read IP; do + kubectl get nodes -o wide --no-headers=true | awk -v role="$CONTROL_PLANE_NODE_ROLE" '$3 !~ role && $1 ~ /win/ {print $6}' | while read IP; do for i in `seq 5`; do sleep 5 timeout 5s ssh -o StrictHostKeyChecking=no -n Administrator@${IP} "powershell Get-NetAdapter -Name br-int -ErrorAction SilentlyContinue" && break @@ -238,7 +237,7 @@ function wait_for_antrea_windows_processes_ready { kubectl rollout status deployment/coredns -n kube-system kubectl rollout status deployment.apps/antrea-controller -n kube-system kubectl rollout status daemonset/antrea-agent -n kube-system - kubectl get nodes -o wide --no-headers=true | awk -v role="$CONTROL_PLANE_NODE_ROLE" '$3 != role && $1 ~ /win/ {print $6}' | while read IP; do + kubectl get nodes -o wide --no-headers=true | awk -v role="$CONTROL_PLANE_NODE_ROLE" '$3 !~ role && $1 ~ /win/ {print $6}' | while read IP; do echo "===== Run script to startup Antrea agent =====" ANTREA_VERSION=$(ssh -o StrictHostKeyChecking=no -n Administrator@${IP} "/cygdrive/c/k/antrea/bin/antrea-agent.exe --version" | awk '{print $3}') ssh -o StrictHostKeyChecking=no -n Administrator@${IP} "chmod +x /cygdrive/c/k/antrea/Start.ps1 && powershell 'c:\k\antrea\Start.ps1 -AntreaVersion ${ANTREA_VERSION}'" @@ -295,8 +294,8 @@ function deliver_antrea_windows { KUBERNETES_SVC_EP_IP=$(kubectl get endpoints kubernetes -o jsonpath='{.subsets[0].addresses[0].ip}') KUBERNETES_SVC_EP_PORT=$(kubectl get endpoints kubernetes -o jsonpath='{.subsets[0].ports[0].port}') KUBERNETES_SVC_EP_ADDR="${KUBERNETES_SVC_EP_IP}:${KUBERNETES_SVC_EP_PORT}" - sed -i "s|#kubeAPIServerOverride: \"\"|kubeAPIServerOverride: \"${KUBERNETES_SVC_EP_ADDR}\"|g" build/yamls/antrea.yml build/yamls/antrea-windows.yml - sed -i "s|#proxyAll: false|proxyAll: true|g" build/yamls/antrea.yml build/yamls/antrea-windows.yml + sed -i "s|.*kubeAPIServerOverride: \"\"| kubeAPIServerOverride: \"${KUBERNETES_SVC_EP_ADDR}\"|g" build/yamls/antrea.yml build/yamls/antrea-windows.yml + sed -i "s|.*proxyAll: false| proxyAll: true|g" build/yamls/antrea.yml build/yamls/antrea-windows.yml fi cp -f build/yamls/*.yml $WORKDIR @@ -311,7 +310,7 @@ function deliver_antrea_windows { docker tag "${DOCKER_REGISTRY}/antrea/${harbor_images[i]}" "${antrea_images[i]}" done echo "===== Deliver Antrea to Linux worker nodes and pull necessary images on worker nodes =====" - kubectl get nodes -o wide --no-headers=true | awk -v role="$CONTROL_PLANE_NODE_ROLE" '$3 != role && $1 !~ /win/ {print $6}' | while read IP; do + kubectl get nodes -o wide --no-headers=true | awk -v role="$CONTROL_PLANE_NODE_ROLE" '$3 !~ role && $1 !~ /win/ {print $6}' | while read IP; do rsync -avr --progress --inplace -e "ssh -o StrictHostKeyChecking=no" antrea-ubuntu.tar jenkins@${IP}:${WORKDIR}/antrea-ubuntu.tar ssh -o StrictHostKeyChecking=no -n jenkins@${IP} "${CLEAN_STALE_IMAGES}; docker load -i ${WORKDIR}/antrea-ubuntu.tar" || true @@ -329,13 +328,13 @@ function deliver_antrea_windows { echo "===== Deliver Antrea Windows to Windows worker nodes and pull necessary images on Windows worker nodes =====" rm -f antrea-windows.tar.gz sed -i 's/if (!(Test-Path $AntreaAgentConfigPath))/if ($true)/' hack/windows/Helper.psm1 - kubectl get nodes -o wide --no-headers=true | awk -v role="$CONTROL_PLANE_NODE_ROLE" '$3 != role && $1 ~ /win/ {print $1}' | while read WORKER_NAME; do + kubectl get nodes -o wide --no-headers=true | awk -v role="$CONTROL_PLANE_NODE_ROLE" '$3 !~ role && $1 ~ /win/ {print $1}' | while read WORKER_NAME; do echo "==== Reverting Windows VM ${WORKER_NAME} =====" govc snapshot.revert -vm ${WORKER_NAME} win-initial # If Windows VM fails to power on correctly in time, retry several times. winVMIPs="" - for i in `seq 3`; do - winVMIPs=$(govc vm.ip -wait=1m -a ${WORKER_NAME}) + for i in `seq 10`; do + winVMIPs=$(govc vm.ip -wait=2m -a ${WORKER_NAME}) if [[ $winVMIPs != "" ]]; then echo "Windows VM ${WORKER_NAME} powered on" break @@ -353,17 +352,16 @@ function deliver_antrea_windows { sleep 5 ssh -o StrictHostKeyChecking=no -n Administrator@${IP} "W32tm /resync /force" | grep successfully && break done + # Avoid potential resync delay error + sleep 5 # Some tests need us.gcr.io/k8s-artifacts-prod/e2e-test-images/agnhost:2.13 image but it is not for windows/amd64 10.0.17763 # Use e2eteam/agnhost:2.13 instead - harbor_images=("sigwindowstools-kube-proxy:v1.18.0" "agnhost:2.13" "agnhost:2.13" "e2eteam-jessie-dnsutils:1.0" "e2eteam-pause:3.2") - antrea_images=("sigwindowstools/kube-proxy:v1.18.0" "e2eteam/agnhost:2.13" "us.gcr.io/k8s-artifacts-prod/e2e-test-images/agnhost:2.13" "e2eteam/jessie-dnsutils:1.0" "e2eteam/pause:3.2") + harbor_images=("sigwindowstools-kube-proxy:v1.18.0" "agnhost:2.13" "agnhost:2.13" "agnhost:2.29" "e2eteam-jessie-dnsutils:1.0" "e2eteam-pause:3.2") + antrea_images=("sigwindowstools/kube-proxy:v1.18.0" "e2eteam/agnhost:2.13" "us.gcr.io/k8s-artifacts-prod/e2e-test-images/agnhost:2.13" "k8s.gcr.io/e2e-test-images/agnhost:2.29" "e2eteam/jessie-dnsutils:1.0" "e2eteam/pause:3.2") + # Pull necessary images in advance to avoid transient error for i in "${!harbor_images[@]}"; do ssh -o StrictHostKeyChecking=no -n Administrator@${IP} "docker pull -q ${DOCKER_REGISTRY}/antrea/${harbor_images[i]} && docker tag ${DOCKER_REGISTRY}/antrea/${harbor_images[i]} ${antrea_images[i]}" || true done - # Pull necessary images in advance to avoid transient error - for image in "${common_images[@]}"; do - ssh -o StrictHostKeyChecking=no -n Administrator@${IP} "docker pull -q ${image}" || true - done # Use a script to run antrea agent in windows Network Policy cases if [ "$TESTCASE" == "windows-networkpolicy-process" ]; then @@ -416,6 +414,7 @@ function deliver_antrea { clean_up_one_ns "antrea-ipam-test-12" clean_up_one_ns "antrea-ipam-test" clean_up_one_ns "antrea-test" + kubectl delete -f ${WORKDIR}/antrea-prometheus.yml || true kubectl delete daemonset antrea-agent -n kube-system || true kubectl delete -f ${WORKDIR}/antrea.yml || true @@ -460,7 +459,7 @@ function deliver_antrea { cat build/yamls/antrea-prometheus.yml >> build/yamls/antrea.yml if [[ $FLEXIBLE_IPAM == true ]]; then - control_plane_ip="$(kubectl get nodes -o wide --no-headers=true | awk -v role="$CONTROL_PLANE_NODE_ROLE" '$3 == role {print $6}')" + control_plane_ip="$(kubectl get nodes -o wide --no-headers=true | awk -v role="$CONTROL_PLANE_NODE_ROLE" '$3 ~ role {print $6}')" scp -q -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -i "${WORKDIR}/jenkins_id_rsa" build/yamls/*.yml jenkins@${control_plane_ip}:~ else cp -f build/yamls/*.yml $WORKDIR @@ -477,7 +476,7 @@ function deliver_antrea { ssh -o StrictHostKeyChecking=no -i "${WORKDIR}/jenkins_id_rsa" -n jenkins@${IP} "${CLEAN_STALE_IMAGES}; docker load -i ${DEFAULT_WORKDIR}/antrea-ubuntu.tar; docker load -i ${DEFAULT_WORKDIR}/flow-aggregator.tar" || true done else - kubectl get nodes -o wide --no-headers=true | awk -v role="$CONTROL_PLANE_NODE_ROLE" '$3 != role {print $6}' | while read IP; do + kubectl get nodes -o wide --no-headers=true | awk -v role="$CONTROL_PLANE_NODE_ROLE" '$3 !~ role {print $6}' | while read IP; do rsync -avr --progress --inplace -e "ssh -o StrictHostKeyChecking=no" antrea-ubuntu.tar jenkins@[${IP}]:${WORKDIR}/antrea-ubuntu.tar rsync -avr --progress --inplace -e "ssh -o StrictHostKeyChecking=no" flow-aggregator.tar jenkins@[${IP}]:${WORKDIR}/flow-aggregator.tar ssh -o StrictHostKeyChecking=no -n jenkins@${IP} "${CLEAN_STALE_IMAGES}; docker load -i ${WORKDIR}/antrea-ubuntu.tar; docker load -i ${WORKDIR}/flow-aggregator.tar" || true diff --git a/ci/k8s-conformance-image-version b/ci/k8s-conformance-image-version deleted file mode 100644 index 9b43a2ccda9..00000000000 --- a/ci/k8s-conformance-image-version +++ /dev/null @@ -1 +0,0 @@ -v1.19.4 diff --git a/ci/kind/kind-setup.sh b/ci/kind/kind-setup.sh index d24ff229811..1bd32e08113 100755 --- a/ci/kind/kind-setup.sh +++ b/ci/kind/kind-setup.sh @@ -41,12 +41,10 @@ function echoerr { _usage=" Usage: $0 create CLUSTER_NAME [--pod-cidr POD_CIDR] [--antrea-cni] [--num-workers NUM_WORKERS] [--images IMAGES] [--subnets SUBNETS] [--ip-family ipv4|ipv6] destroy CLUSTER_NAME - modify-node NODE_NAME help where: create: create a kind cluster with name CLUSTER_NAME destroy: delete a kind cluster with name CLUSTER_NAME - modify-node: modify kind node with name NODE_NAME --pod-cidr: specifies pod cidr used in kind cluster, default is $POD_CIDR --encap-mode: inter-node pod traffic encap mode, default is encap --no-proxy: disable Antrea proxy @@ -76,17 +74,6 @@ function get_encap_mode { echo "--encap-mode $ENCAP_MODE" } -function modify { - node="$1" - # In Kind cluster, DNAT operation is configured by Docker as all DNS requests from Pod CoreDNS are NAT'd to the Docker - # DNS embedded resolver, which is running on localhost. When kube-proxy is enabled, parameter net.ipv4.conf.all.route_localnet - # is set to 1 by kube-proxy. This setting ensures that the DNS response can be forwarded back to Pod CoreDNS, otherwise - # DNS response from Docker DNS embedded resolver will be discarded. When kube-proxy is disabled, to ensure that DNS - # response can be forwarded back to Pod CoreDNS, we also set parameter net.ipv4.conf.all.route_localnet to 1 through - # the following command: - docker exec "$node" sysctl -w net.ipv4.conf.all.route_localnet=1 -} - function configure_networks { echo "Configuring networks" networks=$(docker network ls -f name=antrea --format '{{.Name}}') @@ -165,7 +152,8 @@ function configure_networks { # this is needed to ensure that the worker node can still connect to the apiserver docker exec -t $node bash -c "echo '$control_plane_ip $CLUSTER_NAME-control-plane' >> /etc/hosts" docker exec -t $node pkill kubelet - docker exec -t $node pkill kube-proxy + # it's possible that kube-proxy is not running yet on some Nodes + docker exec -t $node pkill kube-proxy || true i=$((i+1)) if [[ $i -ge $num_networks ]]; then i=0 @@ -191,7 +179,6 @@ function configure_networks { # otherwise we observe that inter-Node tunnelled traffic crossing Docker networks is dropped # because of an invalid outer checksum. docker exec "$node" ethtool -K eth0 tx off - modify $node done } @@ -295,12 +282,6 @@ EOF configure_networks load_images - nodes="$(kind get nodes --name $CLUSTER_NAME)" - nodes="$(echo $nodes)" - for node in $nodes; do - modify $node - done - if [[ $ANTREA_CNI == true ]]; then cmd=$(dirname $0) cmd+="/../../hack/generate-manifest.sh" @@ -331,6 +312,12 @@ function destroy { delete_networks } +if ! command -v kind &> /dev/null +then + echoerr "kind could not be found" + exit 1 +fi + while [[ $# -gt 0 ]] do key="$1" @@ -345,10 +332,6 @@ while [[ $# -gt 0 ]] destroy exit 0 ;; - modify-node) - modify "$2" - exit 0 - ;; --pod-cidr) POD_CIDR="$2" shift 2 @@ -400,4 +383,15 @@ while [[ $# -gt 0 ]] esac done +kind_version=$(kind version | awk '{print $2}') +kind_version=${kind_version:1} # strip leading 'v' +function version_lt() { test "$(printf '%s\n' "$@" | sort -rV | head -n 1)" != "$1"; } +if version_lt "$kind_version" "0.12.0" && [[ "$KUBE_PROXY_MODE" == "none" ]]; then + # This patch is required when using Antrea without kube-proxy: + # https://github.com/kubernetes-sigs/kind/pull/2375 + echoerr "You have kind version v$kind_version installed" + echoerr "You need to upgrade to kind >= v0.12.0 when disabling kube-proxy" + exit 1 +fi + create diff --git a/ci/kind/test-e2e-kind.sh b/ci/kind/test-e2e-kind.sh index edd52f7c516..f4ad6e2178a 100755 --- a/ci/kind/test-e2e-kind.sh +++ b/ci/kind/test-e2e-kind.sh @@ -29,27 +29,35 @@ _usage="Usage: $0 [--encap-mode ] [--ip-family ] [--no-proxy] [--np --proxy-all Enables Antrea proxy with all Service support. --endpointslice Enables Antrea proxy and EndpointSlice support. --no-np Disables Antrea-native policies. + --flow-visibility Only run flow visibility related e2e tests. --skip A comma-separated list of keywords, with which tests should be skipped. --coverage Enables measure Antrea code coverage when run e2e tests on kind. + --setup-only Only perform setting up the cluster and run test. + --cleanup-only Only perform cleaning up the cluster. + --test-only Only run test on current cluster. Not set up/clean up the cluster. --help, -h Print this message and exit. " function print_usage { - echoerr "$_usage" + echoerr -n "$_usage" } TESTBED_CMD=$(dirname $0)"/kind-setup.sh" YML_CMD=$(dirname $0)"/../../hack/generate-manifest.sh" FLOWAGGREGATOR_YML_CMD=$(dirname $0)"/../../hack/generate-manifest-flow-aggregator.sh" +FLOW_VISIBILITY_CMD=$(dirname $0)"/../../hack/generate-manifest-flow-visibility.sh --mode e2e" +FLOW_VISIBILITY_HELM_VALUES=$(dirname $0)"/values-flow-exporter.yml" +CH_OPERATOR_YML=$(dirname $0)"/../../build/yamls/clickhouse-operator-install-bundle.yml" function quit { - if [[ $? != 0 ]]; then - echoerr " Test failed cleaning testbed" - $TESTBED_CMD destroy kind + result=$? + if [[ $setup_only || $test_only ]]; then + exit $result fi + echoerr "Cleaning testbed" + $TESTBED_CMD destroy kind } -trap "quit" INT EXIT mode="" ipfamily="v4" @@ -57,8 +65,12 @@ proxy=true proxy_all=false endpointslice=false np=true +flow_visibility=false coverage=false skiplist="" +setup_only=false +cleanup_only=false +test_only=false while [[ $# -gt 0 ]] do key="$1" @@ -84,6 +96,10 @@ case $key in np=false shift ;; + --flow-visibility) + flow_visibility=true + shift + ;; --skip) skiplist="$2" shift 2 @@ -96,6 +112,18 @@ case $key in coverage=true shift ;; + --setup-only) + setup_only=true + shift + ;; + --cleanup-only) + cleanup_only=true + shift + ;; + --test-only) + test_only=true + shift + ;; -h|--help) print_usage exit 0 @@ -107,6 +135,13 @@ case $key in esac done +if [[ $cleanup_only == "true" ]];then + $TESTBED_CMD destroy kind + exit 0 +fi + +trap "quit" INT EXIT + manifest_args="" if ! $proxy; then manifest_args="$manifest_args --no-proxy" @@ -124,35 +159,48 @@ fi if ! $np; then manifest_args="$manifest_args --no-np" fi +if $flow_visibility; then + manifest_args="$manifest_args --flow-exporter --extra-helm-values-file $FLOW_VISIBILITY_HELM_VALUES" +fi COMMON_IMAGES_LIST=("k8s.gcr.io/e2e-test-images/agnhost:2.29" \ - "projects.registry.vmware.com/library/busybox" \ + "projects.registry.vmware.com/antrea/busybox" \ "projects.registry.vmware.com/antrea/nginx:1.21.6-alpine" \ - "projects.registry.vmware.com/antrea/perftool" \ - "projects.registry.vmware.com/antrea/ipfix-collector:v0.5.12") -for image in "${COMMON_IMAGES_LIST[@]}"; do - for i in `seq 3`; do - docker pull $image && break - sleep 1 - done -done + "projects.registry.vmware.com/antrea/perftool") + +FLOW_VISIBILITY_IMAGE_LIST=("projects.registry.vmware.com/antrea/ipfix-collector:v0.5.12" \ + "projects.registry.vmware.com/antrea/flow-visibility-clickhouse-operator:0.18.2" \ + "projects.registry.vmware.com/antrea/flow-visibility-metrics-exporter:0.18.2" \ + "projects.registry.vmware.com/antrea/flow-visibility-clickhouse-server:21.11" \ + "projects.registry.vmware.com/antrea/flow-visibility-clickhouse-monitor:latest") if $coverage; then manifest_args="$manifest_args --coverage" COMMON_IMAGES_LIST+=("antrea/antrea-ubuntu-coverage:latest") - COMMON_IMAGES_LIST+=("antrea/flow-aggregator-coverage:latest") else COMMON_IMAGES_LIST+=("projects.registry.vmware.com/antrea/antrea-ubuntu:latest") - COMMON_IMAGES_LIST+=("projects.registry.vmware.com/antrea/flow-aggregator:latest") fi if $proxy_all; then COMMON_IMAGES_LIST+=("k8s.gcr.io/echoserver:1.10") fi +if $flow_visibility; then + COMMON_IMAGES_LIST+=("${FLOW_VISIBILITY_IMAGE_LIST[@]}") + if $coverage; then + COMMON_IMAGES_LIST+=("antrea/flow-aggregator-coverage:latest") + else + COMMON_IMAGES_LIST+=("projects.registry.vmware.com/antrea/flow-aggregator:latest") + fi +fi +for image in "${COMMON_IMAGES_LIST[@]}"; do + for i in `seq 3`; do + docker pull $image && break + sleep 1 + done +done printf -v COMMON_IMAGES "%s " "${COMMON_IMAGES_LIST[@]}" -function run_test { - current_mode=$1 - args=$2 +function setup_cluster { + args=$1 if [[ "$ipfamily" == "v6" ]]; then args="$args --ip-family ipv6 --pod-cidr fd00:10:244::/56" @@ -166,45 +214,69 @@ function run_test { echo "creating test bed with args $args" eval "timeout 600 $TESTBED_CMD create kind $args" +} + +function run_test { + current_mode=$1 + coverage_args="" + flow_visibility_args="" if $coverage; then $YML_CMD --encap-mode $current_mode $manifest_args | docker exec -i kind-control-plane dd of=/root/antrea-coverage.yml $YML_CMD --ipsec $manifest_args | docker exec -i kind-control-plane dd of=/root/antrea-ipsec-coverage.yml - $FLOWAGGREGATOR_YML_CMD --coverage | docker exec -i kind-control-plane dd of=/root/flow-aggregator-coverage.yml + timeout="80m" + coverage_args="--coverage --coverage-dir $ANTREA_COV_DIR" else $YML_CMD --encap-mode $current_mode $manifest_args | docker exec -i kind-control-plane dd of=/root/antrea.yml $YML_CMD --ipsec $manifest_args | docker exec -i kind-control-plane dd of=/root/antrea-ipsec.yml - $FLOWAGGREGATOR_YML_CMD | docker exec -i kind-control-plane dd of=/root/flow-aggregator.yml + timeout="75m" fi + + if $flow_visibility; then + timeout="10m" + flow_visibility_args="-run=TestFlowAggregator --flow-visibility" + if $coverage; then + $FLOWAGGREGATOR_YML_CMD --coverage | docker exec -i kind-control-plane dd of=/root/flow-aggregator-coverage.yml + else + $FLOWAGGREGATOR_YML_CMD | docker exec -i kind-control-plane dd of=/root/flow-aggregator.yml + fi + $FLOW_VISIBILITY_CMD | docker exec -i kind-control-plane dd of=/root/flow-visibility.yml + cat $CH_OPERATOR_YML | docker exec -i kind-control-plane dd of=/root/clickhouse-operator-install-bundle.yml + fi + if $proxy_all; then apiserver=$(docker exec -i kind-control-plane kubectl get endpoints kubernetes --no-headers | awk '{print $2}') if $coverage; then - docker exec -i kind-control-plane sed -i.bak -E "s/^[[:space:]]*#kubeAPIServerOverride[[:space:]]*:[[:space:]]*[a-z\"]+[[:space:]]*$/ kubeAPIServerOverride: \"$apiserver\"/" /root/antrea-coverage.yml /root/antrea-ipsec-coverage.yml + docker exec -i kind-control-plane sed -i.bak -E "s/^[[:space:]]*[#]?kubeAPIServerOverride[[:space:]]*:[[:space:]]*[a-z\"]+[[:space:]]*$/ kubeAPIServerOverride: \"$apiserver\"/" /root/antrea-coverage.yml /root/antrea-ipsec-coverage.yml else - docker exec -i kind-control-plane sed -i.bak -E "s/^[[:space:]]*#kubeAPIServerOverride[[:space:]]*:[[:space:]]*[a-z\"]+[[:space:]]*$/ kubeAPIServerOverride: \"$apiserver\"/" /root/antrea.yml /root/antrea-ipsec.yml + docker exec -i kind-control-plane sed -i.bak -E "s/^[[:space:]]*[#]?kubeAPIServerOverride[[:space:]]*:[[:space:]]*[a-z\"]+[[:space:]]*$/ kubeAPIServerOverride: \"$apiserver\"/" /root/antrea.yml /root/antrea-ipsec.yml fi fi sleep 1 - if $coverage; then - go test -v -timeout=80m antrea.io/antrea/test/e2e -provider=kind --logs-export-dir=$ANTREA_LOG_DIR --coverage --coverage-dir $ANTREA_COV_DIR --skip=$skiplist - else - go test -v -timeout=75m antrea.io/antrea/test/e2e -provider=kind --logs-export-dir=$ANTREA_LOG_DIR --skip=$skiplist - fi - $TESTBED_CMD destroy kind + go test -v -timeout=$timeout antrea.io/antrea/test/e2e $flow_visibility_args -provider=kind --logs-export-dir=$ANTREA_LOG_DIR --skip=$skiplist $coverage_args } if [[ "$mode" == "" ]] || [[ "$mode" == "encap" ]]; then echo "======== Test encap mode ==========" - run_test encap "--images \"$COMMON_IMAGES\"" + if [[ $test_only == "false" ]];then + setup_cluster "--images \"$COMMON_IMAGES\"" + fi + run_test encap fi if [[ "$mode" == "" ]] || [[ "$mode" == "noEncap" ]]; then echo "======== Test noencap mode ==========" - run_test noEncap "--images \"$COMMON_IMAGES\"" + if [[ $test_only == "false" ]];then + setup_cluster "--images \"$COMMON_IMAGES\"" + fi + run_test noEncap fi if [[ "$mode" == "" ]] || [[ "$mode" == "hybrid" ]]; then echo "======== Test hybrid mode ==========" - run_test hybrid "--subnets \"20.20.20.0/24\" --images \"$COMMON_IMAGES\"" + if [[ $test_only == "false" ]];then + setup_cluster "--subnets \"20.20.20.0/24\" --images \"$COMMON_IMAGES\"" + fi + run_test hybrid fi exit 0 diff --git a/ci/kind/validate-metrics-doc.sh b/ci/kind/validate-metrics-doc.sh index 907f008836b..e64f09b143b 100755 --- a/ci/kind/validate-metrics-doc.sh +++ b/ci/kind/validate-metrics-doc.sh @@ -35,11 +35,11 @@ METRICS_DOC="$THIS_DIR/../../docs/prometheus-integration.md" cp -v $METRICS_DOC $METRICS_TMP_DOC $MAKE_CMD $METRICS_TMP_DOC -cmp -s $METRICS_DOC $METRICS_TMP_DOC -result=$? +result=0 +cmp -s $METRICS_DOC $METRICS_TMP_DOC || result=$? if [ $result -ne 0 ]; then echo "Error: Prometheus metrics document should be updated" - echo "You can update it by building the Antrea Docker image locally (with `make`), running ./hack/make-metrics-doc.sh and committing the changes" + echo "You can update it by building the Antrea Docker image locally (with 'make'), running ./hack/make-metrics-doc.sh and committing the changes" exit 1 fi diff --git a/ci/kind/values-flow-exporter.yml b/ci/kind/values-flow-exporter.yml new file mode 100644 index 00000000000..ff606cd67c3 --- /dev/null +++ b/ci/kind/values-flow-exporter.yml @@ -0,0 +1,4 @@ +flowCollector: + flowPollInterval: "1s" + activeFlowExportTimeout: "2s" + idleFlowExportTimeout: "1s" diff --git a/ci/run-k8s-e2e-tests.sh b/ci/run-k8s-e2e-tests.sh index 1d6bb743ee0..fe692537d8a 100755 --- a/ci/run-k8s-e2e-tests.sh +++ b/ci/run-k8s-e2e-tests.sh @@ -37,12 +37,12 @@ DEFAULT_E2E_NETWORKPOLICY_FOCUS="\[Feature:NetworkPolicy\]" DEFAULT_E2E_NETWORKPOLICY_SKIP="" MODE="report" THIS_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" -KUBE_CONFORMANCE_IMAGE="" -KUBE_CONFORMANCE_IMAGE_VERSION="$(head -n1 $THIS_DIR/k8s-conformance-image-version)" +KUBE_CONFORMANCE_IMAGE_OPTION="" +KUBE_CONFORMANCE_IMAGE_VERSION_OPTION="" IMAGE_PULL_POLICY="Always" CONFORMANCE_IMAGE_CONFIG_PATH="${THIS_DIR}/conformance-image-config.yaml" -SONOBUOY_IMAGE="projects.registry.vmware.com/sonobuoy/sonobuoy:v0.19.0" -SYSTEMD_LOGS_IMAGE="projects.registry.vmware.com/sonobuoy/systemd-logs:v0.3" +SONOBUOY_IMAGE="projects.registry.vmware.com/sonobuoy/sonobuoy:v0.56.4" +SYSTEMD_LOGS_IMAGE="projects.registry.vmware.com/sonobuoy/systemd-logs:v0.4" _usage="Usage: $0 [--e2e-conformance] [--e2e-network-policy] [--e2e-focus ] [--e2e-skip ] [--kubeconfig ] [--kube-conformance-image-version ] @@ -91,7 +91,7 @@ case $key in shift 2 ;; --kube-conformance-image-version) - KUBE_CONFORMANCE_IMAGE_VERSION="$2" + KUBE_CONFORMANCE_IMAGE_VERSION_OPTION="--kube-conformance-image-version $2" shift 2 ;; --e2e-conformance) @@ -172,14 +172,14 @@ function run_sonobuoy() { $SONOBUOY run --wait \ $KUBECONFIG_OPTION \ $KUBE_CONFORMANCE_IMAGE_OPTION \ - --kube-conformance-image-version $KUBE_CONFORMANCE_IMAGE_VERSION \ + $KUBE_CONFORMANCE_IMAGE_VERSION_OPTION \ --mode "certified-conformance" --image-pull-policy ${IMAGE_PULL_POLICY} \ --sonobuoy-image ${SONOBUOY_IMAGE} --systemd-logs-image ${SYSTEMD_LOGS_IMAGE} --e2e-repo-config ${CONFORMANCE_IMAGE_CONFIG_PATH} else $SONOBUOY run --wait \ $KUBECONFIG_OPTION \ $KUBE_CONFORMANCE_IMAGE_OPTION \ - --kube-conformance-image-version $KUBE_CONFORMANCE_IMAGE_VERSION \ + $KUBE_CONFORMANCE_IMAGE_VERSION_OPTION \ --e2e-focus "$focus_regex" --e2e-skip "$skip_regex" --image-pull-policy ${IMAGE_PULL_POLICY} \ --sonobuoy-image ${SONOBUOY_IMAGE} --systemd-logs-image ${SYSTEMD_LOGS_IMAGE} --e2e-repo-config ${CONFORMANCE_IMAGE_CONFIG_PATH} fi diff --git a/ci/test-conformance-aks.sh b/ci/test-conformance-aks.sh index 2657c18525b..8312334ab37 100755 --- a/ci/test-conformance-aks.sh +++ b/ci/test-conformance-aks.sh @@ -30,7 +30,7 @@ RUN_CLEANUP_ONLY=false KUBECONFIG_PATH="$HOME/jenkins/out/aks" TEST_SCRIPT_RC=0 MODE="report" -KUBE_CONFORMANCE_IMAGE_VERSION=v1.19.4 +KUBE_CONFORMANCE_IMAGE_VERSION=auto _usage="Usage: $0 [--cluster-name ] [--kubeconfig ] [--k8s-version ]\ [--azure-app-id ] [--azure-tenant-id ] [--azure-password ] \ diff --git a/ci/test-conformance-eks.sh b/ci/test-conformance-eks.sh index 72c88277718..ebe179b150d 100755 --- a/ci/test-conformance-eks.sh +++ b/ci/test-conformance-eks.sh @@ -31,7 +31,7 @@ RUN_CLEANUP_ONLY=false KUBECONFIG_PATH="$HOME/jenkins/out/eks" MODE="report" TEST_SCRIPT_RC=0 -KUBE_CONFORMANCE_IMAGE_VERSION=v1.18.5 +KUBE_CONFORMANCE_IMAGE_VERSION=auto _usage="Usage: $0 [--cluster-name ] [--kubeconfig ] [--k8s-version ]\ [--aws-access-key ] [--aws-secret-key ] [--aws-region ] [--ssh-key /dev/null 2>&1 && pwd )" -GIT_CHECKOUT_DIR=${THIS_DIR}/.. - -_usage="Usage: $0 [--kubeconfig ] - -Setup Elastic stack (elk) flow collector and Antrea Agent flow exporter to validate elk-flow-collector.yml. - - --kubeconfig Path to kubeconfig. - -" - -echoerr() { - >&2 echo "$@" -} - -print_usage() { - echoerr "$_usage" -} - - -while [[ $# -gt 0 ]] -do -key="$1" -case $key in - --kubeconfig) - export KUBECONFIG="$2" - echo "kube" - shift 2 - ;; - -h|--help) - print_usage - exit 0 - ;; - *) - echoerr "Unknown option $1" - exit 1 - ;; -esac -done - -start_antrea() { - echo "=== Starting Antrea ===" - kubectl apply -f ${GIT_CHECKOUT_DIR}/build/yamls/antrea.yml - kubectl rollout status --timeout=5m deployment/coredns -n kube-system - kubectl rollout status --timeout=5m deployment.apps/antrea-controller -n kube-system - kubectl rollout status --timeout=5m daemonset/antrea-agent -n kube-system -} - -setup_flow_collector() { - echo "=== Starting Flow Collector ===" - kubectl create namespace elk-flow-collector - kubectl create configmap logstash-configmap -n elk-flow-collector --from-file=${GIT_CHECKOUT_DIR}/build/yamls/elk-flow-collector/logstash/ - kubectl apply -f ${GIT_CHECKOUT_DIR}/build/yamls/elk-flow-collector/elk-flow-collector.yml -n elk-flow-collector - echo "=== Waiting for Elastic Stack to be ready ===" - kubectl wait --for=condition=ready pod -l app=kibana -n elk-flow-collector --timeout=600s - kubectl wait --for=condition=ready pod -l app=logstash -n elk-flow-collector --timeout=600s - kubectl wait --for=condition=ready pod -l app=elasticsearch -n elk-flow-collector --timeout=600s - # wait some time for logstash to connect to elasticsearch - sleep 30s - # get cluster-ip of logstash - LOGSTASH_IP=$(kubectl get svc logstash -n elk-flow-collector -o jsonpath='{.spec.clusterIP}') - if [ ${LOGSTASH_PROTOCOL} = "udp" ]; then - nc -zvu ${LOGSTASH_IP} ${LOGSTASH_PORT} - fi - echo "=== Flow Collector is listening on ${LOGSTASH_IP}:${LOGSTASH_PORT} ===" -} - -config_antrea() { - echo "=== Stopping Antrea === " - kubectl delete -f ${GIT_CHECKOUT_DIR}/build/yamls/antrea.yml - echo "=== Configuring Antrea Flow Exporter Address ===" - sed -i -e "s/#flowCollectorAddr.*/flowCollectorAddr: \"${LOGSTASH_IP}:${LOGSTASH_PORT}:${LOGSTASH_PROTOCOL}\"/g" ${GIT_CHECKOUT_DIR}/build/yamls/antrea.yml - sed -i -e "s/# FlowExporter: false/ FlowExporter: true/g" ${GIT_CHECKOUT_DIR}/build/yamls/antrea.yml -} - -# Antrea agent flow exporter starts to send CoreDNS flow records. -# It will check if flow records with one of desired fields (soursePodName) are received correctly. -check_record() { - echo "=== Wait for up to 5 minutes to receive data ===" - for i in `seq 5` - do - sleep 1m - echo "=== Get flow record (try for 1m) ===" - # if the records are received in logstash and processed correctly, the logstash logs should show the formatted data, which have 'sourcePodName' field - LOGSTASH_LOGS=$(kubectl logs -n elk-flow-collector $(kubectl -n elk-flow-collector get pod -l app=logstash -o jsonpath="{.items[0].metadata.name}")) - if ( echo ${LOGSTASH_LOGS} | grep -q 'sourcePodName' ); then - echo "=== Record is received correctly ===" - break - elif [ $i == 5 ]; then - echo "=== Record is NOT received correctly ===" - FAILURE=true - fi - done -} - -start_antrea -setup_flow_collector -config_antrea -start_antrea -check_record - -if ( ${FAILURE} == true ); then - echo "=== TEST FAILURE !! ===" - touch TEST_FAILURE -fi diff --git a/ci/verify-sonobuoy.sh b/ci/verify-sonobuoy.sh index 7a8b19d8c7a..513ddf5e8f4 100755 --- a/ci/verify-sonobuoy.sh +++ b/ci/verify-sonobuoy.sh @@ -16,7 +16,7 @@ _SONOBUOY_BINDIR="/tmp/antrea" _SONOBUOY_TARBALL="/tmp/sonobuoy.tar.gz" -_MIN_SONOBUOY_VERSION="v0.19.0" +_MIN_SONOBUOY_VERSION="v0.56.4" install_sonobuoy() { local ostype="" diff --git a/cmd/antctl/main.go b/cmd/antctl/main.go index 6628b920386..128fe96f413 100644 --- a/cmd/antctl/main.go +++ b/cmd/antctl/main.go @@ -15,17 +15,15 @@ package main import ( - "flag" "math/rand" "os" "path" "time" "github.com/spf13/cobra" - "github.com/spf13/pflag" - "k8s.io/component-base/logs" "antrea.io/antrea/pkg/antctl" + "antrea.io/antrea/pkg/log" ) var commandName = path.Base(os.Args[0]) @@ -36,22 +34,14 @@ var rootCmd = &cobra.Command{ Long: commandName + " is the command line tool for Antrea that supports showing status of ${component}", } -func init() { - // prevent any unexpected output at beginning - flag.Set("logtostderr", "false") - flag.Set("v", "0") - pflag.CommandLine.MarkHidden("log-flush-frequency") -} - func main() { - logs.InitLogs() - defer logs.FlushLogs() + defer log.FlushLogs() rand.Seed(time.Now().UTC().UnixNano()) antctl.CommandList.ApplyToRootCommand(rootCmd) err := rootCmd.Execute() if err != nil { - logs.FlushLogs() + log.FlushLogs() os.Exit(1) } } diff --git a/cmd/antrea-agent-simulator/main.go b/cmd/antrea-agent-simulator/main.go index 611b1905e2c..c63321bac85 100644 --- a/cmd/antrea-agent-simulator/main.go +++ b/cmd/antrea-agent-simulator/main.go @@ -18,11 +18,9 @@ package main import ( - "flag" "os" "github.com/spf13/cobra" - "k8s.io/component-base/logs" "k8s.io/klog/v2" "antrea.io/antrea/pkg/log" @@ -30,12 +28,8 @@ import ( ) func main() { - logs.InitLogs() - defer logs.FlushLogs() - command := newSimulatorCommand() if err := command.Execute(); err != nil { - logs.FlushLogs() os.Exit(1) } } @@ -45,7 +39,8 @@ func newSimulatorCommand() *cobra.Command { Use: "antrea-agent-simulator", Long: "The Antrea agent simulator.", Run: func(cmd *cobra.Command, args []string) { - log.InitLogFileLimits(cmd.Flags()) + log.InitLogs(cmd.Flags()) + defer log.FlushLogs() if err := run(); err != nil { klog.Fatalf("Error running agent: %v", err) @@ -57,7 +52,5 @@ func newSimulatorCommand() *cobra.Command { flags := cmd.Flags() log.AddFlags(flags) - // Install log flags - flags.AddGoFlagSet(flag.CommandLine) return cmd } diff --git a/cmd/antrea-agent-simulator/simulator.go b/cmd/antrea-agent-simulator/simulator.go index 06241127bbe..bcc4835078d 100644 --- a/cmd/antrea-agent-simulator/simulator.go +++ b/cmd/antrea-agent-simulator/simulator.go @@ -57,8 +57,13 @@ func run() error { // Create the stop chan with signals stopCh := signals.RegisterSignalHandlers() + // Generate a context for functions which require one (instead of stopCh). + // We cancel the context when the function returns, which in the normal case will be when + // stopCh is closed. + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() - go antreaClientProvider.Run(stopCh) + go antreaClientProvider.Run(ctx) // Add loop to check whether client is ready attempts := 0 diff --git a/cmd/antrea-agent/agent.go b/cmd/antrea-agent/agent.go index 0f3bd816c05..362e3788996 100644 --- a/cmd/antrea-agent/agent.go +++ b/cmd/antrea-agent/agent.go @@ -15,6 +15,7 @@ package main import ( + "context" "fmt" "net" "time" @@ -64,7 +65,6 @@ import ( "antrea.io/antrea/pkg/util/channel" "antrea.io/antrea/pkg/util/cipher" "antrea.io/antrea/pkg/util/k8s" - "antrea.io/antrea/pkg/util/runtime" "antrea.io/antrea/pkg/version" ) @@ -84,9 +84,6 @@ var excludeNodePortDevices = []string{"antrea-egress0", "antrea-ingress0", "kube func run(o *Options) error { klog.Infof("Starting Antrea agent (version %s)", version.GetFullVersion()) - // Windows platform doesn't support Egress feature yet. - egressEnabled := features.DefaultFeatureGate.Enabled(features.Egress) && !runtime.IsWindowsPlatform() - // Create K8s Clientset, CRD Clientset and SharedInformerFactory for the given config. k8sClient, _, crdClient, _, err := k8s.CreateClients(o.config.ClientConnection, o.config.KubeAPIServerOverride) if err != nil { @@ -119,25 +116,28 @@ func run(o *Options) error { } defer ovsdbConnection.Close() - enableBridgingMode := features.DefaultFeatureGate.Enabled(features.AntreaIPAM) && o.config.EnableBridgingMode + egressEnabled := features.DefaultFeatureGate.Enabled(features.Egress) + enableAntreaIPAM := features.DefaultFeatureGate.Enabled(features.AntreaIPAM) + enableBridgingMode := enableAntreaIPAM && o.config.EnableBridgingMode // Bridging mode will connect the uplink interface to the OVS bridge. connectUplinkToBridge := enableBridgingMode ovsDatapathType := ovsconfig.OVSDatapathType(o.config.OVSDatapathType) ovsBridgeClient := ovsconfig.NewOVSBridge(o.config.OVSBridge, ovsDatapathType, ovsdbConnection) ovsBridgeMgmtAddr := ofconfig.GetMgmtAddress(o.config.OVSRunDir, o.config.OVSBridge) - ofClient := openflow.NewClient(o.config.OVSBridge, ovsBridgeMgmtAddr, ovsDatapathType, + ofClient := openflow.NewClient(o.config.OVSBridge, ovsBridgeMgmtAddr, features.DefaultFeatureGate.Enabled(features.AntreaProxy), features.DefaultFeatureGate.Enabled(features.AntreaPolicy), egressEnabled, features.DefaultFeatureGate.Enabled(features.FlowExporter), o.config.AntreaProxy.ProxyAll, connectUplinkToBridge, - features.DefaultFeatureGate.Enabled(features.Multicast)) + features.DefaultFeatureGate.Enabled(features.Multicast), + features.DefaultFeatureGate.Enabled(features.TrafficControl), + ) _, serviceCIDRNet, _ := net.ParseCIDR(o.config.ServiceCIDR) var serviceCIDRNetv6 *net.IPNet - // Todo: use FeatureGate to check if IPv6 is enabled and then read configuration item "ServiceCIDRv6". if o.config.ServiceCIDRv6 != "" { _, serviceCIDRNetv6, _ = net.ParseCIDR(o.config.ServiceCIDRv6) } @@ -182,6 +182,11 @@ func run(o *Options) error { // cause the stopCh channel to be closed; if another signal is received before the program // exits, we will force exit. stopCh := signals.RegisterSignalHandlers() + // Generate a context for functions which require one (instead of stopCh). + // We cancel the context when the function returns, which in the normal case will be when + // stopCh is closed. + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() // Get all available NodePort addresses. var nodePortAddressesIPv4, nodePortAddressesIPv6 []net.IP @@ -191,6 +196,12 @@ func run(o *Options) error { return fmt.Errorf("getting available NodePort IP addresses failed: %v", err) } } + serviceConfig := &config.ServiceConfig{ + ServiceCIDR: serviceCIDRNet, + ServiceCIDRv6: serviceCIDRNetv6, + NodePortAddressesIPv4: nodePortAddressesIPv4, + NodePortAddressesIPv6: nodePortAddressesIPv6, + } // Initialize agent and node network. agentInitializer := agent.NewInitializer( @@ -202,17 +213,14 @@ func run(o *Options) error { o.config.OVSBridge, o.config.HostGateway, o.config.DefaultMTU, - serviceCIDRNet, - serviceCIDRNetv6, networkConfig, wireguardConfig, egressConfig, + serviceConfig, networkReadyCh, stopCh, features.DefaultFeatureGate.Enabled(features.AntreaProxy), o.config.AntreaProxy.ProxyAll, - nodePortAddressesIPv4, - nodePortAddressesIPv6, connectUplinkToBridge) err = agentInitializer.Initialize() if err != nil { @@ -362,9 +370,11 @@ func run(o *Options) error { o.config.HostProcPathPrefix, nodeConfig, k8sClient, - isChaining, - enableBridgingMode, // activate AntreaIPAM in CNIServer when bridging mode is enabled routeClient, + isChaining, + enableBridgingMode, + enableAntreaIPAM, + o.config.DisableTXChecksumOffload, networkReadyCh) var cniPodInfoStore cnipodcache.CNIPodInfoStore @@ -472,7 +482,7 @@ func run(o *Options) error { go cniServer.Run(stopCh) - go antreaClientProvider.Run(stopCh) + go antreaClientProvider.Run(ctx) go nodeRouteController.Run(stopCh) @@ -493,15 +503,11 @@ func run(o *Options) error { go nplController.Run(stopCh) } - // Now Antrea IPAM is used only by bridging mode, so we initialize AntreaIPAMController only - // when the bridging mode is enabled. - if enableBridgingMode { + // Antrea IPAM is needed by bridging mode and secondary network IPAM. + if enableAntreaIPAM { ipamController, err := ipam.InitializeAntreaIPAMController( - k8sClient, - crdClient, - informerFactory, - localPodInformer, - crdInformerFactory) + crdClient, informerFactory, crdInformerFactory, + localPodInformer, enableBridgingMode) if err != nil { return fmt.Errorf("failed to start Antrea IPAM agent: %v", err) } @@ -579,11 +585,14 @@ func run(o *Options) error { } mcastController := multicast.NewMulticastController( ofClient, + v4GroupIDAllocator, nodeConfig, ifaceStore, multicastSocket, - sets.NewString(append(o.config.MulticastInterfaces, nodeConfig.NodeTransportInterfaceName)...), - ovsBridgeClient) + sets.NewString(append(o.config.Multicast.MulticastInterfaces, nodeConfig.NodeTransportInterfaceName)...), + ovsBridgeClient, + podUpdateChannel, + o.igmpQueryInterval) if err := mcastController.Initialize(); err != nil { return err } @@ -612,6 +621,7 @@ func run(o *Options) error { apiServer, err := apiserver.New( agentQuerier, networkPolicyController, + externalIPController, o.config.APIPort, *o.config.EnablePrometheusMetrics, o.config.ClientConnection.Kubeconfig, @@ -624,17 +634,8 @@ func run(o *Options) error { } go apiServer.Run(stopCh) - // Start PacketIn for features and specify their own reason. - var packetInReasons []uint8 - if features.DefaultFeatureGate.Enabled(features.Traceflow) { - packetInReasons = append(packetInReasons, uint8(openflow.PacketInReasonTF)) - } - if features.DefaultFeatureGate.Enabled(features.AntreaPolicy) { - packetInReasons = append(packetInReasons, uint8(openflow.PacketInReasonNP)) - } - if len(packetInReasons) > 0 { - go ofClient.StartPacketInHandler(packetInReasons, stopCh) - } + // Start PacketIn + go ofClient.StartPacketInHandler(stopCh) // Start the goroutine to periodically export IPFIX flow records. if features.DefaultFeatureGate.Enabled(features.FlowExporter) { diff --git a/cmd/antrea-agent/main.go b/cmd/antrea-agent/main.go index 5387996e1eb..7035eb40dc2 100644 --- a/cmd/antrea-agent/main.go +++ b/cmd/antrea-agent/main.go @@ -18,11 +18,9 @@ package main import ( - "flag" "os" "github.com/spf13/cobra" - "k8s.io/component-base/logs" "k8s.io/klog/v2" "antrea.io/antrea/pkg/log" @@ -30,12 +28,8 @@ import ( ) func main() { - logs.InitLogs() - defer logs.FlushLogs() - command := newAgentCommand() if err := command.Execute(); err != nil { - logs.FlushLogs() os.Exit(1) } } @@ -47,7 +41,8 @@ func newAgentCommand() *cobra.Command { Use: "antrea-agent", Long: "The Antrea agent runs on each node.", Run: func(cmd *cobra.Command, args []string) { - log.InitLogFileLimits(cmd.Flags()) + log.InitLogs(cmd.Flags()) + defer log.FlushLogs() if err := opts.complete(args); err != nil { klog.Fatalf("Failed to complete: %v", err) } @@ -64,7 +59,5 @@ func newAgentCommand() *cobra.Command { flags := cmd.Flags() opts.addFlags(flags) log.AddFlags(flags) - // Install log flags - flags.AddGoFlagSet(flag.CommandLine) return cmd } diff --git a/cmd/antrea-agent/options.go b/cmd/antrea-agent/options.go index 988b8a3b832..fbc7c7784d0 100644 --- a/cmd/antrea-agent/options.go +++ b/cmd/antrea-agent/options.go @@ -47,6 +47,7 @@ const ( defaultFlowPollInterval = 5 * time.Second defaultActiveFlowExportTimeout = 30 * time.Second defaultIdleFlowExportTimeout = 15 * time.Second + defaultIGMPQueryInterval = 125 * time.Second defaultStaleConnectionTimeout = 5 * time.Minute defaultNPLPortRange = "61000-62000" ) @@ -68,6 +69,7 @@ type Options struct { idleFlowTimeout time.Duration // Stale connection timeout to delete connections if they are not exported. staleConnectionTimeout time.Duration + igmpQueryInterval time.Duration nplStartPort int nplEndPort int } @@ -161,6 +163,9 @@ func (o *Options) validate(args []string) error { if err := o.validateFlowExporterConfig(); err != nil { return fmt.Errorf("failed to validate flow exporter config: %v", err) } + if err := o.validateMulticastConfig(); err != nil { + return fmt.Errorf("failed to validate multicast config: %v", err) + } if features.DefaultFeatureGate.Enabled(features.Egress) { for _, cidr := range o.config.Egress.ExceptCIDRs { _, _, err := net.ParseCIDR(cidr) @@ -271,6 +276,12 @@ func (o *Options) setDefaults() { o.config.NodePortLocal.PortRange = defaultNPLPortRange } } + + if features.DefaultFeatureGate.Enabled(features.Multicast) { + if o.config.Multicast.IGMPQueryInterval == "" { + o.igmpQueryInterval = defaultIGMPQueryInterval + } + } } func (o *Options) validateAntreaProxyConfig() error { @@ -351,13 +362,25 @@ func (o *Options) validateFlowExporterConfig() error { return nil } +func (o *Options) validateMulticastConfig() error { + if features.DefaultFeatureGate.Enabled(features.Multicast) { + var err error + if o.config.Multicast.IGMPQueryInterval != "" { + o.igmpQueryInterval, err = time.ParseDuration(o.config.Multicast.IGMPQueryInterval) + if err != nil { + return err + } + } + } + return nil +} + func (o *Options) validateAntreaIPAMConfig() error { if !o.config.EnableBridgingMode { return nil } if !features.DefaultFeatureGate.Enabled(features.AntreaIPAM) { - klog.InfoS("The enableBridgingMode option is set to true, but it will be ignored because the AntreaIPAM feature gate is disabled") - return nil + return fmt.Errorf("AntreaIPAM feature gate must be enabled to configure bridging mode") } // Bridging mode will connect uplink to OVS bridge, which is not compatible with OVSDatapathSystem 'netdev'. if o.config.OVSDatapathType != string(ovsconfig.OVSDatapathSystem) { diff --git a/cmd/antrea-controller/controller.go b/cmd/antrea-controller/controller.go index 121c44b8e01..25b75bca3bb 100644 --- a/cmd/antrea-controller/controller.go +++ b/cmd/antrea-controller/controller.go @@ -15,6 +15,7 @@ package main import ( + "context" "fmt" "io/ioutil" "net" @@ -244,6 +245,11 @@ func run(o *Options) error { // cause the stopCh channel to be closed; if another signal is received before the program // exits, we will force exit. stopCh := signals.RegisterSignalHandlers() + // Generate a context for functions which require one (instead of stopCh). + // We cancel the context when the function returns, which in the normal case will be when + // stopCh is closed. + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() log.StartLogFileNumberMonitor(stopCh) @@ -262,7 +268,7 @@ func run(o *Options) error { go networkPolicyController.Run(stopCh) - go apiServer.Run(stopCh) + go apiServer.Run(ctx) if features.DefaultFeatureGate.Enabled(features.NetworkPolicyStats) { go statsAggregator.Run(stopCh) diff --git a/cmd/antrea-controller/main.go b/cmd/antrea-controller/main.go index 2b350c41108..8ac508bbe9d 100644 --- a/cmd/antrea-controller/main.go +++ b/cmd/antrea-controller/main.go @@ -18,11 +18,9 @@ package main import ( - "flag" "os" "github.com/spf13/cobra" - "k8s.io/component-base/logs" "k8s.io/klog/v2" "antrea.io/antrea/pkg/log" @@ -30,13 +28,8 @@ import ( ) func main() { - logs.InitLogs() - defer logs.FlushLogs() - command := newControllerCommand() - if err := command.Execute(); err != nil { - logs.FlushLogs() os.Exit(1) } } @@ -48,7 +41,8 @@ func newControllerCommand() *cobra.Command { Use: "antrea-controller", Long: "The Antrea Controller.", Run: func(cmd *cobra.Command, args []string) { - log.InitLogFileLimits(cmd.Flags()) + log.InitLogs(cmd.Flags()) + defer log.FlushLogs() if err := opts.complete(args); err != nil { klog.Fatalf("Failed to complete: %v", err) } @@ -65,7 +59,5 @@ func newControllerCommand() *cobra.Command { flags := cmd.Flags() opts.addFlags(flags) log.AddFlags(flags) - // Install log flags - flags.AddGoFlagSet(flag.CommandLine) return cmd } diff --git a/cmd/flow-aggregator/main.go b/cmd/flow-aggregator/main.go index 24c6439e113..4868c0820fc 100644 --- a/cmd/flow-aggregator/main.go +++ b/cmd/flow-aggregator/main.go @@ -18,11 +18,9 @@ package main import ( - "flag" "os" "github.com/spf13/cobra" - "k8s.io/component-base/logs" "k8s.io/klog/v2" "antrea.io/antrea/pkg/log" @@ -30,13 +28,8 @@ import ( ) func main() { - logs.InitLogs() - defer logs.FlushLogs() - command := newFlowAggregatorCommand() - if err := command.Execute(); err != nil { - logs.FlushLogs() os.Exit(1) } } @@ -48,7 +41,8 @@ func newFlowAggregatorCommand() *cobra.Command { Use: "flow-aggregator", Long: "The Flow Aggregator.", Run: func(cmd *cobra.Command, args []string) { - log.InitLogFileLimits(cmd.Flags()) + log.InitLogs(cmd.Flags()) + defer log.FlushLogs() if err := opts.complete(args); err != nil { klog.Fatalf("Failed to complete args: %v", err) } @@ -65,7 +59,5 @@ func newFlowAggregatorCommand() *cobra.Command { flags := cmd.Flags() opts.addFlags(flags) log.AddFlags(flags) - // Install log flags - flags.AddGoFlagSet(flag.CommandLine) return cmd } diff --git a/docs/antrea-ipam.md b/docs/antrea-ipam.md index 6cf76d8b6cc..a63a1110d1d 100644 --- a/docs/antrea-ipam.md +++ b/docs/antrea-ipam.md @@ -93,7 +93,7 @@ Antrea deployment YAML are: #### Create IPPool CR -The following example YAML manifests create an IPPool CR. +The following example YAML manifest creates an IPPool CR. ```yaml apiVersion: "crd.antrea.io/v1alpha2" @@ -112,7 +112,7 @@ spec: #### IPPool Annotations on Namespace -The following example YAML manifests create a Namespace to allocate Pod IPs from the IP pool. +The following example YAML manifest creates a Namespace to allocate Pod IPs from the IP pool. ```yaml kind: Namespace @@ -214,3 +214,165 @@ IP, because inter-Node traffic of AntreaIPAM Pods is forwarded by the Node netwo router should provide the network connectivity for these VLANs. Only a single IP pool can be included in the Namespace annotation. In the future, annotation of up to two pools for IPv4 and IPv6 respectively will be supported. + +## IPAM for Secondary Network + +With the AntreaIPAM feature, Antrea can allocate IPs for Pod secondary networks. At the +moment, AntreaIPAM supports secondary networks managed by [Multus](https://github.com/k8snetworkplumbingwg/multus-cni), +we will add support for [secondary networks managed by Antrea](feature-gates.md#secondarynetwork) +in the future. + +### Prerequisites + +The IPAM capability for secondary network was added in Antrea version 1.7. It +requires the `AntreaIPAM` feature gate to be enabled on both `antrea-controller` +and `antrea-agent`, as `AntreaIPAM` is still an alpha feature at this moment and +is not enabled by default. + +### CNI IPAM configuration + +To configure Antrea IPAM, `antrea` should be specified as the IPAM plugin in the +the CNI IPAM configuration, and at least one Antrea IPPool should be specified +in the `ippools` field. IPs will be allocated from the specified IPPool(s) for +the secondary network. + +```json +{ + "cniVersion": "0.3.0", + "name": "ipv4-net-1", + "type": "macvlan", + "master": "eth0", + "mode": "bridge", + "ipam": { + "type": "antrea", + "ippools": [ "ipv4-pool-1" ] + } +} +``` + +Multiple IPPools can be specified to allocate multiple IPs from each IPPool for +the secondary network. For example, you can specify one IPPool to allocate an +IPv4 address and another IPPool to allocate an IPv6 address in the dual-stack +case. + +```json +{ + "cniVersion": "0.3.0", + "name": "dual-stack-net-1", + "type": "macvlan", + "master": "eth0", + "mode": "bridge", + "ipam": { + "type": "antrea", + "ippools": [ "ipv4-pool-1", "ipv6-pool-1" ] + } +} +``` + +Additionally, Antrea IPAM also supports the same configuration of static IP +addresses, static routes, and DNS settings, as what is supported by the +[static IPAM plugin](https://www.cni.dev/plugins/current/ipam/static). The +following example requests an IP from an IPPool and also specifies two +additional static IP addresses. It also includes static routes and DNS settings. + +```json +{ + "cniVersion": "0.3.0", + "name": "pool-and-static-net-1", + "type": "bridge", + "bridge": "br0" + "ipam": { + "type": "antrea", + "ippools": [ "ipv4-pool-1" ], + "addresses": [ + { + "address": "10.10.0.1/24", + "gateway": "10.10.0.254" + }, + { + "address": "3ffe:ffff:0:01ff::1/64", + "gateway": "3ffe:ffff:0::1" + } + ], + "routes": [ + { "dst": "0.0.0.0/0" }, + { "dst": "192.168.0.0/16", "gw": "10.10.5.1" }, + { "dst": "3ffe:ffff:0:01ff::1/64" } + ], + "dns": { + "nameservers" : ["8.8.8.8"], + "domain": "example.com", + "search": [ "example.com" ] + } + } +} +``` + +The CNI IPAM configuration can include only static addresses without IPPools, if +only static IP addresses are needed. + +### Configuration with `NetworkAttachmentDefinition` CRD + +CNI and IPAM configuration of a secondary network is typically defined with the +`NetworkAttachmentDefinition` CRD. For example: + +```yaml +apiVersion: "k8s.cni.cncf.io/v1" +kind: NetworkAttachmentDefinition +metadata: + name: ipv4-net-1 +spec: + { + "cniVersion": "0.3.0", + "type": "macvlan", + "master": "eth0", + "mode": "bridge", + "ipam": { + "type": "antrea", + "ippools": [ "ipv4-pool-1" ] + } + } +``` + +## `IPPool` CRD + +Antrea IP pools are defined with the `IPPool` CRD. The following two examples +define an IPv4 and an IPv6 IP pool respectively. + +```yaml +apiVersion: "crd.antrea.io/v1alpha2" +kind: IPPool +metadata: + name: ipv4-pool-1 +spec: + ipVersion: 4 + ipRanges: + - cidr: "10.10.1.0/26" + gateway: "10.10.1.1" + prefixLength: 24 +``` + +```yaml +apiVersion: "crd.antrea.io/v1alpha2" +kind: IPPool +metadata: + name: ipv6-pool-1 +spec: + ipVersion: 6 + ipRanges: + - start: "3ffe:ffff:1:01ff::0100" + end: "3ffe:ffff:1:01ff::0200" + gateway: "3ffe:ffff:1:01ff::1" + prefixLength: 64 +``` + +VLAN ID in the IP range subnet definition of `IPPool` CRD is not supported for +secondary network IPAM. + +### Secondary Network creation with Multus + +To leverage Antrea for secondary network IPAM, Antrea must be used as the CNI +for the Pods' primary network, while the secondary networks are implemented by +other CNIs which are managed by Multus. The [Antrea + Multus guide](cookbooks/multus) +talks about how to use Antrea with Multus, including the option of using Antrea +IPAM for secondary networks. diff --git a/docs/antrea-network-policy.md b/docs/antrea-network-policy.md index 1e3304d7950..f2ff83ceb86 100644 --- a/docs/antrea-network-policy.md +++ b/docs/antrea-network-policy.md @@ -16,6 +16,7 @@ - [ACNP for strict Namespace isolation](#acnp-for-strict-namespace-isolation) - [ACNP for default zero-trust cluster security posture](#acnp-for-default-zero-trust-cluster-security-posture) - [ACNP for toServices rule](#acnp-for-toservices-rule) + - [ACNP for ICMP traffic](#acnp-for-icmp-traffic) - [Behavior of to and from selectors](#behavior-of-to-and-from-selectors) - [Key differences from K8s NetworkPolicy](#key-differences-from-k8s-networkpolicy) - [kubectl commands for Antrea ClusterNetworkPolicy](#kubectl-commands-for-antrea-clusternetworkpolicy) @@ -381,6 +382,33 @@ spec: enableLogging: true ``` +#### ACNP for ICMP traffic + +```yaml +apiVersion: crd.antrea.io/v1alpha1 +kind: ClusterNetworkPolicy +metadata: + name: acnp-reject-ping-request +spec: + priority: 5 + tier: securityops + appliedTo: + - podSelector: + matchLabels: + role: server + namespaceSelector: + matchLabels: + env: prod + egress: + - action: Reject + protocols: + - icmp: + icmpType: 8 + icmpCode: 0 + name: DropPingRequest + enableLogging: true +``` + **spec**: The ClusterNetworkPolicy `spec` has all the information needed to define a cluster-wide security policy. @@ -423,7 +451,7 @@ default tier i.e. the "application" Tier. **action**: Each ingress or egress rule of a ClusterNetworkPolicy must have the `action` field set. As of now, the available actions are ["Allow", "Drop", "Reject", "Pass"]. When the rule action is "Allow" or "Drop", Antrea will allow or drop traffic which -matches both `from/to` and `ports` sections of that rule, given that traffic does not +matches both `from/to`, `ports` and `protocols` sections of that rule, given that traffic does not match a higher precedence rule in the cluster (ACNP rules created in higher order Tiers or policy instances in the same Tier with lower priority number). If a "Reject" rule is matched, the client initiating the traffic will receive `ICMP host administratively @@ -439,6 +467,9 @@ configurations will be rejected by the admission controller. **ingress**: Each ClusterNetworkPolicy may consist of zero or more ordered set of ingress rules. Under `ports`, the optional field `endPort` can only be set when a numerical `port` is set to represent a range of ports from `port` to `endPort` inclusive. +`protocols` defines additional protocols that are not supported by `ports`. Currently, only +ICMP protocol is under `protocols`. `icmpType` and `icmpCode` could be used to specify the ICMP +traffic that this rule matches. Also, each rule has an optional `name` field, which should be unique within the policy describing the intention of this rule. If `name` is not provided for a rule, it will be auto-generated by Antrea. The auto-generated name will be @@ -470,6 +501,9 @@ of egress rules. Each rule, depending on the `action` field of the rule, allows or drops traffic which matches all `from`, `ports` sections. Under `ports`, the optional field `endPort` can only be set when a numerical `port` is set to represent a range of ports from `port` to `endPort` inclusive. +`protocols` defines additional protocols that are not supported by `ports`. Currently, only +ICMP protocol is under `protocols`. `icmpType` and `icmpCode` could be used to specify the ICMP +traffic that this rule matches. Also, each rule has an optional `name` field, which should be unique within the policy describing the intention of this rule. If `name` is not provided for a rule, it will be auto-generated by Antrea. The rule name auto-generation process diff --git a/docs/antrea-proxy.md b/docs/antrea-proxy.md new file mode 100644 index 00000000000..c504d7ec84b --- /dev/null +++ b/docs/antrea-proxy.md @@ -0,0 +1,219 @@ +# AntreaProxy + +## Table of Contents + + +- [Introduction](#introduction) +- [AntreaProxy with proxyAll](#antreaproxy-with-proxyall) + - [Removing kube-proxy](#removing-kube-proxy) + - [Windows Nodes](#windows-nodes) +- [Special use cases](#special-use-cases) + - [When you are using NodeLocal DNSCache](#when-you-are-using-nodelocal-dnscache) + - [When you want your external LoadBalancer to handle Pod traffic](#when-you-want-your-external-loadbalancer-to-handle-pod-traffic) +- [Known issues or limitations](#known-issues-or-limitations) + + +## Introduction + +AntreaProxy was first introduced in Antrea v0.8 and has been enabled by default +on all platforms since v0.11. AntreaProxy enables some or all of the cluster's +Service traffic to be load-balanced as part of the OVS pipeline, instead of +depending on kube-proxy. We typically observe latency improvements for Service +traffic when AntreaProxy is used. + +While AntreaProxy can be disabled on Linux Nodes by setting the `AntreaProxy` +Feature Gate to `false`, it should remain enabled on all Windows Nodes, as it is +needed for correct NetworkPolicy implementation for Pod-to-Service traffic. + +By default, AntreaProxy will only handle Service traffic originating from Pods +in the cluster, with no support for NodePort. However, starting with Antrea +v1.4, a new operating mode was introduced in which AntreaProxy can handle all +Service traffic, including NodePort. See the following +[section](#antreaproxy-with-proxyall) for more information. + +## AntreaProxy with proxyAll + +The `proxyAll` configuration parameter can be enabled in the Antrea +configuration if you want AntreaProxy to handle all Service traffic, with the +possibility to remove kube-proxy altogether and have one less DaemonSet running +in the cluster. This is particularly interesting on Windows Nodes, since until +the introduction of `proxyAll`, Antrea relied on userspace kube-proxy, which is +no longer actively maintained by the K8s community and is slower than other +kube-proxy backends. + +Note that on Linux, even when `proxyAll` is enabled, kube-proxy will usually +take priority and will keep handling NodePort Service traffic (unless the source +is a Pod, which is pretty unusual as Pods typically access Services by +ClusterIP). This is because kube-proxy rules typically come before the rules +installed by AntreaProxy to redirect traffic to OVS. When kube-proxy is not +deployed or is removed from the cluster, AntreaProxy will then handle all +Service traffic. + +### Removing kube-proxy + +In this section, we will provide steps to run a K8s cluster without kube-proxy, +with Antrea being responsible for all Service traffic. + +You can create a K8s cluster without kube-proxy with kubeadm as follows: + +```bash +kubeadm init --skip-phases=addon/kube-proxy +``` + +To remove kube-proxy from an existing cluster, you can use the following steps: + +```bash +# Delete the kube-proxy DaemonSet +kubectl -n kube-system delete ds/kube-proxy +# Delete the kube-proxy ConfigMap to prevent kube-proxy from being re-deployed +# by kubeadm during "upgrade apply". This workaround will not take effect for +# kubeadm versions older than v1.19 as the following patch is required: +# https://github.com/kubernetes/kubernetes/pull/89593 +kubectl -n kube-system delete cm/kube-proxy +# Delete existing kube-proxy rules; there are several options for doing that +# Option 1 (if using kube-proxy in iptables mode), run the following on each Node: +iptables-save | grep -v KUBE | iptables-restore +# Option 2 (any mode), restart all Nodes +# Option 3 (any mode), run the following on each Node: +kube-proxy --cleanup +# You can create a DeamonSet to easily run the above command on all Nodes, using +# the kube-proxy container image +``` + +You will then need to deploy [Antrea](getting-started.md), after making the +necessary changes to the `antrea-config` ConfigMap: + +```yaml +kind: ConfigMap +apiVersion: v1 +metadata: + name: antrea-config + namespace: kube-system +data: + antrea-agent.conf: | + kubeAPIServerOverride: "" + antreaProxy: + proxyAll: true +``` + +The `kubeAPIServerOverride` option will enable the Antrea Agent to connect to +the K8s apiserver. This is required now that kube-proxy is no longer running and +that the Antrea Agent can no longer use the ClusterIP for the `kubernetes` +Service during initialization. If you are unsure about which values to use, take +a look at your Kubeconfig file, and look for a line like this one: + +```yaml +... + server: https://192.168.77.100:6443 +... +``` + +Then use this value as is (e.g., `"https://192.168.77.100:6443"`) for +`kubeAPIServerOverride`. + +And that's it! All you have to do now is make sure that the `antrea-agent` Pods +came up correctly and perhaps validate that NodePort Services can be accessed +correctly. + +#### Windows Nodes + +Assuming you are following the steps we [documented](windows.md) to add Windows +Nodes to your K8s cluster with Antrea, you will simply need to skip running +kube-proxy: + +* Do not install or start the `kube-proxy` service [when using containderd as + the container runtime](windows.md#installation-as-a-service-containerd-based-runtimes) +* Do not create the `kube-proxy-windows` DaemonSet [when using Docker as the + container runtime](windows.md#installation-via-wins-docker-based-runtimes) + +## Special use cases + +### When you are using NodeLocal DNSCache + +[NodeLocal DNSCache](https://kubernetes.io/docs/tasks/administer-cluster/nodelocaldns/) +improves performance of DNS queries in a K8s cluster by running a DNS cache on +each Node. DNS queries are intercepted by a local instance of CoreDNS, which +forwards the requests to CoreDNS (cluster local queries) or the upstream DNS +server in case of a cache miss. + +The way it works (normally) is by assigning the the kube-dns ClusterIP to a +local "dummy" interface, and installing iptables rules to disable connection +tracking for the queries and bypass kube-proxy. The local CoreDNS instance is +configured to bind to that address and can therefore intercept queries. In case +of a cache miss, queries can be sent to the cluster CoreDNS Pods thanks to a +"shadow" Service which will expose CoreDNS Pods via a new ClusterIP. + +When AntreaProxy is enabled (default), Pod DNS queries to the kube-dns ClusterIP +will be load-balanced directly by AntreaProxy to a CoreDNS Pod endpoint. This +means that NodeLocal DNSCache is completely bypassed, which is probably not +acceptable for users who want to leverage this feature to improve DNS +performance in their clusters. While these users can update the Pod +configuration to use the local IP assigned by NodeLocal DNSCache to the "dummy" +interface, this is not always ideal in the context of CaaS, as it can require +everyone running Pods in the cluster to be aware of the situation. + +This is the reason why we initially introduced the `skipServices` configuration +option for AntreaProxy in Antrea v1.4. By adding the kube-dns Service (which +exposes CoreDNS) to the list, you can ensure that AntreaProxy will "ignore" Pod +DNS queries, and that they will be forwarded to NodeLocal DNSCache. You can edit +the `antrea-config` ConfigMap as follows: + +```yaml +kind: ConfigMap +apiVersion: v1 +metadata: + name: antrea-config + namespace: kube-system +data: + antrea-agent.conf: | + antreaProxy: + skipServices: ["kube-system/kube-dns"] +``` + +### When you want your external LoadBalancer to handle Pod traffic + +In some cases, the external LoadBalancer for a cluster provides additional +capabilities (e.g., TLS termination) and it is desirable for Pods to access +in-cluster Services through the external LoadBalancer. By default, this is not +the case as both kube-proxy and AntreaProxy will install rules to load-balance +this traffic directly at the source Node (even when the destination IP is set to +the external `loadBalancerIP`). To circumvent this behavior, we introduced the +`proxyLoadBalancerIPs` configuration option for AntreaProxy in Antrea v1.5. This +option defaults to `true`, but when setting it to `false`, AntreaProxy will no +longer load-balance traffic destined to external `loadBalancerIP`s, hence +ensuring that this traffic can go to the external LoadBalancer. You can set it +to `false` by editing the `antrea-config` ConfigMap as follows: + +```yaml +kind: ConfigMap +apiVersion: v1 +metadata: + name: antrea-config + namespace: kube-system +data: + antrea-agent.conf: | + antreaProxy: + proxyLoadBalancerIPs: false +``` + +There are two important prerequisites for this feature: + +* You must enable `proxyAll` and [remove kube-proxy](#removing-kube-proxy) from + the cluster, otherwise kube-proxy will still load-balance the traffic and you + will not achieve the desired behavior. +* Your external LoadBalancer must SNAT the traffic, in order for the reply + traffic to go back through the external LoadBalancer. + +## Known issues or limitations + +* Due to some restrictions on the implementation of Services in Antrea, the + maximum number of Endpoints that Antrea can support at the moment is 800. If + the number of Endpoints for a given Service exceeds 800, extra Endpoints will + be dropped (with non-local Endpoints being dropped in priority by each Antrea + Agent). This will be fixed eventually. +* Due to some restrictions on the implementation of Services in Antrea, the + maximum timeout value supported for ClientIP-based Service SessionAffinity is + 65535 seconds (the K8s Service specs allow values up to 86400 seconds). Values + greater than 65535 seconds will be truncated and the Antrea Agent will log a + warning. [We do not intend to address this + limitation](https://github.com/antrea-io/antrea/issues/1578). diff --git a/docs/assets/README.md b/docs/assets/README.md index 1fde9d1a36a..61dc9ea7d40 100644 --- a/docs/assets/README.md +++ b/docs/assets/README.md @@ -3,7 +3,7 @@ ## SVG images The SVG images / diagrams in this directory have been created using -[Inkscape](https://inkscape.org/) and exported as PNG files - which can be embedded in Makrdown +[Inkscape](https://inkscape.org/) and exported as PNG files - which can be embedded in Markdown files. If you edit these images, please re-export them as PNG with a 300 dpi resolution. If you create new SVG images / diagrams for documentation, please check-in both the SVG source and the exported PNG file. diff --git a/docs/assets/adopters/infrabuilder-logo.png b/docs/assets/adopters/infrabuilder-logo.png deleted file mode 100644 index 2e81c08eaf2..00000000000 Binary files a/docs/assets/adopters/infrabuilder-logo.png and /dev/null differ diff --git a/docs/assets/adopters/terasky-logo.png b/docs/assets/adopters/terasky-logo.png new file mode 100644 index 00000000000..d26875f4d23 Binary files /dev/null and b/docs/assets/adopters/terasky-logo.png differ diff --git a/docs/assets/adopters/transwarp-logo.png b/docs/assets/adopters/transwarp-logo.png new file mode 100644 index 00000000000..072541113c0 Binary files /dev/null and b/docs/assets/adopters/transwarp-logo.png differ diff --git a/docs/assets/flow_visibility.svg b/docs/assets/flow_visibility.svg index 25e094b13fa..fdbb990a46f 100644 --- a/docs/assets/flow_visibility.svg +++ b/docs/assets/flow_visibility.svg @@ -5,8 +5,8 @@ viewBox="0 0 672.09662 383.12097" version="1.1" id="svg8" - inkscape:version="1.1-dev (b39e6d56, 2020-09-19)" - sodipodi:docname="flow_exporter.svg" + inkscape:version="1.1.2 (b8e25be8, 2022-02-05)" + sodipodi:docname="flow_visibility.svg" inkscape:export-filename="/Users/stati/work/antrea_all/flow_exporter.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96" @@ -17,6 +17,7 @@ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/"> + + lock-margins="false" + inkscape:lockguides="false"> + style="display:inline"> + style="display:none"> K8s Cluster + y="-59.720242" + id="tspan137496">K8s Cluster Kubelet + y="115.46043" + id="tspan137498">Kubelet (ELK Flow Collector) + id="tspan6290">(Flow Collector) + inkscape:label="TextAsPath"> @@ -1541,8 +1541,7 @@ Daemon Set" id="path3687" /> @@ -1584,8 +1583,7 @@ CNI" id="path3672" /> @@ -1803,242 +1801,261 @@ Exporter" id="path3575" /> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -2148,8 +2165,7 @@ Records" id="path3441" /> @@ -2203,8 +2219,7 @@ Pods" id="path3388" /> @@ -2274,8 +2289,7 @@ Server" id="path3363" /> @@ -2353,10 +2367,7 @@ Metrics" id="path3330" /> @@ -2478,8 +2489,7 @@ Aggregator id="path3293" /> diff --git a/docs/assets/hns_integration.svg b/docs/assets/hns_integration.svg index 42272c33289..172b49e2c42 100644 --- a/docs/assets/hns_integration.svg +++ b/docs/assets/hns_integration.svg @@ -15,6 +15,7 @@ viewBox="0 0 160.96114 113.4893" version="1.1" id="svg8"> + + + + + + = 2.8.0 userspace daemon `ovs-vswitchd` and `ovsdb-server` should run on all worker nodes. See -[Installing Open vSwitch](https://docs.openvswitch.org/en/latest/intro/install/#installation-from-packages) for details. - -### antrea-controller - -`antrea-controller` is required to implement Kubernetes Network Policies. At any time, there should be only a single -active replica of `antrea-controller`. - -1. Grant the `antrea-controller` ServiceAccount necessary permissions to Kubernetes APIs. You can apply -[controller-rbac.yaml](/build/yamls/base/controller-rbac.yml) to do it. - - ```bash - kubectl apply -f build/yamls/base/controller-rbac.yml - ``` - -2. Create the kubeconfig file that contains the K8s APIServer endpoint and the token of ServiceAccount created in the -above step. See [Configure Access to Multiple Clusters]( -https://kubernetes.io/docs/tasks/access-application-cluster/configure-access-multiple-clusters/) for more information. - - ```bash - APISERVER=$(kubectl config view --minify -o jsonpath='{.clusters[0].cluster.server}') - TOKEN=$(kubectl get secrets -n kube-system -o jsonpath="{.items[?(@.metadata.annotations['kubernetes\.io/service-account\.name']=='antrea-controller')].data.token}"|base64 --decode) - kubectl config --kubeconfig=antrea-controller.kubeconfig set-cluster kubernetes --server=$APISERVER --insecure-skip-tls-verify - kubectl config --kubeconfig=antrea-controller.kubeconfig set-credentials antrea-controller --token=$TOKEN - kubectl config --kubeconfig=antrea-controller.kubeconfig set-context antrea-controller@kubernetes --cluster=kubernetes --user=antrea-controller - kubectl config --kubeconfig=antrea-controller.kubeconfig use-context antrea-controller@kubernetes - ``` - -3. Create the `antrea-controller` config file, see [Configuration](../configuration.md) for details. - - ```bash - cat >antrea-controller.conf <antrea-agent.conf </etc/cni/net.d/10-antrea.conflist <= 1.7.0 should be used. There is no Antrea version requirement for +other IPAM options. + All the required software will be deployed using YAML manifests, and the corresponding container images will be downloaded from public registries. For the sake of this guide, we will use macvlan in "bridge" mode, which supports the creation of multiple subinterfaces on one parent interface, and connects -them all using a bridge. For more information on the different macvlan modes, -you can refer to this [blog post](https://hicu.be/bridge-vs-macvlan). Macvlan in -"bridge" mode requires the network to be able to handle "promiscuous mode", as -the same physical interface / virtual adapter ends up being assigned multiple -MAC addresses. When using a virtual network for the Nodes, some configuration -changes are usually required, which depend on the virtualization technology. For -example: +them all using a bridge. Macvlan in "bridge" mode requires the network to be +able to handle "promiscuous mode", as the same physical interface / virtual +adapter ends up being assigned multiple MAC addresses. When using a virtual +network for the Nodes, some configuration changes are usually required, which +depend on the virtualization technology. For example: * when using VirtualBox and [Internal Networking](https://www.virtualbox.org/manual/ch06.html#network_internal), set @@ -79,26 +82,57 @@ use as an example in this guide. ### Step 1: Deploying Antrea For detailed information on the Antrea requirements and instructions on how to -deploy Antrea, please refer to -[getting-started.md](../../getting-started.md). To deploy the latest version of -Antrea, use: +deploy Antrea, please refer to [getting-started.md](../../getting-started.md). +You can deploy the latest version of Antrea with +[the manifest](https://raw.githubusercontent.com/antrea-io/antrea/main/build/yamls/antrea.yml). +You may also choose a [released Antrea version](https://github.com/antrea-io/antrea/releases). + +To leverage Antrea IPAM to assign IP addresses for the secondary network, you +need to edit the Antrea deployment manifest and enable the `AntreaIPAM` feature +gate for both `antrea-controller` and `antrea-agent`, and then deploy Antrea +with: ```bash kubectl apply -f https://raw.githubusercontent.com/antrea-io/antrea/main/build/yamls/antrea.yml ``` -You may also choose a [released Antrea -version](https://github.com/antrea-io/antrea/releases). +If you choose other IPAM options like DHCP or Whereabouts, you can just deploy +Antrea with the Antrea deployment manifest without modification: + +```bash +kubectl apply -f https://raw.githubusercontent.com/antrea-io/antrea/main/build/yamls/antrea.yml +``` ### Step 2: Deploy Multus as a DaemonSet ```bash git clone https://github.com/k8snetworkplumbingwg/multus-cni && cd multus-cni -cat ./images/multus-daemonset.yml | kubectl apply -f - +cat ./deployments/multus-daemonset-thick-plugin.yml | kubectl apply -f - ``` -### Step 3: Create a NetworkAttachmentDefinition +### Step 3: Create an `IPPool` and a `NetworkAttachmentDefinition` + +With Antrea IPAM, the subnet and IP ranges for the secondary network are defined +with an Antrea `IPPool` CR. To learn more information about Antrea IPAM for +secondary network, please refer to the [Antrea IPAM documentation](../../antrea-ipam.md#ipam-for-secondary-network). + +```bash +cat < -## Using [whereabouts] for IPAM +## Using [Whereabouts] for IPAM If you do not already have a DHCP server for the underlying parent network and you find that deploying one in-cluster is impractical, you may want to consider -using [whereabouts] to assign IP addresses to the secondary interfaces. When -using [whereabouts], follow steps 1 and 2 above, along with step 4 if you want +using [Whereabouts] to assign IP addresses to the secondary interfaces. When +using [Whereabouts], follow steps 1 and 2 above, along with step 4 if you want the Nodes to be able to communicate with the Pods using the secondary network. -The next step is to install the [whereabouts] plugin as follows: +The next step is to install the [Whereabouts] plugin as follows: ```bash git clone https://github.com/dougbtv/whereabouts && cd whereabouts @@ -331,11 +375,12 @@ EOF You can then validate that the configuration works by running the same [test](#testing) as above. -[whereabouts]: https://github.com/dougbtv/whereabouts +[Whereabouts]: https://github.com/dougbtv/whereabouts [test cluster]: #suggested-test-cluster +[DHCP]: #using-dhcp-for-ipam [step-1]: #step-1-deploying-antrea [step-2]: #step-2-deploy-multus-as-a-daemonset -[step-3]: #step-3-create-a-networkattachmentdefinition +[step-3]: #step-3-create-an-ippool-and-a-networkattachmentdefinition [step-4]: #step-4-optional-create-a-macvlan-subinterface-on-each-node [step-5]: #step-5-run-a-dhcp-server [step-6]: #step-6-run-the-dhcp-daemons diff --git a/docs/cookbooks/multus/resources/netAttachDef.yml b/docs/cookbooks/multus/resources/netAttachDef.yml deleted file mode 100644 index 650058a7530..00000000000 --- a/docs/cookbooks/multus/resources/netAttachDef.yml +++ /dev/null @@ -1,14 +0,0 @@ -apiVersion: "k8s.cni.cncf.io/v1" -kind: NetworkAttachmentDefinition -metadata: - name: macvlan-conf -spec: - config: '{ - "cniVersion": "0.3.0", - "type": "macvlan", - "master": "enp0s9", - "mode": "bridge", - "ipam": { - "type": "dhcp" - } - }' diff --git a/docs/cookbooks/multus/resources/netattachdef-ippool.yml b/docs/cookbooks/multus/resources/netattachdef-ippool.yml new file mode 100644 index 00000000000..55f8da11a7b --- /dev/null +++ b/docs/cookbooks/multus/resources/netattachdef-ippool.yml @@ -0,0 +1,27 @@ +apiVersion: "crd.antrea.io/v1alpha2" +kind: IPPool +metadata: + name: macvlan-ippool +spec: + ipVersion: 4 + ipRanges: + - start: "192.168.78.200" + end: "192.168.78.250" + gateway: "192.168.78.1" + prefixLength: 24 +--- +apiVersion: "k8s.cni.cncf.io/v1" +kind: NetworkAttachmentDefinition +metadata: + name: macvlan-conf +spec: + config: '{ + "cniVersion": "0.3.0", + "type": "macvlan", + "master": "enp0s9", + "mode": "bridge", + "ipam": { + "type": "antrea", + "ippools" [ "macvlan-ippool" ] + } + }' diff --git a/docs/design/architecture.md b/docs/design/architecture.md index cc70fed3b8d..e5d913caecf 100644 --- a/docs/design/architecture.md +++ b/docs/design/architecture.md @@ -159,14 +159,14 @@ tunnels to other Nodes. Antrea Node Network -Each Node is assigned a single subnet, and all Pods on the Node get an IP from -the subnet. Antrea leverages Kubernetes' `NodeIPAMController` for the Node -subnet allocation, which sets the `podCIDR` field of the Kubernetes Node spec -to the allocated subnet. Antrea Agent retrieves the subnets of Nodes from the -`podCIDR` field. It reserves the first IP of the local Node's subnet to be the -gateway IP and assigns it to the `antrea-gw0` port, and invokes the -[host-local IPAM plugin](https://github.com/containernetworking/plugins/tree/master/plugins/ipam/host-local) -to allocate IPs from the subnet to all local Pods. A local Pod is assigned an IP +By default, Antrea leverages Kubernetes' `NodeIPAMController` to allocate a +single subnet for each Kubernetes Node, and Antrea Agent on a Node allocates an +IP for each Pod on the Node from the Node's subnet. `NodeIPAMController` sets +the `podCIDR` field of the Kubernetes Node spec to the allocated subnet. Antrea +Agent retrieves the subnets of Nodes from the `podCIDR` field. It reserves the +first IP of the local Node's subnet to be the gateway IP and assigns it to the +`antrea-gw0` port, and invokes the [host-local IPAM plugin](https://github.com/containernetworking/plugins/tree/master/plugins/ipam/host-local) +to allocate IPs from the subnet to all Pods. A local Pod is assigned an IP when the CNI ADD command is received for that Pod. `NodeIPAMController` can run in `kube-controller-manager` context, or within @@ -176,6 +176,10 @@ For every remote Node, Antrea Agent adds an OVS flow to send the traffic to that Node through the appropriate tunnel. The flow matches the packets' destination IP against each Node's subnet. +In addition to Kubernetes NodeIPAM, Antrea also implements its own IPAM feature, +which can allocate IPs for Pods from user-defined IP pools. For more +information, please refer to the [Antrea IPAM documentation](../antrea-ipam.md). + ### Traffic walk Antrea Traffic Walk @@ -354,6 +358,14 @@ using IPFIX. The exported network flows can be visualized using Elastic Stack and Kibana dashboards. For more information, refer to the [network flow visibility document](../network-flow-visibility.md). +### Prometheus integration + +Antrea supports exporting metrics to Prometheus. Both Antrea Controller and +Antrea Agent implement the `/metrics` API endpoint on their API server to expose +various metrics generated by Antrea components or 3rd party components used by +Antrea. Prometheus can be configured to collect metrics from the API endpoints. +For more information, please refer to the [Prometheus integration document](../prometheus-integration.md). + ### Windows Node On a Windows Node, Antrea acts very much like it does on a Linux Node. Antrea @@ -365,3 +377,13 @@ daemons are run and managed, how the OVS bridge is configured and Pod network interfaces are connected to the bridge, and how host network routing and SNAT are implemented. For more information about the Antrea Windows implementation, refer to the [Windows design document](windows-design.md). + +### Antrea Multi-cluster + +Antrea Multi-cluster implements Multi-cluster Service API, which allows users to +create multi-cluster Services that can be accessed cross clusters in a +ClusterSet. Antrea Multi-cluster also supports Antrea ClusterNetworkPolicy +replication. Multi-cluster admins can define ClusterNetworkPolicies to be +replicated across the entire ClusterSet, and enforced in all member clusters. +To learn more information about the Antrea Multi-cluster architecture, please +refer to the [Antrea Multi-cluster architecture document](../multicluster/architecture.md). diff --git a/docs/egress.md b/docs/egress.md index 5cacd2087f9..0306c828feb 100644 --- a/docs/egress.md +++ b/docs/egress.md @@ -297,3 +297,11 @@ Namespace to the new Node. This feature is currently only supported for Nodes running Linux and "encap" mode. The support for Windows and other traffic modes will be added in the future. + +The current implementation of Antrea Egress does not work with the `strictARP` +configuration of `kube-proxy` IPVS mode. The `strictARP` configuration is +required by some Service load balancing solutions including: [Antrea Service +external IP management, MetalLB](service-loadbalancer.md#interoperability-with-kube-proxy-ipvs-mode), +and kube-vip. It means Antrea Egress cannot work together with these solutions +in a cluster using `kube-proxy` IPVS. We assume this issue will be fixed in a +near future Antrea version. diff --git a/docs/feature-gates.md b/docs/feature-gates.md index fdb82952bcf..023251f56de 100644 --- a/docs/feature-gates.md +++ b/docs/feature-gates.md @@ -67,6 +67,9 @@ manifest provided as part of releases enables this feature by default. If you edit the manifest, make sure you do not disable it, as it is needed for correct NetworkPolicy implementation for Pod-to-Service traffic. +Please refer to this [document](antrea-proxy.md) for extra information on +AntreaProxy and how it can be configured. + ### EndpointSlice `EndpointSlice` enables Service EndpointSlice support in AntreaProxy. The @@ -248,23 +251,33 @@ there is a risk of conflicts in CIDR allocation between the two. ### AntreaIPAM -`AntreaIPAM` feature allows flexible control over Pod IP addressing. This can be -achieved by configuring `IPPool` CRD with a desired set of IP ranges and VLANs. The -`IPPool` can be annotated to Namespace, Pod and PodTemplate of StatefulSet/Deployment. -Antrea will manage IP address assignment for corresponding Pods according to `IPPool` -spec. Refer to this [document](antrea-ipam.md) for more information. +`AntreaIPAM` feature allocates IP addresses from IPPools. It is required by +bridging mode Pods. The bridging mode allows flexible control over Pod IP +addressing. The desired set of IP ranges, optionally with VLANs, are defined +with `IPPool` CRD. An IPPool can be annotated to Namespace, Pod and PodTemplate +of StatefulSet/Deployment. Then, Antrea will manage IP address assignment for +corresponding Pods according to `IPPool` spec. On a Node, cross-Node/VLAN +traffic of AntreaIPAM Pods is sent to the underlay network, and forwarded/routed +by the underlay network. For more information, please refer to the +[Antrea IPAM document](antrea-ipam.md#antrea-flexible-ipam). + +This feature gate also needs to be enabled to use Antrea for IPAM when +configuring secondary network interfaces with Multus, in which case Antrea works +as an IPAM plugin and allocates IP addresses for Pods' secondary networks, +again from the configured IPPools of a secondary network. Refer to the +[secondary network IPAM document](antrea-ipam.md#ipam-for-secondary-network) to +learn more information. #### Requirements for this Feature -As of now, this feature is supported on Linux Nodes, with IPv4, `system` OVS datapath -type, and `noEncap`, `noSNAT` traffic mode. +Both bridging mode and secondary network IPAM are supported only on Linux Nodes. -The IPs in the `IPPools` without VLAN must be in the same underlay subnet as the Node -IP, because inter-Node traffic of AntreaIPAM Pods is forwarded by the Node network. -`IPPools` with VLAN must not overlap with other network subnets, and the underlay network -router should provide the network connectivity for these VLANs. Only a single IP pool can -be included in the Namespace annotation. In the future, annotation of up to two pools for -IPv4 and IPv6 respectively will be supported. +The bridging mode works only with `system` OVS datapath type; and `noEncap`, +`noSNAT` traffic mode. At the moment, it supports only IPv4. The IPs in an IP +range without a VLAN must be in the same underlay subnet as the Node IPs, + because inter-Node traffic of AntreaIPAM Pods is forwarded by the Node network. +IP ranges with a VLAN must not overlap with other network subnets, and the +underlay network router should provide the network connectivity for these VLANs. ### Multicast diff --git a/docs/getting-started.md b/docs/getting-started.md index da853a82a7f..758832507a6 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -146,10 +146,6 @@ or simply reboot your Nodes. To build the image locally, you can follow the instructions in the [Contributor Guide](../CONTRIBUTING.md#building-and-testing-your-change). -Antrea components can also be run manually as processes for development -purposes. See [Manual Installation](contributors/manual-installation.md) for -information. - ### Deploying Antrea in Kind To deploy Antrea in a [Kind](https://github.com/kubernetes-sigs/kind) cluster, @@ -187,10 +183,11 @@ CRDs, which provide advanced features including: policy priority, tiering, deny action, external entity, and policy statistics. For more information on usage of Antrea Network Policies, refer to the [Antrea Network Policy document](antrea-network-policy.md). -### Traffic Encryption +### Egress -Antrea supports encrypting traffic between Linux Nodes using IPsec or WireGuard. -To deploy Antrea with traffic encryption enabled, please refer to [this guide](traffic-encryption.md). +Antrea supports specifying which egress (SNAT) IP the traffic from the selected +Pods to the external network should use and which Node the traffic should leave +the cluster from. For more information, refer to the [Egress document](egress.md). ### Network Flow Visibility @@ -199,12 +196,6 @@ reference cookbook on how to visualize the exported network flows using Elastic Stack and Kibana dashboards. For more information, refer to the [network flow visibility document](network-flow-visibility.md). -### Egress - -Antrea supports specifying which egress (SNAT) IP the traffic from the selected -Pods to the external network should use and which Node the traffic should leave -the cluster from. For more information, refer to the [Egress document](egress.md). - ### NoEncap and Hybrid Traffic Modes Besides the default `Encap` mode, in which Pod traffic across Nodes will be @@ -234,8 +225,30 @@ the [OVS hardware offload guide](ovs-offload.md). Antrea supports exporting metrics to Prometheus. For more information, refer to the [Prometheus integration document](prometheus-integration.md). +### Support for Services of type LoadBalancer + +By leveraging Antrea's Service external IP management feature or configuring +MetalLB to work with Antrea, Services of type LoadBalancer can be supported +without requiring an external LoadBalancer. To learn more information, please +refer to the [Service LoadBalancer document](service-loadbalancer.md). + ### Traceflow Traceflow is a very useful network diagnosis feature in Antrea. It can trace and report the forwarding path of a specified packet in the Antrea network. For usage of this feature, refer to the [Traceflow user guide](traceflow-guide.md). + +### Traffic Encryption + +Antrea supports encrypting traffic between Linux Nodes using IPsec or WireGuard. +To deploy Antrea with traffic encryption enabled, please refer to [this guide](traffic-encryption.md). + +### Antrea Multi-cluster + +Antrea Multi-cluster implements Multi-cluster Service API, which allows users to +create multi-cluster Services that can be accessed cross clusters in a +ClusterSet. Antrea Multi-cluster also supports Antrea ClusterNetworkPolicy +replication. Multi-cluster admins can define ClusterNetworkPolicies to be +replicated across the entire ClusterSet, and enforced in all member clusters. +To learn more information about Antrea Multi-cluster, please refer to the +[Antrea Multi-cluster user guide](multicluster/user-guide.md). diff --git a/docs/multicluster/architecture.md b/docs/multicluster/architecture.md index dee62cea984..ac7e8f0fb0a 100644 --- a/docs/multicluster/architecture.md +++ b/docs/multicluster/architecture.md @@ -1,11 +1,14 @@ # Antrea Multi-cluster Architecture -Antrea Multi-cluster implements [Multi-cluster Service API](https://github.com/kubernetes/enhancements/tree/master/keps/sig-multicluster/1645-multi-cluster-services-api) for Service communication -across multiple Kubernetes clusters. +Antrea Multi-cluster implements [Multi-cluster Service API](https://github.com/kubernetes/enhancements/tree/master/keps/sig-multicluster/1645-multi-cluster-services-api), +which allows users to create multi-cluster Services that can be accessed cross clusters in a +ClusterSet. Antrea Multi-cluster also supports Antrea ClusterNetworkPolicy replication. +Multi-cluster admins can define ClusterNetworkPolicies to be replicated across the entire +ClusterSet, and enforced in all member clusters. -The below diagram depicts a basic multi-cluster topology in Antrea. +The diagram below depicts a basic multi-cluster topology in Antrea. -Antrea Multi-cluster Topology +Antrea Multi-cluster Topology Given a set of Kubernetes clusters, there will be a leader cluster and several member clusters. By default, a leader cluster itself is also a member cluster of a ClusterSet. A cluster @@ -90,7 +93,7 @@ IPs from all member clusters. The new created Antrea Multi-cluster Service is ju Kubernetes Service, so Pods in a member cluster can access the multi-cluster Service as usual without any extra setting. -## Antrea Multi-cluster policy enforcement +## Antrea Multi-cluster NetworkPolicy At this moment, Antrea does not support Pod-level policy enforcement for cross-cluster traffic. Access towards Multi-cluster Services can be regulated with Antrea ClusterNetworkPolicy `toService` rules. In diff --git a/docs/multicluster/user-guide.md b/docs/multicluster/user-guide.md index e09bc778fc6..13cae798e08 100644 --- a/docs/multicluster/user-guide.md +++ b/docs/multicluster/user-guide.md @@ -160,7 +160,7 @@ member clusters. * Create below `ClusterClaim` and `ClusterSet` in the member cluster `test-cluster-east`. Note: Update `server: "https://172.18.0.2:6443"` in `ClusterSet` resource to -the correct the leader cluster API address. +the correct the leader cluster API address. You can refer to [multicluster_membercluster_template.yaml](../../multicluster/config/samples/clusterset_init/multicluster_membercluster_template.yaml). ```yaml apiVersion: multicluster.crd.antrea.io/v1alpha1 @@ -231,7 +231,7 @@ spec: namespace: antrea-mcs-ns ``` -* Create `ClusterClaim` and `ClusterSet` in the leader cluster `test-cluster-north`. +* Create `ClusterClaim` and `ClusterSet` in the leader cluster `test-cluster-north`. A sample is like below, you can also refer to [multicluster_clusterset_template.yaml](../../multicluster/config/samples/clusterset_init/multicluster_clusterset_template.yaml). ```yaml apiVersion: multicluster.crd.antrea.io/v1alpha1 @@ -412,8 +412,8 @@ converging the update until users correct it to match the Service definition in ResourceImport. 2. When a member cluster has already exported a Service, e.g.: `default/nginx` with TCP Port `80`, then other member clusters can only export the same Service with the same Ports -definition. Otherwise, Antrea Multi-cluster Controller will skip converging the mismatched -ResourceExport into the corresponding ResourceImport until users correct it. +definition including port names. Otherwise, Antrea Multi-cluster Controller will skip converting +the mismatched ResourceExport into the corresponding ResourceImport until users correct it. 3. When a member cluster's Service ResourceExport has not been converged successfully due to forementioned mismatch issue, Antrea Multi-cluster Controller will also skip converging the corresponding Endpoints ResourceExport until users correct it. diff --git a/docs/network-flow-visibility.md b/docs/network-flow-visibility.md index 3d202f5f47a..3acefa34f19 100644 --- a/docs/network-flow-visibility.md +++ b/docs/network-flow-visibility.md @@ -24,16 +24,21 @@ - [Aggregation of Flow Records](#aggregation-of-flow-records) - [Antctl support](#antctl-support) - [Quick deployment](#quick-deployment) + - [Image-building steps](#image-building-steps) + - [Deployment Steps](#deployment-steps) - [Flow Collectors](#flow-collectors) - [Go-ipfix Collector](#go-ipfix-collector) - - [Deployment Steps](#deployment-steps) + - [Deployment Steps](#deployment-steps-1) - [Output Flow Records](#output-flow-records) - [Grafana Flow Collector](#grafana-flow-collector) - [Purpose](#purpose) - [About Grafana and ClickHouse](#about-grafana-and-clickhouse) - - [Deployment Steps](#deployment-steps-1) + - [Deployment Steps](#deployment-steps-2) - [Credentials Configuration](#credentials-configuration) - - [ClickHouse Configuration](#clickhouse-configuration) + - [ClickHouse Configuration](#clickhouse-configuration) + - [Service Customization](#service-customization) + - [Performance Configuration](#performance-configuration) + - [Persistent Volumes](#persistent-volumes) - [Pre-built Dashboards](#pre-built-dashboards) - [Flow Records Dashboard](#flow-records-dashboard) - [Pod-to-Pod Flows Dashboard](#pod-to-pod-flows-dashboard) @@ -42,18 +47,7 @@ - [Node-to-Node Flows Dashboard](#node-to-node-flows-dashboard) - [Network-Policy Flows Dashboard](#network-policy-flows-dashboard) - [Dashboards Customization](#dashboards-customization) - - [ELK Flow Collector (deprecated)](#elk-flow-collector-deprecated) - - [Purpose](#purpose-1) - - [About Elastic Stack](#about-elastic-stack) - - [Deployment Steps](#deployment-steps-2) - - [Pre-built Dashboards](#pre-built-dashboards-1) - - [Overview](#overview-1) - - [Pod-to-Pod Flows](#pod-to-pod-flows) - - [Pod-to-External Flows](#pod-to-external-flows) - - [Pod-to-Service Flows](#pod-to-service-flows) - - [Flow Records](#flow-records) - - [Node Throughput](#node-throughput) - - [Network Policy](#network-policy) + - [ELK Flow Collector (removed)](#elk-flow-collector-removed) ## Overview @@ -275,20 +269,13 @@ kubectl apply -f https://raw.githubusercontent.com/antrea-io/antrea/main/build/y The following configuration parameters have to be provided through the Flow Aggregator ConfigMap. Flow aggregator needs to be configured with at least one of the supported [Flow Collectors](#flow-collectors). -`flowCollector` is mandatory for [go-ipfix collector](#deployment-steps) or -[ELK flow collector](#deployment-steps-2), and `clickHouse` is mandatory for -[Grafana Flow Collector](#grafana-flow-collector). We provide an example value -for this parameter in the following snippet. +`flowCollector` is mandatory for [go-ipfix collector](#deployment-steps), and +`clickHouse` is mandatory for [Grafana Flow Collector](#grafana-flow-collector). +We provide an example value for this parameter in the following snippet. * If you have deployed the [go-ipfix collector](#deployment-steps), then please set `flowCollector.enable` to `true` and use the address for `flowCollector.address`: `::` -* If you have deployed the [ELK flow collector](#deployment-steps-2), then -please set `flowCollector.enable` to `true` and use the address for -`flowCollector.address`:`:4739:` for sending -IPFIX messages, or `:4736:` for sending JSON -format records. Record format is specified with `flowCollector.recordFormat` -(defaults to IPFIX) and must match the format expected by the collector. * If you have deployed the [Grafana Flow Collector](#grafana-flow-collector), then please enable the collector by setting `clickHouse.enable` to `true`. If it is deployed following the [deployment steps](#deployment-steps-1), the @@ -486,40 +473,46 @@ about flow record processing. Refer to the ## Quick deployment If you would like to quickly try Network Flow Visibility feature, you can deploy -Antrea, the Flow Aggregator Service and the ELK Flow Collector on the -[Vagrant setup](../test/e2e/README.md). You can use the following command: +Antrea, the Flow Aggregator Service, the Grafana Flow Collector on the +[Vagrant setup](../test/e2e/README.md). + +### Image-building steps + +Build required image under antrea by using make command: ```shell -./infra/vagrant/provision.sh -./infra/vagrant/push_antrea.sh --flow-collector ELK +make +make flow-aggregator-image ``` -If you would like to deploy elastic search with high resources, you can change -the `ES_JAVA_OPTS` in the [ELK Flow Collector configuration](../build/yamls/elk-flow-collector/elk-flow-collector.yml) -according to the [guide](https://www.elastic.co/guide/en/elasticsearch/reference/7.8/heap-size.html). -A larger heap size, like `-Xms1g -Xmx2g`, requires the Vagrant Nodes to have -higher memory than default. In this case, we need to provision the Nodes with -the `--large` option as with the following command: +If you would like to use Grafana flow collector, run: ```shell -./infra/vagrant/provision.sh --large -./infra/vagrant/push_antrea.sh --flow-collector ELK +make flow-visibility-clickhouse-monitor ``` -Alternatively, given any external IPFIX flow collector, you can deploy Antrea and -the Flow Aggregator Service on a default Vagrant setup by running the following -commands: +### Deployment Steps + +Given any external IPFIX flow collector, you can deploy Antrea and the Flow +Aggregator Service on a default Vagrant setup by running the following commands: ```shell ./infra/vagrant/provision.sh ./infra/vagrant/push_antrea.sh --flow-collector ``` +If you would like to deploy the Grafana Flow Collector, you can run the following command: + +```shell +./infra/vagrant/provision.sh +./infra/vagrant/push_antrea.sh --flow-collector Grafana +``` + ## Flow Collectors -Here we list three choices the external configured flow collector: go-ipfix collector, -Grafana flow collector and ELK flow collector. For each collector, we introduce how to -deploy it and how to output or visualize the collected flow records information. +Here we list two choices the external configured flow collector: go-ipfix collector +and Grafana flow collector. For each collector, we introduce how to deploy it and +how to output or visualize the collected flow records information. ### Go-ipfix Collector @@ -585,7 +578,7 @@ for more information about the ClickHouse Operator. Current checked-in yaml is b will install ClickHouse Operator into `kube-system` Namespace. ```bash -kubectl apply -f https://raw.githubusercontent.com/antrea-io/antrea/main/build/yamls/clickhouse-operator-install-bundle.yaml +kubectl apply -f https://raw.githubusercontent.com/antrea-io/antrea/main/build/yamls/clickhouse-operator-install-bundle.yml ``` To deploy a released version of the Grafana Flow Collector, find a deployment manifest @@ -677,7 +670,7 @@ To stop the Grafana Flow Collector, run the following commands: ```shell kubectl delete -f flow-visibility.yml -kubectl delete -f https://raw.githubusercontent.com/antrea-io/antrea/main/build/yamls/clickhouse-operator-install-bundle.yaml -n kube-system +kubectl delete -f https://raw.githubusercontent.com/antrea-io/antrea/main/build/yamls/clickhouse-operator-install-bundle.yml -n kube-system ``` ##### Credentials Configuration @@ -750,7 +743,9 @@ type: Opaque We recommend changing all the credentials above if you are going to run the Flow Collector in production. -##### ClickHouse Configuration +#### ClickHouse Configuration + +##### Service Customization The ClickHouse database can be accessed through the Service `clickhouse-clickhouse`. The Pod exposes HTTP port at 8123 and TCP port at 9000 by default. The ports are @@ -800,6 +795,8 @@ metadata: namespace: flow-visibility ``` +##### Performance Configuration + The ClickHouse throughput depends on two factors - the storage size of the ClickHouse and the time interval between the batch commits to the ClickHouse. Larger storage size and longer commit interval provide higher throughput. @@ -819,11 +816,121 @@ storage size, please modify the `sizeLimit` in the following section. name: clickhouse-storage-volume ``` +To deploy ClickHouse with Persistent Volumes and limited storage size, please refer +to [Persistent Volumes](#persistent-volumes). + The time interval between the batch commits to the ClickHouse is specified in the [Flow Aggregator Configuration](#configuration-1) as `commitInterval`. The ClickHouse throughput grows sightly when the commit interval grows from 1s to 8s. A commit interval larger than 8s provides little improvement on the throughput. +##### Persistent Volumes + +By default, ClickHouse is deployed in memory. From Antrea v1.7, we support deploying +ClickHouse with Persistent Volumes. + +[PersistentVolume](https://kubernetes.io/docs/concepts/storage/persistent-volumes/) +(PV) is a piece of storage in the K8s cluster, which requires to be manually +provisioned by an administrator or dynamically provisioned using Storage Classes. +A PersistentVolumeClaim (PVC) is a request for storage which consumes PV. As +ClickHouse is deployed as a StatefulSet, the volume can be claimed using +`volumeClaimTemplate`. + +To generate the manifest automatically with default settings, you can clone the +repository and run one of the following commands: + +```yaml +# To generate a manifest with Local PV for the ClickHouse +./hack/generate-manifest-flow-visibility.sh --volume pv --local > flow-visibility.yml + +# To generate a manifest with NFS PV for the ClickHouse +./hack/generate-manifest-flow-visibility.sh --volume pv --nfs :/ > flow-visibility.yml + +# To generate a manifest with a customized StorageClass for the ClickHouse +./hack/generate-manifest-flow-visibility.sh --volume pv --storageclass > flow-visibility.yml +``` + +If you prefer not to clone the repository and prefer to create a customized +manifest manually, please follow the steps below to deploy the ClickHouse with +Persistent Volumes: + +1. Provision the PersistentVolume. K8s supports a great number of +[PersistentVolume types](https://kubernetes.io/docs/concepts/storage/persistent-volumes/#types-of-persistent-volumes). +You can provision your own PersistentVolume per your requirements. Here are +two simple examples for your reference. + + - Local PV allows you to store the ClickHouse data at a pre-defined path on + a specific Node. Refer to [createLocalPv.yml][local_pv_yaml] to create the + PV. Please replace `LOCAL_PATH` with the path to store the ClickHouse data + and label the Node used to store the ClickHouse data with + `antrea.io/clickhouse-data-node=`. + + - NFS PV allows you to store the ClickHouse data on an existing NFS server. + Refer to [createNfsPv.yml][nfs_pv_yaml] to create the PV. Please replace + `NFS_SERVER_ADDRESS` with the host name of the NFS server and `NFS_SERVER_PATH` + with the exported path on the NFS server. + + In both examples, you can set `.spec.capacity.storage` in PersistentVolume + to your storage size. This value is for informative purpose as K8s does not + enforce the capacity of PVs. If you want to limit the storage usage, you need + to ask for your storage system to enforce that. For example, you can create + a Local PV on a partition with the limited size. We recommend using a dedicated + saving space for the ClickHouse if you are going to run the Flow Collector in + production. + + As these examples do not use any dynamic provisioner, the reclaim policy + for the PVs is `Retain` by default. After stopping the Grafana Flow Collector, + if you no long need the data for future use, you may need to manually clean + up the data on the local disk or NFS server. + +1. Request the PV for ClickHouse. Please add a `volumeClaimTemplate` section +under `.spec.templates` for the resource `ClickHouseInstallation` in +`flow-visibility.yml` as shown in the example below. `storageClassName` should +be set to your own `StorageClass` name, and `.resources.requests.storage` +should be set to your storage size. + + ```yaml + volumeClaimTemplates: + - name: clickhouse-storage-template + spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 8Gi + storageClassName: clickhouse-storage + ``` + + Then add this template as `dataVolumeClaimTemplate` to the section below. + + ```yaml + defaults: + templates: + dataVolumeClaimTemplate: clickhouse-storage-template + podTemplate: pod-template + serviceTemplate: service-template + ``` + +1. Remove the in-memory related deployment options, by removing the appropriate +`volume` and `volumeMount` for the `ClickHouseInstallation` resource in +`flow-visibility.yml`. + + The `volumeMounts` entry to be removed is the following one: + + ```yaml + - mountPath: /var/lib/clickhouse + name: clickhouse-storage-volume + ``` + + The `volumes` entry to be removed is the following one: + + ```yaml + - emptyDir: + medium: Memory + sizeLimit: 8Gi + name: clickhouse-storage-volume + ``` + #### Pre-built Dashboards The following dashboards are pre-built and are recommended for Antrea flow @@ -831,6 +938,27 @@ visualization. They can be found in the Home page of Grafana, by clicking the Magnifier button on the left menu bar. Grafana Search Dashboards Guide +- Note that all pre-built dashboards (except for the "Flow Records Dashboard") +filter out Pod traffic for which the source or destination Namespace is one of +`kube-system`, `flow-visibility`, or `flow-aggregator`. The primary motivation +for this is to avoid showing the connections between the Antrea Agents and the +Flow Aggregator, between the Flow Aggregator and ClickHouse, and between +ClickHouse and Grafana. + +- Also note that we limit the number of values displayed on panels. For table +panel on the Flow Records Dashboard, the limit is set to 10000. For Sankey +diagrams, the limit is 50. For time-series line graphs, the limit is 50. For +pie charts, the limit is 25. The motivation is, when the input data is very +large, we want to keep the charts readable and avoid consuming too much time +and resources to render them. + +If you want to stop filtering traffic by Namespace, or edit the panel limit, +you will need to edit the ClickHouse SQL query for each individual panel. Please +follow the [dashboards customization](#dashboards-customization) section for +more information. As a special case, to edit the panel limit for pie charts, +instead of editing the query, please follow the [doc](https://grafana.com/docs/grafana/latest/visualizations/pie-chart-panel/#limit) +to edit `Value options - Limit`. + ##### Flow Records Dashboard Flow Records Dashboard displays the number of flow records being captured in the @@ -946,165 +1074,12 @@ by adding the file in the following section: ./hack/generate-manifest-flow-visibility.sh > build/yamls/flow-visibility.yml ``` -### ELK Flow Collector (deprecated) - -#### Purpose - -Antrea supports sending IPFIX flow records through the Flow Exporter feature -described above. The Elastic Stack (ELK Stack) works as the data collector, data -storage and visualization tool for flow records and flow-related information. This -document provides the guidelines for deploying Elastic Stack with support for -Antrea-specific IPFIX fields in a Kubernetes cluster. - -#### About Elastic Stack - -[Elastic Stack](https://www.elastic.co) is a group of open source products to -help collect, store, search, analyze and visualize data in real time. We will -use Logstash, Elasticsearch and Kibana in Antrea flow visualization. -[Logstash](https://www.elastic.co/logstash) works as data collector to -centralize flow records. [Logstash Netflow codec plugin](https://www.elastic.co/guide/en/logstash/current/plugins-codecs-netflow.html) -supports Netflow v5/v9/v10(IPFIX) protocols for flow data collection. -The flow exporter feature in Antrea Agent uses the IPFIX (Netflow v10) protocol -to export flow records. - -[Elasticsearch](https://www.elastic.co/elasticsearch/), as a RESTful search -engine, supports storing, searching and indexing records received. -[Kibana](https://www.elastic.co/kibana/) is mainly for data visualization and -exploration. - -#### Deployment Steps - -If you are looking for steps to deploy the ELK flow collector along with a new Antrea -cluster and the Flow Aggregator Service, then please refer to the -[quick deployment](#quick-deployment) section. - -The following steps will deploy the ELK flow collector on an existing Kubernetes -cluster, which uses Antrea as the CNI. First step is to fetch the necessary resources -from the Antrea repository. You can either clone the entire repo or download the -particular folder using the subversion(svn) utility. If the deployed version of -Antrea has a release `` (e.g. `v0.10.0`), then you can use the following command: - -```shell -git clone --depth 1 --branch https://github.com/antrea-io/antrea.git && cd antrea/build/yamls/ -or -svn export https://github.com/antrea-io/antrea/tags//build/yamls/elk-flow-collector/ -``` - -If the deployed version of Antrea is the latest version, i.e., built from the main -branch, then you can use the following command: - -```shell -git clone --depth 1 --branch main https://github.com/antrea-io/antrea.git && cd antrea/build/yamls/ -or -svn export https://github.com/antrea-io/antrea/trunk/build/yamls/elk-flow-collector/ -``` - -To create the required K8s resources in the `elk-flow-collector` folder and get -everything up-and-running, run following commands: - -```shell -kubectl create namespace elk-flow-collector -kubectl create configmap logstash-configmap -n elk-flow-collector --from-file=./elk-flow-collector/logstash/ -kubectl apply -f ./elk-flow-collector/elk-flow-collector.yml -n elk-flow-collector -``` - -Please refer to the [Flow Aggregator Configuration](#configuration-1) to configure -external flow collector as Logstash Service Cluster IP. - -Kibana dashboard is exposed as a Nodeport Service, which can be accessed via -`http://[NodeIP]: 30007`. `elk-flow-collector/kibana.ndjson` is an auto-generated -reusable file containing pre-built objects for visualizing Pod-to-Pod, Pod-to-Service -and Node-to-Node flow records. To import the dashboards into Kibana, go to -**Management -> Saved Objects** and import `elk-flow-collector/kibana.ndjson`. - -#### Pre-built Dashboards - -The following dashboards are pre-built and are recommended for Antrea flow -visualization. - -##### Overview - -An overview of Pod-based flow records information is provided. - -Flow
-Visualization Overview Dashboard - -##### Pod-to-Pod Flows - -Pod-to-Pod cumulative Tx and Rx traffic is shown in sankey diagrams. Corresponding -source or destination Pod throughput is visualized using line graph. - -Flow
-Visualization Pod-to-Pod Dashboard - -Flow
-Visualization Pod-to-Pod Dashboard - -Flow
-Visualization Pod-to-Pod Dashboard - -##### Pod-to-External Flows - -Pod-to-External cumulative Tx and Rx traffic is shown in sankey diagrams. Corresponding -source or destination throughput is visualized using line graph. - -Flow
-Visualization Pod-to-External Dashboard - -Flow
-Visualization Pod-to-External Dashboard - -##### Pod-to-Service Flows - -Pod-to-Service traffic is presented similar to Pod-to-Pod/External traffic. -Corresponding source or destination IP addresses is shown in tooltips. - -Flow
-Visualization Pod-to-Service Dashboard - -Aggregated Tx and Rx traffic based on destination Service is shown in line graph. -Flow
-Visualization Pod-to-Service Dashboard - -Flow
-Visualization Pod-to-Service Dashboard - -##### Flow Records - -Flow Records dashboard shows the raw flow records over time with support -for filters. - -Flow
-Visualization Flow Record Dashboard - -##### Node Throughput - -Node Throughput dashboard shows the visualization of inter-Node and -intra-Node traffic by aggregating all the Pod traffic per Node. - -Flow
-Visualization Node Throughput Dashboard - -We also present aggregated Tx and Rx Mbps by Node in heatmap to give -a better overview of Node bandwidth consumption. - -Flow
-Visualization Node Throughput Dashboard - -##### Network Policy - -Network Policy dashboard provides filters over ingress network policy name and namespace, egress -network policy name and namespace to view corresponding flow throughput under network policy. Flows -are grouped by egress network policies (source) and ingress network policies (destination) in the -sankey diagram. When hovering over the flow, it will show corresponding Pod-to-Pod traffic details -and network policies. - -Flow
-Visualization Network Policy Dashboard - -With filters applied: +### ELK Flow Collector (removed) -Flow
-Visualization Network Policy Dashboard +**Starting with Antrea v1.7, support for the ELK Flow Collector has been removed.** +Please consider using the [Grafana Flow Collector](#grafana-flow-collector) +instead, which is actively maintained. [flow_visibility_kustomization_yaml]: ../build/yamls/flow-visibility/base/kustomization.yml +[local_pv_yaml]: ../build/yamls/flow-visibility/patches/pv/createLocalPv.yml +[nfs_pv_yaml]: ../build/yamls/flow-visibility/patches/pv/createNfsPv.yml diff --git a/docs/node-port-local.md b/docs/node-port-local.md index 156a2336152..9d78d1333b5 100644 --- a/docs/node-port-local.md +++ b/docs/node-port-local.md @@ -6,6 +6,7 @@ - [What is NodePortLocal?](#what-is-nodeportlocal) - [Prerequisites](#prerequisites) - [Usage](#usage) + - [Usage pre Antrea v1.7](#usage-pre-antrea-v17) - [Usage pre Antrea v1.4](#usage-pre-antrea-v14) - [Usage pre Antrea v1.2](#usage-pre-antrea-v12) - [Limitations](#limitations) @@ -29,7 +30,7 @@ directly to backend Pods. NodePortLocal was introduced in v0.13 as an alpha feature, and was graduated to beta in v1.4, at which time it was enabled by default. Prior to v1.4, a feature gate, `NodePortLocal`, must be enabled on the antrea-agent for the feature to -work. +work. Starting from Antrea v1.7, NPL is supported on the Windows antrea-agent. ## Usage @@ -114,12 +115,12 @@ metadata: labels: app: nginx annotations: - nodeportlocal.antrea.io: '[{"podPort":8080,"nodeIP":"10.10.10.10","nodePort":61002}]' + nodeportlocal.antrea.io: '[{"podPort":8080,"nodeIP":"10.10.10.10","nodePort":61002,"protocol":"tcp","protocols":["tcp"]}]' ... ``` This annotation indicates that port 8080 of the Pod can be reached through port -61002 of the Node with IP Address 10.10.10.10. +61002 of the Node with IP Address 10.10.10.10 for TCP traffic. The `nodeportlocal.antrea.io` annotation is generated and managed by Antrea. It is not meant to be created or modified by users directly. A user-provided @@ -131,6 +132,38 @@ NodePortLocal can only be used with Services of type `ClusterIP` or Services of type `NodePort` or `ExternalName`. The annotation also has no effect for Services with an empty or missing Selector. +Starting from the Antrea v1.7 minor release, the `protocols` field in the +annotation is deprecated. The array contains a single member, equal to the +`protocol` field. +The `protocols` field will be removed from Antrea for minor releases post March 2023, +as per our deprecation policy. + +### Usage pre Antrea v1.7 + +Prior to the Antrea v1.7 minor release, the `nodeportlocal.antrea.io` annotation +could contain multiple members in `protocols`. +An example may look like this: + +```yaml +apiVersion: v1 +kind: Pod +metadata: + name: nginx-6799fc88d8-9rx8z + labels: + app: nginx + annotations: + nodeportlocal.antrea.io: '[{"podPort":8080,"nodeIP":"10.10.10.10","nodePort":61002}, "protocols":["tcp","udp"]]' +... +``` + +This annotation indicates that port 8080 of the Pod can be reached through port +61002 of the Node with IP Address 10.10.10.10 for both TCP and UDP traffic. + +Prior to v1.7, the implementation would always allocate the same nodePort value +for all the protocols exposed for a given podPort. +Starting with v1.7, there will be multiple annotations for the different protocols +for a given podPort, and the allocated nodePort may be different for each one. + ### Usage pre Antrea v1.4 Prior to the Antrea v1.4 minor release, the `nodePortLocal` option group in the @@ -179,8 +212,8 @@ mapped. ## Limitations -This feature is currently only supported for Nodes running Linux with IPv4 -addresses. Only TCP & UDP Service ports are supported (not SCTP). +This feature is currently only supported for Nodes running Linux or Windows +with IPv4 addresses. Only TCP & UDP Service ports are supported (not SCTP). ## Integrations with External Load Balancers diff --git a/docs/prometheus-integration.md b/docs/prometheus-integration.md index 86dad107257..aa6981d3e98 100644 --- a/docs/prometheus-integration.md +++ b/docs/prometheus-integration.md @@ -227,15 +227,26 @@ rejected due to an error in audit logging backend. remaining lifetime on the certificate used to authenticate a request. - **apiserver_current_inflight_requests:** Maximal number of currently used inflight request limit of this apiserver per request kind in last second. +- **apiserver_delegated_authn_request_duration_seconds:** Request latency +in seconds. Broken down by status code. +- **apiserver_delegated_authn_request_total:** Number of HTTP requests +partitioned by status code. +- **apiserver_delegated_authz_request_duration_seconds:** Request latency +in seconds. Broken down by status code. +- **apiserver_delegated_authz_request_total:** Number of HTTP requests +partitioned by status code. - **apiserver_envelope_encryption_dek_cache_fill_percent:** Percent of the cache slots currently occupied by cached DEKs. - **apiserver_flowcontrol_read_vs_write_request_count_samples:** Periodic -observations of the number of requests +observations of the number of requests waiting or in regular stage of execution - **apiserver_flowcontrol_read_vs_write_request_count_watermarks:** Watermarks -of the number of requests +of the number of requests waiting or in regular stage of execution - **apiserver_longrunning_gauge:** Gauge of all active long-running apiserver requests broken out by verb, group, version, resource, scope and component. Not all requests are tracked this way. +- **apiserver_longrunning_requests:** Gauge of all active long-running +apiserver requests broken out by verb, group, version, resource, scope and +component. Not all requests are tracked this way. - **apiserver_registered_watchers:** Number of currently registered watchers for a given resources - **apiserver_request_duration_seconds:** Response latency distribution in @@ -243,6 +254,9 @@ seconds for each verb, dry run value, group, version, resource, subresource, scope and component. - **apiserver_request_filter_duration_seconds:** Request filter latency distribution in seconds, for each filter type +- **apiserver_request_slo_duration_seconds:** Response latency distribution +(not counting webhook duration) in seconds for each verb, group, version, +resource, subresource, scope and component. - **apiserver_request_total:** Counter of apiserver requests broken out for each verb, dry run value, group, version, resource, scope, component, and HTTP response code. @@ -258,6 +272,14 @@ number of cache misses while accessing key decryption key(KEK). 'TLS handshake error from' error - **apiserver_watch_events_sizes:** Watch event size distribution in bytes - **apiserver_watch_events_total:** Number of events sent in watch clients +- **apiserver_webhooks_x509_insecure_sha1_total:** Counts the number of +requests to servers with insecure SHA1 signatures in their serving certificate +OR the number of connection failures due to the insecure SHA1 signatures +(either/or, based on the runtime environment) +- **apiserver_webhooks_x509_missing_san_total:** Counts the number of requests +to servers missing SAN extension in their serving certificate OR the number +of connection failures due to the lack of x509 certificate SAN extension +missing (either/or, based on the runtime environment) #### Authenticated Metrics @@ -274,12 +296,85 @@ broken out by result. - **authentication_token_cache_request_duration_seconds:** - **authentication_token_cache_request_total:** +#### Field Metrics + +- **field_validation_request_duration_seconds:** Response latency distribution +in seconds for each field validation value and whether field validation is +enabled or not + #### Go Metrics +- **go_gc_cycles_automatic_gc_cycles_total:** Count of completed GC cycles +generated by the Go runtime. +- **go_gc_cycles_forced_gc_cycles_total:** Count of completed GC cycles +forced by the application. +- **go_gc_cycles_total_gc_cycles_total:** Count of all completed GC cycles. - **go_gc_duration_seconds:** A summary of the pause duration of garbage collection cycles. +- **go_gc_heap_allocs_by_size_bytes_total:** Distribution of heap allocations +by approximate size. Note that this does not include tiny objects as defined +by /gc/heap/tiny/allocs:objects, only tiny blocks. +- **go_gc_heap_allocs_bytes_total:** Cumulative sum of memory allocated to +the heap by the application. +- **go_gc_heap_allocs_objects_total:** Cumulative count of heap allocations +triggered by the application. Note that this does not include tiny objects +as defined by /gc/heap/tiny/allocs:objects, only tiny blocks. +- **go_gc_heap_frees_by_size_bytes_total:** Distribution of freed heap +allocations by approximate size. Note that this does not include tiny objects +as defined by /gc/heap/tiny/allocs:objects, only tiny blocks. +- **go_gc_heap_frees_bytes_total:** Cumulative sum of heap memory freed by +the garbage collector. +- **go_gc_heap_frees_objects_total:** Cumulative count of heap allocations +whose storage was freed by the garbage collector. Note that this does +not include tiny objects as defined by /gc/heap/tiny/allocs:objects, only +tiny blocks. +- **go_gc_heap_goal_bytes:** Heap size target for the end of the GC cycle. +- **go_gc_heap_objects_objects:** Number of objects, live or unswept, +occupying heap memory. +- **go_gc_heap_tiny_allocs_objects_total:** Count of small allocations that +are packed together into blocks. These allocations are counted separately +from other allocations because each individual allocation is not tracked +by the runtime, only their block. Each block is already accounted for in +allocs-by-size and frees-by-size. +- **go_gc_pauses_seconds_total:** Distribution individual GC-related +stop-the-world pause latencies. - **go_goroutines:** Number of goroutines that currently exist. - **go_info:** Information about the Go environment. +- **go_memory_classes_heap_free_bytes:** Memory that is completely free and +eligible to be returned to the underlying system, but has not been. This +metric is the runtime's estimate of free address space that is backed by +physical memory. +- **go_memory_classes_heap_objects_bytes:** Memory occupied by live objects +and dead objects that have not yet been marked free by the garbage collector. +- **go_memory_classes_heap_released_bytes:** Memory that is completely free +and has been returned to the underlying system. This metric is the runtime's +estimate of free address space that is still mapped into the process, but +is not backed by physical memory. +- **go_memory_classes_heap_stacks_bytes:** Memory allocated from the heap +that is reserved for stack space, whether or not it is currently in-use. +- **go_memory_classes_heap_unused_bytes:** Memory that is reserved for heap +objects but is not currently used to hold heap objects. +- **go_memory_classes_metadata_mcache_free_bytes:** Memory that is reserved +for runtime mcache structures, but not in-use. +- **go_memory_classes_metadata_mcache_inuse_bytes:** Memory that is occupied +by runtime mcache structures that are currently being used. +- **go_memory_classes_metadata_mspan_free_bytes:** Memory that is reserved +for runtime mspan structures, but not in-use. +- **go_memory_classes_metadata_mspan_inuse_bytes:** Memory that is occupied +by runtime mspan structures that are currently being used. +- **go_memory_classes_metadata_other_bytes:** Memory that is reserved for +or used to hold runtime metadata. +- **go_memory_classes_os_stacks_bytes:** Stack memory allocated by the +underlying operating system. +- **go_memory_classes_other_bytes:** Memory used by execution trace buffers, +structures for debugging the runtime, finalizer and profiler specials, +and more. +- **go_memory_classes_profiling_buckets_bytes:** Memory that is used by the +stack trace hash map used for profiling. +- **go_memory_classes_total_bytes:** All memory mapped by the Go runtime +into the current process as read-write. Note that this does not include +memory mapped by code called via cgo or via the syscall package. Sum of all +metrics in /memory/classes. - **go_memstats_alloc_bytes:** Number of bytes allocated and still in use. - **go_memstats_alloc_bytes_total:** Total number of bytes allocated, even if freed. @@ -318,6 +413,9 @@ allocator. - **go_memstats_stack_sys_bytes:** Number of bytes obtained from system for stack allocator. - **go_memstats_sys_bytes:** Number of bytes obtained from system. +- **go_sched_goroutines_goroutines:** Count of live goroutines. +- **go_sched_latencies_seconds:** Distribution of the time goroutines have +spent in the scheduler in a runnable state before actually running. - **go_threads:** Number of OS threads created. #### Process Metrics diff --git a/docs/security.md b/docs/security.md index ecc4477d827..81e2fe68abc 100644 --- a/docs/security.md +++ b/docs/security.md @@ -10,6 +10,140 @@ To report a vulnerability in Antrea, please refer to For information about securing Antrea control-plane communications, refer to this [document](securing-control-plane.md). +## Protecting Your Cluster Against Privilege Escalations + +### Antrea Agent + +Like all other K8s Network Plugins, Antrea runs an agent (the Antrea Agent) on +every Node on the cluster, using a K8s DaemonSet. And just like for other K8s +Network Plugins, this agent requires a specific set of permissions which grant +it access to the K8s API using +[RBAC](https://kubernetes.io/docs/reference/access-authn-authz/rbac/). These +permissions are required to implement the different features offered by +Antrea. If any Node in the cluster happens to become compromised (e.g., by an +escaped container) and the token for the `antrea-agent` ServiceAccount is +harvested by the attacker, some of these permissions can be leveraged to +negatively affect other workloads running on the cluster. In particular, the +Antrea Agent is granted the following permissions: + +* `patch` the `pods/status` resources: a successful attacker could abuse this + permission to re-label Pods to facilitate [confused deputy + attacks](https://en.wikipedia.org/wiki/Confused_deputy_problem) against + built-in controllers. For example, making a Pod match a Service selector in + order to man-in-the-middle (MITM) the Service traffic, or making a Pod match a + ReplicaSet selector so that the ReplicaSet controller deletes legitimate + replicas. +* `patch` the `nodes/status` resources: a successful attacker could abuse this + permission to affect scheduling by modifying Node fields like labels, + capacity, and conditions. + +In both cases, the Antrea Agent only requires the ability to mutate the +annotations field for all Pods and Nodes, but with K8s RBAC, the lowest +permission level that we can grant the Antrea Agent to satisfy this requirement +is the `patch` verb for the `status` subresource for Pods and Nodes (which also +provides the ability to mutate labels). + +To mitigate the risk presented by these permissions in case of a compromised +token, we suggest that you use +[Gatekeeper](https://github.com/open-policy-agent/gatekeeper), with the +appropriate policy. We provide the following Gatekeeper policy, consisting of a +`ConstraintTemplate` and the corresponding `Constraint`. When using this policy, +it will no longer be possible for the `antrea-agent` ServiceAccount to mutate +anything besides annotations for the Pods and Nodes resources. + +```yaml +# ConstraintTemplate +apiVersion: templates.gatekeeper.sh/v1 +kind: ConstraintTemplate +metadata: + name: antreaagentstatusupdates + annotations: + description: >- + Disallows unauthorized updates to status subresource by Antrea Agent + Only annotations can be mutated +spec: + crd: + spec: + names: + kind: AntreaAgentStatusUpdates + targets: + - target: admission.k8s.gatekeeper.sh + rego: | + package antreaagentstatusupdates + username := object.get(input.review.userInfo, "username", "") + targetUsername := "system:serviceaccount:kube-system:antrea-agent" + + allowed_mutation(object, oldObject) { + object.status == oldObject.status + object.metadata.labels == oldObject.metadata.labels + } + + violation[{"msg": msg}] { + username == targetUsername + input.review.operation == "UPDATE" + input.review.requestSubResource == "status" + not allowed_mutation(input.review.object, input.review.oldObject) + msg := "Antrea Agent is not allowed to mutate this field" + } +``` + +```yaml +# Constraint +apiVersion: constraints.gatekeeper.sh/v1beta1 +kind: AntreaAgentStatusUpdates +metadata: + name: antrea-agent-status-updates +spec: + match: + kinds: + - apiGroups: [""] + kinds: ["Pod", "Node"] +``` + +***Please ensure that the `ValidatingWebhookConfiguration` for your Gatekeeper + installation enables policies to be applied on the `pods/status` and + `nodes/status` subresources, which may not be the case by default.*** + +As a reference, the following `ValidatingWebhookConfiguration` rule will cause +policies to be applied to all resources and their subresources: + +```yaml + - apiGroups: + - '*' + apiVersions: + - '*' + operations: + - CREATE + - UPDATE + resources: + - '*/*' + scope: '*' +``` + +while the following rule will cause policies to be applied to all resources, but +not their subresources: + +```yaml + - apiGroups: + - '*' + apiVersions: + - '*' + operations: + - CREATE + - UPDATE + resources: + - '*' + scope: '*' +``` + +### Antrea Controller + +The Antrea Controller, which runs as a single-replica Deployment, enjoys higher +level permissions than the Antrea Agent. We recommend for production clusters +running Antrea to schedule the `antrea-controller` Pod on a "secure" Node, which +could for example be the Node (or one of the Nodes) running the K8s +control-plane. + ## Protecting Access to Antrea Configuration Files Antrea relies on persisting files on each K8s Node's filesystem, in order to diff --git a/docs/service-loadbalancer.md b/docs/service-loadbalancer.md index be3543730ff..6367b7012f4 100644 --- a/docs/service-loadbalancer.md +++ b/docs/service-loadbalancer.md @@ -4,6 +4,7 @@ - [Service external IP management by Antrea](#service-external-ip-management-by-antrea) + - [Preparation](#preparation) - [Configuration](#configuration) - [Enable Service external IP management feature](#enable-service-external-ip-management-feature) - [Create an ExternalIPPool custom resource](#create-an-externalippool-custom-resource) @@ -14,6 +15,8 @@ - [Install MetalLB](#install-metallb) - [Configure MetalLB with layer 2 mode](#configure-metallb-with-layer-2-mode) - [Configure MetalLB with BGP mode](#configure-metallb-with-bgp-mode) +- [Interoperability with kube-proxy IPVS mode](#interoperability-with-kube-proxy-ipvs-mode) + - [Issue with Antrea Egress](#issue-with-antrea-egress) In Kubernetes, implementing Services of type LoadBalancer usually requires @@ -46,6 +49,16 @@ Endpoints. Antrea also implements a Node failover mechanism for Service external IPs. When Antrea detects a Node hosting an external IP is down, it will move the external IP to another available Node of the ExternalIPPool. +### Preparation + +If you are using `kube-proxy` in IPVS mode, you need to make sure `strictARP` is +enabled in the `kube-proxy` configuration. For more information about how to +configure `kube-proxy`, please refer to the [Interoperability with kube-proxy +IPVS mode](#interoperability-with-kube-proxy-ipvs-mode) section. + +If you are using `kube-proxy` iptables mode or [`AntreaProxy` with `proxyAll`](antrea-proxy.md#antreaproxy-with-proxyall), +no extra configuration change is needed. + ### Configuration #### Enable Service external IP management feature @@ -246,6 +259,12 @@ default configuration (in which the `ServiceExternalIP` feature gate of ### Configure MetalLB with layer 2 mode +Similar to the case of Antrea Service external IP management, MetalLB layer 2 +mode also requires `kube-proxy`'s `strictARP` configuration to be enabled, when +you are using `kube-proxy` IPVS. Please refer to the [Interoperability with +kube-proxy IPVS mode](#interoperability-with-kube-proxy-ipvs-mode) section for +more information. + MetalLB is configured through a ConfigMap. To configure MetalLB to work in the layer 2 mode, you just need to provide the IP ranges to allocate external IPs. The IP ranges should be from the Node network subnet. @@ -296,3 +315,43 @@ In addition to the basic layer 2 and BGP mode configurations described in this document, MetalLB supports a few more advanced BGP configurations and supports configuring multiple IP pools which can use different modes. For more information, please refer to the [MetalLB configuration guide](https://metallb.universe.tf/configuration). + +## Interoperability with kube-proxy IPVS mode + +Both Antrea Service external IP management and MetalLB layer 2 mode require +`kube-proxy`'s `strictARP` configuration to be enabled, to work with +`kube-proxy` in IPVS mode. You can check the `strictARP` configuration in the +`kube-proxy` ConfigMap: + +```bash +$ kubectl describe configmap -n kube-system kube-proxy | grep strictARP + strictARP: false +``` + +You can set `strictARP` to `true` by editing the `kube-proxy` ConfigMap: + +```bash +kubectl edit configmap -n kube-system kube-proxy +``` + +Or, simply run the following command to set it: + +```bash +$ kubectl get configmap kube-proxy -n kube-system -o yaml | \ + sed -e "s/strictARP: false/strictARP: true/" | \ + kubectl apply -f - -n kube-system +``` + +Last, to check the change is made: + +```bash +$ kubectl describe configmap -n kube-system kube-proxy | grep strictARP + strictARP: true +``` + +### Issue with Antrea Egress + +The current implementation of Antrea Egress does not work with the `strictARP` +configuration of `kube-proxy`. It means Antrea Egress cannot work together with +Service external IP management or MetalLB layer 2 mode, when `kube-proxy` IPVS +is used. We assume this issue will be fixed in a near future Antrea version. diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md index fb9c46e760a..65d71760196 100644 --- a/docs/troubleshooting.md +++ b/docs/troubleshooting.md @@ -126,7 +126,7 @@ address and pass an authentication token when accessing it, like this: # Get the antrea Service address ANTREA_SVC=$(kubectl get service antrea -n kube-system -o jsonpath='{.spec.clusterIP}') # Get the token value of antctl account, you can use any ServiceAccount that has permissions to antrea API. -TOKEN=$(kubectl get secrets -n kube-system -o jsonpath="{.items[?(@.metadata.annotations['kubernetes\.io/service-account\.name']=='antctl')].data.token}"|base64 --decode) +TOKEN=$(kubectl get secret/antctl-service-account-token -n kube-system -o jsonpath="{.data.token}"|base64 --decode) # Access antrea API with TOKEN curl --insecure --header "Authorization: Bearer $TOKEN" https://$ANTREA_SVC/apis ``` @@ -176,13 +176,14 @@ using the authentication token of the `antctl` ServiceAccount: ```bash # Get the token value of antctl account. -TOKEN=$(kubectl get secrets -n kube-system -o jsonpath="{.items[?(@.metadata.annotations['kubernetes\.io/service-account\.name']=='antctl')].data.token}"|base64 --decode) +TOKEN=$(kubectl get secret/antctl-service-account-token -n kube-system -o jsonpath="{.data.token}"|base64 --decode) # Access antrea API with TOKEN curl --insecure --header "Authorization: Bearer $TOKEN" https://:10350/podinterfaces ``` However, in this case you will be limited to the endpoints that `antctl` is -allowed to access, as defined [here](/build/yamls/base/antctl.yml). +allowed to access, as defined +[here](../build/charts/antrea/templates/antctl/clusterrole.yaml). ## Accessing the flow-aggregator API @@ -256,7 +257,7 @@ f06768ee-17ec-4abb-a971-b3b76abc8cda Port antrea-gw0 Interface antrea-gw0 type: internal - ovs_version: "2.15.1" + ovs_version: "2.17.0" ``` - `ovs-ofctl show br-int`: show OpenFlow information of the OVS bridge. diff --git a/docs/windows.md b/docs/windows.md index 6d35e84b394..a1128f32e4d 100644 --- a/docs/windows.md +++ b/docs/windows.md @@ -67,7 +67,7 @@ First install Antrea (v0.13.0+ is required for Containerd). ```bash # Example: -kubectl apply -f https://github.com/antrea-io/antrea/releases/download/v0.13.0/antrea.yml +kubectl apply -f https://github.com/antrea-io/antrea/releases/download/v1.6.0/antrea.yml ``` Then, you can run the following commands. [nssm](https://nssm.cc/) will install Antrea as a Windows service. Please ensure @@ -75,14 +75,14 @@ Then, you can run the following commands. [nssm](https://nssm.cc/) will install `` and `` should be set by you. E.g. ```powershell -$KubernetesVersion="v1.20.4" +$KubernetesVersion="v1.23.5" $KubeConfig="C:/Users/Administrator/.kube/config" # admin kubeconfig $KubeletKubeconfigPath="C:/etc/kubernetes/kubelet.conf" $KubeProxyKubeconfigPath="C:/Users/Administrator/kubeproxy.conf" ``` ```powershell -$TAG="v0.13.0" +$TAG="v1.6.0" $KubernetesVersion="" $KubeConfig="" $KubeletKubeconfigPath="" @@ -134,7 +134,7 @@ kube-proxy version. ```bash # Example: -curl -L "https://github.com/kubernetes-sigs/sig-windows-tools/releases/download/v0.1.5/kube-proxy.yml" | sed 's/VERSION/v1.18.0/g' > kube-proxy.yml +curl -L "https://github.com/kubernetes-sigs/sig-windows-tools/releases/download/v0.1.5/kube-proxy.yml" | sed 's/VERSION/v1.23.5/g' > kube-proxy.yml ``` Replace the content of `run-script.ps1` in configmap named `kube-proxy-windows` @@ -184,13 +184,6 @@ spec: hostNetwork: true ``` -If the powershell version on your Window Node is earlier than v6.0, -change the command from `pwsh` to `powershell` in kube-proxy.yml. - -```bash -sed -i 's/pwsh/powershell/g' kube-proxy.yml -``` - Then apply the `kube-proxy.yml`. ```bash @@ -262,7 +255,7 @@ container. ```powershell # Example: curl.exe -LO "https://github.com/kubernetes-sigs/sig-windows-tools/releases/download/v0.1.5/PrepareNode.ps1" -.\PrepareNode.ps1 -KubernetesVersion v1.18.0 +.\PrepareNode.ps1 -KubernetesVersion v1.23.5 ``` #### 4. Prepare Node environment needed by antrea-agent @@ -360,9 +353,9 @@ Nodes and Pods in your cluster by running: # Show Nodes kubectl get nodes -o wide -n kube-system NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME -control-plane Ready control-plane,master 1h v1.18.3 10.176.27.168 Ubuntu 18.04.3 LTS 4.15.0-66-generic docker://19.3.9 -win-5akrf2tpq91 Ready 1h v1.18.0 10.176.27.150 Windows Server 2019 Standard Evaluation 10.0.17763.1158 docker://19.3.5 -win-5akrf2tpq92 Ready 1h v1.18.0 10.176.27.197 Windows Server 2019 Standard Evaluation 10.0.17763.1158 docker://19.3.5 +control-plane Ready control-plane,master 1h v1.23.5 10.176.27.168 Ubuntu 20.04.3 LTS 5.11.0-1022-generic docker://20.10.14 +win-5akrf2tpq91 Ready 1h v1.23.5 10.176.27.150 Windows Server 2019 Standard Evaluation 10.0.17763.2686 docker://20.10.9 +win-5akrf2tpq92 Ready 1h v1.23.5 10.176.27.197 Windows Server 2019 Standard Evaluation 10.0.17763.2686 docker://20.10.9 # Show antrea-agent and kube-proxy Pods kubectl get pods -o wide -n kube-system | grep windows diff --git a/go.mod b/go.mod index ad8d8289322..cd85569e479 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.17 require ( antrea.io/libOpenflow v0.6.2 - antrea.io/ofnet v0.5.5 + antrea.io/ofnet v0.5.7 github.com/ClickHouse/clickhouse-go v1.5.1 github.com/DATA-DOG/go-sqlmock v1.5.0 github.com/Mellanox/sriovnet v1.0.2 @@ -19,8 +19,7 @@ require ( github.com/containernetworking/plugins v0.8.7 github.com/coreos/go-iptables v0.6.0 github.com/gammazero/deque v0.1.0 - github.com/go-logr/logr v0.4.0 - github.com/go-openapi/spec v0.19.5 + github.com/go-logr/logr v1.2.0 github.com/gogo/protobuf v1.3.2 github.com/golang/mock v1.6.0 github.com/golang/protobuf v1.5.2 @@ -36,56 +35,56 @@ require ( github.com/mdlayher/raw v0.0.0-20211126142749-4eae47f3d54b github.com/miekg/dns v1.1.43 github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 - github.com/onsi/ginkgo v1.16.4 - github.com/onsi/gomega v1.13.0 + github.com/onsi/ginkgo v1.16.5 + github.com/onsi/gomega v1.17.0 github.com/pkg/errors v0.9.1 - github.com/prometheus/client_golang v1.11.0 - github.com/prometheus/common v0.26.0 + github.com/prometheus/client_golang v1.12.1 + github.com/prometheus/common v0.32.1 github.com/satori/go.uuid v1.2.0 github.com/sirupsen/logrus v1.8.1 github.com/spf13/afero v1.6.0 github.com/spf13/cobra v1.4.0 github.com/spf13/pflag v1.0.5 - github.com/stretchr/testify v1.7.0 + github.com/stretchr/testify v1.7.1 github.com/ti-mo/conntrack v0.4.0 github.com/vishvananda/netlink v1.1.1-0.20210510164352-d17758a128bf github.com/vmware/go-ipfix v0.5.12 go.uber.org/multierr v1.6.0 - golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e + golang.org/x/crypto v0.0.0-20220214200702-86341886e292 golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6 - golang.org/x/mod v0.4.2 - golang.org/x/net v0.0.0-20210504132125-bbd867fde50d + golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 + golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd golang.org/x/sync v0.0.0-20210220032951-036812b2e83c - golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40 - golang.org/x/time v0.0.0-20210611083556-38a9dc6acbc6 + golang.org/x/sys v0.0.0-20220209214540-3681064d5158 + golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 golang.zx2c4.com/wireguard/wgctrl v0.0.0-20210506160403-92e472f520a5 - google.golang.org/grpc v1.27.1 + google.golang.org/grpc v1.40.0 google.golang.org/protobuf v1.27.1 gopkg.in/natefinch/lumberjack.v2 v2.0.0 gopkg.in/yaml.v2 v2.4.0 - k8s.io/api v0.21.2 - k8s.io/apiextensions-apiserver v0.21.2 - k8s.io/apimachinery v0.21.2 - k8s.io/apiserver v0.21.2 - k8s.io/client-go v0.21.2 - k8s.io/component-base v0.21.2 - k8s.io/klog/v2 v2.8.0 - k8s.io/kube-aggregator v0.21.0 - k8s.io/kube-openapi v0.0.0-20210305164622-f622666832c1 - k8s.io/kubectl v0.21.0 - k8s.io/kubelet v0.21.0 - k8s.io/utils v0.0.0-20210527160623-6fdb442a123b - sigs.k8s.io/controller-runtime v0.9.1 + k8s.io/api v0.24.0 + k8s.io/apiextensions-apiserver v0.24.0 + k8s.io/apimachinery v0.24.0 + k8s.io/apiserver v0.24.0 + k8s.io/client-go v0.24.0 + k8s.io/component-base v0.24.0 + k8s.io/klog/v2 v2.60.1 + k8s.io/kube-aggregator v0.24.0 + k8s.io/kube-openapi v0.0.0-20220328201542-3ee0da9b0b42 + k8s.io/kubectl v0.24.0 + k8s.io/kubelet v0.24.0 + k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9 + sigs.k8s.io/controller-runtime v0.11.2 sigs.k8s.io/mcs-api v0.1.0 ) require ( - cloud.google.com/go v0.54.0 // indirect + cloud.google.com/go v0.81.0 // indirect github.com/Azure/go-autorest v14.2.0+incompatible // indirect - github.com/Azure/go-autorest/autorest v0.11.12 // indirect - github.com/Azure/go-autorest/autorest/adal v0.9.5 // indirect + github.com/Azure/go-autorest/autorest v0.11.18 // indirect + github.com/Azure/go-autorest/autorest/adal v0.9.13 // indirect github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect - github.com/Azure/go-autorest/logger v0.2.0 // indirect + github.com/Azure/go-autorest/logger v0.2.1 // indirect github.com/Azure/go-autorest/tracing v0.6.0 // indirect github.com/NYTimes/gziphandler v1.1.1 // indirect github.com/PuerkitoBio/purell v1.1.1 // indirect @@ -93,32 +92,34 @@ require ( github.com/VividCortex/ewma v1.1.1 // indirect github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da // indirect github.com/beorn7/perks v1.0.1 // indirect + github.com/blang/semver/v4 v4.0.0 // indirect github.com/cenk/hub v1.0.1 // indirect github.com/cenkalti/hub v1.0.1 // indirect github.com/cenkalti/rpc2 v0.0.0-20180727162946-9642ea02d0aa // indirect - github.com/cespare/xxhash/v2 v2.1.1 // indirect + github.com/cespare/xxhash/v2 v2.1.2 // indirect github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58 // indirect github.com/containerd/cgroups v0.0.0-20200531161412-0dbf7f05ba59 // indirect github.com/contiv/libovsdb v0.0.0-20170227191248-d0061a53e358 // indirect github.com/coreos/go-semver v0.3.0 // indirect - github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e // indirect - github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f // indirect + github.com/coreos/go-systemd/v22 v22.3.2 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/elazarl/goproxy v0.0.0-20190911111923-ecfe977594f1 // indirect github.com/emicklei/go-restful v2.10.0+incompatible // indirect - github.com/evanphx/json-patch v4.11.0+incompatible // indirect + github.com/evanphx/json-patch v4.12.0+incompatible // indirect github.com/fatih/color v1.10.0 // indirect - github.com/form3tech-oss/jwt-go v3.2.2+incompatible // indirect - github.com/fsnotify/fsnotify v1.4.9 // indirect - github.com/go-logr/zapr v0.4.0 // indirect - github.com/go-openapi/jsonpointer v0.19.3 // indirect - github.com/go-openapi/jsonreference v0.19.3 // indirect - github.com/go-openapi/swag v0.19.5 // indirect - github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect + github.com/felixge/httpsnoop v1.0.1 // indirect + github.com/form3tech-oss/jwt-go v3.2.3+incompatible // indirect + github.com/fsnotify/fsnotify v1.5.1 // indirect + github.com/go-logr/zapr v1.2.0 // indirect + github.com/go-openapi/jsonpointer v0.19.5 // indirect + github.com/go-openapi/jsonreference v0.19.5 // indirect + github.com/go-openapi/swag v0.19.14 // indirect + github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect + github.com/google/gnostic v0.5.7-v3refs // indirect github.com/google/go-cmp v0.5.5 // indirect github.com/google/gofuzz v1.1.0 // indirect - github.com/googleapis/gnostic v0.5.5 // indirect github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect + github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect github.com/hashicorp/errwrap v1.0.0 // indirect github.com/hashicorp/go-immutable-radix v1.0.0 // indirect github.com/hashicorp/go-msgpack v0.5.3 // indirect @@ -127,9 +128,10 @@ require ( github.com/hashicorp/golang-lru v0.5.4 // indirect github.com/imdario/mergo v0.3.12 // indirect github.com/inconshreveable/mousetrap v1.0.0 // indirect + github.com/josharian/intern v1.0.0 // indirect github.com/josharian/native v0.0.0-20200817173448-b6b71def0850 // indirect - github.com/json-iterator/go v1.1.11 // indirect - github.com/mailru/easyjson v0.7.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/mailru/easyjson v0.7.6 // indirect github.com/mattn/go-colorable v0.1.8 // indirect github.com/mattn/go-isatty v0.0.12 // indirect github.com/mattn/go-runewidth v0.0.12 // indirect @@ -138,7 +140,7 @@ require ( github.com/mdlayher/netlink v1.4.0 // indirect github.com/moby/spdystream v0.2.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect - github.com/modern-go/reflect2 v1.0.1 // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect github.com/nxadm/tail v1.4.8 // indirect github.com/pion/dtls/v2 v2.0.3 // indirect @@ -147,7 +149,7 @@ require ( github.com/pion/udp v0.1.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_model v0.2.0 // indirect - github.com/prometheus/procfs v0.6.0 // indirect + github.com/prometheus/procfs v0.7.3 // indirect github.com/rivo/uniseg v0.2.0 // indirect github.com/safchain/ethtool v0.0.0-20190326074333-42ed695e3de8 // indirect github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 // indirect @@ -155,24 +157,38 @@ require ( github.com/ti-mo/netfilter v0.3.1 // indirect github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae // indirect gitlab.com/golang-commonmark/puny v0.0.0-20191124015043-9f83538fa04f // indirect - go.etcd.io/etcd v0.5.0-alpha.5.0.20200910180754-dd1b699fc489 // indirect - go.opencensus.io v0.22.3 // indirect + go.etcd.io/etcd/api/v3 v3.5.1 // indirect + go.etcd.io/etcd/client/pkg/v3 v3.5.1 // indirect + go.etcd.io/etcd/client/v3 v3.5.1 // indirect + go.opencensus.io v0.23.0 // indirect + go.opentelemetry.io/contrib v0.20.0 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.20.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.20.0 // indirect + go.opentelemetry.io/otel v0.20.0 // indirect + go.opentelemetry.io/otel/exporters/otlp v0.20.0 // indirect + go.opentelemetry.io/otel/metric v0.20.0 // indirect + go.opentelemetry.io/otel/sdk v0.20.0 // indirect + go.opentelemetry.io/otel/sdk/export/metric v0.20.0 // indirect + go.opentelemetry.io/otel/sdk/metric v0.20.0 // indirect + go.opentelemetry.io/otel/trace v0.20.0 // indirect + go.opentelemetry.io/proto/otlp v0.7.0 // indirect go.uber.org/atomic v1.7.0 // indirect - go.uber.org/zap v1.17.0 // indirect - golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d // indirect - golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d // indirect - golang.org/x/text v0.3.6 // indirect + go.uber.org/zap v1.19.1 // indirect + golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 // indirect + golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect + golang.org/x/text v0.3.7 // indirect golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect golang.zx2c4.com/wireguard v0.0.0-20210427022245-097af6e1351b // indirect gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a // indirect + google.golang.org/genproto v0.0.0-20220107163113-42d7afdf6368 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect - sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.19 // indirect - sigs.k8s.io/structured-merge-diff/v4 v4.1.0 // indirect - sigs.k8s.io/yaml v1.2.0 // indirect + sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.30 // indirect + sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2 // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.2.1 // indirect + sigs.k8s.io/yaml v1.3.0 // indirect ) // Newer version of github.com/googleapis/gnostic make use of newer gopkg.in/yaml(v3), which conflicts with diff --git a/go.sum b/go.sum index a73e2933519..0b990a41ceb 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,7 @@ antrea.io/libOpenflow v0.6.2 h1:1JMSJ7Lp7yOhKybHey9VDtRI6JuIgkhUWJBX5GIFY9I= antrea.io/libOpenflow v0.6.2/go.mod h1:CzEJZxDNAupiGxeL5VOw92PsxfyvehEAvE3PiC6gr8o= -antrea.io/ofnet v0.5.5 h1:4CLYWqQE4/XyuIUaTSqB83Zj+YnuplrlEXPvVm/r0JE= -antrea.io/ofnet v0.5.5/go.mod h1:8TJVF6MLe9/gZ/KbhGUvULs9/TxssepEaYEe+o1SEgs= +antrea.io/ofnet v0.5.7 h1:x0q0lZqp05wu01gk1+S5S15FmIpmTGPhi/z/aIDmuMw= +antrea.io/ofnet v0.5.7/go.mod h1:8TJVF6MLe9/gZ/KbhGUvULs9/TxssepEaYEe+o1SEgs= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= @@ -12,30 +12,49 @@ cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= -cloud.google.com/go v0.54.0 h1:3ithwDMr7/3vpAMXiH+ZQnYbuIsh+OPhUPMFC9enmn0= cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= +cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= +cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= +cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= +cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= +cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= +cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= +cloud.google.com/go v0.81.0 h1:at8Tk2zUz63cLPR0JPWm5vp77pEZmzxEQBEfRKn1VV8= +cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= +cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= +cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= +cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= +github.com/Azure/go-ansiterm v0.0.0-20210608223527-2377c96fe795/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= +github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs= github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= -github.com/Azure/go-autorest/autorest v0.11.12 h1:gI8ytXbxMfI+IVbI9mP2JGCTXIuhHLgRlvQ9X4PsnHE= github.com/Azure/go-autorest/autorest v0.11.12/go.mod h1:eipySxLmqSyC5s5k1CLupqet0PSENBEDP93LQ9a8QYw= +github.com/Azure/go-autorest/autorest v0.11.18 h1:90Y4srNYrwOtAgVo3ndrQkTYn6kf1Eg/AjTFJ8Is2aM= +github.com/Azure/go-autorest/autorest v0.11.18/go.mod h1:dSiJPy22c3u0OtOKDNttNgqpNFY/GeWa7GH/Pz56QRA= github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= -github.com/Azure/go-autorest/autorest/adal v0.9.5 h1:Y3bBUV4rTuxenJJs41HU3qmqsb+auo+a3Lz+PlJPpL0= github.com/Azure/go-autorest/autorest/adal v0.9.5/go.mod h1:B7KF7jKIeC9Mct5spmyCB/A8CG/sEz1vwIRGv/bbw7A= +github.com/Azure/go-autorest/autorest/adal v0.9.13 h1:Mp5hbtOePIzM8pJVRa3YLrWWmZtoxRXqUEzCfJt3+/Q= +github.com/Azure/go-autorest/autorest/adal v0.9.13/go.mod h1:W/MM4U6nLxnIskrw4UwWzlHfGjwUS50aOsc/I3yuU8M= github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= github.com/Azure/go-autorest/autorest/date v0.3.0 h1:7gUk1U5M/CQbp9WoqinNzJar+8KY+LPI6wiWrP/myHw= github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= @@ -44,8 +63,9 @@ github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxB github.com/Azure/go-autorest/autorest/mocks v0.4.1 h1:K0laFcLE6VLTOwNgSxaGbUcLPuGXlNkbVvq4cW4nIHk= github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= -github.com/Azure/go-autorest/logger v0.2.0 h1:e4RVHVZKC5p6UANLJHkM4OfR1UKZPj8Wt8Pcx+3oqrE= github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= +github.com/Azure/go-autorest/logger v0.2.1 h1:IG7i4p/mDa2Ce4TRyAO8IHnVhAVF3RFU+ZtXWSmf4Tg= +github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo= github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= @@ -93,15 +113,22 @@ github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk5 github.com/alessio/shellescape v1.2.2/go.mod h1:PZAiSCk0LJaZkiCSkPv8qIobYglO3FPpyFjDCtHLS30= github.com/alexflint/go-filemutex v0.0.0-20171022225611-72bdc8eae2ae/go.mod h1:CgnQgUtFrFz9mxFNtED3jI5tLDjKlOM+oUF/sTk6ps0= github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/antlr/antlr4/runtime/Go/antlr v0.0.0-20210826220005-b48c857c3a0e/go.mod h1:F7bn7fEU90QkQ3tnmaTx3LTKLEDqnwWODIYppRQ5hnY= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da h1:8GUt8eRujhVEGZFFEjBj46YV4rDjvGrNxb0KMWYkL2I= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/awalterschulze/gographviz v2.0.1+incompatible h1:XIECBRq9VPEQqkQL5pw2OtjCAdrtIgFKoJU8eT98AS8= github.com/awalterschulze/gographviz v2.0.1+incompatible/go.mod h1:GEV5wmg4YquNw7v1kkyoX9etIk8yVmXj+AkDHuuETHs= +github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM= +github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= +github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= @@ -110,9 +137,12 @@ github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kB github.com/bkaradzic/go-lz4 v1.0.0 h1:RXc4wYsyz985CkXXeX04y4VnZFGG8Rd43pRaHsOXAKk= github.com/bkaradzic/go-lz4 v1.0.0/go.mod h1:0YdlkowM3VswSROI7qDxhRvJ3sLhlFrRRwjwegp5jy4= github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= +github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM= github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ= github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= +github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= +github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= github.com/buger/jsonparser v0.0.0-20180808090653-f4dd9f5a6b44/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= github.com/cenk/hub v1.0.1 h1:RBwXNOF4a8KjD8BJ08XqN8KbrqaGiQLDrgvUGJSHuPA= github.com/cenk/hub v1.0.1/go.mod h1:rJM1LNAW0ppT8FMMuPK6c2NP/R2nH/UthtuRySSaf6Y= @@ -123,10 +153,13 @@ github.com/cenkalti/rpc2 v0.0.0-20140912135055-44d0d95e4f52/go.mod h1:v2npkhrXyk github.com/cenkalti/rpc2 v0.0.0-20180727162946-9642ea02d0aa h1:t+iWhuJE2aropY4uxKMVbyP+IJ29o422f7YAd73aTjg= github.com/cenkalti/rpc2 v0.0.0-20180727162946-9642ea02d0aa/go.mod h1:v2npkhrXyk5BCnkNIiPdRI23Uq6uWPUQGL2hnRcRr/M= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/certifi/gocertifi v0.0.0-20191021191039-0944d244cd40/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA= +github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA= github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= -github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= +github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5/go.mod h1:/iP1qXHoty45bqomnu2LM+VVyAEdWN+vtSHGlQgyxbw= github.com/cheggaaa/pb/v3 v3.0.8 h1:bC8oemdChbke2FHIIGy9mn4DPJ2caZYQnfbRqwmdCoA= github.com/cheggaaa/pb/v3 v3.0.8/go.mod h1:UICbiLec/XO6Hw6k+BHEtHeQFzzBH4i2/qk/ow1EJTA= @@ -137,8 +170,14 @@ github.com/cilium/ebpf v0.0.0-20200110133405-4032b1d8aae3/go.mod h1:MA5e5Lr8slmE github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58 h1:F1EaeKL/ta07PY/k9Os/UFtwERei2/XzGemhpGnBKNg= github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58/go.mod h1:EOBUe0h4xcZ5GoxqC5SDxFQ8gwyZPKQoEzownBlhI80= -github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa h1:OaNxuTZr7kxeODyLWsRMC+OD03aFUH+mW6r2d+MWa5Y= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= +github.com/cockroachdb/datadriven v0.0.0-20200714090401-bf6692d28da5/go.mod h1:h6jFvWxBdQXxjopDMZyH2UVceIRfR84bdzbkoKrsWNo= +github.com/cockroachdb/errors v1.2.4/go.mod h1:rQD95gz6FARkaKkQXUksEje/d9a6wBJoCr5oaCLELYA= +github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI= github.com/confluentinc/bincover v0.1.0 h1:M4Gfj4rCXuUQVe8TqT/VXcAMjLyvN81oDRy79fjSv3o= github.com/confluentinc/bincover v0.1.0/go.mod h1:qeI1wx0RxdGTZtrJY0HVlgJ4NqC/X2Z+fHbvy87tgHE= github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f/go.mod h1:OApqhQ4XNSNC13gXIwDjhOQxjWa/NxkwZXJ1EvqT0ko= @@ -174,9 +213,10 @@ github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7 github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e h1:Wf6HqHfScWJN9/ZjdUKyjop4mf3Qdd+1TvvltAvM3m8= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd/v22 v22.0.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= +github.com/coreos/go-systemd/v22 v22.3.2 h1:D9/bQk5vlXQFZ6Kwuu6zaiXJ9oTPe68++AzAJc1DzSI= +github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= -github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f h1:lBNOc5arjvs8E5mO2tbpBpLoyyu8B6e44T7hJy6potg= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= @@ -193,10 +233,9 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/daviddengcn/go-colortext v0.0.0-20160507010035-511bcaf42ccd/go.mod h1:dv4zxwHi5C/8AeI+4gX4dCWOIvNi7I6JCSX0HvlKPgE= -github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= -github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/docker v0.7.3-0.20190327010347-be7ac8be2ae0/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= @@ -216,30 +255,43 @@ github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= github.com/emicklei/go-restful v2.10.0+incompatible h1:l6Soi8WCOOVAeCo4W98iBFC6Og7/X8bpRt51oNLZ2C8= github.com/emicklei/go-restful v2.10.0+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/evanphx/json-patch v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMikGIFbs31qQ= github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch v4.5.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/evanphx/json-patch v4.11.0+incompatible h1:glyUF9yIYtMHzn8xaKw5rMhdWcwsYV8dZHIq5567/xs= github.com/evanphx/json-patch v4.11.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch v4.12.0+incompatible h1:4onqiflcdA9EOZ4RxV643DvftH5pOlLGNtQ5lPWQu84= +github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch/v5 v5.0.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d/go.mod h1:ZZMPRZwes7CROmyNKgQzC3XPs6L/G2EJLHddWejkmf4= github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.10.0 h1:s36xzo75JdqLaaWoiEHk767eHiwo0598uUxyfiPkDsg= github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= -github.com/form3tech-oss/jwt-go v3.2.2+incompatible h1:TcekIExNqud5crz4xD2pavyTgWiPvpYe4Xau31I0PRk= +github.com/felixge/httpsnoop v1.0.1 h1:lvB5Jl89CsZtGIWuTcDM1E/vkVs49/Ml7JJe07l8SPQ= +github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= +github.com/form3tech-oss/jwt-go v3.2.3+incompatible h1:7ZaBxOI7TMoYBfyA3cQHErNNyAWIKUMIwqxEtgHOs5c= +github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= github.com/frankban/quicktest v1.10.2/go.mod h1:K+q6oSqb0W0Ininfk863uOk1lMy69l/P6txr3mVT54s= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI= +github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= github.com/fvbommel/sortorder v1.0.1/go.mod h1:uk88iVf1ovNn1iLfgUVU2F9o5eO30ui720w+kxuqRs0= github.com/gammazero/deque v0.1.0 h1:f9LnNmq66VDeuAlSAapemq/U7hJ2jpIWa4c09q8Dlik= github.com/gammazero/deque v0.1.0/go.mod h1:KQw7vFau1hHuM8xmI9RbgKFbAsQFWmBpqQ2KenFLk6M= +github.com/getkin/kin-openapi v0.76.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSyhcnluiMv+Xg= +github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ= github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= @@ -256,11 +308,12 @@ github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= -github.com/go-logr/logr v0.4.0 h1:K7/B1jt6fIBQVd4Owv2MqGQClcgf0R266+7C/QjRcLc= github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= +github.com/go-logr/logr v1.2.0 h1:QK40JKJyMdUDz+h+xvCsru/bJhvG0UxvePV0ufL/AcE= +github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/zapr v0.1.0/go.mod h1:tabnROwaDl0UNxkVeFRbY8bwB37GwRv0P8lg6aAiEnk= -github.com/go-logr/zapr v0.4.0 h1:uc1uML3hRYL9/ZZPdgHS/n8Nzo+eaYL/Efxkkamf7OM= -github.com/go-logr/zapr v0.4.0/go.mod h1:tabnROwaDl0UNxkVeFRbY8bwB37GwRv0P8lg6aAiEnk= +github.com/go-logr/zapr v1.2.0 h1:n4JnPI1T3Qq1SFEi/F8rwLrZERp2bso19PJZDB9dayk= +github.com/go-logr/zapr v1.2.0/go.mod h1:Qa4Bsj2Vb+FAVeAKsLD8RLQ+YRJB8YDmOAKxaBQf7Ro= github.com/go-openapi/analysis v0.0.0-20180825180245-b006789cd277/go.mod h1:k70tL6pCuVxPJOHXQ+wIac1FUrvNkHolPie/cLEU6hI= github.com/go-openapi/analysis v0.17.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= github.com/go-openapi/analysis v0.18.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= @@ -273,14 +326,16 @@ github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+ github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= github.com/go-openapi/jsonpointer v0.18.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= -github.com/go-openapi/jsonpointer v0.19.3 h1:gihV7YNZK1iK6Tgwwsxo2rJbD1GTbdm72325Bq8FI3w= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= +github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= github.com/go-openapi/jsonreference v0.18.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= -github.com/go-openapi/jsonreference v0.19.3 h1:5cxNfTy0UVC3X8JL5ymxzyoUZmo8iZb+jeTWn7tUa8o= github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= +github.com/go-openapi/jsonreference v0.19.5 h1:1WJP/wi4OjB4iV8KVbH73rQaoialJrqv8gitZLxGLtM= +github.com/go-openapi/jsonreference v0.19.5/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg= github.com/go-openapi/loads v0.17.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= github.com/go-openapi/loads v0.18.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= github.com/go-openapi/loads v0.19.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= @@ -294,50 +349,50 @@ github.com/go-openapi/spec v0.17.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsd github.com/go-openapi/spec v0.18.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= github.com/go-openapi/spec v0.19.2/go.mod h1:sCxk3jxKgioEJikev4fgkNmwS+3kuYdJtcsZsD5zxMY= github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= -github.com/go-openapi/spec v0.19.5 h1:Xm0Ao53uqnk9QE/LlYV5DEU09UAgpliA85QoT9LzqPw= -github.com/go-openapi/spec v0.19.5/go.mod h1:Hm2Jr4jv8G1ciIAo+frC/Ft+rR2kQDh8JHKHb3gWUSk= github.com/go-openapi/strfmt v0.17.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= github.com/go-openapi/strfmt v0.18.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= github.com/go-openapi/strfmt v0.19.0/go.mod h1:+uW+93UVvGGq2qGaZxdDeJqSAqBqBdl+ZPMF/cC8nDY= github.com/go-openapi/strfmt v0.19.3/go.mod h1:0yX7dbo8mKIvc3XSKp7MNfxw4JytCfCD6+bY1AVL9LU= -github.com/go-openapi/strfmt v0.19.5/go.mod h1:eftuHTlB/dI8Uq8JJOyRlieZf+WkkxUuk0dgdHXr2Qk= github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= github.com/go-openapi/swag v0.18.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= -github.com/go-openapi/swag v0.19.5 h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tFY= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.14 h1:gm3vOOXfiuw5i9p5N9xJvfjvuofpyvLA9Wr6QfK5Fng= +github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= github.com/go-openapi/validate v0.18.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4= github.com/go-openapi/validate v0.19.2/go.mod h1:1tRCw7m3jtI8eNWEEliiAqUIcBztB2KDnRCRMUi7GTA= github.com/go-openapi/validate v0.19.5/go.mod h1:8DJv2CVJQ6kGNpFW6eV9N3JviE1C85nY1c2z52x1Gk4= -github.com/go-openapi/validate v0.19.8/go.mod h1:8DJv2CVJQ6kGNpFW6eV9N3JviE1C85nY1c2z52x1Gk4= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/gobuffalo/flect v0.2.0/go.mod h1:W3K3X9ksuZfir8f/LrfVtWmCDQFfayuylOJ7sz/Fj80= -github.com/gobuffalo/here v0.6.0/go.mod h1:wAG085dHOYqUpf+Ap+WOdrPTp5IYcDAs/x7PLa8Y5fM= github.com/godbus/dbus v0.0.0-20180201030542-885f9cc04c9c/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw= github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -346,6 +401,7 @@ github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= @@ -355,6 +411,7 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= @@ -363,13 +420,20 @@ github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Z github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4= github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= +github.com/google/cel-go v0.9.0/go.mod h1:U7ayypeSkw23szu4GaQTPJGx66c20mx8JklMSxrmI1w= +github.com/google/cel-go v0.10.1/go.mod h1:U7ayypeSkw23szu4GaQTPJGx66c20mx8JklMSxrmI1w= +github.com/google/cel-spec v0.6.0/go.mod h1:Nwjgxy5CbjlPrtCWjeDjUyKMl8w41YBYGjsyDdqk0xA= +github.com/google/gnostic v0.5.7-v3refs h1:FhTMOKj2VhjpouxvWJAV1TL304uMlb9zcDqkl6cEI54= +github.com/google/gnostic v0.5.7-v3refs/go.mod h1:73MKFl6jIHelAJNaBGFzt3SPtZULs9dYrGFt8OiIsHQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= @@ -377,11 +441,19 @@ github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/ github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -394,23 +466,26 @@ github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsC github.com/googleapis/gnostic v0.1.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= github.com/googleapis/gnostic v0.2.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= github.com/googleapis/gnostic v0.3.1/go.mod h1:on+2t9HRStVgn95RSsFWFz+6Q0Snyqv1awfrALZdbtU= -github.com/googleapis/gnostic v0.4.1 h1:DLJCy1n/vrD4HPjOvYcT8aYQXpPIzoRZONaYwyycI+I= github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= +github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU= github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= -github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4 h1:z53tR0945TRRQO/fLEVPI6SMv7ZflF0TEaTAoU7tOzg= github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 h1:+9834+KizmvFV7pXQGSXQTsaWhq2GjuNUt0aUU0YBYw= +github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= -github.com/grpc-ecosystem/grpc-gateway v1.9.5 h1:UImYN5qQ8tuGpGE16ZmjvcTtTw24zw1QAp/SlnNrZhI= github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= @@ -444,6 +519,7 @@ github.com/hashicorp/memberlist v0.2.4/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOn github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.9/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= @@ -454,8 +530,11 @@ github.com/j-keck/arping v0.0.0-20160618110441-2cf9dc699c56/go.mod h1:ymszkNOg6t github.com/jcmturner/gofork v1.0.0/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks= -github.com/jonboulle/clockwork v0.1.0 h1:VKV+ZcuP6l3yW9doeqz6ziZGgcynBVQO+obU0+0hcPo= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/jonboulle/clockwork v0.2.2 h1:UOGuzwb1PwsrDAObMuhUnj0p5ULPj8V/xJ7Kx9qUBdQ= +github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= +github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/josharian/native v0.0.0-20200817173448-b6b71def0850 h1:uhL5Gw7BINiiPAo24A2sxkcDI0Jt/sqp1v5xQCniEFA= github.com/josharian/native v0.0.0-20200817173448-b6b71def0850/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= @@ -471,8 +550,9 @@ github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCV github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.11 h1:uVUAXhF2To8cbw/3xN3pxj6kk7TYKs98NIrTqPlMWAQ= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= @@ -507,14 +587,15 @@ github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9 github.com/lithammer/dedent v1.1.0/go.mod h1:jrXYCQtgg0nJiN+StA2KgR7w6CiQNv9Fd/Z9BP0jIOc= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.7.0 h1:aizVhC/NAAcKWb+5QsU1iNOZb4Yws5UO2I+aIprQITM= github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= -github.com/markbates/pkger v0.17.1/go.mod h1:0JoVlrol20BSywW79rN3kdFFsE5xYM+rSCQDXbLhiuI= +github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA= +github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8= @@ -574,15 +655,19 @@ github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS4 github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8= github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= github.com/moby/term v0.0.0-20201216013528-df9cb8a40635/go.mod h1:FBS0z0QWA44HXygs7VXDUOGoN/1TV3RuWkLO04am3wc= +github.com/moby/term v0.0.0-20210610120745-9d4ed1856297/go.mod h1:vgPCkQMyxTZ7IDy8SXRufE172gr8+K/JE/7hHFxHW3A= +github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6/go.mod h1:E2VnQOmVuvZB6UYnnDB0qG5Nq/1tD9acaOpo6xmt0Kw= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4= github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= @@ -605,27 +690,29 @@ github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= -github.com/onsi/ginkgo v1.16.2/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvwxz1E= -github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= +github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= +github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= github.com/onsi/gomega v0.0.0-20151007035656-2152b45fa28a/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.8.1/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.13.0 h1:7lLHu94wT9Ij0o6EWWclhu0aOh32VxhkwEJvzuWPeak= -github.com/onsi/gomega v1.13.0/go.mod h1:lRk9szgn8TxENtWd0Tp4c3wjlRfMTMH27I+3Je41yGY= +github.com/onsi/gomega v1.17.0 h1:9Luw4uT5HTjHTN8+aNcSThgH1vdXnmdJ8xIfZ4wyTRE= +github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/runc v0.0.0-20190115041553-12f6a991201f/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c h1:Lgl0gzECD8GnQ5QCWA8o6BtfL6mDH5rQgM4/fX3avOs= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE= +github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pierrec/lz4 v2.5.2+incompatible h1:WCjObylUIOlKy/+7Abdn34TLIkXiA4UWUMhxq9m9ZXI= @@ -652,8 +739,9 @@ github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXP github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= -github.com/prometheus/client_golang v1.11.0 h1:HNkLOAEQMIDv/K+04rukrLx6ch7msSRwf3/SASFAGtQ= github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= +github.com/prometheus/client_golang v1.12.1 h1:ZiaPsmm9uiBeaSMRznKsCDNtPCS0T3JVDGF+06gjBzk= +github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= @@ -663,8 +751,10 @@ github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7q github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= -github.com/prometheus/common v0.26.0 h1:iMAkS2TDoNWnKM+Kopnx/8tnEStIfpYA0ur0xQzzhMQ= github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= +github.com/prometheus/common v0.28.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= +github.com/prometheus/common v0.32.1 h1:hWIdL3N2HoUx3B8j3YN9mWor0qhY/NlEKZEaXxuIRh4= +github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= @@ -672,14 +762,16 @@ github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsT github.com/prometheus/procfs v0.0.11/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= -github.com/prometheus/procfs v0.6.0 h1:mxy4L2jP6qMonqmq+aTtOx1ifVWUgG/TAmntgbh3xv4= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU= +github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= @@ -705,8 +797,9 @@ github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= -github.com/soheilhy/cmux v0.1.4 h1:0HKaf1o97UwFjHH9o5XsHUOF+tqmdA7KEzXLpiyaw0E= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/soheilhy/cmux v0.1.5 h1:jjzc5WVemNEDTLwv9tlmemhC73tI08BNOIGwBOo10Js= +github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= @@ -714,13 +807,17 @@ github.com/spf13/afero v1.4.1/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z github.com/spf13/afero v1.6.0 h1:xoax2sJ2DT8S8xA2paPFjDCScCNeWsg75VG0DLRreiY= github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI= +github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo= +github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk= github.com/spf13/cobra v1.4.0 h1:y+wJpx64xcgO1V+RcnwW0LEHxTKRi2ZDPSBjWnrg88Q= github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= @@ -729,6 +826,8 @@ github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= +github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns= +github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= github.com/streamrail/concurrent-map v0.0.0-20160803124810-238fe79560e1/go.mod h1:yqDD2twFAqxvvH5gtpwwgLsj5L1kbNwtoPoDOwBzXcs= github.com/streamrail/concurrent-map v0.0.0-20160823150647-8bf1e9bacbf6 h1:XklXvOrWxWCDX2n4vdEQWkjuIP820XD6C4kF0O0FzH4= github.com/streamrail/concurrent-map v0.0.0-20160823150647-8bf1e9bacbf6/go.mod h1:yqDD2twFAqxvvH5gtpwwgLsj5L1kbNwtoPoDOwBzXcs= @@ -740,8 +839,9 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/ti-mo/conntrack v0.4.0 h1:6TZXNqhsJmeBl1Pyzg43Y0V1Nx8jyZ4dpOtItCVXE+8= github.com/ti-mo/conntrack v0.4.0/go.mod h1:L0vkIzG/TECsuVYMMlID9QWmZQLjyP9gDq8XKTlbg4Q= @@ -749,8 +849,9 @@ github.com/ti-mo/netfilter v0.3.1 h1:+ZTmeTx+64Jw2N/1gmqm42kruDWjQ90SMjWEB1e6VDs github.com/ti-mo/netfilter v0.3.1/go.mod h1:t/5HvCCHA1LAYj/AZF2fWcJ23BQTA7lzTPCuwwi7xQY= github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5 h1:LnC5Kc/wtumK+WB441p7ynQJzVuNRJiqddSIE3IlSEQ= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802 h1:uruHq4dN7GR16kFc5fp3d1RIYzJW5onx8Ybykw2YQFA= +github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= @@ -773,39 +874,90 @@ github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5 github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= gitlab.com/golang-commonmark/puny v0.0.0-20191124015043-9f83538fa04f h1:Wku8eEdeJqIOFHtrfkYUByc4bCaTeA6fL0UJgfEiFMI= gitlab.com/golang-commonmark/puny v0.0.0-20191124015043-9f83538fa04f/go.mod h1:Tiuhl+njh/JIg0uS/sOJVYi0x2HEa5rc1OAaVsb5tAs= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= -go.etcd.io/bbolt v1.3.5 h1:XAzx9gjCb0Rxj7EoqcClPD1d5ZBxZJk0jbuoPHenBt0= -go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= +go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU= +go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4= +go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738 h1:VcrIfasaLFkyjk6KNlXQSzO+B0fZcnECiDrKJsfxka0= go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= -go.etcd.io/etcd v0.5.0-alpha.5.0.20200910180754-dd1b699fc489 h1:1JFLBqwIgdyHN1ZtgjTBwO+blA6gVOmZurpiMEsETKo= -go.etcd.io/etcd v0.5.0-alpha.5.0.20200910180754-dd1b699fc489/go.mod h1:yVHk9ub3CSBatqGNg7GRmsnfLWtoW60w4eDYfh7vHDg= +go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= +go.etcd.io/etcd/api/v3 v3.5.1 h1:v28cktvBq+7vGyJXF8G+rWJmj+1XUmMtqcLnH8hDocM= +go.etcd.io/etcd/api/v3 v3.5.1/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= +go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= +go.etcd.io/etcd/client/pkg/v3 v3.5.1 h1:XIQcHCFSG53bJETYeRJtIxdLv2EWRGxcfzR8lSnTH4E= +go.etcd.io/etcd/client/pkg/v3 v3.5.1/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= +go.etcd.io/etcd/client/v2 v2.305.0 h1:ftQ0nOOHMcbMS3KIaDQ0g5Qcd6bhaBrQT6b89DfwLTs= +go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ= +go.etcd.io/etcd/client/v3 v3.5.0/go.mod h1:AIKXXVX/DQXtfTEqBryiLTUXwON+GuvO6Z7lLS/oTh0= +go.etcd.io/etcd/client/v3 v3.5.1 h1:oImGuV5LGKjCqXdjkMHCyWa5OO1gYKCnC/1sgdfj1Uk= +go.etcd.io/etcd/client/v3 v3.5.1/go.mod h1:OnjH4M8OnAotwaB2l9bVgZzRFKru7/ZMoS46OtKyd3Q= +go.etcd.io/etcd/pkg/v3 v3.5.0 h1:ntrg6vvKRW26JRmHTE0iNlDgYK6JX3hg/4cD62X0ixk= +go.etcd.io/etcd/pkg/v3 v3.5.0/go.mod h1:UzJGatBQ1lXChBkQF0AuAtkRQMYnHubxAEYIrC3MSsE= +go.etcd.io/etcd/raft/v3 v3.5.0 h1:kw2TmO3yFTgE+F0mdKkG7xMxkit2duBDa2Hu6D/HMlw= +go.etcd.io/etcd/raft/v3 v3.5.0/go.mod h1:UFOHSIvO/nKwd4lhkwabrTD3cqW5yVyYYf/KlD00Szc= +go.etcd.io/etcd/server/v3 v3.5.0 h1:jk8D/lwGEDlQU9kZXUFMSANkE22Sg5+mW27ip8xcF9E= +go.etcd.io/etcd/server/v3 v3.5.0/go.mod h1:3Ah5ruV+M+7RZr0+Y/5mNLwC+eQlni+mQmOVdCRJoS4= go.mongodb.org/mongo-driver v1.0.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= go.mongodb.org/mongo-driver v1.1.1/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= go.mongodb.org/mongo-driver v1.1.2/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.3 h1:8sGtKOrtQqkN1bp2AtX+misvLIlOmsEsNd+9NIcPEm8= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= +go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M= +go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= +go.opentelemetry.io/contrib v0.20.0 h1:ubFQUn0VCZ0gPwIoJfBJVpeBlyRMxu8Mm/huKWYd9p0= +go.opentelemetry.io/contrib v0.20.0/go.mod h1:G/EtFaa6qaN7+LxqfIAT3GiZa7Wv5DTBUzl5H4LY0Kc= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.20.0 h1:sO4WKdPAudZGKPcpZT4MJn6JaDmpyLrMPDGGyA1SttE= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.20.0/go.mod h1:oVGt1LRbBOBq1A5BQLlUg9UaU/54aiHw8cgjV3aWZ/E= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.20.0 h1:Q3C9yzW6I9jqEc8sawxzxZmY48fs9u220KXq6d5s3XU= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.20.0/go.mod h1:2AboqHi0CiIZU0qwhtUfCYD1GeUzvvIXWNkhDt7ZMG4= +go.opentelemetry.io/otel v0.20.0 h1:eaP0Fqu7SXHwvjiqDq83zImeehOHX8doTvU9AwXON8g= +go.opentelemetry.io/otel v0.20.0/go.mod h1:Y3ugLH2oa81t5QO+Lty+zXf8zC9L26ax4Nzoxm/dooo= +go.opentelemetry.io/otel/exporters/otlp v0.20.0 h1:PTNgq9MRmQqqJY0REVbZFvwkYOA85vbdQU/nVfxDyqg= +go.opentelemetry.io/otel/exporters/otlp v0.20.0/go.mod h1:YIieizyaN77rtLJra0buKiNBOm9XQfkPEKBeuhoMwAM= +go.opentelemetry.io/otel/metric v0.20.0 h1:4kzhXFP+btKm4jwxpjIqjs41A7MakRFUS86bqLHTIw8= +go.opentelemetry.io/otel/metric v0.20.0/go.mod h1:598I5tYlH1vzBjn+BTuhzTCSb/9debfNp6R3s7Pr1eU= +go.opentelemetry.io/otel/oteltest v0.20.0 h1:HiITxCawalo5vQzdHfKeZurV8x7ljcqAgiWzF6Vaeaw= +go.opentelemetry.io/otel/oteltest v0.20.0/go.mod h1:L7bgKf9ZB7qCwT9Up7i9/pn0PWIa9FqQ2IQ8LoxiGnw= +go.opentelemetry.io/otel/sdk v0.20.0 h1:JsxtGXd06J8jrnya7fdI/U/MR6yXA5DtbZy+qoHQlr8= +go.opentelemetry.io/otel/sdk v0.20.0/go.mod h1:g/IcepuwNsoiX5Byy2nNV0ySUF1em498m7hBWC279Yc= +go.opentelemetry.io/otel/sdk/export/metric v0.20.0 h1:c5VRjxCXdQlx1HjzwGdQHzZaVI82b5EbBgOu2ljD92g= +go.opentelemetry.io/otel/sdk/export/metric v0.20.0/go.mod h1:h7RBNMsDJ5pmI1zExLi+bJK+Dr8NQCh0qGhm1KDnNlE= +go.opentelemetry.io/otel/sdk/metric v0.20.0 h1:7ao1wpzHRVKf0OQ7GIxiQJA6X7DLX9o14gmVon7mMK8= +go.opentelemetry.io/otel/sdk/metric v0.20.0/go.mod h1:knxiS8Xd4E/N+ZqKmUPf3gTTZ4/0TjTXukfxjzSTpHE= +go.opentelemetry.io/otel/trace v0.20.0 h1:1DL6EXUdcg95gukhuRRvLDO/4X5THh/5dIV52lqtnbw= +go.opentelemetry.io/otel/trace v0.20.0/go.mod h1:6GjCW8zgDjwGHGa6GkyeB8+/5vjT16gUEi0Nf1iBdgw= +go.opentelemetry.io/proto/otlp v0.7.0 h1:rwOQPCuKAKmwGKq2aVNnYIibI6wnV7EvzgfTCzcdGg8= +go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5/go.mod h1:nmDLcffg48OtT/PSW0Hg7FvpRQsQh5OSqIylirxKC7o= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/goleak v1.1.10 h1:z+mqJhf6ss6BSfSM671tgKyZBFPTTJM+HLxnhPC3wu0= go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= +go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= +go.uber.org/goleak v1.1.12 h1:gZAh5/EyT/HQwlpkCy6wTpqfH9H8Lz8zbm3dZh+OyzA= +go.uber.org/goleak v1.1.12/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -go.uber.org/zap v1.17.0 h1:MTjgFu6ZLKvY6Pvaqk97GlxNBuMpV4Hy/3P6tRGlI2U= go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= +go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= +go.uber.org/zap v1.19.1 h1:ue41HOKd1vGURxrmeKIgELGb3jPW9DMUDGtsinblHwI= +go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181009213950-7c1a557ab941/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -825,8 +977,11 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= -golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e h1:8foAy0aoO5GkqCvAEJ4VC4P3zksTg4X4aJCDpZzmgQI= golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= +golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20220214200702-86341886e292 h1:f+lwQ+GtmgoY+A2YaQxlSOnDjXcQ7ZRLWOHbC6HtRqE= +golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -849,8 +1004,9 @@ golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20200302205851-738671d3881b h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= @@ -859,9 +1015,11 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.3.1-0.20200828183125-ce943fd02449/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= +golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 h1:kQgndtyPBW/JIYERgdxfwMYh3AVStj88WQTlNDi2a+o= +golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -885,6 +1043,7 @@ golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -898,30 +1057,56 @@ golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200904194848-62affa334b73/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201016165138-7b1cca2348c0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20201216054612-986b41b23924/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210224082022-3d97a244fca7/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= -golang.org/x/net v0.0.0-20210504132125-bbd867fde50d h1:nTDGCTeAu2LhcsHTRzjyIUbZHCJ4QePArsm27Hka0UM= golang.org/x/net v0.0.0-20210504132125-bbd867fde50d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210825183410-e898025ed96a/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd h1:O7DYs+zxREGLKzKoMQrtrEacpb0ZVXA5rIwylE2Xchk= +golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d h1:TzXSXBo42m9gQenoE3b9BGiEpg5IG2JkU5FkPIawgtw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 h1:RerP+noqYHUQ8CMRcPlC2nvTa4dcBIjegkuWdcUDuqg= +golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -929,6 +1114,7 @@ golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= @@ -986,39 +1172,63 @@ golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200602100848-8d3cce7afc34/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200831180312-196b9ba8737a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201017003518-b09fb700fbb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201118182958-a01c418693c7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201218084310-7d0127a74742/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210110051926-789bb1bd4061/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210123111255-9b0068b26619/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210216163648-f7da38b97c65/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210309040221-94ec62e08169/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210503173754-0981d6026fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40 h1:JWgyZ1qgdTaF3N3oxC+MdTV7qvEEgHo3otj+HB5CM7Q= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211029165221-6e7872819dc8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220209214540-3681064d5158 h1:rm+CHSpPEEW2IsXUib1ThaHIjuBVZjxNgSKmBLFfD4c= +golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d h1:SZxvLBoTP5yHO3Frd4z4vrF+DBX9vMVanchswa69toE= golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1026,15 +1236,18 @@ golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3 golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20210611083556-38a9dc6acbc6 h1:Vv0JUPWTyeqUq42B2WJ1FeIDjjvGKoA2Ss+Ts0lAVbs= -golang.org/x/time v0.0.0-20210611083556-38a9dc6acbc6/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 h1:vVKdlvoWBphwdxWKrFZEuM0kGgGLxUOYcY4U/2Vjg44= +golang.org/x/time v0.0.0-20220210224613-90d013bbcef8/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -1077,14 +1290,32 @@ golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapK golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= +golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= -golang.org/x/tools v0.1.1 h1:wGiQel/hW0NnEkJUk8lbzkX2gFJU6PFxf1v5OlCfuOs= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.6-0.20210820212750-d4cc65f0b2ff/go.mod h1:YD9qOF0M9xpSpdWTBbzEl5e/RnCefISl8E5Noe10jFM= +golang.org/x/tools v0.1.10-0.20220218145154-897bd77cd717/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -1106,12 +1337,25 @@ google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsb google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= +google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= +google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= +google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= +google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= +google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= +google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= +google.golang.org/api v0.44.0/go.mod h1:EBOGZqzyhtvMDoxwS97ctnh0zUmYY6CxqXsc1AvkYD8= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= @@ -1131,20 +1375,61 @@ google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvx google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a h1:pOwg4OoaRYScjmR4LlLgdtnyoHYTSAVhhqe5uPdpII8= -google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201102152239-715cce707fb0/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= +google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20220107163113-42d7afdf6368 h1:Et6SkiuvnBn+SgrSYXs/BrUpGB4mbdwt4R3vaPIlicA= +google.golang.org/genproto v0.0.0-20220107163113-42d7afdf6368/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.1 h1:zvIju4sqAGvwKspUQOhwnpcqSbzi7/H6QomNNjTL4sk= google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= +google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= +google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.40.0 h1:AGJ0Ih4mHjSeibYkFGh1dD9KJ/eOtZ93I6hoHhukQ5Q= +google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -1174,6 +1459,7 @@ gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKW gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/jcmturner/aescts.v1 v1.0.1/go.mod h1:nsR8qBOg+OucoIW+WMhB3GspUQXq9XorLnQb9XtvcOo= gopkg.in/jcmturner/dnsutils.v1 v1.0.1/go.mod h1:m3v+5svpVOhtFAP/wSz+yzh4Mc0Fg7eRhxkJMWSIz9Q= gopkg.in/jcmturner/goidentity.v3 v3.0.0/go.mod h1:oG2kH0IvSYNIu80dVAyu/yoefjq1mNfM5bm88whjWx4= @@ -1188,6 +1474,7 @@ gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWD gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -1210,97 +1497,114 @@ honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= k8s.io/api v0.18.2/go.mod h1:SJCWI7OLzhZSvbY7U8zwNl9UA4o1fizoug34OV/2r78= k8s.io/api v0.18.3/go.mod h1:UOaMwERbqJMfeeeHc8XJKawj4P9TgDRnViIqqBeH2QA= k8s.io/api v0.18.4/go.mod h1:lOIQAKYgai1+vz9J7YcDZwC26Z0zQewYOGWdyIPUUQ4= k8s.io/api v0.21.0/go.mod h1:+YbrhBBGgsxbF6o6Kj4KJPJnBmAKuXDeS3E18bgHNVU= -k8s.io/api v0.21.2 h1:vz7DqmRsXTCSa6pNxXwQ1IYeAZgdIsua+DZU+o+SX3Y= -k8s.io/api v0.21.2/go.mod h1:Lv6UGJZ1rlMI1qusN8ruAp9PUBFyBwpEHAdG24vIsiU= +k8s.io/api v0.23.5/go.mod h1:Na4XuKng8PXJ2JsploYYrivXrINeTaycCGcYgF91Xm8= +k8s.io/api v0.24.0 h1:J0hann2hfxWr1hinZIDefw7Q96wmCBx6SSB8IY0MdDg= +k8s.io/api v0.24.0/go.mod h1:5Jl90IUrJHUJYEMANRURMiVvJ0g7Ax7r3R1bqO8zx8I= k8s.io/apiextensions-apiserver v0.18.2/go.mod h1:q3faSnRGmYimiocj6cHQ1I3WpLqmDgJFlKL37fC4ZvY= k8s.io/apiextensions-apiserver v0.18.4/go.mod h1:NYeyeYq4SIpFlPxSAB6jHPIdvu3hL0pc36wuRChybio= -k8s.io/apiextensions-apiserver v0.21.2 h1:+exKMRep4pDrphEafRvpEi79wTnCFMqKf8LBtlA3yrE= -k8s.io/apiextensions-apiserver v0.21.2/go.mod h1:+Axoz5/l3AYpGLlhJDfcVQzCerVYq3K3CvDMvw6X1RA= +k8s.io/apiextensions-apiserver v0.23.5/go.mod h1:ntcPWNXS8ZPKN+zTXuzYMeg731CP0heCTl6gYBxLcuQ= +k8s.io/apiextensions-apiserver v0.24.0 h1:JfgFqbA8gKJ/uDT++feAqk9jBIwNnL9YGdQvaI9DLtY= +k8s.io/apiextensions-apiserver v0.24.0/go.mod h1:iuVe4aEpe6827lvO6yWQVxiPSpPoSKVjkq+MIdg84cM= k8s.io/apimachinery v0.18.2/go.mod h1:9SnR/e11v5IbyPCGbvJViimtJ0SwHG4nfZFjU77ftcA= k8s.io/apimachinery v0.18.3/go.mod h1:OaXp26zu/5J7p0f92ASynJa1pZo06YlV9fG7BoWbCko= k8s.io/apimachinery v0.18.4/go.mod h1:OaXp26zu/5J7p0f92ASynJa1pZo06YlV9fG7BoWbCko= k8s.io/apimachinery v0.21.0/go.mod h1:jbreFvJo3ov9rj7eWT7+sYiRx+qZuCYXwWT1bcDswPY= -k8s.io/apimachinery v0.21.2 h1:vezUc/BHqWlQDnZ+XkrpXSmnANSLbpnlpwo0Lhk0gpc= -k8s.io/apimachinery v0.21.2/go.mod h1:CdTY8fU/BlvAbJ2z/8kBwimGki5Zp8/fbVuLY8gJumM= +k8s.io/apimachinery v0.23.5/go.mod h1:BEuFMMBaIbcOqVIJqNZJXGFTP4W6AycEpb5+m/97hrM= +k8s.io/apimachinery v0.24.0 h1:ydFCyC/DjCvFCHK5OPMKBlxayQytB8pxy8YQInd5UyQ= +k8s.io/apimachinery v0.24.0/go.mod h1:82Bi4sCzVBdpYjyI4jY6aHX+YCUchUIrZrXKedjd2UM= k8s.io/apiserver v0.18.2/go.mod h1:Xbh066NqrZO8cbsoenCwyDJ1OSi8Ag8I2lezeHxzwzw= k8s.io/apiserver v0.18.4/go.mod h1:q+zoFct5ABNnYkGIaGQ3bcbUNdmPyOCoEBcg51LChY8= -k8s.io/apiserver v0.21.0/go.mod h1:w2YSn4/WIwYuxG5zJmcqtRdtqgW/J2JRgFAqps3bBpg= -k8s.io/apiserver v0.21.2 h1:vfGLD8biFXHzbcIEXyW3652lDwkV8tZEFJAaS2iuJlw= -k8s.io/apiserver v0.21.2/go.mod h1:lN4yBoGyiNT7SC1dmNk0ue6a5Wi6O3SWOIw91TsucQw= -k8s.io/cli-runtime v0.21.0/go.mod h1:XoaHP93mGPF37MkLbjGVYqg3S1MnsFdKtiA/RZzzxOo= +k8s.io/apiserver v0.23.5/go.mod h1:7wvMtGJ42VRxzgVI7jkbKvMbuCbVbgsWFT7RyXiRNTw= +k8s.io/apiserver v0.24.0 h1:GR7kGsjOMfilRvlG3Stxv/3uz/ryvJ/aZXc5pqdsNV0= +k8s.io/apiserver v0.24.0/go.mod h1:WFx2yiOMawnogNToVvUYT9nn1jaIkMKj41ZYCVycsBA= +k8s.io/cli-runtime v0.24.0/go.mod h1:9XxoZDsEkRFUThnwqNviqzljtT/LdHtNWvcNFrAXl0A= k8s.io/client-go v0.18.2/go.mod h1:Xcm5wVGXX9HAA2JJ2sSBUn3tCJ+4SVlCbl2MNNv+CIU= k8s.io/client-go v0.18.3/go.mod h1:4a/dpQEvzAhT1BbuWW09qvIaGw6Gbu1gZYiQZIi1DMw= k8s.io/client-go v0.18.4/go.mod h1:f5sXwL4yAZRkAtzOxRWUhA/N8XzGCb+nPZI8PfobZ9g= k8s.io/client-go v0.21.0/go.mod h1:nNBytTF9qPFDEhoqgEPaarobC8QPae13bElIVHzIglA= -k8s.io/client-go v0.21.2 h1:Q1j4L/iMN4pTw6Y4DWppBoUxgKO8LbffEMVEV00MUp0= -k8s.io/client-go v0.21.2/go.mod h1:HdJ9iknWpbl3vMGtib6T2PyI/VYxiZfq936WNVHBRrA= +k8s.io/client-go v0.23.5/go.mod h1:flkeinTO1CirYgzMPRWxUCnV0G4Fbu2vLhYCObnt/r4= +k8s.io/client-go v0.24.0 h1:lbE4aB1gTHvYFSwm6eD3OF14NhFDKCejlnsGYlSJe5U= +k8s.io/client-go v0.24.0/go.mod h1:VFPQET+cAFpYxh6Bq6f4xyMY80G6jKKktU6G0m00VDw= k8s.io/code-generator v0.18.2/go.mod h1:+UHX5rSbxmR8kzS+FAv7um6dtYrZokQvjHpDSYRVkTc= k8s.io/code-generator v0.18.3/go.mod h1:TgNEVx9hCyPGpdtCWA34olQYLkh3ok9ar7XfSsr8b6c= k8s.io/code-generator v0.18.4/go.mod h1:TgNEVx9hCyPGpdtCWA34olQYLkh3ok9ar7XfSsr8b6c= -k8s.io/code-generator v0.21.0/go.mod h1:hUlps5+9QaTrKx+jiM4rmq7YmH8wPOIko64uZCHDh6Q= -k8s.io/code-generator v0.21.2/go.mod h1:8mXJDCB7HcRo1xiEQstcguZkbxZaqeUOrO9SsicWs3U= +k8s.io/code-generator v0.23.5/go.mod h1:S0Q1JVA+kSzTI1oUvbKAxZY/DYbA/ZUb4Uknog12ETk= +k8s.io/code-generator v0.24.0/go.mod h1:dpVhs00hTuTdTY6jvVxvTFCk6gSMrtfRydbhZwHI15w= k8s.io/component-base v0.18.2/go.mod h1:kqLlMuhJNHQ9lz8Z7V5bxUUtjFZnrypArGl58gmDfUM= k8s.io/component-base v0.18.4/go.mod h1:7jr/Ef5PGmKwQhyAz/pjByxJbC58mhKAhiaDu0vXfPk= k8s.io/component-base v0.21.0/go.mod h1:qvtjz6X0USWXbgmbfXR+Agik4RZ3jv2Bgr5QnZzdPYw= -k8s.io/component-base v0.21.2 h1:EsnmFFoJ86cEywC0DoIkAUiEV6fjgauNugiw1lmIjs4= -k8s.io/component-base v0.21.2/go.mod h1:9lvmIThzdlrJj5Hp8Z/TOgIkdfsNARQ1pT+3PByuiuc= -k8s.io/component-helpers v0.21.0/go.mod h1:tezqefP7lxfvJyR+0a+6QtVrkZ/wIkyMLK4WcQ3Cj8U= +k8s.io/component-base v0.23.5/go.mod h1:c5Nq44KZyt1aLl0IpHX82fhsn84Sb0jjzwjpcA42bY0= +k8s.io/component-base v0.24.0 h1:h5jieHZQoHrY/lHG+HyrSbJeyfuitheBvqvKwKHVC0g= +k8s.io/component-base v0.24.0/go.mod h1:Dgazgon0i7KYUsS8krG8muGiMVtUZxG037l1MKyXgrA= +k8s.io/component-helpers v0.24.0/go.mod h1:Q2SlLm4h6g6lPTC9GMMfzdywfLSvJT2f1hOnnjaWD8c= k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/gengo v0.0.0-20200114144118-36b2048a9120/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= -k8s.io/gengo v0.0.0-20201214224949-b6c5ce23f027/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= +k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= +k8s.io/gengo v0.0.0-20211129171323-c02415ce4185/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8= k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= -k8s.io/klog/v2 v2.8.0 h1:Q3gmuM9hKEjefWFFYF0Mat+YyFJvsUyYuwyNNJ5C9Ts= k8s.io/klog/v2 v2.8.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec= -k8s.io/kube-aggregator v0.21.0 h1:my2WYu8RJcj/ZzWAjPPnmxNRELk/iCdPjMaOmsZOeBU= -k8s.io/kube-aggregator v0.21.0/go.mod h1:sIaa9L4QCBo9gjPyoGJns4cBjYVLq3s49FxF7m/1A0A= +k8s.io/klog/v2 v2.30.0/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= +k8s.io/klog/v2 v2.60.1 h1:VW25q3bZx9uE3vvdL6M8ezOX79vA2Aq1nEWLqNQclHc= +k8s.io/klog/v2 v2.60.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= +k8s.io/kube-aggregator v0.24.0 h1:ax2B6v5y+sLISgal5COnlDRKOSr97uXpwif6nnK3a/M= +k8s.io/kube-aggregator v0.24.0/go.mod h1:ftfs6Fi46z3cKzeF2kvNBPLbMlSKuqZbesJGNp/cQnw= k8s.io/kube-openapi v0.0.0-20200121204235-bf4fb3bd569c/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E= k8s.io/kube-openapi v0.0.0-20200410145947-61e04a5be9a6/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E= k8s.io/kube-openapi v0.0.0-20210305001622-591a79e4bda7/go.mod h1:wXW5VT87nVfh/iLV8FpR2uDvrFyomxbtb1KivDbvPTE= -k8s.io/kube-openapi v0.0.0-20210305164622-f622666832c1 h1:bKbnE878105Y2291CtM1YO9XIQJe/QsG2SRx6vxQmDI= -k8s.io/kube-openapi v0.0.0-20210305164622-f622666832c1/go.mod h1:wXW5VT87nVfh/iLV8FpR2uDvrFyomxbtb1KivDbvPTE= -k8s.io/kubectl v0.21.0 h1:WZXlnG/yjcE4LWO2g6ULjFxtzK6H1TKzsfaBFuVIhNg= -k8s.io/kubectl v0.21.0/go.mod h1:EU37NukZRXn1TpAkMUoy8Z/B2u6wjHDS4aInsDzVvks= -k8s.io/kubelet v0.21.0 h1:1VUfM5vKqLPlWFI0zee6fm9kwIZ/UEOGCodVFN+OZrg= -k8s.io/kubelet v0.21.0/go.mod h1:G5ZxMTVev9t4bhmsSxDAWhH6wXDYEVHVVFyYsw4laR4= -k8s.io/metrics v0.21.0/go.mod h1:L3Ji9EGPP1YBbfm9sPfEXSpnj8i24bfQbAFAsW0NueQ= +k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw= +k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65/go.mod h1:sX9MT8g7NVZM5lVL/j8QyCCJe8YSMW30QvGZWaCIDIk= +k8s.io/kube-openapi v0.0.0-20220328201542-3ee0da9b0b42 h1:Gii5eqf+GmIEwGNKQYQClCayuJCe2/4fZUvF7VG99sU= +k8s.io/kube-openapi v0.0.0-20220328201542-3ee0da9b0b42/go.mod h1:Z/45zLw8lUo4wdiUkI+v/ImEGAvu3WatcZl3lPMR4Rk= +k8s.io/kubectl v0.24.0 h1:nA+WtMLVdXUs4wLogGd1mPTAesnLdBpCVgCmz3I7dXo= +k8s.io/kubectl v0.24.0/go.mod h1:pdXkmCyHiRTqjYfyUJiXtbVNURhv0/Q1TyRhy2d5ic0= +k8s.io/kubelet v0.24.0 h1:fH+D6mSr4DGIeHp/O2+mCEJhkVq3Gpgv9BVOHI+GrWY= +k8s.io/kubelet v0.24.0/go.mod h1:p3BBacmHTCMpUf+nluhlyzuGHmONKAspqCvpu9oPAyA= +k8s.io/metrics v0.24.0/go.mod h1:jrLlFGdKl3X+szubOXPG0Lf2aVxuV3QJcbsgVRAM6fI= k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= k8s.io/utils v0.0.0-20200603063816-c1c6865ac451/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= -k8s.io/utils v0.0.0-20210527160623-6fdb442a123b h1:MSqsVQ3pZvPGTqCjptfimO2WjG7A9un2zcpiHkA6M/s= -k8s.io/utils v0.0.0-20210527160623-6fdb442a123b/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/utils v0.0.0-20211116205334-6203023598ed/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9 h1:HNSDgDCrr/6Ly3WEGKZftiE7IY19Vz2GdbOCyI4qqhc= +k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.7/go.mod h1:PHgbrJT7lCHcxMU+mDHEm+nx46H4zuuHZkDP6icnhu0= -sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.15/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= -sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.19 h1:0jaDAAxtqIrrqas4vtTqxct4xS5kHfRNycTRLTyJmVM= -sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.19/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.30 h1:dUk62HQ3ZFhD48Qr8MIXCiKA8wInBQCtuE4QGfFW7yA= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.30/go.mod h1:fEO7lRTdivWO2qYVCVG7dEADOMo/MLDCVr8So2g88Uw= sigs.k8s.io/controller-runtime v0.6.1/go.mod h1:XRYBPdbf5XJu9kpS84VJiZ7h/u1hF3gEORz0efEja7A= -sigs.k8s.io/controller-runtime v0.9.1 h1:+LAqHAhkVW4lt/jLlrKmnGPA7OORMw/xEUH3Ey1h1Bs= -sigs.k8s.io/controller-runtime v0.9.1/go.mod h1:cTqsgnwSOsYS03XwySYZj8k6vf0+eC4FJRcCgQ9elb4= +sigs.k8s.io/controller-runtime v0.11.2 h1:H5GTxQl0Mc9UjRJhORusqfJCIjBO8UtUxGggCwL1rLA= +sigs.k8s.io/controller-runtime v0.11.2/go.mod h1:P6QCzrEjLaZGqHsfd+os7JQ+WFZhvB8MRFsn4dWF7O4= sigs.k8s.io/controller-tools v0.3.0/go.mod h1:enhtKGfxZD1GFEoMgP8Fdbu+uKQ/cq1/WGJhdVChfvI= +sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6/go.mod h1:p4QtZmO4uMYipTQNzagwnNoseA6OxSUutVw05NhYDRs= +sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2 h1:kDi4JBNAsJWfz1aEXhO8Jg87JJaPNLh5tIzYHgStQ9Y= +sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2/go.mod h1:B+TnT182UBxE84DiCz4CVE26eOSDAeYCpfDnC2kdKMY= sigs.k8s.io/kind v0.8.1/go.mod h1:oNKTxUVPYkV9lWzY6CVMNluVq8cBsyq+UgPJdvA3uu4= -sigs.k8s.io/kustomize/api v0.8.5/go.mod h1:M377apnKT5ZHJS++6H4rQoCHmWtt6qTpp3mbe7p6OLY= -sigs.k8s.io/kustomize/cmd/config v0.9.7/go.mod h1:MvXCpHs77cfyxRmCNUQjIqCmZyYsbn5PyQpWiq44nW0= -sigs.k8s.io/kustomize/kustomize/v4 v4.0.5/go.mod h1:C7rYla7sI8EnxHE/xEhRBSHMNfcL91fx0uKmUlUhrBk= -sigs.k8s.io/kustomize/kyaml v0.10.15/go.mod h1:mlQFagmkm1P+W4lZJbJ/yaxMd8PqMRSC4cPcfUVt5Hg= +sigs.k8s.io/kustomize/api v0.11.4/go.mod h1:k+8RsqYbgpkIrJ4p9jcdPqe8DprLxFUUO0yNOq8C+xI= +sigs.k8s.io/kustomize/cmd/config v0.10.6/go.mod h1:/S4A4nUANUa4bZJ/Edt7ZQTyKOY9WCER0uBS1SW2Rco= +sigs.k8s.io/kustomize/kustomize/v4 v4.5.4/go.mod h1:Zo/Xc5FKD6sHl0lilbrieeGeZHVYCA4BzxeAaLI05Bg= +sigs.k8s.io/kustomize/kyaml v0.13.6/go.mod h1:yHP031rn1QX1lr/Xd934Ri/xdVNG8BE2ECa78Ht/kEg= sigs.k8s.io/mcs-api v0.1.0 h1:edDbg0oRGfXw8TmZjKYep06LcJLv/qcYLidejnUp0PM= sigs.k8s.io/mcs-api v0.1.0/go.mod h1:gGiAryeFNB4GBsq2LBmVqSgKoobLxt+p7ii/WG5QYYw= sigs.k8s.io/structured-merge-diff/v3 v3.0.0-20200116222232-67a7b8c61874/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= sigs.k8s.io/structured-merge-diff/v3 v3.0.0/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= -sigs.k8s.io/structured-merge-diff/v4 v4.1.0 h1:C4r9BgJ98vrKnnVCjwCSXcWjWe0NKcUQkmzDXZXGwH8= sigs.k8s.io/structured-merge-diff/v4 v4.1.0/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/structured-merge-diff/v4 v4.2.1 h1:bKCqE9GvQ5tiVHn5rfn1r+yao3aLQEaLzkkmAkf+A6Y= +sigs.k8s.io/structured-merge-diff/v4 v4.2.1/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= -sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= +sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= +sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= diff --git a/.markdownlint-config.yml b/hack/.markdownlint-config.yml similarity index 100% rename from .markdownlint-config.yml rename to hack/.markdownlint-config.yml diff --git a/hack/.markdownlint-ignore b/hack/.markdownlint-ignore new file mode 100644 index 00000000000..724578f287c --- /dev/null +++ b/hack/.markdownlint-ignore @@ -0,0 +1,6 @@ +CHANGELOG/ +CHANGELOG.md +hack/netpol +CODE_OF_CONDUCT.md +# auto-generated file +build/charts/antrea/README.md diff --git a/hack/.md_links_config.json b/hack/.md_links_config.json index b3ddbb58aa8..0c6b1b8d37a 100644 --- a/hack/.md_links_config.json +++ b/hack/.md_links_config.json @@ -26,6 +26,9 @@ }, { "pattern": "https://www.virtualbox.org/*" + }, + { + "pattern": "https://avinetworks.com/*" } ], "retryOn429": false, diff --git a/hack/.notableofcontents b/hack/.notableofcontents index 6f9811354f2..720e2f957e8 100644 --- a/hack/.notableofcontents +++ b/hack/.notableofcontents @@ -9,7 +9,6 @@ docs/contributors/code-generation.md docs/contributors/docker-desktop-alternatives.md docs/contributors/eks-terraform.md docs/contributors/github-labels.md -docs/contributors/manual-installation.md docs/configuration.md docs/cookbooks/multus/README.md docs/cookbooks/multus/build/cni-dhcp-daemon/README.md diff --git a/hack/generate-manifest-flow-visibility.sh b/hack/generate-manifest-flow-visibility.sh index bcb11af965e..5dd22fa60ac 100755 --- a/hack/generate-manifest-flow-visibility.sh +++ b/hack/generate-manifest-flow-visibility.sh @@ -20,14 +20,29 @@ function echoerr { >&2 echo "$@" } -_usage="Usage: $0 [--mode (dev|release)] [--keep] [--help|-h] -Generate a YAML manifest for the Clickhouse-Grafana Flow-visibility Solution, using Kustomize, and +_usage="Usage: $0 [--mode (dev|release|e2e)] [--keep] [--help|-h] +Generate a YAML manifest for the ClickHouse-Grafana Flow-visibility Solution, using Kustomize, and print it to stdout. - --mode (dev|release) Choose the configuration variant that you need (default is 'dev') - --keep Debug flag which will preserve the generated kustomization.yml - + --mode (dev|release|e2e) Choose the configuration variant that you need (default is 'dev') + e2e mode generates YAML manifest for e2e test, which includes + ClickHouse operator and server with default credentials, + but not Grafana-related functionality and ClickHouse monitor. + --keep Debug flag which will preserve the generated kustomization.yml + --volume (ram|pv) Choose the volume provider that you need (default is 'ram'). + --storageclass -sc Provide the StorageClass used to dynamically provision the + PersistentVolume for ClickHouse storage. + --local Create the PersistentVolume for ClickHouse with a provided + local path. + --nfs Create the PersistentVolume for ClickHouse with a provided + NFS server hostname or IP address and the path exported in the + form of hostname:path. + --size Deploy the ClickHouse with a specific storage size. Can be a + plain integer or as a fixed-point number using one of these quantity + suffixes: E, P, T, G, M, K. Or the power-of-two equivalents: + Ei, Pi, Ti, Gi, Mi, Ki. The default is 8Gi. + --help, -h Print this message and exit This tool uses kustomize (https://github.com/kubernetes-sigs/kustomize) to generate manifests for -Clickhouse-Grafana Flow-visibility Solution. You can set the KUSTOMIZE environment variable to the +ClickHouse-Grafana Flow-visibility Solution. You can set the KUSTOMIZE environment variable to the path of the kustomize binary you want us to use. Otherwise we will look for kustomize in your PATH and your GOPATH. If we cannot find kustomize there, we will try to install it." @@ -41,11 +56,15 @@ function print_help { MODE="dev" KEEP=false +VOLUME="ram" +STORAGECLASS="" +LOCALPATH="" +NFSPATH="" +SIZE="8Gi" while [[ $# -gt 0 ]] do key="$1" - case $key in --mode) MODE="$2" @@ -55,6 +74,26 @@ case $key in KEEP=true shift ;; + --volume) + VOLUME="$2" + shift 2 + ;; + -sc|--storageclass) + STORAGECLASS="$2" + shift 2 + ;; + --local) + LOCALPATH="$2" + shift 2 + ;; + --nfs) + NFSPATH="$2" + shift 2 + ;; + --size) + SIZE="$2" + shift 2 + ;; -h|--help) print_usage exit 0 @@ -66,8 +105,8 @@ case $key in esac done -if [ "$MODE" != "dev" ] && [ "$MODE" != "release" ]; then - echoerr "--mode must be one of 'dev' or 'release'" +if [ "$MODE" != "dev" ] && [ "$MODE" != "release" ] && [ "$MODE" != "e2e" ]; then + echoerr "--mode must be one of 'dev', 'release' or 'e2e'" print_help exit 1 fi @@ -84,6 +123,33 @@ if [ "$MODE" == "release" ] && [ -z "$IMG_TAG" ]; then exit 1 fi +if [ "$VOLUME" != "ram" ] && [ "$VOLUME" != "pv" ]; then + echoerr "--volume must be one of 'ram' or 'pv'" + print_help + exit 1 +fi + +if [ "$VOLUME" == "pv" ] && [ "$LOCALPATH" == "" ] && [ "$NFSPATH" == "" ] && [ "$STORAGECLASS" == "" ]; then + echoerr "When deploying with 'pv', one of '--local', '--nfs', '--storageclass' should be set" + print_help + exit 1 +fi + +if ([ "$LOCALPATH" != "" ] && [ "$NFSPATH" != "" ]) || ([ "$LOCALPATH" != "" ] && [ "$STORAGECLASS" != "" ]) || ([ "$STORAGECLASS" != "" ] && [ "$NFSPATH" != "" ]); then + echoerr "Cannot set '--local', '--nfs' or '--storageclass' at the same time" + print_help + exit 1 +fi + +if [ "$NFSPATH" != "" ]; then + pathPair=(${NFSPATH//:/ }) + if [ ${#pathPair[@]} != 2 ]; then + echoerr "--nfs must be in the form of hostname:path" + print_help + exit 1 + fi +fi + THIS_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" source $THIS_DIR/verify-kustomize.sh @@ -106,10 +172,26 @@ BASE=../../base mkdir $MODE && cd $MODE touch kustomization.yml -$KUSTOMIZE edit add base $BASE # ../../patches/$MODE may be empty so we use find and not simply cp find ../../patches/$MODE -name \*.yml -exec cp {} . \; +if [ "$MODE" == "e2e" ]; then + mkdir -p base/provisioning/datasources + cp $KUSTOMIZATION_DIR/base/clickhouse.yml base/clickhouse.yml + cp $KUSTOMIZATION_DIR/base/kustomization-e2e.yml base/kustomization.yml + cp $KUSTOMIZATION_DIR/base/kustomize-config.yml base/kustomize-config.yml + cp $KUSTOMIZATION_DIR/base/provisioning/datasources/create_table.sh base/provisioning/datasources/create_table.sh + cp $KUSTOMIZATION_DIR/../clickhouse-operator-install-bundle.yml clickhouse-operator-install-bundle.yml + $KUSTOMIZE edit add base base + $KUSTOMIZE edit add patch --path imagePullPolicyClickhouse.yml --group clickhouse.altinity.com --version v1 --kind ClickHouseInstallation --name clickhouse +else + # patch the clickhouse monitor with desired storage size + cp $KUSTOMIZATION_DIR/patches/chmonitor/*.yml . + $KUSTOMIZE edit add base $BASE + sed -i.bak -E "s/STORAGE_SIZE_VALUE/$SIZE/" chMonitor.yml + $KUSTOMIZE edit add patch --path chMonitor.yml --group clickhouse.altinity.com --version v1 --kind ClickHouseInstallation --name clickhouse +fi + if [ "$MODE" == "dev" ]; then $KUSTOMIZE edit set image flow-visibility-clickhouse-monitor=projects.registry.vmware.com/antrea/flow-visibility-clickhouse-monitor:latest $KUSTOMIZE edit add patch --path imagePullPolicy.yml --group clickhouse.altinity.com --version v1 --kind ClickHouseInstallation --name clickhouse @@ -118,12 +200,48 @@ fi if [ "$MODE" == "release" ]; then $KUSTOMIZE edit set image flow-visibility-clickhouse-monitor=$IMG_NAME:$IMG_TAG fi +BASE=../$MODE +cd .. + +if [ "$VOLUME" == "ram" ]; then + mkdir ram && cd ram + cp $KUSTOMIZATION_DIR/patches/ram/*.yml . + touch kustomization.yml + $KUSTOMIZE edit add base $BASE + sed -i.bak -E "s/STORAGE_SIZE/$SIZE/" mountRam.yml + $KUSTOMIZE edit add patch --path mountRam.yml --group clickhouse.altinity.com --version v1 --kind ClickHouseInstallation --name clickhouse +fi + +if [ "$VOLUME" == "pv" ]; then + mkdir pv && cd pv + cp $KUSTOMIZATION_DIR/patches/pv/*.yml . + touch kustomization.yml + $KUSTOMIZE edit add base $BASE + + if [[ $STORAGECLASS != "" ]]; then + sed -i.bak -E "s/STORAGECLASS_NAME/$STORAGECLASS/" mountPv.yml + else + sed -i.bak -E "s/STORAGECLASS_NAME/clickhouse-storage/" mountPv.yml + fi + if [[ $LOCALPATH != "" ]]; then + sed -i.bak -E "s~LOCAL_PATH~$LOCALPATH~" createLocalPv.yml + sed -i.bak -E "s/STORAGE_SIZE/$SIZE/" createLocalPv.yml + $KUSTOMIZE edit add base createLocalPv.yml + fi + if [[ $NFSPATH != "" ]]; then + sed -i.bak -E "s~NFS_SERVER_ADDRESS~${pathPair[0]}~" createNfsPv.yml + sed -i.bak -E "s~NFS_SERVER_PATH~${pathPair[1]}~" createNfsPv.yml + sed -i.bak -E "s/STORAGE_SIZE/$SIZE/" createNfsPv.yml + $KUSTOMIZE edit add base createNfsPv.yml + fi + sed -i.bak -E "s/STORAGE_SIZE/$SIZE/" mountPv.yml + $KUSTOMIZE edit add patch --path mountPv.yml --group clickhouse.altinity.com --version v1 --kind ClickHouseInstallation --name clickhouse +fi $KUSTOMIZE build popd > /dev/null - if $KEEP; then echoerr "Kustomization file is at $TMP_DIR/$MODE/kustomization.yml" else diff --git a/hack/generate-manifest.sh b/hack/generate-manifest.sh index fcb427c5f64..a126c20ff3f 100755 --- a/hack/generate-manifest.sh +++ b/hack/generate-manifest.sh @@ -21,7 +21,7 @@ function echoerr { } _usage="Usage: $0 [--mode (dev|release)] [--encap-mode] [--ipsec] [--no-proxy] [--no-np] [--keep] [--tun (geneve|vxlan|gre|stt)] [--verbose-log] [--help|-h] -Generate a YAML manifest for Antrea using Kustomize and print it to stdout. +Generate a YAML manifest for Antrea using Helm and print it to stdout. --mode (dev|release) Choose the configuration variant that you need (default is 'dev') --encap-mode Traffic encapsulation mode. (default is 'encap') --cloud Generate a manifest appropriate for running Antrea in Public Cloud @@ -29,10 +29,9 @@ Generate a YAML manifest for Antrea using Kustomize and print it to stdout. --all-features Generate a manifest with all alpha features enabled --no-proxy Generate a manifest with Antrea proxy disabled --proxy-all Generate a manifest with Antrea proxy with all Service support enabled - --no-legacy-crd Generate a manifest without legacy CRD mirroring support enabled --endpointslice Generate a manifest with EndpointSlice support enabled + --flow-exporter Generate a manifest with FlowExporter support enabled --no-np Generate a manifest with Antrea-native policies disabled - --keep Debug flag which will preserve the generated kustomization.yml --tun (geneve|vxlan|gre|stt) Choose encap tunnel type from geneve, gre, stt and vxlan (default is geneve) --verbose-log Generate a manifest with increased log-level (level 4) for Antrea agent and controller. This option will work only in 'dev' mode. @@ -48,16 +47,16 @@ Generate a YAML manifest for Antrea using Kustomize and print it to stdout. --help, -h Print this message and exit --multicast Generates a manifest for multicast. --multicast-interfaces Multicast interface names (default is empty) + --extra-helm-values-file Optional extra helm values file to override the default config values In 'release' mode, environment variables IMG_NAME and IMG_TAG must be set. In 'dev' mode, environment variable IMG_NAME can be set to use a custom image. -This tool uses kustomize (https://github.com/kubernetes-sigs/kustomize) to generate manifests for -Antrea. You can set the KUSTOMIZE environment variable to the path of the kustomize binary you want -us to use. Otherwise we will download the appropriate version of the kustomize binary and use -it (this is the recommended approach since different versions of kustomize may create different -output YAMLs)." +This tool uses Helm 3 (https://helm.sh/) to generate manifests for Antrea. You can set the HELM +environment variable to the path of the helm binary you want us to use. Otherwise we will download +the appropriate version of the helm binary and use it (this is the recommended approach since +different versions of helm may create different output YAMLs)." function print_usage { echoerr "$_usage" @@ -72,8 +71,8 @@ IPSEC=false ALLFEATURES=false PROXY=true PROXY_ALL=false -LEGACY_CRD=true ENDPOINTSLICE=false +FLOW_EXPORTER=false NP=true KEEP=false ENCAP_MODE="" @@ -91,6 +90,7 @@ WHEREABOUTS=false FLEXIBLE_IPAM=false MULTICAST=false MULTICAST_INTERFACES="" +HELM_VALUES_FILES=() while [[ $# -gt 0 ]] do @@ -130,15 +130,15 @@ case $key in PROXY_ALL=true shift ;; - --no-legacy-crd) - LEGACY_CRD=false - shift - ;; --endpointslice) PROXY=true ENDPOINTSLICE=true shift ;; + --flow-exporter) + FLOW_EXPORTER=true + shift + ;; --no-np) NP=false shift @@ -201,6 +201,14 @@ case $key in MULTICAST_INTERFACES="$2" shift 2 ;; + --extra-helm-values-file) + if [[ ! -f "$2" ]]; then + echoerr "Helm values file $2 does not exist." + exit 1 + fi + HELM_VALUES_FILES=("$2") + shift 2 + ;; -h|--help) print_usage exit 0 @@ -277,264 +285,152 @@ fi THIS_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" -source $THIS_DIR/verify-kustomize.sh +source $THIS_DIR/verify-helm.sh -if [ -z "$KUSTOMIZE" ]; then - KUSTOMIZE="$(verify_kustomize)" -elif ! $KUSTOMIZE version > /dev/null 2>&1; then - echoerr "$KUSTOMIZE does not appear to be a valid kustomize binary" +if [ -z "$HELM" ]; then + HELM="$(verify_helm)" +elif ! $HELM version > /dev/null 2>&1; then + echoerr "$HELM does not appear to be a valid helm binary" print_help exit 1 fi -KUSTOMIZATION_DIR=$THIS_DIR/../build/yamls - -TMP_DIR=$(mktemp -d $KUSTOMIZATION_DIR/overlays.XXXXXXXX) - -pushd $TMP_DIR > /dev/null - -BASE=../../base - -# do all ConfigMap edits -mkdir configMap && cd configMap -# user is not expected to make changes directly to antrea-agent.conf and antrea-controller.conf, -# but instead to the generated YAML manifest, so our regexs need not be too robust. -cp $KUSTOMIZATION_DIR/base/conf/antrea-agent.conf antrea-agent.conf -cp $KUSTOMIZATION_DIR/base/conf/antrea-controller.conf antrea-controller.conf +TMP_DIR=$(mktemp -d $THIS_DIR/../build/yamls/chart-values.XXXXXXXX) +HELM_VALUES=() if $IPSEC; then - sed -i.bak -E "s/^[[:space:]]*#[[:space:]]*trafficEncryptionMode[[:space:]]*:[[:space:]]*[a-z]+[[:space:]]*$/trafficEncryptionMode: ipsec/" antrea-agent.conf - # change the tunnel type to GRE which works better with IPsec encryption than other types. - sed -i.bak -E "s/^[[:space:]]*#[[:space:]]*tunnelType[[:space:]]*:[[:space:]]*[a-z]+[[:space:]]*$/tunnelType: gre/" antrea-agent.conf + HELM_VALUES+=("trafficEncryptionMode=ipsec" "tunnelType=gre") fi if $FLEXIBLE_IPAM; then - sed -i.bak -E "s/^[[:space:]]*#[[:space:]]*AntreaIPAM[[:space:]]*:[[:space:]]*[a-z]+[[:space:]]*$/ AntreaIPAM: true/" antrea-controller.conf - sed -i.bak -E "s/^[[:space:]]*#[[:space:]]*AntreaIPAM[[:space:]]*:[[:space:]]*[a-z]+[[:space:]]*$/ AntreaIPAM: true/" antrea-agent.conf - sed -i.bak -E "s/^[[:space:]]*#[[:space:]]*enableBridgingMode[[:space:]]*:[[:space:]]*[a-z]+[[:space:]]*$/enableBridgingMode: true/" antrea-agent.conf - sed -i.bak -E "s/^[[:space:]]*#[[:space:]]*trafficEncapMode[[:space:]]*:[[:space:]]*[a-z]+[[:space:]]*$/trafficEncapMode: noEncap/" antrea-agent.conf - sed -i.bak -E "s/^[[:space:]]*#[[:space:]]*noSNAT[[:space:]]*:[[:space:]]*[a-z]+[[:space:]]*$/noSNAT: true/" antrea-agent.conf + HELM_VALUES+=("featureGates.AntreaIPAM=true" "enableBridgingMode=true" "trafficEncapMode=noEncap" "noSNAT=true") fi if $MULTICAST; then - sed -i.bak -E "s/^[[:space:]]*#[[:space:]]*trafficEncapMode[[:space:]]*:[[:space:]]*[a-z]+[[:space:]]*$/trafficEncapMode: noEncap/" antrea-agent.conf - sed -i.bak -E "s/^[[:space:]]*#[[:space:]]*Multicast[[:space:]]*:[[:space:]]*[a-z]+[[:space:]]*$/ Multicast: true/" antrea-agent.conf - sed -i.bak -E "s/^[[:space:]]*#[[:space:]]*multicastInterfaces[[:space:]]*:[[:space:]]*\[([a-zA-Z0-9]*,[[:space:]]*)*[a-zA-Z0-9]*\][[:space:]]*$/multicastInterfaces: [$MULTICAST_INTERFACES]/" antrea-agent.conf + HELM_VALUES+=("trafficEncapMode=noEncap" "featureGates.Multicast=true" "multicast.multicastInterfaces={$MULTICAST_INTERFACES}") fi if $ALLFEATURES; then - sed -i.bak -E "s/^[[:space:]]*#[[:space:]]*AntreaPolicy[[:space:]]*:[[:space:]]*[a-z]+[[:space:]]*$/ AntreaPolicy: true/" antrea-agent.conf - sed -i.bak -E "s/^[[:space:]]*#[[:space:]]*FlowExporter[[:space:]]*:[[:space:]]*[a-z]+[[:space:]]*$/ FlowExporter: true/" antrea-agent.conf - sed -i.bak -E "s/^[[:space:]]*#[[:space:]]*NetworkPolicyStats[[:space:]]*:[[:space:]]*[a-z]+[[:space:]]*$/ NetworkPolicyStats: true/" antrea-agent.conf - sed -i.bak -E "s/^[[:space:]]*#[[:space:]]*EndpointSlice[[:space:]]*:[[:space:]]*[a-z]+[[:space:]]*$/ EndpointSlice: true/" antrea-agent.conf - sed -i.bak -E "s/^[[:space:]]*#proxyAll[[:space:]]*:[[:space:]]*[a-z]+[[:space:]]*$/ proxyAll: true/" antrea-agent.conf + HELM_VALUES+=("featureGates.FlowExporter=true" "featureGates.EndpointSlice=true" "antreaProxy.proxyAll=true") fi if ! $PROXY; then - sed -i.bak -E "s/^[[:space:]]*#[[:space:]]*AntreaProxy[[:space:]]*:[[:space:]]*[a-z]+[[:space:]]*$/ AntreaProxy: false/" antrea-agent.conf + HELM_VALUES+=("featureGates.AntreaProxy=false") fi if $PROXY_ALL; then - sed -i.bak -E "s/^[[:space:]]*#proxyAll[[:space:]]*:[[:space:]]*[a-z]+[[:space:]]*$/ proxyAll: true/" antrea-agent.conf + HELM_VALUES+=("antreaProxy.proxyAll=true") fi -if ! $LEGACY_CRD; then - sed -i.bak -E "s/^#legacyCRDMirroring[[:space:]]*:[[:space:]]*[a-z]+[[:space:]]*$/legacyCRDMirroring: false/" antrea-controller.conf +if $ENDPOINTSLICE; then + HELM_VALUES+=("featureGates.EndpointSlice=true") fi -if $ENDPOINTSLICE; then - sed -i.bak -E "s/^[[:space:]]*#[[:space:]]*EndpointSlice[[:space:]]*:[[:space:]]*[a-z]+[[:space:]]*$/ EndpointSlice: true/" antrea-agent.conf +if $FLOW_EXPORTER; then + HELM_VALUES+=("featureGates.FlowExporter=true") fi if ! $NP; then - sed -i.bak -E "s/^[[:space:]]*#[[:space:]]*AntreaPolicy[[:space:]]*:[[:space:]]*[a-z]+[[:space:]]*$/ AntreaPolicy: false/" antrea-controller.conf - sed -i.bak -E "s/^[[:space:]]*#[[:space:]]*AntreaPolicy[[:space:]]*:[[:space:]]*[a-z]+[[:space:]]*$/ AntreaPolicy: false/" antrea-agent.conf + HELM_VALUES+=("featureGates.AntreaPolicy=false") fi if [[ $ENCAP_MODE != "" ]]; then - sed -i.bak -E "s/^[[:space:]]*#[[:space:]]*trafficEncapMode[[:space:]]*:[[:space:]]*[a-z]+[[:space:]]*$/trafficEncapMode: $ENCAP_MODE/" antrea-agent.conf + HELM_VALUES+=("trafficEncapMode=$ENCAP_MODE") fi if [[ $TUN_TYPE != "geneve" ]]; then - sed -i.bak -E "s/^[[:space:]]*#[[:space:]]*tunnelType[[:space:]]*:[[:space:]]*[a-z]+[[:space:]]*$/tunnelType: $TUN_TYPE/" antrea-agent.conf -fi - -if [[ $CLOUD != "" ]]; then - # Delete the serviceCIDR parameter for the cloud (AKS, EKS, GKE) deployment yamls, because - # AntreaProxy is always enabled for the cloud managed K8s clusters, and the serviceCIDR - # parameter is not needed in this case. - # delete all blank lines after "#serviceCIDR:" - sed -i.bak '/#serviceCIDR:/,/^$/{/^$/d;}' antrea-agent.conf - # delete lines from "# ClusterIP CIDR range for Services" to "#serviceCIDR:" - sed -i.bak '/# ClusterIP CIDR range for Services/,/#serviceCIDR:/d' antrea-agent.conf -fi - -# unfortunately 'kustomize edit add configmap' does not support specifying 'merge' as the behavior, -# which is why we use a template kustomization file. -sed -e "s//antrea-agent.conf/; s//antrea-controller.conf/" ../../patches/kustomization.configMap.tpl.yml > kustomization.yml -$KUSTOMIZE edit add base $BASE -BASE=../configMap -cd .. - -if $IPSEC; then - mkdir ipsec && cd ipsec - # we copy the patch files to avoid having to use the '--load-restrictor. flag when calling - # 'kustomize build'. See https://github.com/kubernetes-sigs/kustomize/blob/master/docs/FAQ.md#security-file-foo-is-not-in-or-below-bar - cp ../../patches/ipsec/*.yml . - touch kustomization.yml - $KUSTOMIZE edit add base $BASE - # create a K8s Secret to save the PSK (pre-shared key) for IKE authentication. - $KUSTOMIZE edit add resource ipsecSecret.yml - # add a container to the Agent DaemonSet that runs the OVS IPsec and strongSwan daemons. - $KUSTOMIZE edit add patch --path ipsecContainer.yml - # add an environment variable to the antrea-agent container for passing the PSK to Agent. - $KUSTOMIZE edit add patch --path pskEnv.yml - BASE=../ipsec - cd .. + HELM_VALUES+=("tunnelType=$TUN_TYPE") fi if $COVERAGE; then - mkdir coverage && cd coverage - cp ../../patches/coverage/*.yml . - touch kustomization.yml - $KUSTOMIZE edit add base $BASE - # this runs antrea-controller via the instrumented binary. - $KUSTOMIZE edit add patch --path startControllerCov.yml - # this runs antrea-agent via the instrumented binary. - $KUSTOMIZE edit add patch --path startAgentCov.yml - BASE=../coverage - cd .. + HELM_VALUES+=("testing.coverage=true") fi -if [[ $ENCAP_MODE == "networkPolicyOnly" ]] ; then - mkdir chaining && cd chaining - cp ../../patches/chaining/*.yml . - touch kustomization.yml - $KUSTOMIZE edit add base $BASE - # change initContainer script and add antrea to CNI chain - $KUSTOMIZE edit add patch --path installCni.yml - BASE=../chaining - cd .. -fi - if [[ $CLOUD == "GKE" ]]; then - mkdir gke && cd gke - cp ../../patches/gke/*.yml . - touch kustomization.yml - $KUSTOMIZE edit add base $BASE - $KUSTOMIZE edit add patch --path cniPath.yml - BASE=../gke - cd .. + HELM_VALUES+=("cni.hostBinPath=/home/kubernetes/bin") fi if [[ $CLOUD == "EKS" ]]; then - mkdir eks && cd eks - cp ../../patches/eks/*.yml . - touch kustomization.yml - $KUSTOMIZE edit add base $BASE - $KUSTOMIZE edit add patch --path eksEnv.yml - BASE=../eks - cd .. + HELM_VALUES+=("agent.antreaAgent.extraEnv.ANTREA_CLOUD_EKS=true") fi if $SIMULATOR; then - mkdir simulator && cd simulator - cp ../../patches/simulator/*.yml . - touch kustomization.yml - $KUSTOMIZE edit add base $BASE - $KUSTOMIZE edit add patch --path agentNodeAffinity.yml - $KUSTOMIZE edit add patch --path controllerNodeAffinity.yml - $KUSTOMIZE edit add resource antrea-agent-simulator.yml - BASE=../simulator - cd .. + HELM_VALUES+=("testing.simulator.enable=true") fi if $CUSTOM_ADM_CONTROLLER; then - mkdir admissioncontroller && cd admissioncontroller - cp ../../patches/admissioncontroller/*.yml . - touch kustomization.yml - $KUSTOMIZE edit add base $BASE - $KUSTOMIZE edit add resource webhook.yml - BASE=../admissioncontroller - cd .. + HELM_VALUES+=("webhooks.labelsMutator.enable=true") fi if $HW_OFFLOAD; then - mkdir hwoffload && cd hwoffload - cp ../../patches/hwoffload/hwOffload.yml . - touch kustomization.yml - $KUSTOMIZE edit add base $BASE - $KUSTOMIZE edit add patch --path hwOffload.yml - BASE=../hwoffload - cd .. + HELM_VALUES+=("ovs.hwOffload=true") fi if $SRIOV; then - mkdir sriov && cd sriov - cp ../../patches/sriov/sriov.yml . - touch kustomization.yml - $KUSTOMIZE edit add base $BASE - $KUSTOMIZE edit add patch --path sriov.yml - BASE=../sriov - cd .. + cat << EOF > $TMP_DIR/sriov.yml +agent: + antreaAgent: + extraVolumeMounts: + - mountPath: /var/lib/kubelet + name: host-kubelet + readOnly: true + extraVolumes: + - hostPath: + path: /var/lib/kubelet + name: host-kubelet +EOF + HELM_VALUES_FILES+=("$TMP_DIR/sriov.yml") fi if $WHEREABOUTS; then - mkdir whereabouts && cd whereabouts - cp ../../patches/whereabouts/*.yml . - touch kustomization.yml - $KUSTOMIZE edit add base $BASE - $KUSTOMIZE edit add patch --path whereabouts.yml - $KUSTOMIZE edit add resource whereabouts-rbac.yml - BASE=../whereabouts - cd .. -fi - -mkdir $MODE && cd $MODE -touch kustomization.yml -$KUSTOMIZE edit add base $BASE -# ../../patches/$MODE may be empty so we use find and not simply cp -find ../../patches/$MODE -name \*.yml -exec cp {} . \; + HELM_VALUES+=("whereabouts.enable=true") +fi if [ "$MODE" == "dev" ]; then if [[ -z "$IMG_NAME" ]]; then if $COVERAGE; then - IMG_NAME="antrea/antrea-ubuntu-coverage:latest" - else - IMG_NAME="projects.registry.vmware.com/antrea/antrea-ubuntu:latest" + HELM_VALUES+=("image.repository=antrea/antrea-ubuntu-coverage") fi + else + HELM_VALUES+=("image.repository=$IMG_NAME") fi - $KUSTOMIZE edit set image antrea=$IMG_NAME - - $KUSTOMIZE edit add patch --path agentImagePullPolicy.yml - $KUSTOMIZE edit add patch --path controllerImagePullPolicy.yml if $VERBOSE_LOG; then - $KUSTOMIZE edit add patch --path agentVerboseLog.yml - $KUSTOMIZE edit add patch --path controllerVerboseLog.yml - fi - - # only required because there is no good way at the moment to update the imagePullPolicy for all - # containers. See https://github.com/kubernetes-sigs/kustomize/issues/1493 - if $IPSEC; then - $KUSTOMIZE edit add patch --path agentIpsecImagePullPolicy.yml + HELM_VALUES+=("logVerbosity=4") fi if $ON_DELETE; then - $KUSTOMIZE edit add patch --path onDeleteUpdateStrategy.yml + HELM_VALUES+=("agent.updateStrategy.type=OnDelete") fi fi if [ "$MODE" == "release" ]; then - $KUSTOMIZE edit set image antrea=$IMG_NAME:$IMG_TAG + HELM_VALUES+=("image.repository=$IMG_NAME,image.tag=$IMG_TAG") fi -$KUSTOMIZE build +delim="" +HELM_VALUES_OPTION="" +for v in "${HELM_VALUES[@]}"; do + HELM_VALUES_OPTION="$HELM_VALUES_OPTION$delim$v" + delim="," +done +if [ "$HELM_VALUES_OPTION" != "" ]; then + HELM_VALUES_OPTION="--set $HELM_VALUES_OPTION" +fi -popd > /dev/null +HELM_VALUES_FILES_OPTION="" +for v in "${HELM_VALUES_FILES[@]}"; do + HELM_VALUES_FILES_OPTION="$HELM_VALUES_FILES_OPTION -f $v" +done -if $KEEP; then - echoerr "Kustomization file is at $TMP_DIR/$MODE/kustomization.yml" -else - rm -rf $TMP_DIR -fi +ANTREA_CHART="$THIS_DIR/../build/charts/antrea" +# Suppress potential Helm warnings about invalid permissions for Kubeconfig file +# by throwing away related warnings. +$HELM template \ + --namespace kube-system \ + $HELM_VALUES_OPTION \ + $HELM_VALUES_FILES_OPTION \ + "$ANTREA_CHART" \ + 2> >(grep -v 'This is insecure' >&2) + +rm -rf $TMP_DIR diff --git a/hack/generate-standard-manifests.sh b/hack/generate-standard-manifests.sh new file mode 100755 index 00000000000..b9270c33a26 --- /dev/null +++ b/hack/generate-standard-manifests.sh @@ -0,0 +1,131 @@ +#!/usr/bin/env bash + +# Copyright 2022 Antrea Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set -eo pipefail + +function echoerr { + >&2 echo "$@" +} + +_usage="Usage: $0 [--mode (dev|release)] --out +Generate standard YAML manifests for Antrea using Helm and writes them to output directory. + --mode (dev|release) Choose the configuration variant that you need (default is 'dev') + --out Output directory for generated manifetss + --help, -h Print this message and exit + +In 'release' mode, environment variables IMG_NAME and IMG_TAG must be set. + +In 'dev' mode, environment variable IMG_NAME can be set to use a custom image. + +This tool uses Helm 3 (https://helm.sh/) to generate the \"standard\" manifests for Antrea. These +are the manifests that are checked-in into the Antrea source tree, and that are uploaded as release +assets for each new Antrea release. This script looks for all the Helm values YAML files under +/build/yamls/chart-values/, and generates the corresponding manifest for each one. + +You can set the HELM environment variable to the path of the helm binary you wan t us to +use. Otherwise we will download the appropriate version of the helm binary and use it (this is the +recommended approach since different versions of helm may create different output YAMLs)." + +function print_usage { + echoerr "$_usage" +} + +function print_help { + echoerr "Try '$0 --help' for more information." +} + +MODE="dev" +OUTPUT_DIR="" + +while [[ $# -gt 0 ]] +do +key="$1" + +case $key in + --mode) + MODE="$2" + shift 2 + ;; + --out) + OUTPUT_DIR="$2" + shift 2 + ;; + -h|--help) + print_usage + exit 0 + ;; + *) # unknown option + echoerr "Unknown option $1" + exit 1 + ;; +esac +done + +if [ "$MODE" != "dev" ] && [ "$MODE" != "release" ]; then + echoerr "--mode must be one of 'dev' or 'release'" + print_help + exit 1 +fi + +if [ "$MODE" == "release" ] && [ -z "$IMG_NAME" ]; then + echoerr "In 'release' mode, environment variable IMG_NAME must be set" + print_help + exit 1 +fi + +if [ "$MODE" == "release" ] && [ -z "$IMG_TAG" ]; then + echoerr "In 'release' mode, environment variable IMG_TAG must be set" + print_help + exit 1 +fi + +if [ "$OUTPUT_DIR" == "" ]; then + echoerr "--out is required to provide output directory for generated manifests" + print_help + exit 1 +fi + +THIS_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" + +source $THIS_DIR/verify-helm.sh + +if [ -z "$HELM" ]; then + HELM="$(verify_helm)" +elif ! $HELM version > /dev/null 2>&1; then + echoerr "$HELM does not appear to be a valid helm binary" + print_help + exit 1 +fi + +EXTRA_VALUES="" +if [ "$MODE" == "release" ]; then + EXTRA_VALUES="--set image.repository=$IMG_NAME,image.tag=$IMG_TAG" +fi + +ANTREA_CHART="$THIS_DIR/../build/charts/antrea" +VALUES_DIR="$THIS_DIR/../build/yamls/chart-values" +VALUES_FILES=$(cd $VALUES_DIR && find * -type f -name "*.yml" ) +# Suppress potential Helm warnings about invalid permissions for Kubeconfig file +# by throwing away related warnings. +for values in $VALUES_FILES; do + $HELM template \ + --namespace kube-system \ + -f "$VALUES_DIR/$values" \ + $EXTRA_VALUES \ + "$ANTREA_CHART" \ + > "$OUTPUT_DIR/$values" \ + 2> >(grep -v 'This is insecure' >&2) +done diff --git a/hack/git_client_side_hooks/pre-commit b/hack/git_client_side_hooks/pre-commit new file mode 100644 index 00000000000..c07b1509bf6 --- /dev/null +++ b/hack/git_client_side_hooks/pre-commit @@ -0,0 +1,42 @@ +#!/bin/sh + +# Copyright 2022 Antrea Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +COUNT_DOC_DIFF=$(git diff --name-only --staged '*.md' | wc -l) +COUNT_GOLANG_DIFF=$(git diff --name-only --staged '*.go' | wc -l) + +if [ "$COUNT_DOC_DIFF" -gt 0 ] +then + make verify + MAKE_VERIFY=$? + + if [ "$MAKE_VERIFY" != 0 ] + then + echo "The command: 'make verify' failed! Please fix and try again!" + exit 1 + fi +fi + +if [ "$COUNT_GOLANG_DIFF" -gt 0 ] +then + make golangci + MAKE_GOLANGCI=$? + + if [ "$MAKE_GOLANGCI" != 0 ] + then + echo "The command: 'make golangci' failed! Please fix and try again!" + exit 1 + fi +fi diff --git a/hack/release/prepare-assets.sh b/hack/release/prepare-assets.sh index 6055f1e261b..f90831be9dd 100755 --- a/hack/release/prepare-assets.sh +++ b/hack/release/prepare-assets.sh @@ -70,11 +70,7 @@ sed "s/AntreaVersion=\"latest\"/AntreaVersion=\"$VERSION\"/" ./hack/windows/Star export IMG_TAG=$VERSION export IMG_NAME=projects.registry.vmware.com/antrea/antrea-ubuntu -./hack/generate-manifest.sh --mode release > "$OUTPUT_DIR"/antrea.yml -./hack/generate-manifest.sh --mode release --ipsec > "$OUTPUT_DIR"/antrea-ipsec.yml -./hack/generate-manifest.sh --mode release --cloud EKS --encap-mode networkPolicyOnly > "$OUTPUT_DIR"/antrea-eks.yml -./hack/generate-manifest.sh --mode release --cloud GKE --encap-mode noEncap > "$OUTPUT_DIR"/antrea-gke.yml -./hack/generate-manifest.sh --mode release --cloud AKS --encap-mode networkPolicyOnly > "$OUTPUT_DIR"/antrea-aks.yml +./hack/generate-standard-manifests.sh --mode release --out "$OUTPUT_DIR" export IMG_NAME=projects.registry.vmware.com/antrea/octant-antrea-ubuntu ./hack/generate-manifest-octant.sh --mode release > "$OUTPUT_DIR"/antrea-octant.yml diff --git a/hack/release/prepare-changelog.sh b/hack/release/prepare-changelog.sh new file mode 100755 index 00000000000..f5ba0bbd6a7 --- /dev/null +++ b/hack/release/prepare-changelog.sh @@ -0,0 +1,137 @@ +#!/usr/bin/env bash + +# Copyright 2022 Antrea Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set -eo pipefail + +function echoerr { + >&2 echo "$@" +} + +_usage="Usage: $0 --release [--from-release ] [--all] +Draft the changelog for a release based on PR history starting from the last release. +For a minor release such as 1.5.0, the changelog will base on PRs merged to main branch since the fork of release-1.4. +For a patch release such as 1.5.2, the changelog will base on PRs merged to release-1.5 branch since the release of 1.5.1. + +Options: + --release The release for which the changelog is generated + --from-release The last release from which the changelog is generated. It's supposed to be used only + when running the script for a major release such as 2.0.0 + --all Include PRs that are not labelled with 'action/release-note' in a separate section" + +function print_usage { + echoerr "$_usage" +} + +if ! command -v gh > /dev/null; then + echo "Can't find 'gh' tool in PATH, please install from https://github.com/cli/cli" + exit 1 +fi + +release="" +from_release="" +all="no" +limit=500 + +while [[ $# -gt 0 ]] +do +key="$1" + +case $key in + --release) + release="$2" + shift 2 + ;; + --from-release) + from_release="$2" + shift 2 + ;; + --all) + all="yes" + shift + ;; + -h|--help) + print_usage + exit 0 + ;; + *) # unknown option + echoerr "Unknown option $1" + exit 1 + ;; +esac +done + +if [ "$release" == "" ]; then + echoerr "--release must be set" + exit 1 +fi + +major_minor_number="${release%.*}" +major_number="${major_minor_number%.*}" +minor_number="${major_minor_number#*.}" +patch_number="${release##*.}" + +if [ "$from_release" == "" ]; then + if [ "$patch_number" == "0" ]; then + from_release="${major_number}.$(( minor_number-1 )).0" + else + from_release="${major_number}.${minor_number}.$(( patch_number-1 ))" + fi +fi + +# For minor releases, PRs are merged to main branch. +# For patch releases, PRs are merged to release branches. +branch="main" +if [ "$patch_number" != "0" ]; then + branch="release-${major_minor_number}" +fi + +# Get the best common ancestor between the current branch and the last release. +common_ancestor=$(git merge-base "v${from_release}" "${branch}") +# Get the merge time of the common ancestor and use it as the start time of the current release. +release_start_time=$(gh pr list --state merged --search "${common_ancestor}" --json mergedAt -q .[0].mergedAt) + +# Do not generate the title for patch releases. +if [ "$patch_number" == "0" ]; then + echo "# Changelog ${major_minor_number}" + echo "" +fi +echo "## ${release} - $(date +%F)" +echo "" +echo "### Added" +echo "" + +echo "### Changed" +echo "" +# Put the changes under "Changed" first, release manager needs to move them to appropriate sections manually. +gh pr list -s merged -B ${branch} --search "merged:>${release_start_time} sort:updated-desc label:action/release-note" -L $limit --json number,title,author,labels --template \ +'{{range .}}{{tablerow (printf "- %s. ([#%v](https://github.com/antrea-io/antrea/pull/%v), [@%s])" .title .number .number .author.login)}}{{end}}' +echo "" + +echo "### Fixed" +echo "" + +if [ "$all" == "yes" ]; then + # There may be some changes not being labelled properly, release manager needs to move them to appropriate sections manually. + echo "### Unlabelled (Remove this section eventually)" + echo "" + gh pr list -s merged -B ${branch} --search "merged:>${release_start_time} sort:updated-desc -label:action/release-note" -L $limit --json number,title,author,labels --template \ + '{{range .}}{{tablerow (printf "- %s. ([#%v](https://github.com/antrea-io/antrea/pull/%v), [@%s])" .title .number .number .author.login)}}{{end}}' +fi + +echo "" +echo "" + +gh pr list -s merged -B ${branch} --search "merged:>${release_start_time} sort:author" -L $limit --json author --jq .[].author.login | sort | uniq | xargs -I AUTHOR echo "[@AUTHOR]: https://github.com/AUTHOR" diff --git a/hack/update-codegen-dockerized.sh b/hack/update-codegen-dockerized.sh index 797f1620ac0..f802031cb44 100755 --- a/hack/update-codegen-dockerized.sh +++ b/hack/update-codegen-dockerized.sh @@ -36,6 +36,75 @@ ANTREA_PKG="antrea.io/antrea" # https://github.com/kubernetes-sigs/gateway-api/issues/11 ANTREA_PROTO_PKG="antrea_io.antrea" +function generate_mocks { + # Generate mocks for testing with mockgen. + MOCKGEN_TARGETS=( + "pkg/agent/cniserver/ipam IPAMDriver testing" + "pkg/agent/flowexporter/connections ConnTrackDumper,NetFilterConnTrack testing" + "pkg/agent/interfacestore InterfaceStore testing" + "pkg/agent/multicast RouteInterface testing" + "pkg/agent/nodeportlocal/portcache LocalPortOpener testing" + "pkg/agent/nodeportlocal/rules PodPortRules testing" + "pkg/agent/openflow Client,OFEntryOperations testing" + "pkg/agent/proxy Proxier testing" + "pkg/agent/querier AgentQuerier testing" + "pkg/agent/route Interface testing" + "pkg/agent/ipassigner IPAssigner testing" + "pkg/antctl AntctlClient ." + "pkg/controller/networkpolicy EndpointQuerier testing" + "pkg/controller/querier ControllerQuerier testing" + "pkg/ipfix IPFIXExportingProcess,IPFIXRegistry,IPFIXCollectingProcess,IPFIXAggregationProcess testing" + "pkg/ovs/openflow Bridge,Table,Flow,Action,CTAction,FlowBuilder testing" + "pkg/ovs/ovsconfig OVSBridgeClient testing" + "pkg/ovs/ovsctl OVSCtlClient testing" + "pkg/querier AgentNetworkPolicyInfoQuerier testing" + "third_party/proxy Provider testing" + ) + + # Command mockgen does not automatically replace variable YEAR with current year + # like others do, e.g. client-gen. + current_year=$(date +"%Y") + sed -i "s/YEAR/${current_year}/g" hack/boilerplate/license_header.raw.txt + for target in "${MOCKGEN_TARGETS[@]}"; do + read -r package interfaces mock_package <<<"${target}" + package_name=$(basename "${package}") + if [[ "${mock_package}" == "." ]]; then # generate mocks in same package as src + $GOPATH/bin/mockgen \ + -copyright_file hack/boilerplate/license_header.raw.txt \ + -destination "${package}/mock_${package_name}_test.go" \ + -package="${package_name}" \ + "${ANTREA_PKG}/${package}" "${interfaces}" + else # generate mocks in subpackage + $GOPATH/bin/mockgen \ + -copyright_file hack/boilerplate/license_header.raw.txt \ + -destination "${package}/${mock_package}/mock_${package_name}.go" \ + -package="${mock_package}" \ + "${ANTREA_PKG}/${package}" "${interfaces}" + fi + done + git checkout HEAD -- hack/boilerplate/license_header.raw.txt +} + +function reset_year_change { + set +x + echo "=== Start resetting changes introduced by YEAR ===" + # The call to 'tac' ensures that we cannot have concurrent git processes, by + # waiting for the call to 'git diff --numstat' to complete before iterating + # over the files and calling 'git diff ${file}'. + git diff --numstat | awk '$1 == "1" && $2 == "1" {print $3}' | tac | while read file; do + if [[ "$(git diff ${file})" == *"-// Copyright "*" Antrea Authors"* ]]; then + git checkout HEAD -- "${file}" + echo "=== ${file} is reset ===" + fi + done +} + +if [[ "$#" -eq 1 && $1 == "mockgen" ]]; then + generate_mocks + reset_year_change + exit 0 +fi + # Generate protobuf code for CNI gRPC service with protoc. protoc --go_out=plugins=grpc:. pkg/apis/cni/v1beta1/cni.proto @@ -107,52 +176,7 @@ $GOPATH/bin/openapi-gen \ -O zz_generated.openapi \ --go-header-file hack/boilerplate/license_header.go.txt -# Generate mocks for testing with mockgen. -MOCKGEN_TARGETS=( - "pkg/agent/cniserver/ipam IPAMDriver testing" - "pkg/agent/flowexporter/connections ConnTrackDumper,NetFilterConnTrack testing" - "pkg/agent/interfacestore InterfaceStore testing" - "pkg/agent/multicast RouteInterface testing" - "pkg/agent/nodeportlocal/portcache LocalPortOpener testing" - "pkg/agent/nodeportlocal/rules PodPortRules testing" - "pkg/agent/openflow Client,OFEntryOperations testing" - "pkg/agent/proxy Proxier testing" - "pkg/agent/querier AgentQuerier testing" - "pkg/agent/route Interface testing" - "pkg/agent/ipassigner IPAssigner testing" - "pkg/antctl AntctlClient ." - "pkg/controller/networkpolicy EndpointQuerier testing" - "pkg/controller/querier ControllerQuerier testing" - "pkg/ipfix IPFIXExportingProcess,IPFIXRegistry,IPFIXCollectingProcess,IPFIXAggregationProcess testing" - "pkg/ovs/openflow Bridge,Table,Flow,Action,CTAction,FlowBuilder testing" - "pkg/ovs/ovsconfig OVSBridgeClient testing" - "pkg/ovs/ovsctl OVSCtlClient testing" - "pkg/querier AgentNetworkPolicyInfoQuerier testing" - "third_party/proxy Provider testing" -) - -# Command mockgen does not automatically replace variable YEAR with current year -# like others do, e.g. client-gen. -current_year=$(date +"%Y") -sed -i "s/YEAR/${current_year}/g" hack/boilerplate/license_header.raw.txt -for target in "${MOCKGEN_TARGETS[@]}"; do - read -r package interfaces mock_package <<<"${target}" - package_name=$(basename "${package}") - if [[ "${mock_package}" == "." ]]; then # generate mocks in same package as src - $GOPATH/bin/mockgen \ - -copyright_file hack/boilerplate/license_header.raw.txt \ - -destination "${package}/mock_${package_name}_test.go" \ - -package="${package_name}" \ - "${ANTREA_PKG}/${package}" "${interfaces}" - else # generate mocks in subpackage - $GOPATH/bin/mockgen \ - -copyright_file hack/boilerplate/license_header.raw.txt \ - -destination "${package}/${mock_package}/mock_${package_name}.go" \ - -package="${mock_package}" \ - "${ANTREA_PKG}/${package}" "${interfaces}" - fi -done -git checkout HEAD -- hack/boilerplate/license_header.raw.txt +generate_mocks # Download vendored modules to the vendor directory so it's easier to # specify the search path of required protobuf files. @@ -173,15 +197,4 @@ $GOPATH/bin/go-to-protobuf \ --go-header-file hack/boilerplate/license_header.go.txt rm -rf /tmp/includes -set +x - -echo "=== Start resetting changes introduced by YEAR ===" -# The call to 'tac' ensures that we cannot have concurrent git processes, by -# waiting for the call to 'git diff --numstat' to complete before iterating -# over the files and calling 'git diff ${file}'. -git diff --numstat | awk '$1 == "1" && $2 == "1" {print $3}' | tac | while read file; do - if [[ "$(git diff ${file})" == *"-// Copyright "*" Antrea Authors"* ]]; then - git checkout HEAD -- "${file}" - echo "=== ${file} is reset ===" - fi -done +reset_year_change diff --git a/hack/update-codegen.sh b/hack/update-codegen.sh index c24d65b34bb..db3bb9f66b1 100755 --- a/hack/update-codegen.sh +++ b/hack/update-codegen.sh @@ -15,18 +15,19 @@ # limitations under the License. set -o errexit -set -o nounset set -o pipefail ANTREA_ROOT="$( cd "$( dirname "${BASH_SOURCE[0]}" )/../" && pwd )" -IMAGE_NAME="antrea/codegen:kubernetes-1.21.0-build.1" +IMAGE_NAME="antrea/codegen:kubernetes-1.24.0" function docker_run() { docker pull ${IMAGE_NAME} + set -x docker run --rm \ + -e GOPROXY=${GOPROXY} \ -w /go/src/antrea.io/antrea \ -v ${ANTREA_ROOT}:/go/src/antrea.io/antrea \ "${IMAGE_NAME}" "$@" } -docker_run hack/update-codegen-dockerized.sh +docker_run hack/update-codegen-dockerized.sh "$@" diff --git a/hack/verify-helm.sh b/hack/verify-helm.sh new file mode 100644 index 00000000000..40f2929b557 --- /dev/null +++ b/hack/verify-helm.sh @@ -0,0 +1,73 @@ +#!/usr/bin/env bash + +# Copyright 2022 Antrea Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +THIS_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" +_BINDIR="$THIS_DIR/.bin" +# Must be an exact match, as the generated YAMLs may not be consistent across +# versions +_HELM_VERSION="v3.8.1" + +# Ensure the helm tool exists and is the correct version, or install it +verify_helm() { + # Check if there is already a helm binary in $_BINDIR and if yes, check if + # the version matches the expected one. + local helm="$(PATH=$_BINDIR command -v helm)" + if [ -x "$helm" ]; then + # Verify version if helm was already installed. + local helm_version="$($helm version --short 2> >(grep -v 'This is insecure' >&2))" + # Should work with: + # - v3.8.1 + # - v3.8.1+g5cb9af4 + helm_version="${helm_version%+*}" + if [ "${helm_version}" == "${_HELM_VERSION}" ]; then + # If version is exact match, stop here. + echo "$helm" + return 0 + fi + >&2 echo "Detected helm version ($helm_version) does not match expected one ($_HELM_VERSION), installing correct version" + fi + local ostype="" + if [[ "$OSTYPE" == "linux-gnu" ]]; then + ostype="linux" + elif [[ "$OSTYPE" == "darwin"* ]]; then + ostype="darwin" + else + >&2 echo "Unsupported OS type $OSTYPE" + return 1 + fi + rc=0 + local unameArch="$(uname -m)" || rc=$? + if [ $rc -ne 0 ]; then + >&2 echo "Cannot detect architecture type, uname not available?" + return 1 + fi + local arch="" + case "$unameArch" in + x86_64) arch="amd64";; + arm64) arch="arm64";; + *) >&2 echo "Unsupported architecture type $unameArch"; return 1;; + esac + + >&2 echo "Installing helm" + local helm_url="https://get.helm.sh/helm-${_HELM_VERSION}-${ostype}-${arch}.tar.gz" + curl -sLo helm.tar.gz "${helm_url}" || return 1 + mkdir -p "$_BINDIR" || return 1 + tar -xzf helm.tar.gz -C "$_BINDIR" --strip-components=1 "${ostype}-${arch}/helm" || return 1 + rm -f helm.tar.gz + helm="$_BINDIR/helm" + echo "$helm" + return 0 +} diff --git a/hack/windows/Helper.psm1 b/hack/windows/Helper.psm1 index 09d0b7f3dc6..be77681137f 100644 --- a/hack/windows/Helper.psm1 +++ b/hack/windows/Helper.psm1 @@ -127,7 +127,7 @@ function Install-AntreaAgent { $APIServer=$(kubectl --kubeconfig=$KubeConfig get service kubernetes -o jsonpath='{.spec.clusterIP}') $APIServerPort=$(kubectl --kubeconfig=$KubeConfig get service kubernetes -o jsonpath='{.spec.ports[0].port}') $APIServer="https://$APIServer" + ":" + $APIServerPort - $TOKEN=$(kubectl --kubeconfig=$KubeConfig get secrets -n kube-system -o jsonpath="{.items[?(@.metadata.annotations['kubernetes\.io/service-account\.name']=='antrea-agent')].data.token}") + $TOKEN=$(kubectl --kubeconfig=$KubeConfig get secret/antrea-agent-service-account-token -n kube-system -o jsonpath="{.data.token}") $TOKEN=$([System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($TOKEN))) kubectl config --kubeconfig=$AntreaEtc\antrea-agent.kubeconfig set-cluster kubernetes --server=$APIServer --insecure-skip-tls-verify kubectl config --kubeconfig=$AntreaEtc\antrea-agent.kubeconfig set-credentials antrea-agent --token=$TOKEN @@ -262,7 +262,7 @@ function Start-AntreaAgent { $AntreaAgent = "$AntreaHome\bin\antrea-agent.exe" $AntreaAgentConfigPath = "$AntreaHome\etc\antrea-agent.conf" if ($LogDir -eq "") { - $LogDir = "$AntreaHome\logs" + $LogDir = "c:\var\log\antrea" } New-DirectoryIfNotExist $LogDir [Environment]::SetEnvironmentVariable("NODE_NAME", (hostname).ToLower()) diff --git a/multicluster/PROJECT b/multicluster/PROJECT index 2cdf5d456b6..4521d93d44b 100644 --- a/multicluster/PROJECT +++ b/multicluster/PROJECT @@ -96,4 +96,22 @@ resources: kind: MultiClusterConfig path: antrea.io/antrea/multicluster/apis/multicluster/v1alpha1 version: v1alpha1 +- api: + crdVersion: v1 + namespaced: true + controller: true + domain: crd.antrea.io + group: multicluster + kind: ClusterInfoImport + path: antrea.io/antrea/multicluster/apis/multicluster/v1alpha1 + version: v1alpha1 +- api: + crdVersion: v1 + namespaced: true + controller: true + domain: crd.antrea.io + group: multicluster + kind: Gateway + path: antrea.io/antrea/multicluster/apis/multicluster/v1alpha1 + version: v1alpha1 version: "3" diff --git a/multicluster/apis/multicluster/v1alpha1/clusterinfoimport_types.go b/multicluster/apis/multicluster/v1alpha1/clusterinfoimport_types.go new file mode 100644 index 00000000000..86d2ec565b2 --- /dev/null +++ b/multicluster/apis/multicluster/v1alpha1/clusterinfoimport_types.go @@ -0,0 +1,50 @@ +/* +Copyright 2022 Antrea Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// ClusterInfoImportStatus defines the observed state of ClusterInfoImport. +type ClusterInfoImportStatus struct { + Conditions []ResourceCondition `json:"conditions,omitempty"` +} + +// +genclient +//+kubebuilder:object:root=true +//+kubebuilder:subresource:status + +type ClusterInfoImport struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec ClusterInfo `json:"spec,omitempty"` + Status ClusterInfoImportStatus `json:"status,omitempty"` +} + +//+kubebuilder:object:root=true + +type ClusterInfoImportList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []ClusterInfoImport `json:"items"` +} + +func init() { + SchemeBuilder.Register(&ClusterInfoImport{}, &ClusterInfoImportList{}) +} diff --git a/multicluster/apis/multicluster/v1alpha1/gateway_types.go b/multicluster/apis/multicluster/v1alpha1/gateway_types.go new file mode 100644 index 00000000000..2ada2119d97 --- /dev/null +++ b/multicluster/apis/multicluster/v1alpha1/gateway_types.go @@ -0,0 +1,63 @@ +/* +Copyright 2022 Antrea Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// GatewayInfo includes information of a Gateway. +type GatewayInfo struct { + GatewayIP string `json:"gatewayIP,omitempty"` +} + +// +genclient +//+kubebuilder:object:root=true +//+kubebuilder:subresource:status + +// Gateway includes information of a Multi-cluster Gateway. +type Gateway struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + // Tunnel IP of the Gateway. It might be assigned by user manually + // through a Node annotation. + GatewayIP string `json:"gatewayIP,omitempty"` + // Internal tunnel IP of the Gateway. + InternalIP string `json:"internalIP,omitempty"` +} + +type ClusterInfo struct { + // ClusterID of the member cluster. + ClusterID string `json:"clusterID,omitempty"` + // ServiceCIDR is the IP ranges used by Service ClusterIP. + ServiceCIDR string `json:"serviceCIDR,omitempty"` + // GatewayInfos has information of Gateways + GatewayInfos []GatewayInfo `json:"gatewayInfos,omitempty"` +} + +//+kubebuilder:object:root=true + +type GatewayList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []Gateway `json:"items"` +} + +func init() { + SchemeBuilder.Register(&Gateway{}, &GatewayList{}) +} diff --git a/multicluster/apis/multicluster/v1alpha1/multiclusterconfig_types.go b/multicluster/apis/multicluster/v1alpha1/multiclusterconfig_types.go index 4a21f8d8998..febe78626d3 100644 --- a/multicluster/apis/multicluster/v1alpha1/multiclusterconfig_types.go +++ b/multicluster/apis/multicluster/v1alpha1/multiclusterconfig_types.go @@ -21,13 +21,25 @@ import ( config "sigs.k8s.io/controller-runtime/pkg/config/v1alpha1" ) +// Precedence defines the precedence of Node IP type. +type Precedence string + +const ( + PrecedencePrivate = "private" + PrecedencePublic = "public" +) + //+kubebuilder:object:root=true -// MultiClusterConfig is the Schema for the multiclusterconfigs API type MultiClusterConfig struct { metav1.TypeMeta `json:",inline"` - // ControllerManagerConfigurationSpec returns the contfigurations for controllers + // ControllerManagerConfigurationSpec returns the contfigurations for controllers. config.ControllerManagerConfigurationSpec `json:",inline"` + // ServiceCIDR allows user to set the ClusterIP range of the cluster manually. + ServiceCIDR string `json:"serviceCIDR,omitempty"` + // The precedence about which IP (private or public one) of Node is preferred to + // be used as tunnel endpoint. if not specified, private IP will be chosen. + GatewayIPPrecedence Precedence `json:"gatewayIPPrecedence,omitempty"` } func init() { diff --git a/multicluster/apis/multicluster/v1alpha1/resourceexport_types.go b/multicluster/apis/multicluster/v1alpha1/resourceexport_types.go index fe0afdb9e36..9de12b5b738 100644 --- a/multicluster/apis/multicluster/v1alpha1/resourceexport_types.go +++ b/multicluster/apis/multicluster/v1alpha1/resourceexport_types.go @@ -46,9 +46,6 @@ type RawResourceExport struct { // ResourceExportSpec defines the desired state of ResourceExport. type ResourceExportSpec struct { - // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster - // Important: Run "make" to regenerate code after modifying this file - // ClusterID specifies the member cluster this resource exported from. ClusterID string `json:"clusterID,omitempty"` // Name of exported resource. @@ -60,14 +57,16 @@ type ResourceExportSpec struct { // If exported resource is Service. Service *ServiceExport `json:"service,omitempty"` - // If exported resource is EndPoints. + // If exported resource is Endpoints. Endpoints *EndpointsExport `json:"endpoints,omitempty"` + // If exported resource is ClusterInfo. + ClusterInfo *ClusterInfo `json:"clusterinfo,omitempty"` // If exported resource is ExternalEntity. ExternalEntity *ExternalEntityExport `json:"externalentity,omitempty"` // If exported resource is AntreaClusterNetworkPolicy. ClusterNetworkPolicy *v1alpha1.ClusterNetworkPolicySpec `json:"clusternetworkpolicy,omitempty"` - // If exported resource Kind is unknown. - Raw RawResourceExport `json:"raw,omitempty"` + // If exported resource kind is unknown. + Raw *RawResourceExport `json:"raw,omitempty"` } type ResourceExportConditionType string diff --git a/multicluster/apis/multicluster/v1alpha1/resourceimport_types.go b/multicluster/apis/multicluster/v1alpha1/resourceimport_types.go index de0b8eb1c23..48024e114ba 100644 --- a/multicluster/apis/multicluster/v1alpha1/resourceimport_types.go +++ b/multicluster/apis/multicluster/v1alpha1/resourceimport_types.go @@ -56,6 +56,8 @@ type ResourceImportSpec struct { ServiceImport *mcs.ServiceImport `json:"serviceImport,omitempty"` // If imported resource is EndPoints. Endpoints *EndpointsImport `json:"endpoints,omitempty"` + // If imported resource is ClusterInfo. + ClusterInfo *ClusterInfo `json:"clusterinfo,omitempty"` // If imported resource is ExternalEntity. ExternalEntity *ExternalEntityImport `json:"externalentity,omitempty"` // If imported resource is AntreaClusterNetworkPolicy. @@ -64,7 +66,7 @@ type ResourceImportSpec struct { // TODO: // ANP uses float64 as priority. Type float64 is discouraged by k8s, and is not supported by controller-gen tools. // NetworkPolicy *v1alpha1.NetworkPolicySpec `json:"networkpolicy,omitempty"` - // If imported resource Kind is unknown. + // If imported resource kind is unknown. Raw *RawResourceImport `json:"raw,omitempty"` } diff --git a/multicluster/apis/multicluster/v1alpha1/status.go b/multicluster/apis/multicluster/v1alpha1/status.go new file mode 100644 index 00000000000..943c88e3bfb --- /dev/null +++ b/multicluster/apis/multicluster/v1alpha1/status.go @@ -0,0 +1,46 @@ +/* +Copyright 2022 Antrea Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +import ( + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +type ResourceConditionType string + +const ( + ResourceReady ResourceConditionType = "Ready" +) + +// ResourceCondition indicates the readiness condition of a Resource. +type ResourceCondition struct { + // Type is the type of the condition. + Type ResourceConditionType `json:"type,omitempty"` + // Status of the condition, one of True, False, Unknown. + Status v1.ConditionStatus `json:"status,omitempty"` + + // +optional + // Last time the condition transited from one status to another. + LastTransitionTime metav1.Time `json:"lastTransitionTime,omitempty"` + // +optional + // A human readable message indicating details about the transition. + Message string `json:"message,omitempty"` + // +optional + // Unique, one-word, CamelCase reason for the condition's last transition. + Reason string `json:"reason,omitempty"` +} diff --git a/multicluster/apis/multicluster/v1alpha1/zz_generated.deepcopy.go b/multicluster/apis/multicluster/v1alpha1/zz_generated.deepcopy.go index bff1779a65d..37f01bd3462 100644 --- a/multicluster/apis/multicluster/v1alpha1/zz_generated.deepcopy.go +++ b/multicluster/apis/multicluster/v1alpha1/zz_generated.deepcopy.go @@ -102,6 +102,107 @@ func (in *ClusterCondition) DeepCopy() *ClusterCondition { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ClusterInfo) DeepCopyInto(out *ClusterInfo) { + *out = *in + if in.GatewayInfos != nil { + in, out := &in.GatewayInfos, &out.GatewayInfos + *out = make([]GatewayInfo, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterInfo. +func (in *ClusterInfo) DeepCopy() *ClusterInfo { + if in == nil { + return nil + } + out := new(ClusterInfo) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ClusterInfoImport) DeepCopyInto(out *ClusterInfoImport) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterInfoImport. +func (in *ClusterInfoImport) DeepCopy() *ClusterInfoImport { + if in == nil { + return nil + } + out := new(ClusterInfoImport) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ClusterInfoImport) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ClusterInfoImportList) DeepCopyInto(out *ClusterInfoImportList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]ClusterInfoImport, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterInfoImportList. +func (in *ClusterInfoImportList) DeepCopy() *ClusterInfoImportList { + if in == nil { + return nil + } + out := new(ClusterInfoImportList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ClusterInfoImportList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ClusterInfoImportStatus) DeepCopyInto(out *ClusterInfoImportStatus) { + *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]ResourceCondition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterInfoImportStatus. +func (in *ClusterInfoImportStatus) DeepCopy() *ClusterInfoImportStatus { + if in == nil { + return nil + } + out := new(ClusterInfoImportStatus) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ClusterSet) DeepCopyInto(out *ClusterSet) { *out = *in @@ -333,6 +434,78 @@ func (in *ExternalEntityImport) DeepCopy() *ExternalEntityImport { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Gateway) DeepCopyInto(out *Gateway) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Gateway. +func (in *Gateway) DeepCopy() *Gateway { + if in == nil { + return nil + } + out := new(Gateway) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Gateway) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *GatewayInfo) DeepCopyInto(out *GatewayInfo) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GatewayInfo. +func (in *GatewayInfo) DeepCopy() *GatewayInfo { + if in == nil { + return nil + } + out := new(GatewayInfo) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *GatewayList) DeepCopyInto(out *GatewayList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Gateway, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GatewayList. +func (in *GatewayList) DeepCopy() *GatewayList { + if in == nil { + return nil + } + out := new(GatewayList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *GatewayList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *MemberCluster) DeepCopyInto(out *MemberCluster) { *out = *in @@ -470,6 +643,22 @@ func (in *RawResourceImport) DeepCopy() *RawResourceImport { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ResourceCondition) DeepCopyInto(out *ResourceCondition) { + *out = *in + in.LastTransitionTime.DeepCopyInto(&out.LastTransitionTime) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourceCondition. +func (in *ResourceCondition) DeepCopy() *ResourceCondition { + if in == nil { + return nil + } + out := new(ResourceCondition) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ResourceExport) DeepCopyInto(out *ResourceExport) { *out = *in @@ -647,6 +836,11 @@ func (in *ResourceExportSpec) DeepCopyInto(out *ResourceExportSpec) { *out = new(EndpointsExport) (*in).DeepCopyInto(*out) } + if in.ClusterInfo != nil { + in, out := &in.ClusterInfo, &out.ClusterInfo + *out = new(ClusterInfo) + (*in).DeepCopyInto(*out) + } if in.ExternalEntity != nil { in, out := &in.ExternalEntity, &out.ExternalEntity *out = new(ExternalEntityExport) @@ -657,7 +851,11 @@ func (in *ResourceExportSpec) DeepCopyInto(out *ResourceExportSpec) { *out = new(crdv1alpha1.ClusterNetworkPolicySpec) (*in).DeepCopyInto(*out) } - in.Raw.DeepCopyInto(&out.Raw) + if in.Raw != nil { + in, out := &in.Raw, &out.Raw + *out = new(RawResourceExport) + (*in).DeepCopyInto(*out) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourceExportSpec. @@ -896,6 +1094,11 @@ func (in *ResourceImportSpec) DeepCopyInto(out *ResourceImportSpec) { *out = new(EndpointsImport) (*in).DeepCopyInto(*out) } + if in.ClusterInfo != nil { + in, out := &in.ClusterInfo, &out.ClusterInfo + *out = new(ClusterInfo) + (*in).DeepCopyInto(*out) + } if in.ExternalEntity != nil { in, out := &in.ExternalEntity, &out.ExternalEntity *out = new(ExternalEntityImport) diff --git a/multicluster/build/yamls/antrea-multicluster-leader-global.yml b/multicluster/build/yamls/antrea-multicluster-leader-global.yml index a93a121a83e..50d228d0c97 100644 --- a/multicluster/build/yamls/antrea-multicluster-leader-global.yml +++ b/multicluster/build/yamls/antrea-multicluster-leader-global.yml @@ -376,6 +376,25 @@ spec: description: ClusterID specifies the member cluster this resource exported from. type: string + clusterinfo: + description: If exported resource is ClusterInfo. + properties: + clusterID: + description: ClusterID of the member cluster. + type: string + gatewayInfos: + description: GatewayInfos has information of Gateways + items: + description: GatewayInfo includes information of a Gateway. + properties: + gatewayIP: + type: string + type: object + type: array + serviceCIDR: + description: ServiceCIDR is the IP ranges used by Service ClusterIP. + type: string + type: object clusternetworkpolicy: description: If exported resource is AntreaClusterNetworkPolicy. properties: @@ -526,6 +545,53 @@ spec: matching strategy. type: string type: object + nodeSelector: + description: Select certain Nodes which match the label + selector. A NodeSelector cannot be set in AppliedTo field + or set with any other selector. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, + NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values array + must be non-empty. If the operator is Exists + or DoesNotExist, the values array must be empty. + This array is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} pairs. + A single {key,value} in the matchLabels map is equivalent + to an element of matchExpressions, whose key field + is "key", the operator is "In", and the values array + contains only "value". The requirements are ANDed. + type: object + type: object podSelector: description: Select Pods from NetworkPolicy's Namespace as workloads in AppliedTo/To/From fields. If set with @@ -753,6 +819,55 @@ spec: matching strategy. type: string type: object + nodeSelector: + description: Select certain Nodes which match the + label selector. A NodeSelector cannot be set in + AppliedTo field or set with any other selector. + properties: + matchExpressions: + description: matchExpressions is a list of label + selector requirements. The requirements are + ANDed. + items: + description: A label selector requirement is + a selector that contains values, a key, and + an operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If + the operator is Exists or DoesNotExist, + the values array must be empty. This array + is replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, + whose key field is "key", the operator is "In", + and the values array contains only "value". + The requirements are ANDed. + type: object + type: object podSelector: description: Select Pods from NetworkPolicy's Namespace as workloads in AppliedTo/To/From fields. If set @@ -974,6 +1089,55 @@ spec: matching strategy. type: string type: object + nodeSelector: + description: Select certain Nodes which match the + label selector. A NodeSelector cannot be set in + AppliedTo field or set with any other selector. + properties: + matchExpressions: + description: matchExpressions is a list of label + selector requirements. The requirements are + ANDed. + items: + description: A label selector requirement is + a selector that contains values, a key, and + an operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If + the operator is Exists or DoesNotExist, + the values array must be empty. This array + is replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, + whose key field is "key", the operator is "In", + and the values array contains only "value". + The requirements are ANDed. + type: object + type: object podSelector: description: Select Pods from NetworkPolicy's Namespace as workloads in AppliedTo/To/From fields. If set @@ -1042,9 +1206,9 @@ spec: Name should be unique within the policy. type: string ports: - description: Set of port and protocol allowed/denied by - the rule. If this field is unset or empty, this rule matches - all ports. + description: Set of ports and protocols matched by the rule. + If this field and Protocols are unset or empty, this rule + matches all ports. items: description: NetworkPolicyPort describes the port and protocol to match in a rule. @@ -1072,6 +1236,30 @@ spec: type: string type: object type: array + protocols: + description: Set of protocols matched by the rule. If this + field and Ports are unset or empty, this rule matches + all protocols supported. + items: + description: NetworkPolicyProtocol defines additional + protocols that are not supported by `ports`. All fields + should be used as a standalone field. + properties: + icmp: + description: ICMPProtocol matches ICMP traffic with + specific ICMPType and/or ICMPCode. All fields could + be used alone or together. If all fields are not + provided, this matches all ICMP traffic. + properties: + icmpCode: + format: int32 + type: integer + icmpType: + format: int32 + type: integer + type: object + type: object + type: array to: description: Rule is matched if traffic is intended for workloads selected by this field. This field can't be @@ -1226,6 +1414,55 @@ spec: matching strategy. type: string type: object + nodeSelector: + description: Select certain Nodes which match the + label selector. A NodeSelector cannot be set in + AppliedTo field or set with any other selector. + properties: + matchExpressions: + description: matchExpressions is a list of label + selector requirements. The requirements are + ANDed. + items: + description: A label selector requirement is + a selector that contains values, a key, and + an operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If + the operator is Exists or DoesNotExist, + the values array must be empty. This array + is replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, + whose key field is "key", the operator is "In", + and the values array contains only "value". + The requirements are ANDed. + type: object + type: object podSelector: description: Select Pods from NetworkPolicy's Namespace as workloads in AppliedTo/To/From fields. If set @@ -1476,6 +1713,55 @@ spec: matching strategy. type: string type: object + nodeSelector: + description: Select certain Nodes which match the + label selector. A NodeSelector cannot be set in + AppliedTo field or set with any other selector. + properties: + matchExpressions: + description: matchExpressions is a list of label + selector requirements. The requirements are + ANDed. + items: + description: A label selector requirement is + a selector that contains values, a key, and + an operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If + the operator is Exists or DoesNotExist, + the values array must be empty. This array + is replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, + whose key field is "key", the operator is "In", + and the values array contains only "value". + The requirements are ANDed. + type: object + type: object podSelector: description: Select Pods from NetworkPolicy's Namespace as workloads in AppliedTo/To/From fields. If set @@ -1697,12 +1983,10 @@ spec: matching strategy. type: string type: object - podSelector: - description: Select Pods from NetworkPolicy's Namespace - as workloads in AppliedTo/To/From fields. If set - with NamespaceSelector, Pods are matched from Namespaces - matched by the NamespaceSelector. Cannot be set - with any other selector except NamespaceSelector. + nodeSelector: + description: Select certain Nodes which match the + label selector. A NodeSelector cannot be set in + AppliedTo field or set with any other selector. properties: matchExpressions: description: matchExpressions is a list of label @@ -1748,13 +2032,64 @@ spec: The requirements are ANDed. type: object type: object - serviceAccount: - description: Select all Pods with the ServiceAccount - matched by this field, as workloads in AppliedTo/To/From - fields. Cannot be set with any other selector. + podSelector: + description: Select Pods from NetworkPolicy's Namespace + as workloads in AppliedTo/To/From fields. If set + with NamespaceSelector, Pods are matched from Namespaces + matched by the NamespaceSelector. Cannot be set + with any other selector except NamespaceSelector. properties: - name: - type: string + matchExpressions: + description: matchExpressions is a list of label + selector requirements. The requirements are + ANDed. + items: + description: A label selector requirement is + a selector that contains values, a key, and + an operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If + the operator is Exists or DoesNotExist, + the values array must be empty. This array + is replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, + whose key field is "key", the operator is "In", + and the values array contains only "value". + The requirements are ANDed. + type: object + type: object + serviceAccount: + description: Select all Pods with the ServiceAccount + matched by this field, as workloads in AppliedTo/To/From + fields. Cannot be set with any other selector. + properties: + name: + type: string namespace: type: string type: object @@ -1765,9 +2100,9 @@ spec: Name should be unique within the policy. type: string ports: - description: Set of port and protocol allowed/denied by - the rule. If this field is unset or empty, this rule matches - all ports. + description: Set of ports and protocols matched by the rule. + If this field and Protocols are unset or empty, this rule + matches all ports. items: description: NetworkPolicyPort describes the port and protocol to match in a rule. @@ -1795,6 +2130,30 @@ spec: type: string type: object type: array + protocols: + description: Set of protocols matched by the rule. If this + field and Ports are unset or empty, this rule matches + all protocols supported. + items: + description: NetworkPolicyProtocol defines additional + protocols that are not supported by `ports`. All fields + should be used as a standalone field. + properties: + icmp: + description: ICMPProtocol matches ICMP traffic with + specific ICMPType and/or ICMPCode. All fields could + be used alone or together. If all fields are not + provided, this matches all ICMP traffic. + properties: + icmpCode: + format: int32 + type: integer + icmpType: + format: int32 + type: integer + type: object + type: object + type: array to: description: Rule is matched if traffic is intended for workloads selected by this field. This field can't be @@ -1949,6 +2308,55 @@ spec: matching strategy. type: string type: object + nodeSelector: + description: Select certain Nodes which match the + label selector. A NodeSelector cannot be set in + AppliedTo field or set with any other selector. + properties: + matchExpressions: + description: matchExpressions is a list of label + selector requirements. The requirements are + ANDed. + items: + description: A label selector requirement is + a selector that contains values, a key, and + an operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If + the operator is Exists or DoesNotExist, + the values array must be empty. This array + is replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, + whose key field is "key", the operator is "In", + and the values array contains only "value". + The requirements are ANDed. + type: object + type: object podSelector: description: Select Pods from NetworkPolicy's Namespace as workloads in AppliedTo/To/From fields. If set @@ -2049,7 +2457,7 @@ spec: - priority type: object endpoints: - description: If exported resource is EndPoints. + description: If exported resource is Endpoints. properties: subsets: items: @@ -2218,11 +2626,9 @@ spec: description: The application protocol for this port. This field follows standard Kubernetes label syntax. Un-prefixed names are reserved for IANA standard - service names (as per RFC-6335 and http://www.iana.org/assignments/service-names). + service names (as per RFC-6335 and https://www.iana.org/assignments/service-names). Non-standard protocols should use prefixed names - such as mycompany.com/my-custom-protocol. This is - a beta field that is guarded by the ServiceAppProtocol - feature gate and enabled by default. + such as mycompany.com/my-custom-protocol. type: string name: description: The name of this port. This must match @@ -2307,7 +2713,7 @@ spec: description: Namespace of exported resource. type: string raw: - description: If exported resource Kind is unknown. + description: If exported resource kind is unknown. properties: data: format: byte @@ -2324,11 +2730,11 @@ spec: description: allocateLoadBalancerNodePorts defines if NodePorts will be automatically allocated for services with type LoadBalancer. Default is "true". It may be set to "false" if the cluster load-balancer - does not rely on NodePorts. allocateLoadBalancerNodePorts - may only be set for services with type LoadBalancer and - will be cleared if the type is changed to any other type. - This field is alpha-level and is only honored by servers - that enable the ServiceLBNodePortControl feature. + does not rely on NodePorts. If the caller requests specific + NodePorts (by specifying a value), those requests will be + respected, regardless of this field. This field may only + be set for services with type LoadBalancer and will be cleared + if the type is changed to any other type. type: boolean clusterIP: description: 'clusterIP is the IP address of the service and @@ -2371,14 +2777,11 @@ spec: a Service to type ExternalName. If this field is not specified, it will be initialized from the clusterIP field. If this field is specified, clients must ensure that clusterIPs[0] - and clusterIP have the same value. \n Unless the \"IPv6DualStack\" - feature gate is enabled, this field is limited to one value, - which must be the same as the clusterIP field. If the feature - gate is enabled, this field may hold a maximum of two entries - (dual-stack IPs, in either order). These IPs must correspond - to the values of the ipFamilies field. Both clusterIPs and - ipFamilies are governed by the ipFamilyPolicy field. More - info: https://kubernetes.io/docs/concepts/services-networking/service/#virtual-ips-and-service-proxies" + and clusterIP have the same value. \n This field may hold + a maximum of two entries (dual-stack IPs, in either order). + These IPs must correspond to the values of the ipFamilies + field. Both clusterIPs and ipFamilies are governed by the + ipFamilyPolicy field. More info: https://kubernetes.io/docs/concepts/services-networking/service/#virtual-ips-and-service-proxies" items: type: string type: array @@ -2433,18 +2836,17 @@ spec: type: string ipFamilies: description: "IPFamilies is a list of IP families (e.g. IPv4, - IPv6) assigned to this service, and is gated by the \"IPv6DualStack\" - feature gate. This field is usually assigned automatically - based on cluster configuration and the ipFamilyPolicy field. - If this field is specified manually, the requested family - is available in the cluster, and ipFamilyPolicy allows it, - it will be used; otherwise creation of the service will - fail. This field is conditionally mutable: it allows for + IPv6) assigned to this service. This field is usually assigned + automatically based on cluster configuration and the ipFamilyPolicy + field. If this field is specified manually, the requested + family is available in the cluster, and ipFamilyPolicy allows + it, it will be used; otherwise creation of the service will + fail. This field is conditionally mutable: it allows for adding or removing a secondary IP family, but it does not - allow changing the primary IP family of the Service. Valid + allow changing the primary IP family of the Service. Valid values are \"IPv4\" and \"IPv6\". This field only applies to Services of types ClusterIP, NodePort, and LoadBalancer, - and does apply to \"headless\" services. This field will + and does apply to \"headless\" services. This field will be wiped when updating a Service to type ExternalName. \n This field may hold a maximum of two entries (dual-stack families, in either order). These families must correspond @@ -2460,15 +2862,14 @@ spec: x-kubernetes-list-type: atomic ipFamilyPolicy: description: IPFamilyPolicy represents the dual-stack-ness - requested or required by this Service, and is gated by the - "IPv6DualStack" feature gate. If there is no value provided, - then this field will be set to SingleStack. Services can - be "SingleStack" (a single IP family), "PreferDualStack" + requested or required by this Service. If there is no value + provided, then this field will be set to SingleStack. Services + can be "SingleStack" (a single IP family), "PreferDualStack" (two IP families on dual-stack configured clusters or a single IP family on single-stack clusters), or "RequireDualStack" (two IP families on dual-stack configured clusters, otherwise fail). The ipFamilies and clusterIPs fields depend on the - value of this field. This field will be wiped when updating + value of this field. This field will be wiped when updating a service to type ExternalName. type: string loadBalancerClass: @@ -2490,19 +2891,23 @@ spec: when a service is updated to a non 'LoadBalancer' type. type: string loadBalancerIP: - description: 'Only applies to Service Type: LoadBalancer LoadBalancer - will get created with the IP specified in this field. This - feature depends on whether the underlying cloud-provider + description: 'Only applies to Service Type: LoadBalancer. + This feature depends on whether the underlying cloud-provider supports specifying the loadBalancerIP when a load balancer is created. This field will be ignored if the cloud-provider - does not support the feature.' + does not support the feature. Deprecated: This field was + under-specified and its meaning varies across implementations, + and it cannot support dual-stack. As of Kubernetes v1.24, + users are encouraged to use implementation-specific annotations + when available. This field may be removed in a future API + version.' type: string loadBalancerSourceRanges: description: 'If specified and supported by the platform, this will restrict traffic through the cloud-provider load-balancer will be restricted to the specified client IPs. This field will be ignored if the cloud-provider does not support the - feature." More info: https://kubernetes.io/docs/tasks/access-application-cluster/configure-cloud-provider-firewall/' + feature." More info: https://kubernetes.io/docs/tasks/access-application-cluster/create-external-load-balancer/' items: type: string type: array @@ -2517,11 +2922,9 @@ spec: description: The application protocol for this port. This field follows standard Kubernetes label syntax. Un-prefixed names are reserved for IANA standard service - names (as per RFC-6335 and http://www.iana.org/assignments/service-names). + names (as per RFC-6335 and https://www.iana.org/assignments/service-names). Non-standard protocols should use prefixed names such - as mycompany.com/my-custom-protocol. This is a beta - field that is guarded by the ServiceAppProtocol feature - gate and enabled by default. + as mycompany.com/my-custom-protocol. type: string name: description: The name of this port within the service. @@ -2598,6 +3001,7 @@ spec: to types ClusterIP, NodePort, and LoadBalancer. Ignored if type is ExternalName. More info: https://kubernetes.io/docs/concepts/services-networking/service/' type: object + x-kubernetes-map-type: atomic sessionAffinity: description: 'Supports "ClientIP" and "None". Used to maintain session affinity. Enable client IP based session affinity. @@ -2620,26 +3024,6 @@ spec: type: integer type: object type: object - topologyKeys: - description: topologyKeys is a preference-order list of topology - keys which implementations of services should use to preferentially - sort endpoints when accessing this Service, it can not be - used at the same time as externalTrafficPolicy=Local. Topology - keys must be valid label keys and at most 16 keys may be - specified. Endpoints are chosen based on the first topology - key with available backends. If this field is specified - and all entries have no backends that match the topology - of the client, the service has no backends for that client - and connections should fail. The special value "*" may be - used to mean "any topology". This catch-all value, if used, - only makes sense as the last value in the list. If this - is not specified or empty, no topology constraints will - be applied. This field is alpha-level and is only honored - by servers that enable the ServiceTopology feature. This - field is deprecated and will be removed in a future version. - items: - type: string - type: array type: description: 'type determines how the Service is exposed. Defaults to ClusterIP. Valid options are ExternalName, ClusterIP, @@ -2801,6 +3185,25 @@ spec: items: type: string type: array + clusterinfo: + description: If imported resource is ClusterInfo. + properties: + clusterID: + description: ClusterID of the member cluster. + type: string + gatewayInfos: + description: GatewayInfos has information of Gateways + items: + description: GatewayInfo includes information of a Gateway. + properties: + gatewayIP: + type: string + type: object + type: array + serviceCIDR: + description: ServiceCIDR is the IP ranges used by Service ClusterIP. + type: string + type: object clusternetworkpolicy: description: If imported resource is AntreaClusterNetworkPolicy. properties: @@ -2951,6 +3354,53 @@ spec: matching strategy. type: string type: object + nodeSelector: + description: Select certain Nodes which match the label + selector. A NodeSelector cannot be set in AppliedTo field + or set with any other selector. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, + NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values array + must be non-empty. If the operator is Exists + or DoesNotExist, the values array must be empty. + This array is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} pairs. + A single {key,value} in the matchLabels map is equivalent + to an element of matchExpressions, whose key field + is "key", the operator is "In", and the values array + contains only "value". The requirements are ANDed. + type: object + type: object podSelector: description: Select Pods from NetworkPolicy's Namespace as workloads in AppliedTo/To/From fields. If set with @@ -3178,6 +3628,55 @@ spec: matching strategy. type: string type: object + nodeSelector: + description: Select certain Nodes which match the + label selector. A NodeSelector cannot be set in + AppliedTo field or set with any other selector. + properties: + matchExpressions: + description: matchExpressions is a list of label + selector requirements. The requirements are + ANDed. + items: + description: A label selector requirement is + a selector that contains values, a key, and + an operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If + the operator is Exists or DoesNotExist, + the values array must be empty. This array + is replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, + whose key field is "key", the operator is "In", + and the values array contains only "value". + The requirements are ANDed. + type: object + type: object podSelector: description: Select Pods from NetworkPolicy's Namespace as workloads in AppliedTo/To/From fields. If set @@ -3399,6 +3898,55 @@ spec: matching strategy. type: string type: object + nodeSelector: + description: Select certain Nodes which match the + label selector. A NodeSelector cannot be set in + AppliedTo field or set with any other selector. + properties: + matchExpressions: + description: matchExpressions is a list of label + selector requirements. The requirements are + ANDed. + items: + description: A label selector requirement is + a selector that contains values, a key, and + an operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If + the operator is Exists or DoesNotExist, + the values array must be empty. This array + is replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, + whose key field is "key", the operator is "In", + and the values array contains only "value". + The requirements are ANDed. + type: object + type: object podSelector: description: Select Pods from NetworkPolicy's Namespace as workloads in AppliedTo/To/From fields. If set @@ -3467,9 +4015,9 @@ spec: Name should be unique within the policy. type: string ports: - description: Set of port and protocol allowed/denied by - the rule. If this field is unset or empty, this rule matches - all ports. + description: Set of ports and protocols matched by the rule. + If this field and Protocols are unset or empty, this rule + matches all ports. items: description: NetworkPolicyPort describes the port and protocol to match in a rule. @@ -3497,6 +4045,30 @@ spec: type: string type: object type: array + protocols: + description: Set of protocols matched by the rule. If this + field and Ports are unset or empty, this rule matches + all protocols supported. + items: + description: NetworkPolicyProtocol defines additional + protocols that are not supported by `ports`. All fields + should be used as a standalone field. + properties: + icmp: + description: ICMPProtocol matches ICMP traffic with + specific ICMPType and/or ICMPCode. All fields could + be used alone or together. If all fields are not + provided, this matches all ICMP traffic. + properties: + icmpCode: + format: int32 + type: integer + icmpType: + format: int32 + type: integer + type: object + type: object + type: array to: description: Rule is matched if traffic is intended for workloads selected by this field. This field can't be @@ -3651,6 +4223,55 @@ spec: matching strategy. type: string type: object + nodeSelector: + description: Select certain Nodes which match the + label selector. A NodeSelector cannot be set in + AppliedTo field or set with any other selector. + properties: + matchExpressions: + description: matchExpressions is a list of label + selector requirements. The requirements are + ANDed. + items: + description: A label selector requirement is + a selector that contains values, a key, and + an operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If + the operator is Exists or DoesNotExist, + the values array must be empty. This array + is replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, + whose key field is "key", the operator is "In", + and the values array contains only "value". + The requirements are ANDed. + type: object + type: object podSelector: description: Select Pods from NetworkPolicy's Namespace as workloads in AppliedTo/To/From fields. If set @@ -3901,6 +4522,55 @@ spec: matching strategy. type: string type: object + nodeSelector: + description: Select certain Nodes which match the + label selector. A NodeSelector cannot be set in + AppliedTo field or set with any other selector. + properties: + matchExpressions: + description: matchExpressions is a list of label + selector requirements. The requirements are + ANDed. + items: + description: A label selector requirement is + a selector that contains values, a key, and + an operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If + the operator is Exists or DoesNotExist, + the values array must be empty. This array + is replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, + whose key field is "key", the operator is "In", + and the values array contains only "value". + The requirements are ANDed. + type: object + type: object podSelector: description: Select Pods from NetworkPolicy's Namespace as workloads in AppliedTo/To/From fields. If set @@ -4122,6 +4792,55 @@ spec: matching strategy. type: string type: object + nodeSelector: + description: Select certain Nodes which match the + label selector. A NodeSelector cannot be set in + AppliedTo field or set with any other selector. + properties: + matchExpressions: + description: matchExpressions is a list of label + selector requirements. The requirements are + ANDed. + items: + description: A label selector requirement is + a selector that contains values, a key, and + an operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If + the operator is Exists or DoesNotExist, + the values array must be empty. This array + is replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, + whose key field is "key", the operator is "In", + and the values array contains only "value". + The requirements are ANDed. + type: object + type: object podSelector: description: Select Pods from NetworkPolicy's Namespace as workloads in AppliedTo/To/From fields. If set @@ -4190,9 +4909,9 @@ spec: Name should be unique within the policy. type: string ports: - description: Set of port and protocol allowed/denied by - the rule. If this field is unset or empty, this rule matches - all ports. + description: Set of ports and protocols matched by the rule. + If this field and Protocols are unset or empty, this rule + matches all ports. items: description: NetworkPolicyPort describes the port and protocol to match in a rule. @@ -4220,6 +4939,30 @@ spec: type: string type: object type: array + protocols: + description: Set of protocols matched by the rule. If this + field and Ports are unset or empty, this rule matches + all protocols supported. + items: + description: NetworkPolicyProtocol defines additional + protocols that are not supported by `ports`. All fields + should be used as a standalone field. + properties: + icmp: + description: ICMPProtocol matches ICMP traffic with + specific ICMPType and/or ICMPCode. All fields could + be used alone or together. If all fields are not + provided, this matches all ICMP traffic. + properties: + icmpCode: + format: int32 + type: integer + icmpType: + format: int32 + type: integer + type: object + type: object + type: array to: description: Rule is matched if traffic is intended for workloads selected by this field. This field can't be @@ -4374,6 +5117,55 @@ spec: matching strategy. type: string type: object + nodeSelector: + description: Select certain Nodes which match the + label selector. A NodeSelector cannot be set in + AppliedTo field or set with any other selector. + properties: + matchExpressions: + description: matchExpressions is a list of label + selector requirements. The requirements are + ANDed. + items: + description: A label selector requirement is + a selector that contains values, a key, and + an operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If + the operator is Exists or DoesNotExist, + the values array must be empty. This array + is replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, + whose key field is "key", the operator is "In", + and the values array contains only "value". + The requirements are ANDed. + type: object + type: object podSelector: description: Select Pods from NetworkPolicy's Namespace as workloads in AppliedTo/To/From fields. If set @@ -4643,11 +5435,9 @@ spec: description: The application protocol for this port. This field follows standard Kubernetes label syntax. Un-prefixed names are reserved for IANA standard - service names (as per RFC-6335 and http://www.iana.org/assignments/service-names). + service names (as per RFC-6335 and https://www.iana.org/assignments/service-names). Non-standard protocols should use prefixed names - such as mycompany.com/my-custom-protocol. This is - a beta field that is guarded by the ServiceAppProtocol - feature gate and enabled by default. + such as mycompany.com/my-custom-protocol. type: string name: description: The name of this port. This must match @@ -4735,7 +5525,7 @@ spec: description: 'If imported resource is ANP. TODO: ANP uses float64 as priority. Type float64 is discouraged by k8s, and is not supported by controller-gen tools. NetworkPolicy *v1alpha1.NetworkPolicySpec - `json:"networkpolicy,omitempty"` If imported resource Kind is unknown.' + `json:"networkpolicy,omitempty"` If imported resource kind is unknown.' properties: data: format: byte diff --git a/multicluster/build/yamls/antrea-multicluster-leader-namespaced.yml b/multicluster/build/yamls/antrea-multicluster-leader-namespaced.yml index 6f9c9b20351..05fb21eb247 100644 --- a/multicluster/build/yamls/antrea-multicluster-leader-namespaced.yml +++ b/multicluster/build/yamls/antrea-multicluster-leader-namespaced.yml @@ -370,11 +370,13 @@ data: resourceName: 6536456a.crd.antrea.io leaseDuration: "30s" renewDeadline: "20s" + serviceCIDR: "" + gatewayIPPrecedence: "private" kind: ConfigMap metadata: labels: app: antrea - name: antrea-mc-controller-config-49875k4ht8 + name: antrea-mc-controller-config-t2b9525b7f namespace: changeme --- apiVersion: v1 @@ -443,12 +445,8 @@ spec: initialDelaySeconds: 5 periodSeconds: 10 resources: - limits: - cpu: 100m - memory: 30Mi requests: - cpu: 100m - memory: 20Mi + cpu: 200m securityContext: allowPrivilegeEscalation: false volumeMounts: @@ -459,7 +457,7 @@ spec: terminationGracePeriodSeconds: 10 volumes: - configMap: - name: antrea-mc-controller-config-49875k4ht8 + name: antrea-mc-controller-config-t2b9525b7f name: antrea-mc-controller-config --- apiVersion: admissionregistration.k8s.io/v1 diff --git a/multicluster/build/yamls/antrea-multicluster-member.yml b/multicluster/build/yamls/antrea-multicluster-member.yml index 1add441ba35..b39efe350f0 100644 --- a/multicluster/build/yamls/antrea-multicluster-member.yml +++ b/multicluster/build/yamls/antrea-multicluster-member.yml @@ -51,6 +51,100 @@ status: --- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.4.1 + creationTimestamp: null + labels: + app: antrea + name: clusterinfoimports.multicluster.crd.antrea.io +spec: + group: multicluster.crd.antrea.io + names: + kind: ClusterInfoImport + listKind: ClusterInfoImportList + plural: clusterinfoimports + singular: clusterinfoimport + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + properties: + clusterID: + description: ClusterID of the member cluster. + type: string + gatewayInfos: + description: GatewayInfos has information of Gateways + items: + description: GatewayInfo includes information of a Gateway. + properties: + gatewayIP: + type: string + type: object + type: array + serviceCIDR: + description: ServiceCIDR is the IP ranges used by Service ClusterIP. + type: string + type: object + status: + description: ClusterInfoImportStatus defines the observed state of ClusterInfoImport. + properties: + conditions: + items: + description: ResourceCondition indicates the readiness condition + of a Resource. + properties: + lastTransitionTime: + description: Last time the condition transited from one status + to another. + format: date-time + type: string + message: + description: A human readable message indicating details about + the transition. + type: string + reason: + description: Unique, one-word, CamelCase reason for the condition's + last transition. + type: string + status: + description: Status of the condition, one of True, False, Unknown. + type: string + type: + description: Type is the type of the condition. + type: string + type: object + type: array + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.4.1 @@ -226,6 +320,60 @@ status: --- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.4.1 + creationTimestamp: null + labels: + app: antrea + name: gateways.multicluster.crd.antrea.io +spec: + group: multicluster.crd.antrea.io + names: + kind: Gateway + listKind: GatewayList + plural: gateways + singular: gateway + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: Gateway includes information of a Multi-cluster Gateway. + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + gatewayIP: + description: Tunnel IP of the Gateway. It might be assigned by user manually + through a Node annotation. + type: string + internalIP: + description: Internal tunnel IP of the Gateway. + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.4.1 @@ -643,6 +791,14 @@ rules: verbs: - get - update +- apiGroups: + - "" + resources: + - nodes + verbs: + - get + - list + - watch - apiGroups: - "" resources: @@ -817,6 +973,58 @@ rules: - get - patch - update +- apiGroups: + - multicluster.crd.antrea.io + resources: + - clusterinfoimports + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - multicluster.crd.antrea.io + resources: + - clusterinfoimports/finalizers + verbs: + - update +- apiGroups: + - multicluster.crd.antrea.io + resources: + - clusterinfoimports/status + verbs: + - get + - patch + - update +- apiGroups: + - multicluster.crd.antrea.io + resources: + - gateways + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - multicluster.crd.antrea.io + resources: + - gateways/finalizers + verbs: + - update +- apiGroups: + - multicluster.crd.antrea.io + resources: + - gateways/status + verbs: + - get + - patch + - update --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding @@ -849,11 +1057,13 @@ data: resourceName: 6536456a.crd.antrea.io leaseDuration: "30s" renewDeadline: "20s" + serviceCIDR: "" + gatewayIPPrecedence: "private" kind: ConfigMap metadata: labels: app: antrea - name: antrea-mc-controller-config-49875k4ht8 + name: antrea-mc-controller-config-t2b9525b7f namespace: kube-system --- apiVersion: v1 @@ -922,12 +1132,8 @@ spec: initialDelaySeconds: 5 periodSeconds: 10 resources: - limits: - cpu: 100m - memory: 30Mi requests: - cpu: 100m - memory: 20Mi + cpu: 200m securityContext: allowPrivilegeEscalation: false volumeMounts: @@ -938,7 +1144,7 @@ spec: terminationGracePeriodSeconds: 10 volumes: - configMap: - name: antrea-mc-controller-config-49875k4ht8 + name: antrea-mc-controller-config-t2b9525b7f name: antrea-mc-controller-config --- apiVersion: admissionregistration.k8s.io/v1 diff --git a/multicluster/cmd/multicluster-controller/controller.go b/multicluster/cmd/multicluster-controller/controller.go index 13fee7972c5..c3dbaab2ab8 100644 --- a/multicluster/cmd/multicluster-controller/controller.go +++ b/multicluster/cmd/multicluster-controller/controller.go @@ -17,6 +17,7 @@ limitations under the License. package main import ( + "context" "fmt" "time" @@ -133,7 +134,7 @@ func setupManagerAndCertController(o *Options) (manager.Manager, error) { if err != nil { return nil, fmt.Errorf("error applying server cert: %v", err) } - if err := caCertController.RunOnce(); err != nil { + if err := caCertController.RunOnce(context.TODO()); err != nil { return nil, err } diff --git a/multicluster/cmd/multicluster-controller/leader.go b/multicluster/cmd/multicluster-controller/leader.go index 62cb22bfdfb..e2f281d4bdc 100644 --- a/multicluster/cmd/multicluster-controller/leader.go +++ b/multicluster/cmd/multicluster-controller/leader.go @@ -25,6 +25,7 @@ import ( multiclusterv1alpha1 "antrea.io/antrea/multicluster/apis/multicluster/v1alpha1" multiclustercontrollers "antrea.io/antrea/multicluster/controllers/multicluster" + "antrea.io/antrea/pkg/log" "antrea.io/antrea/pkg/util/env" ) @@ -34,6 +35,8 @@ func newLeaderCommand() *cobra.Command { Short: "Run the MC controller in leader cluster", Long: "Run the Antrea Multi-Cluster controller for leader cluster", Run: func(cmd *cobra.Command, args []string) { + log.InitLogs(cmd.Flags()) + defer log.FlushLogs() if err := opts.complete(args); err != nil { klog.Fatalf("Failed to complete: %v", err) } diff --git a/multicluster/cmd/multicluster-controller/main.go b/multicluster/cmd/multicluster-controller/main.go index 006cb2ed54a..e2f20a8fd49 100644 --- a/multicluster/cmd/multicluster-controller/main.go +++ b/multicluster/cmd/multicluster-controller/main.go @@ -23,7 +23,8 @@ import ( "github.com/spf13/cobra" "k8s.io/apimachinery/pkg/runtime" - "k8s.io/component-base/logs" + + "antrea.io/antrea/pkg/log" ) var ( @@ -32,28 +33,24 @@ var ( ) func main() { - logs.InitLogs() - defer logs.FlushLogs() - command := newControllerCommand() + flags := command.PersistentFlags() + opts.addFlags(flags) + log.AddFlags(flags) command.AddCommand(newLeaderCommand()) command.AddCommand(newMemberCommand()) if err := command.Execute(); err != nil { - logs.FlushLogs() os.Exit(1) } } func newControllerCommand() *cobra.Command { - cmd := &cobra.Command{ + return &cobra.Command{ Use: "antrea-mc-controller", Long: "The Antrea MultiCluster Controller.", Run: func(cmd *cobra.Command, args []string) { fmt.Println("Error: must be run in leader or member mode") }, } - flags := cmd.PersistentFlags() - opts.addFlags(flags) - return cmd } diff --git a/multicluster/cmd/multicluster-controller/member.go b/multicluster/cmd/multicluster-controller/member.go index aef55f97666..711037f395e 100644 --- a/multicluster/cmd/multicluster-controller/member.go +++ b/multicluster/cmd/multicluster-controller/member.go @@ -23,6 +23,7 @@ import ( ctrl "sigs.k8s.io/controller-runtime" multiclustercontrollers "antrea.io/antrea/multicluster/controllers/multicluster" + "antrea.io/antrea/pkg/log" "antrea.io/antrea/pkg/signals" "antrea.io/antrea/pkg/util/env" ) @@ -33,6 +34,8 @@ func newMemberCommand() *cobra.Command { Short: "Run the MC controller in member cluster", Long: "Run the Antrea Multi-Cluster controller for member cluster", Run: func(cmd *cobra.Command, args []string) { + log.InitLogs(cmd.Flags()) + defer log.FlushLogs() if err := opts.complete(args); err != nil { klog.Fatalf("Failed to complete: %v", err) } @@ -51,28 +54,48 @@ func runMember(o *Options) error { return err } - clusterSetReconciler := &multiclustercontrollers.MemberClusterSetReconciler{ - Client: mgr.GetClient(), - Scheme: mgr.GetScheme(), - Namespace: env.GetPodNamespace(), - } + clusterSetReconciler := multiclustercontrollers.NewMemberClusterSetReconciler(mgr.GetClient(), + mgr.GetScheme(), + env.GetPodNamespace(), + ) if err = clusterSetReconciler.SetupWithManager(mgr); err != nil { return fmt.Errorf("error creating ClusterSet controller: %v", err) } + commonAreaGetter := clusterSetReconciler svcExportReconciler := multiclustercontrollers.NewServiceExportReconciler( mgr.GetClient(), mgr.GetScheme(), - &clusterSetReconciler.RemoteCommonAreaManager) + commonAreaGetter) if err = svcExportReconciler.SetupWithManager(mgr); err != nil { return fmt.Errorf("error creating ServiceExport controller: %v", err) } + gwReconciler := multiclustercontrollers.NewGatewayReconciler( + mgr.GetClient(), + mgr.GetScheme(), + env.GetPodNamespace(), + opts.ServiceCIDR, + commonAreaGetter) + if err = gwReconciler.SetupWithManager(mgr); err != nil { + return fmt.Errorf("error creating Gateway controller: %v", err) + } + + nodeReconciler := multiclustercontrollers.NewNodeReconciler( + mgr.GetClient(), + mgr.GetScheme(), + env.GetPodNamespace(), + opts.GatewayIPPrecedence) + if err = nodeReconciler.SetupWithManager(mgr); err != nil { + return fmt.Errorf("error creating Node controller: %v", err) + } + stopCh := signals.RegisterSignalHandlers() - staleController := multiclustercontrollers.NewStaleController( + staleController := multiclustercontrollers.NewStaleResCleanupController( mgr.GetClient(), mgr.GetScheme(), - &clusterSetReconciler.RemoteCommonAreaManager) + env.GetPodNamespace(), + commonAreaGetter) go staleController.Run(stopCh) // Member runs ResourceImportReconciler from RemoteCommonArea only diff --git a/multicluster/cmd/multicluster-controller/options.go b/multicluster/cmd/multicluster-controller/options.go index 82d0c38b958..e179dcef2fa 100644 --- a/multicluster/cmd/multicluster-controller/options.go +++ b/multicluster/cmd/multicluster-controller/options.go @@ -16,6 +16,7 @@ package main import ( "fmt" + "net" "time" "github.com/spf13/pflag" @@ -30,6 +31,11 @@ type Options struct { configFile string SelfSignedCert bool options ctrl.Options + // The Service ClusterIP range used in the member cluster. + ServiceCIDR string + // The precedence about which IP (private or public one) of Node is preferred to + // be used as tunnel endpoint. If not specified, private IP will be chosen. + GatewayIPPrecedence mcsv1alpha1.Precedence } func newOptions() *Options { @@ -51,6 +57,13 @@ func (o *Options) complete(args []string) error { return fmt.Errorf("failed to load options from configuration file %s", o.configFile) } o.options = options + if ctrlConfig.ServiceCIDR != "" { + if _, _, err := net.ParseCIDR(ctrlConfig.ServiceCIDR); err != nil { + return fmt.Errorf("failed to parse serviceCIDR, invalid CIDR string %s", ctrlConfig.ServiceCIDR) + } + } + o.ServiceCIDR = ctrlConfig.ServiceCIDR + o.GatewayIPPrecedence = ctrlConfig.GatewayIPPrecedence klog.InfoS("Using config from file", "config", o.options) } else { klog.InfoS("Using default config", "config", o.options) diff --git a/multicluster/config/crd/bases/multicluster.crd.antrea.io_clusterinfoimports.yaml b/multicluster/config/crd/bases/multicluster.crd.antrea.io_clusterinfoimports.yaml new file mode 100644 index 00000000000..12800d0961e --- /dev/null +++ b/multicluster/config/crd/bases/multicluster.crd.antrea.io_clusterinfoimports.yaml @@ -0,0 +1,93 @@ + +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.4.1 + creationTimestamp: null + name: clusterinfoimports.multicluster.crd.antrea.io +spec: + group: multicluster.crd.antrea.io + names: + kind: ClusterInfoImport + listKind: ClusterInfoImportList + plural: clusterinfoimports + singular: clusterinfoimport + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + properties: + clusterID: + description: ClusterID of the member cluster. + type: string + gatewayInfos: + description: GatewayInfos has information of Gateways + items: + description: GatewayInfo includes information of a Gateway. + properties: + gatewayIP: + type: string + type: object + type: array + serviceCIDR: + description: ServiceCIDR is the IP ranges used by Service ClusterIP. + type: string + type: object + status: + description: ClusterInfoImportStatus defines the observed state of ClusterInfoImport. + properties: + conditions: + items: + description: ResourceCondition indicates the readiness condition + of a Resource. + properties: + lastTransitionTime: + description: Last time the condition transited from one status + to another. + format: date-time + type: string + message: + description: A human readable message indicating details about + the transition. + type: string + reason: + description: Unique, one-word, CamelCase reason for the condition's + last transition. + type: string + status: + description: Status of the condition, one of True, False, Unknown. + type: string + type: + description: Type is the type of the condition. + type: string + type: object + type: array + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] diff --git a/multicluster/config/crd/bases/multicluster.crd.antrea.io_gateways.yaml b/multicluster/config/crd/bases/multicluster.crd.antrea.io_gateways.yaml new file mode 100644 index 00000000000..77f2f39ad65 --- /dev/null +++ b/multicluster/config/crd/bases/multicluster.crd.antrea.io_gateways.yaml @@ -0,0 +1,53 @@ + +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.4.1 + creationTimestamp: null + name: gateways.multicluster.crd.antrea.io +spec: + group: multicluster.crd.antrea.io + names: + kind: Gateway + listKind: GatewayList + plural: gateways + singular: gateway + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: Gateway includes information of a Multi-cluster Gateway. + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + gatewayIP: + description: Tunnel IP of the Gateway. It might be assigned by user manually + through a Node annotation. + type: string + internalIP: + description: Internal tunnel IP of the Gateway. + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] diff --git a/multicluster/config/crd/bases/multicluster.crd.antrea.io_resourceexports.yaml b/multicluster/config/crd/bases/multicluster.crd.antrea.io_resourceexports.yaml index 32993f38ba1..76c7ace9a2d 100644 --- a/multicluster/config/crd/bases/multicluster.crd.antrea.io_resourceexports.yaml +++ b/multicluster/config/crd/bases/multicluster.crd.antrea.io_resourceexports.yaml @@ -40,6 +40,25 @@ spec: description: ClusterID specifies the member cluster this resource exported from. type: string + clusterinfo: + description: If exported resource is ClusterInfo. + properties: + clusterID: + description: ClusterID of the member cluster. + type: string + gatewayInfos: + description: GatewayInfos has information of Gateways + items: + description: GatewayInfo includes information of a Gateway. + properties: + gatewayIP: + type: string + type: object + type: array + serviceCIDR: + description: ServiceCIDR is the IP ranges used by Service ClusterIP. + type: string + type: object clusternetworkpolicy: description: If exported resource is AntreaClusterNetworkPolicy. properties: @@ -190,6 +209,53 @@ spec: matching strategy. type: string type: object + nodeSelector: + description: Select certain Nodes which match the label + selector. A NodeSelector cannot be set in AppliedTo field + or set with any other selector. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, + NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values array + must be non-empty. If the operator is Exists + or DoesNotExist, the values array must be empty. + This array is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} pairs. + A single {key,value} in the matchLabels map is equivalent + to an element of matchExpressions, whose key field + is "key", the operator is "In", and the values array + contains only "value". The requirements are ANDed. + type: object + type: object podSelector: description: Select Pods from NetworkPolicy's Namespace as workloads in AppliedTo/To/From fields. If set with @@ -417,6 +483,55 @@ spec: matching strategy. type: string type: object + nodeSelector: + description: Select certain Nodes which match the + label selector. A NodeSelector cannot be set in + AppliedTo field or set with any other selector. + properties: + matchExpressions: + description: matchExpressions is a list of label + selector requirements. The requirements are + ANDed. + items: + description: A label selector requirement is + a selector that contains values, a key, and + an operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If + the operator is Exists or DoesNotExist, + the values array must be empty. This array + is replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, + whose key field is "key", the operator is "In", + and the values array contains only "value". + The requirements are ANDed. + type: object + type: object podSelector: description: Select Pods from NetworkPolicy's Namespace as workloads in AppliedTo/To/From fields. If set @@ -638,6 +753,55 @@ spec: matching strategy. type: string type: object + nodeSelector: + description: Select certain Nodes which match the + label selector. A NodeSelector cannot be set in + AppliedTo field or set with any other selector. + properties: + matchExpressions: + description: matchExpressions is a list of label + selector requirements. The requirements are + ANDed. + items: + description: A label selector requirement is + a selector that contains values, a key, and + an operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If + the operator is Exists or DoesNotExist, + the values array must be empty. This array + is replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, + whose key field is "key", the operator is "In", + and the values array contains only "value". + The requirements are ANDed. + type: object + type: object podSelector: description: Select Pods from NetworkPolicy's Namespace as workloads in AppliedTo/To/From fields. If set @@ -706,9 +870,9 @@ spec: Name should be unique within the policy. type: string ports: - description: Set of port and protocol allowed/denied by - the rule. If this field is unset or empty, this rule matches - all ports. + description: Set of ports and protocols matched by the rule. + If this field and Protocols are unset or empty, this rule + matches all ports. items: description: NetworkPolicyPort describes the port and protocol to match in a rule. @@ -736,6 +900,30 @@ spec: type: string type: object type: array + protocols: + description: Set of protocols matched by the rule. If this + field and Ports are unset or empty, this rule matches + all protocols supported. + items: + description: NetworkPolicyProtocol defines additional + protocols that are not supported by `ports`. All fields + should be used as a standalone field. + properties: + icmp: + description: ICMPProtocol matches ICMP traffic with + specific ICMPType and/or ICMPCode. All fields could + be used alone or together. If all fields are not + provided, this matches all ICMP traffic. + properties: + icmpCode: + format: int32 + type: integer + icmpType: + format: int32 + type: integer + type: object + type: object + type: array to: description: Rule is matched if traffic is intended for workloads selected by this field. This field can't be @@ -890,6 +1078,55 @@ spec: matching strategy. type: string type: object + nodeSelector: + description: Select certain Nodes which match the + label selector. A NodeSelector cannot be set in + AppliedTo field or set with any other selector. + properties: + matchExpressions: + description: matchExpressions is a list of label + selector requirements. The requirements are + ANDed. + items: + description: A label selector requirement is + a selector that contains values, a key, and + an operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If + the operator is Exists or DoesNotExist, + the values array must be empty. This array + is replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, + whose key field is "key", the operator is "In", + and the values array contains only "value". + The requirements are ANDed. + type: object + type: object podSelector: description: Select Pods from NetworkPolicy's Namespace as workloads in AppliedTo/To/From fields. If set @@ -1140,6 +1377,55 @@ spec: matching strategy. type: string type: object + nodeSelector: + description: Select certain Nodes which match the + label selector. A NodeSelector cannot be set in + AppliedTo field or set with any other selector. + properties: + matchExpressions: + description: matchExpressions is a list of label + selector requirements. The requirements are + ANDed. + items: + description: A label selector requirement is + a selector that contains values, a key, and + an operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If + the operator is Exists or DoesNotExist, + the values array must be empty. This array + is replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, + whose key field is "key", the operator is "In", + and the values array contains only "value". + The requirements are ANDed. + type: object + type: object podSelector: description: Select Pods from NetworkPolicy's Namespace as workloads in AppliedTo/To/From fields. If set @@ -1361,6 +1647,55 @@ spec: matching strategy. type: string type: object + nodeSelector: + description: Select certain Nodes which match the + label selector. A NodeSelector cannot be set in + AppliedTo field or set with any other selector. + properties: + matchExpressions: + description: matchExpressions is a list of label + selector requirements. The requirements are + ANDed. + items: + description: A label selector requirement is + a selector that contains values, a key, and + an operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If + the operator is Exists or DoesNotExist, + the values array must be empty. This array + is replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, + whose key field is "key", the operator is "In", + and the values array contains only "value". + The requirements are ANDed. + type: object + type: object podSelector: description: Select Pods from NetworkPolicy's Namespace as workloads in AppliedTo/To/From fields. If set @@ -1429,9 +1764,9 @@ spec: Name should be unique within the policy. type: string ports: - description: Set of port and protocol allowed/denied by - the rule. If this field is unset or empty, this rule matches - all ports. + description: Set of ports and protocols matched by the rule. + If this field and Protocols are unset or empty, this rule + matches all ports. items: description: NetworkPolicyPort describes the port and protocol to match in a rule. @@ -1459,6 +1794,30 @@ spec: type: string type: object type: array + protocols: + description: Set of protocols matched by the rule. If this + field and Ports are unset or empty, this rule matches + all protocols supported. + items: + description: NetworkPolicyProtocol defines additional + protocols that are not supported by `ports`. All fields + should be used as a standalone field. + properties: + icmp: + description: ICMPProtocol matches ICMP traffic with + specific ICMPType and/or ICMPCode. All fields could + be used alone or together. If all fields are not + provided, this matches all ICMP traffic. + properties: + icmpCode: + format: int32 + type: integer + icmpType: + format: int32 + type: integer + type: object + type: object + type: array to: description: Rule is matched if traffic is intended for workloads selected by this field. This field can't be @@ -1613,6 +1972,55 @@ spec: matching strategy. type: string type: object + nodeSelector: + description: Select certain Nodes which match the + label selector. A NodeSelector cannot be set in + AppliedTo field or set with any other selector. + properties: + matchExpressions: + description: matchExpressions is a list of label + selector requirements. The requirements are + ANDed. + items: + description: A label selector requirement is + a selector that contains values, a key, and + an operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If + the operator is Exists or DoesNotExist, + the values array must be empty. This array + is replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, + whose key field is "key", the operator is "In", + and the values array contains only "value". + The requirements are ANDed. + type: object + type: object podSelector: description: Select Pods from NetworkPolicy's Namespace as workloads in AppliedTo/To/From fields. If set @@ -1713,7 +2121,7 @@ spec: - priority type: object endpoints: - description: If exported resource is EndPoints. + description: If exported resource is Endpoints. properties: subsets: items: @@ -1882,11 +2290,9 @@ spec: description: The application protocol for this port. This field follows standard Kubernetes label syntax. Un-prefixed names are reserved for IANA standard - service names (as per RFC-6335 and http://www.iana.org/assignments/service-names). + service names (as per RFC-6335 and https://www.iana.org/assignments/service-names). Non-standard protocols should use prefixed names - such as mycompany.com/my-custom-protocol. This is - a beta field that is guarded by the ServiceAppProtocol - feature gate and enabled by default. + such as mycompany.com/my-custom-protocol. type: string name: description: The name of this port. This must match @@ -1971,7 +2377,7 @@ spec: description: Namespace of exported resource. type: string raw: - description: If exported resource Kind is unknown. + description: If exported resource kind is unknown. properties: data: format: byte @@ -1988,11 +2394,11 @@ spec: description: allocateLoadBalancerNodePorts defines if NodePorts will be automatically allocated for services with type LoadBalancer. Default is "true". It may be set to "false" if the cluster load-balancer - does not rely on NodePorts. allocateLoadBalancerNodePorts - may only be set for services with type LoadBalancer and - will be cleared if the type is changed to any other type. - This field is alpha-level and is only honored by servers - that enable the ServiceLBNodePortControl feature. + does not rely on NodePorts. If the caller requests specific + NodePorts (by specifying a value), those requests will be + respected, regardless of this field. This field may only + be set for services with type LoadBalancer and will be cleared + if the type is changed to any other type. type: boolean clusterIP: description: 'clusterIP is the IP address of the service and @@ -2035,14 +2441,11 @@ spec: a Service to type ExternalName. If this field is not specified, it will be initialized from the clusterIP field. If this field is specified, clients must ensure that clusterIPs[0] - and clusterIP have the same value. \n Unless the \"IPv6DualStack\" - feature gate is enabled, this field is limited to one value, - which must be the same as the clusterIP field. If the feature - gate is enabled, this field may hold a maximum of two entries - (dual-stack IPs, in either order). These IPs must correspond - to the values of the ipFamilies field. Both clusterIPs and - ipFamilies are governed by the ipFamilyPolicy field. More - info: https://kubernetes.io/docs/concepts/services-networking/service/#virtual-ips-and-service-proxies" + and clusterIP have the same value. \n This field may hold + a maximum of two entries (dual-stack IPs, in either order). + These IPs must correspond to the values of the ipFamilies + field. Both clusterIPs and ipFamilies are governed by the + ipFamilyPolicy field. More info: https://kubernetes.io/docs/concepts/services-networking/service/#virtual-ips-and-service-proxies" items: type: string type: array @@ -2097,18 +2500,17 @@ spec: type: string ipFamilies: description: "IPFamilies is a list of IP families (e.g. IPv4, - IPv6) assigned to this service, and is gated by the \"IPv6DualStack\" - feature gate. This field is usually assigned automatically - based on cluster configuration and the ipFamilyPolicy field. - If this field is specified manually, the requested family - is available in the cluster, and ipFamilyPolicy allows it, - it will be used; otherwise creation of the service will - fail. This field is conditionally mutable: it allows for + IPv6) assigned to this service. This field is usually assigned + automatically based on cluster configuration and the ipFamilyPolicy + field. If this field is specified manually, the requested + family is available in the cluster, and ipFamilyPolicy allows + it, it will be used; otherwise creation of the service will + fail. This field is conditionally mutable: it allows for adding or removing a secondary IP family, but it does not - allow changing the primary IP family of the Service. Valid + allow changing the primary IP family of the Service. Valid values are \"IPv4\" and \"IPv6\". This field only applies to Services of types ClusterIP, NodePort, and LoadBalancer, - and does apply to \"headless\" services. This field will + and does apply to \"headless\" services. This field will be wiped when updating a Service to type ExternalName. \n This field may hold a maximum of two entries (dual-stack families, in either order). These families must correspond @@ -2124,15 +2526,14 @@ spec: x-kubernetes-list-type: atomic ipFamilyPolicy: description: IPFamilyPolicy represents the dual-stack-ness - requested or required by this Service, and is gated by the - "IPv6DualStack" feature gate. If there is no value provided, - then this field will be set to SingleStack. Services can - be "SingleStack" (a single IP family), "PreferDualStack" + requested or required by this Service. If there is no value + provided, then this field will be set to SingleStack. Services + can be "SingleStack" (a single IP family), "PreferDualStack" (two IP families on dual-stack configured clusters or a single IP family on single-stack clusters), or "RequireDualStack" (two IP families on dual-stack configured clusters, otherwise fail). The ipFamilies and clusterIPs fields depend on the - value of this field. This field will be wiped when updating + value of this field. This field will be wiped when updating a service to type ExternalName. type: string loadBalancerClass: @@ -2154,19 +2555,23 @@ spec: when a service is updated to a non 'LoadBalancer' type. type: string loadBalancerIP: - description: 'Only applies to Service Type: LoadBalancer LoadBalancer - will get created with the IP specified in this field. This - feature depends on whether the underlying cloud-provider + description: 'Only applies to Service Type: LoadBalancer. + This feature depends on whether the underlying cloud-provider supports specifying the loadBalancerIP when a load balancer is created. This field will be ignored if the cloud-provider - does not support the feature.' + does not support the feature. Deprecated: This field was + under-specified and its meaning varies across implementations, + and it cannot support dual-stack. As of Kubernetes v1.24, + users are encouraged to use implementation-specific annotations + when available. This field may be removed in a future API + version.' type: string loadBalancerSourceRanges: description: 'If specified and supported by the platform, this will restrict traffic through the cloud-provider load-balancer will be restricted to the specified client IPs. This field will be ignored if the cloud-provider does not support the - feature." More info: https://kubernetes.io/docs/tasks/access-application-cluster/configure-cloud-provider-firewall/' + feature." More info: https://kubernetes.io/docs/tasks/access-application-cluster/create-external-load-balancer/' items: type: string type: array @@ -2181,11 +2586,9 @@ spec: description: The application protocol for this port. This field follows standard Kubernetes label syntax. Un-prefixed names are reserved for IANA standard service - names (as per RFC-6335 and http://www.iana.org/assignments/service-names). + names (as per RFC-6335 and https://www.iana.org/assignments/service-names). Non-standard protocols should use prefixed names such - as mycompany.com/my-custom-protocol. This is a beta - field that is guarded by the ServiceAppProtocol feature - gate and enabled by default. + as mycompany.com/my-custom-protocol. type: string name: description: The name of this port within the service. @@ -2262,6 +2665,7 @@ spec: to types ClusterIP, NodePort, and LoadBalancer. Ignored if type is ExternalName. More info: https://kubernetes.io/docs/concepts/services-networking/service/' type: object + x-kubernetes-map-type: atomic sessionAffinity: description: 'Supports "ClientIP" and "None". Used to maintain session affinity. Enable client IP based session affinity. @@ -2284,26 +2688,6 @@ spec: type: integer type: object type: object - topologyKeys: - description: topologyKeys is a preference-order list of topology - keys which implementations of services should use to preferentially - sort endpoints when accessing this Service, it can not be - used at the same time as externalTrafficPolicy=Local. Topology - keys must be valid label keys and at most 16 keys may be - specified. Endpoints are chosen based on the first topology - key with available backends. If this field is specified - and all entries have no backends that match the topology - of the client, the service has no backends for that client - and connections should fail. The special value "*" may be - used to mean "any topology". This catch-all value, if used, - only makes sense as the last value in the list. If this - is not specified or empty, no topology constraints will - be applied. This field is alpha-level and is only honored - by servers that enable the ServiceTopology feature. This - field is deprecated and will be removed in a future version. - items: - type: string - type: array type: description: 'type determines how the Service is exposed. Defaults to ClusterIP. Valid options are ExternalName, ClusterIP, diff --git a/multicluster/config/crd/bases/multicluster.crd.antrea.io_resourceimports.yaml b/multicluster/config/crd/bases/multicluster.crd.antrea.io_resourceimports.yaml index 8790288ea66..0f44d662b50 100644 --- a/multicluster/config/crd/bases/multicluster.crd.antrea.io_resourceimports.yaml +++ b/multicluster/config/crd/bases/multicluster.crd.antrea.io_resourceimports.yaml @@ -42,6 +42,25 @@ spec: items: type: string type: array + clusterinfo: + description: If imported resource is ClusterInfo. + properties: + clusterID: + description: ClusterID of the member cluster. + type: string + gatewayInfos: + description: GatewayInfos has information of Gateways + items: + description: GatewayInfo includes information of a Gateway. + properties: + gatewayIP: + type: string + type: object + type: array + serviceCIDR: + description: ServiceCIDR is the IP ranges used by Service ClusterIP. + type: string + type: object clusternetworkpolicy: description: If imported resource is AntreaClusterNetworkPolicy. properties: @@ -192,6 +211,53 @@ spec: matching strategy. type: string type: object + nodeSelector: + description: Select certain Nodes which match the label + selector. A NodeSelector cannot be set in AppliedTo field + or set with any other selector. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, + NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values array + must be non-empty. If the operator is Exists + or DoesNotExist, the values array must be empty. + This array is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} pairs. + A single {key,value} in the matchLabels map is equivalent + to an element of matchExpressions, whose key field + is "key", the operator is "In", and the values array + contains only "value". The requirements are ANDed. + type: object + type: object podSelector: description: Select Pods from NetworkPolicy's Namespace as workloads in AppliedTo/To/From fields. If set with @@ -419,6 +485,55 @@ spec: matching strategy. type: string type: object + nodeSelector: + description: Select certain Nodes which match the + label selector. A NodeSelector cannot be set in + AppliedTo field or set with any other selector. + properties: + matchExpressions: + description: matchExpressions is a list of label + selector requirements. The requirements are + ANDed. + items: + description: A label selector requirement is + a selector that contains values, a key, and + an operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If + the operator is Exists or DoesNotExist, + the values array must be empty. This array + is replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, + whose key field is "key", the operator is "In", + and the values array contains only "value". + The requirements are ANDed. + type: object + type: object podSelector: description: Select Pods from NetworkPolicy's Namespace as workloads in AppliedTo/To/From fields. If set @@ -640,6 +755,55 @@ spec: matching strategy. type: string type: object + nodeSelector: + description: Select certain Nodes which match the + label selector. A NodeSelector cannot be set in + AppliedTo field or set with any other selector. + properties: + matchExpressions: + description: matchExpressions is a list of label + selector requirements. The requirements are + ANDed. + items: + description: A label selector requirement is + a selector that contains values, a key, and + an operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If + the operator is Exists or DoesNotExist, + the values array must be empty. This array + is replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, + whose key field is "key", the operator is "In", + and the values array contains only "value". + The requirements are ANDed. + type: object + type: object podSelector: description: Select Pods from NetworkPolicy's Namespace as workloads in AppliedTo/To/From fields. If set @@ -708,9 +872,9 @@ spec: Name should be unique within the policy. type: string ports: - description: Set of port and protocol allowed/denied by - the rule. If this field is unset or empty, this rule matches - all ports. + description: Set of ports and protocols matched by the rule. + If this field and Protocols are unset or empty, this rule + matches all ports. items: description: NetworkPolicyPort describes the port and protocol to match in a rule. @@ -738,6 +902,30 @@ spec: type: string type: object type: array + protocols: + description: Set of protocols matched by the rule. If this + field and Ports are unset or empty, this rule matches + all protocols supported. + items: + description: NetworkPolicyProtocol defines additional + protocols that are not supported by `ports`. All fields + should be used as a standalone field. + properties: + icmp: + description: ICMPProtocol matches ICMP traffic with + specific ICMPType and/or ICMPCode. All fields could + be used alone or together. If all fields are not + provided, this matches all ICMP traffic. + properties: + icmpCode: + format: int32 + type: integer + icmpType: + format: int32 + type: integer + type: object + type: object + type: array to: description: Rule is matched if traffic is intended for workloads selected by this field. This field can't be @@ -892,6 +1080,55 @@ spec: matching strategy. type: string type: object + nodeSelector: + description: Select certain Nodes which match the + label selector. A NodeSelector cannot be set in + AppliedTo field or set with any other selector. + properties: + matchExpressions: + description: matchExpressions is a list of label + selector requirements. The requirements are + ANDed. + items: + description: A label selector requirement is + a selector that contains values, a key, and + an operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If + the operator is Exists or DoesNotExist, + the values array must be empty. This array + is replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, + whose key field is "key", the operator is "In", + and the values array contains only "value". + The requirements are ANDed. + type: object + type: object podSelector: description: Select Pods from NetworkPolicy's Namespace as workloads in AppliedTo/To/From fields. If set @@ -1142,6 +1379,55 @@ spec: matching strategy. type: string type: object + nodeSelector: + description: Select certain Nodes which match the + label selector. A NodeSelector cannot be set in + AppliedTo field or set with any other selector. + properties: + matchExpressions: + description: matchExpressions is a list of label + selector requirements. The requirements are + ANDed. + items: + description: A label selector requirement is + a selector that contains values, a key, and + an operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If + the operator is Exists or DoesNotExist, + the values array must be empty. This array + is replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, + whose key field is "key", the operator is "In", + and the values array contains only "value". + The requirements are ANDed. + type: object + type: object podSelector: description: Select Pods from NetworkPolicy's Namespace as workloads in AppliedTo/To/From fields. If set @@ -1363,6 +1649,55 @@ spec: matching strategy. type: string type: object + nodeSelector: + description: Select certain Nodes which match the + label selector. A NodeSelector cannot be set in + AppliedTo field or set with any other selector. + properties: + matchExpressions: + description: matchExpressions is a list of label + selector requirements. The requirements are + ANDed. + items: + description: A label selector requirement is + a selector that contains values, a key, and + an operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If + the operator is Exists or DoesNotExist, + the values array must be empty. This array + is replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, + whose key field is "key", the operator is "In", + and the values array contains only "value". + The requirements are ANDed. + type: object + type: object podSelector: description: Select Pods from NetworkPolicy's Namespace as workloads in AppliedTo/To/From fields. If set @@ -1431,9 +1766,9 @@ spec: Name should be unique within the policy. type: string ports: - description: Set of port and protocol allowed/denied by - the rule. If this field is unset or empty, this rule matches - all ports. + description: Set of ports and protocols matched by the rule. + If this field and Protocols are unset or empty, this rule + matches all ports. items: description: NetworkPolicyPort describes the port and protocol to match in a rule. @@ -1461,6 +1796,30 @@ spec: type: string type: object type: array + protocols: + description: Set of protocols matched by the rule. If this + field and Ports are unset or empty, this rule matches + all protocols supported. + items: + description: NetworkPolicyProtocol defines additional + protocols that are not supported by `ports`. All fields + should be used as a standalone field. + properties: + icmp: + description: ICMPProtocol matches ICMP traffic with + specific ICMPType and/or ICMPCode. All fields could + be used alone or together. If all fields are not + provided, this matches all ICMP traffic. + properties: + icmpCode: + format: int32 + type: integer + icmpType: + format: int32 + type: integer + type: object + type: object + type: array to: description: Rule is matched if traffic is intended for workloads selected by this field. This field can't be @@ -1615,6 +1974,55 @@ spec: matching strategy. type: string type: object + nodeSelector: + description: Select certain Nodes which match the + label selector. A NodeSelector cannot be set in + AppliedTo field or set with any other selector. + properties: + matchExpressions: + description: matchExpressions is a list of label + selector requirements. The requirements are + ANDed. + items: + description: A label selector requirement is + a selector that contains values, a key, and + an operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If + the operator is Exists or DoesNotExist, + the values array must be empty. This array + is replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, + whose key field is "key", the operator is "In", + and the values array contains only "value". + The requirements are ANDed. + type: object + type: object podSelector: description: Select Pods from NetworkPolicy's Namespace as workloads in AppliedTo/To/From fields. If set @@ -1884,11 +2292,9 @@ spec: description: The application protocol for this port. This field follows standard Kubernetes label syntax. Un-prefixed names are reserved for IANA standard - service names (as per RFC-6335 and http://www.iana.org/assignments/service-names). + service names (as per RFC-6335 and https://www.iana.org/assignments/service-names). Non-standard protocols should use prefixed names - such as mycompany.com/my-custom-protocol. This is - a beta field that is guarded by the ServiceAppProtocol - feature gate and enabled by default. + such as mycompany.com/my-custom-protocol. type: string name: description: The name of this port. This must match @@ -1976,7 +2382,7 @@ spec: description: 'If imported resource is ANP. TODO: ANP uses float64 as priority. Type float64 is discouraged by k8s, and is not supported by controller-gen tools. NetworkPolicy *v1alpha1.NetworkPolicySpec - `json:"networkpolicy,omitempty"` If imported resource Kind is unknown.' + `json:"networkpolicy,omitempty"` If imported resource kind is unknown.' properties: data: format: byte diff --git a/multicluster/config/crd/kustomization.yaml b/multicluster/config/crd/kustomization.yaml index 7f77de35ec8..d019c3328fa 100644 --- a/multicluster/config/crd/kustomization.yaml +++ b/multicluster/config/crd/kustomization.yaml @@ -11,6 +11,8 @@ resources: - bases/multicluster.crd.antrea.io_resourceimports.yaml - k8smcs/multicluster.x-k8s.io_serviceexports.yaml - k8smcs/multicluster.x-k8s.io_serviceimports.yaml +- bases/multicluster.crd.antrea.io_clusterinfoimports.yaml +- bases/multicluster.crd.antrea.io_gateways.yaml #+kubebuilder:scaffold:crdkustomizeresource patchesStrategicMerge: @@ -24,6 +26,8 @@ patchesStrategicMerge: #- patches/webhook_in_resourceimportfilters.yaml #- patches/webhook_in_resourceexports.yaml #- patches/webhook_in_resourceimports.yaml +#- patches/webhook_in_clusterinfoimports.yaml +#- patches/webhook_in_gateways.yaml #+kubebuilder:scaffold:crdkustomizewebhookpatch # the following config is for teaching kustomize how to do kustomization for CRDs. diff --git a/multicluster/config/crd/patches/webhook_in_clusterinfoimports.yaml b/multicluster/config/crd/patches/webhook_in_clusterinfoimports.yaml new file mode 100644 index 00000000000..2c12568c6b8 --- /dev/null +++ b/multicluster/config/crd/patches/webhook_in_clusterinfoimports.yaml @@ -0,0 +1,14 @@ +# The following patch enables a conversion webhook for the CRD +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: clusterinfoimports.multicluster.crd.antrea.io +spec: + conversion: + strategy: Webhook + webhook: + clientConfig: + service: + namespace: system + name: webhook-service + path: /convert diff --git a/multicluster/config/default/configmap/controller_manager_config.yaml b/multicluster/config/default/configmap/controller_manager_config.yaml index 30d34f2e28e..1e7f5b17609 100644 --- a/multicluster/config/default/configmap/controller_manager_config.yaml +++ b/multicluster/config/default/configmap/controller_manager_config.yaml @@ -11,3 +11,5 @@ leaderElection: resourceName: 6536456a.crd.antrea.io leaseDuration: "30s" renewDeadline: "20s" +serviceCIDR: "" +gatewayIPPrecedence: "private" diff --git a/multicluster/config/default/kustomization.yaml b/multicluster/config/default/kustomization.yaml index 3429ab06cf7..4c373b0bf35 100644 --- a/multicluster/config/default/kustomization.yaml +++ b/multicluster/config/default/kustomization.yaml @@ -36,9 +36,6 @@ patchesStrategicMerge: # crd/kustomization.yaml - manager_webhook_patch.yaml -# the following config is for teaching kustomize how to do var substitution -vars: - configMapGenerator: - name: controller-config files: diff --git a/multicluster/config/manager/manager.yaml b/multicluster/config/manager/manager.yaml index 58ecfc79ff3..42b355b5ac7 100644 --- a/multicluster/config/manager/manager.yaml +++ b/multicluster/config/manager/manager.yaml @@ -40,11 +40,7 @@ spec: initialDelaySeconds: 5 periodSeconds: 10 resources: - limits: - cpu: 100m - memory: 30Mi requests: - cpu: 100m - memory: 20Mi + cpu: 200m serviceAccountName: controller terminationGracePeriodSeconds: 10 diff --git a/multicluster/config/overlays/leader-global/crd_patch.yaml b/multicluster/config/overlays/leader-global/crd_patch.yaml index dd0d7b832f0..cd8cabfb86d 100644 --- a/multicluster/config/overlays/leader-global/crd_patch.yaml +++ b/multicluster/config/overlays/leader-global/crd_patch.yaml @@ -9,3 +9,15 @@ kind: CustomResourceDefinition metadata: name: serviceimports.multicluster.x-k8s.io $patch: delete +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: gateways.multicluster.crd.antrea.io +$patch: delete +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: clusterinfoimports.multicluster.crd.antrea.io +$patch: delete diff --git a/multicluster/config/overlays/member/role.yaml b/multicluster/config/overlays/member/role.yaml index 6d89c1ff717..939bdf418d4 100644 --- a/multicluster/config/overlays/member/role.yaml +++ b/multicluster/config/overlays/member/role.yaml @@ -6,6 +6,14 @@ metadata: creationTimestamp: null name: controller-role rules: +- apiGroups: + - "" + resources: + - nodes + verbs: + - get + - list + - watch - apiGroups: - "" resources: @@ -180,3 +188,55 @@ rules: - get - patch - update +- apiGroups: + - multicluster.crd.antrea.io + resources: + - clusterinfoimports + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - multicluster.crd.antrea.io + resources: + - clusterinfoimports/finalizers + verbs: + - update +- apiGroups: + - multicluster.crd.antrea.io + resources: + - clusterinfoimports/status + verbs: + - get + - patch + - update +- apiGroups: + - multicluster.crd.antrea.io + resources: + - gateways + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - multicluster.crd.antrea.io + resources: + - gateways/finalizers + verbs: + - update +- apiGroups: + - multicluster.crd.antrea.io + resources: + - gateways/status + verbs: + - get + - patch + - update diff --git a/multicluster/config/rbac/clusterinfoimport_editor_role.yaml b/multicluster/config/rbac/clusterinfoimport_editor_role.yaml new file mode 100644 index 00000000000..1ce301af911 --- /dev/null +++ b/multicluster/config/rbac/clusterinfoimport_editor_role.yaml @@ -0,0 +1,24 @@ +# permissions for end users to edit clusterinfoimports. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: clusterinfoimport-editor-role +rules: +- apiGroups: + - multicluster.crd.antrea.io + resources: + - clusterinfoimports + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - multicluster.crd.antrea.io + resources: + - clusterinfoimports/status + verbs: + - get diff --git a/multicluster/config/rbac/clusterinfoimport_viewer_role.yaml b/multicluster/config/rbac/clusterinfoimport_viewer_role.yaml new file mode 100644 index 00000000000..9c9443a974f --- /dev/null +++ b/multicluster/config/rbac/clusterinfoimport_viewer_role.yaml @@ -0,0 +1,20 @@ +# permissions for end users to view clusterinfoimports. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: clusterinfoimport-viewer-role +rules: +- apiGroups: + - multicluster.crd.antrea.io + resources: + - clusterinfoimports + verbs: + - get + - list + - watch +- apiGroups: + - multicluster.crd.antrea.io + resources: + - clusterinfoimports/status + verbs: + - get diff --git a/multicluster/config/rbac/gateway_editor_role.yaml b/multicluster/config/rbac/gateway_editor_role.yaml new file mode 100644 index 00000000000..6624c8ddc09 --- /dev/null +++ b/multicluster/config/rbac/gateway_editor_role.yaml @@ -0,0 +1,24 @@ +# permissions for end users to edit gateways. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: gateway-editor-role +rules: +- apiGroups: + - multicluster.crd.antrea.io + resources: + - gateways + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - multicluster.crd.antrea.io + resources: + - gateways/status + verbs: + - get diff --git a/multicluster/config/rbac/gateway_viewer_role.yaml b/multicluster/config/rbac/gateway_viewer_role.yaml new file mode 100644 index 00000000000..a7aec8bc765 --- /dev/null +++ b/multicluster/config/rbac/gateway_viewer_role.yaml @@ -0,0 +1,20 @@ +# permissions for end users to view gateways. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: gateway-viewer-role +rules: +- apiGroups: + - multicluster.crd.antrea.io + resources: + - gateways + verbs: + - get + - list + - watch +- apiGroups: + - multicluster.crd.antrea.io + resources: + - gateways/status + verbs: + - get diff --git a/multicluster/config/rbac/role.yaml b/multicluster/config/rbac/role.yaml index d5f02c7eea3..35e37eef1c1 100644 --- a/multicluster/config/rbac/role.yaml +++ b/multicluster/config/rbac/role.yaml @@ -24,6 +24,14 @@ rules: - events verbs: - create +- apiGroups: + - "" + resources: + - nodes + verbs: + - get + - list + - watch - apiGroups: - "" resources: @@ -82,6 +90,32 @@ rules: - get - patch - update +- apiGroups: + - multicluster.crd.antrea.io + resources: + - clusterinfoimports + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - multicluster.crd.antrea.io + resources: + - clusterinfoimports/finalizers + verbs: + - update +- apiGroups: + - multicluster.crd.antrea.io + resources: + - clusterinfoimports/status + verbs: + - get + - patch + - update - apiGroups: - multicluster.crd.antrea.io resources: @@ -108,6 +142,32 @@ rules: - get - patch - update +- apiGroups: + - multicluster.crd.antrea.io + resources: + - gateways + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - multicluster.crd.antrea.io + resources: + - gateways/finalizers + verbs: + - update +- apiGroups: + - multicluster.crd.antrea.io + resources: + - gateways/status + verbs: + - get + - patch + - update - apiGroups: - multicluster.crd.antrea.io resources: diff --git a/multicluster/config/samples/clusterset_init/multicluster_clusterset_template.yaml b/multicluster/config/samples/clusterset_init/multicluster_clusterset_template.yaml new file mode 100644 index 00000000000..915ecad32e8 --- /dev/null +++ b/multicluster/config/samples/clusterset_init/multicluster_clusterset_template.yaml @@ -0,0 +1,30 @@ +apiVersion: multicluster.crd.antrea.io/v1alpha1 +kind: ClusterClaim +metadata: + name: leadercluster-id + namespace: changeme +name: id.k8s.io +value: test-cluster-leader +--- +apiVersion: multicluster.crd.antrea.io/v1alpha1 +kind: ClusterClaim +metadata: + name: clusterset-id + namespace: changeme +name: clusterSet.k8s.io +value: test-clusterset +--- +apiVersion: multicluster.crd.antrea.io/v1alpha1 +kind: ClusterSet +metadata: + name: test-clusterset + namespace: changeme +spec: + leaders: + - clusterID: test-cluster-leader + members: + - clusterID: test-cluster-east + serviceAccount: antrea-mc-member-access-sa + - clusterID: test-cluster-west + serviceAccount: antrea-mc-member-access-sa + namespace: antrea-mcs-ns diff --git a/multicluster/config/samples/clusterset_init/multicluster_leader_access_token_template.yaml b/multicluster/config/samples/clusterset_init/multicluster_leader_access_token_template.yaml new file mode 100644 index 00000000000..a75d5d33e3d --- /dev/null +++ b/multicluster/config/samples/clusterset_init/multicluster_leader_access_token_template.yaml @@ -0,0 +1,8 @@ +apiVersion: v1 +kind: Secret +metadata: + name: leader-access-token + namespace: changeme + annotations: + kubernetes.io/service-account.name: antrea-mc-member-access-sa +type: kubernetes.io/service-account-token diff --git a/multicluster/config/samples/clusterset_init/multicluster_membercluster_template.yaml b/multicluster/config/samples/clusterset_init/multicluster_membercluster_template.yaml new file mode 100644 index 00000000000..9510db551a7 --- /dev/null +++ b/multicluster/config/samples/clusterset_init/multicluster_membercluster_template.yaml @@ -0,0 +1,29 @@ +apiVersion: multicluster.crd.antrea.io/v1alpha1 +kind: ClusterClaim +metadata: + name: east-membercluster-id + namespace: kube-system +name: id.k8s.io +value: test-cluster-east +--- +apiVersion: multicluster.crd.antrea.io/v1alpha1 +kind: ClusterClaim +metadata: + name: clusterset-id + namespace: kube-system +name: clusterSet.k8s.io +value: test-clusterset +--- +apiVersion: multicluster.crd.antrea.io/v1alpha1 +kind: ClusterSet +metadata: + name: test-clusterset + namespace: kube-system +spec: + leaders: + - clusterID: test-cluster-leader + secret: leader-access-token + server: https://:6443 + members: + - clusterID: test-cluster-east + namespace: antrea-mcs-ns diff --git a/multicluster/config/samples/multicluster_v1alpha1_clusterinfoimport.yaml b/multicluster/config/samples/multicluster_v1alpha1_clusterinfoimport.yaml new file mode 100644 index 00000000000..d17dc75acec --- /dev/null +++ b/multicluster/config/samples/multicluster_v1alpha1_clusterinfoimport.yaml @@ -0,0 +1,10 @@ +apiVersion: multicluster.crd.antrea.io/v1alpha1 +kind: ClusterInfoImport +metadata: + name: clusterinfoimport-sample + namespace: kube-system +spec: + clusterID: test-cluster-west + GatewayInfos: + - gatewayIP: 10.10.10.10 + serviceCIDR: 10.19.0.0/18 diff --git a/multicluster/config/samples/multicluster_v1alpha1_gateway.yaml b/multicluster/config/samples/multicluster_v1alpha1_gateway.yaml new file mode 100644 index 00000000000..7b51c38eedc --- /dev/null +++ b/multicluster/config/samples/multicluster_v1alpha1_gateway.yaml @@ -0,0 +1,7 @@ +apiVersion: multicluster.crd.antrea.io/v1alpha1 +kind: Gateway +metadata: + name: gateway-sample + namespace: kube-system +gatewayIP: 10.10.10.10 +internalIP: 172.16.27.224 diff --git a/multicluster/controllers/multicluster/clusterinfoexport_handler.go b/multicluster/controllers/multicluster/clusterinfoexport_handler.go new file mode 100644 index 00000000000..dec5438d4ca --- /dev/null +++ b/multicluster/controllers/multicluster/clusterinfoexport_handler.go @@ -0,0 +1,86 @@ +/* +Copyright 2022 Antrea Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package multicluster + +import ( + "context" + "reflect" + + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + "k8s.io/klog/v2" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + + mcsv1alpha1 "antrea.io/antrea/multicluster/apis/multicluster/v1alpha1" + "antrea.io/antrea/multicluster/controllers/multicluster/common" +) + +func (r *ResourceExportReconciler) handleClusterInfo(ctx context.Context, req ctrl.Request, resExport mcsv1alpha1.ResourceExport) (ctrl.Result, error) { + resImport := &mcsv1alpha1.ResourceImport{ + ObjectMeta: metav1.ObjectMeta{ + Name: req.Name, + Namespace: req.Namespace, + }, + } + + if !resExport.DeletionTimestamp.IsZero() { + if common.StringExistsInSlice(resExport.Finalizers, common.ResourceExportFinalizer) { + err := r.Client.Delete(ctx, resImport, &client.DeleteOptions{}) + if err == nil || apierrors.IsNotFound(err) { + return r.deleteResourceExport(&resExport) + } + return ctrl.Result{}, err + } + return ctrl.Result{}, nil + } + + resImport.Spec = mcsv1alpha1.ResourceImportSpec{ + Kind: common.ClusterInfoKind, + Name: resExport.Name, + Namespace: resExport.Namespace, + } + resImportName := types.NamespacedName{ + Name: req.Name, + Namespace: req.Namespace, + } + + var err error + if err = r.Client.Get(ctx, resImportName, resImport); err != nil { + if !apierrors.IsNotFound(err) { + return ctrl.Result{}, err + } + // Create a new ClusterInfo of ResourceImport + resImport.Spec.ClusterInfo = resExport.Spec.ClusterInfo + if err = r.Client.Create(ctx, resImport, &client.CreateOptions{}); err != nil { + return ctrl.Result{}, err + } + return ctrl.Result{}, nil + } + if reflect.DeepEqual(resImport.Spec.ClusterInfo, resExport.Spec.ClusterInfo) { + klog.V(2).InfoS("No data change from ResourceExport, skip reconciling", "resourceexport", klog.KObj(&resExport)) + return ctrl.Result{}, nil + } + // Update an existing ClusterInfo of ResourceImport + resImport.Spec.ClusterInfo = resExport.Spec.ClusterInfo + klog.InfoS("Updating ResourceImport", "resourceimport", klog.KObj(&resExport)) + if err = r.Client.Update(ctx, resImport, &client.UpdateOptions{}); err != nil { + return ctrl.Result{}, err + } + return ctrl.Result{}, nil +} diff --git a/multicluster/controllers/multicluster/common/helper.go b/multicluster/controllers/multicluster/common/helper.go index d6c861f0358..ee7b9e9593b 100644 --- a/multicluster/controllers/multicluster/common/helper.go +++ b/multicluster/controllers/multicluster/common/helper.go @@ -19,12 +19,15 @@ const ( AntreaMCServiceAnnotation = "multicluster.antrea.io/imported-service" AntreaMCACNPAnnotation = "multicluster.antrea.io/imported-acnp" AntreaMCClusterIDAnnotation = "multicluster.antrea.io/local-cluster-id" + GatewayAnnotation = "multicluster.antrea.io/gateway" + GatewayIPAnnotation = "multicluster.antrea.io/gateway-ip" AntreaMCSPrefix = "antrea-mc-" ServiceKind = "Service" EndpointsKind = "Endpoints" AntreaClusterNetworkPolicyKind = "AntreaClusterNetworkPolicy" ServiceImportKind = "ServiceImport" + ClusterInfoKind = "ClusterInfo" SourceName = "sourceName" SourceNamespace = "sourceNamespace" diff --git a/multicluster/controllers/multicluster/commonarea/acnp_resourceimport_controller_test.go b/multicluster/controllers/multicluster/commonarea/acnp_resourceimport_controller_test.go index e9b420b4937..cfb809634a6 100644 --- a/multicluster/controllers/multicluster/commonarea/acnp_resourceimport_controller_test.go +++ b/multicluster/controllers/multicluster/commonarea/acnp_resourceimport_controller_test.go @@ -107,13 +107,13 @@ var ( ) func TestResourceImportReconciler_handleCopySpanACNPCreateEvent(t *testing.T) { - remoteMgr := NewRemoteCommonAreaManager("test-clusterset", common.ClusterID(localClusterID)) - go remoteMgr.Start() + remoteMgr := NewRemoteCommonAreaManager("test-clusterset", common.ClusterID(localClusterID), "kube-system") + remoteMgr.Start() defer remoteMgr.Stop() fakeClient := fake.NewClientBuilder().WithScheme(scheme).WithObjects(securityOpsTier).Build() fakeRemoteClient := fake.NewClientBuilder().WithScheme(scheme).WithObjects(acnpResImport, acnpResImportNoMatchingTier).Build() - remoteCluster := NewFakeRemoteCommonArea(scheme, &remoteMgr, fakeRemoteClient, "leader-cluster", "default") + remoteCluster := NewFakeRemoteCommonArea(scheme, remoteMgr, fakeRemoteClient, "leader-cluster", "default") tests := []struct { name string @@ -134,7 +134,7 @@ func TestResourceImportReconciler_handleCopySpanACNPCreateEvent(t *testing.T) { expectedSuccess: false, }, } - r := NewResourceImportReconciler(fakeClient, scheme, fakeClient, localClusterID, remoteCluster) + r := NewResourceImportReconciler(fakeClient, scheme, fakeClient, localClusterID, "default", remoteCluster) for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if _, err := r.Reconcile(ctx, tt.req); err != nil { @@ -164,8 +164,8 @@ func TestResourceImportReconciler_handleCopySpanACNPCreateEvent(t *testing.T) { } func TestResourceImportReconciler_handleCopySpanACNPDeleteEvent(t *testing.T) { - remoteMgr := NewRemoteCommonAreaManager("test-clusterset", common.ClusterID(localClusterID)) - go remoteMgr.Start() + remoteMgr := NewRemoteCommonAreaManager("test-clusterset", common.ClusterID(localClusterID), "kube-system") + remoteMgr.Start() defer remoteMgr.Stop() existingACNP := &v1alpha1.ClusterNetworkPolicy{ @@ -176,9 +176,9 @@ func TestResourceImportReconciler_handleCopySpanACNPDeleteEvent(t *testing.T) { fakeClient := fake.NewClientBuilder().WithScheme(scheme).WithObjects(existingACNP).Build() fakeRemoteClient := fake.NewClientBuilder().WithScheme(scheme).Build() - remoteCluster := NewFakeRemoteCommonArea(scheme, &remoteMgr, fakeRemoteClient, "leader-cluster", "default") + remoteCluster := NewFakeRemoteCommonArea(scheme, remoteMgr, fakeRemoteClient, "leader-cluster", "default") - r := NewResourceImportReconciler(fakeClient, scheme, fakeClient, localClusterID, remoteCluster) + r := NewResourceImportReconciler(fakeClient, scheme, fakeClient, localClusterID, "default", remoteCluster) r.installedResImports.Add(*acnpResImport) if _, err := r.Reconcile(ctx, acnpImpReq); err != nil { @@ -191,8 +191,8 @@ func TestResourceImportReconciler_handleCopySpanACNPDeleteEvent(t *testing.T) { } func TestResourceImportReconciler_handleCopySpanACNPUpdateEvent(t *testing.T) { - remoteMgr := NewRemoteCommonAreaManager("test-clusterset", common.ClusterID(localClusterID)) - go remoteMgr.Start() + remoteMgr := NewRemoteCommonAreaManager("test-clusterset", common.ClusterID(localClusterID), "kube-system") + remoteMgr.Start() defer remoteMgr.Stop() existingACNP1 := &v1alpha1.ClusterNetworkPolicy{ @@ -290,9 +290,9 @@ func TestResourceImportReconciler_handleCopySpanACNPUpdateEvent(t *testing.T) { fakeClient := fake.NewClientBuilder().WithScheme(scheme).WithObjects(existingACNP1, existingACNP3, existingACNP4, securityOpsTier).Build() fakeRemoteClient := fake.NewClientBuilder().WithScheme(scheme).WithObjects(acnpResImport, updatedResImport2, updatedResImport3).Build() - remoteCluster := NewFakeRemoteCommonArea(scheme, &remoteMgr, fakeRemoteClient, "leader-cluster", "default") + remoteCluster := NewFakeRemoteCommonArea(scheme, remoteMgr, fakeRemoteClient, "leader-cluster", "default") - r := NewResourceImportReconciler(fakeClient, scheme, fakeClient, localClusterID, remoteCluster) + r := NewResourceImportReconciler(fakeClient, scheme, fakeClient, localClusterID, "default", remoteCluster) r.installedResImports.Add(*acnpResImport) r.installedResImports.Add(*acnpResImportNoMatchingTier) r.installedResImports.Add(*updatedResImport3) diff --git a/multicluster/controllers/multicluster/commonarea/clusterinfo_importer.go b/multicluster/controllers/multicluster/commonarea/clusterinfo_importer.go new file mode 100644 index 00000000000..f80cc2ff47a --- /dev/null +++ b/multicluster/controllers/multicluster/commonarea/clusterinfo_importer.go @@ -0,0 +1,88 @@ +/* +Copyright 2022 Antrea Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package commonarea + +import ( + "context" + "reflect" + + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + "k8s.io/klog/v2" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + + mcsv1alpha1 "antrea.io/antrea/multicluster/apis/multicluster/v1alpha1" +) + +func (r *ResourceImportReconciler) handleResImpUpdateForClusterInfo(ctx context.Context, req ctrl.Request, resImp *mcsv1alpha1.ResourceImport) (ctrl.Result, error) { + klog.V(2).InfoS("Reconciling ClusterInfo of ResourceImport", "resourceimport", req.NamespacedName) + var err error + clusterInfo := *resImp.Spec.ClusterInfo + + // If ClusterInfo is from local cluster, skip it. + if clusterInfo.ClusterID == r.localClusterID { + klog.V(2).InfoS("Skip reconciling ResourceImport for ClusterInfo since it's from local cluster", "resourceimport", req.NamespacedName) + return ctrl.Result{}, nil + } + + // Create or update ClusterInfoImport + clusterInfoImport, clusterInfoImportName := newClusterInfoImport(req.Name, r.namespace) + if err = r.localClusterClient.Get(ctx, clusterInfoImportName, clusterInfoImport); err != nil { + if apierrors.IsNotFound(err) { + clusterInfoImport.Spec = clusterInfo + if err = r.localClusterClient.Create(ctx, clusterInfoImport, &client.CreateOptions{}); err != nil { + return ctrl.Result{}, err + } + r.installedResImports.Add(*resImp) + return ctrl.Result{}, nil + } + return ctrl.Result{}, err + } + if reflect.DeepEqual(clusterInfoImport.Spec, clusterInfo) { + klog.InfoS("No change on ClusterInfoImport spec, skip reconciling", "clusterinfoimport", clusterInfoImportName.String(), + "resourceimport", req.NamespacedName.String()) + r.installedResImports.Update(*resImp) + return ctrl.Result{}, nil + } + clusterInfoImport.Spec = clusterInfo + if err = r.localClusterClient.Update(ctx, clusterInfoImport, &client.UpdateOptions{}); err != nil { + return ctrl.Result{}, err + } + r.installedResImports.Update(*resImp) + return ctrl.Result{}, nil +} + +func (r *ResourceImportReconciler) handleResImpDeleteForClusterInfo(ctx context.Context, req ctrl.Request, resImp *mcsv1alpha1.ResourceImport) (ctrl.Result, error) { + clusterInfoImport, clusterInfoImportName := newClusterInfoImport(req.Name, r.namespace) + klog.InfoS("Deleting ClusterInfoImport", "clusterinfoimport", clusterInfoImportName.String()) + err := r.localClusterClient.Delete(ctx, clusterInfoImport, &client.DeleteOptions{}) + return ctrl.Result{}, client.IgnoreNotFound(err) +} + +func newClusterInfoImport(name, namespace string) (*mcsv1alpha1.ClusterInfoImport, types.NamespacedName) { + clusterInfoImport := &mcsv1alpha1.ClusterInfoImport{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: namespace, + }, + } + + clusterInfoImportName := types.NamespacedName{Name: name, Namespace: namespace} + return clusterInfoImport, clusterInfoImportName +} diff --git a/multicluster/controllers/multicluster/commonarea/clusterinfo_importer_test.go b/multicluster/controllers/multicluster/commonarea/clusterinfo_importer_test.go new file mode 100644 index 00000000000..97c657d4860 --- /dev/null +++ b/multicluster/controllers/multicluster/commonarea/clusterinfo_importer_test.go @@ -0,0 +1,204 @@ +/* +Copyright 2022 Antrea Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package commonarea + +import ( + "reflect" + "testing" + + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client/fake" + + mcsv1alpha1 "antrea.io/antrea/multicluster/apis/multicluster/v1alpha1" + "antrea.io/antrea/multicluster/controllers/multicluster/common" +) + +func TestResourceImportReconciler_handleClusterInfo(t *testing.T) { + clusterAInfo := mcsv1alpha1.ClusterInfo{ + ClusterID: "cluster-a", + ServiceCIDR: "10.10.1.0/16", + GatewayInfos: []mcsv1alpha1.GatewayInfo{ + { + GatewayIP: "172.168.10.11", + }, + }, + } + clusterBInfo := mcsv1alpha1.ClusterInfo{ + ClusterID: "cluster-b", + ServiceCIDR: "10.10.1.0/16", + GatewayInfos: []mcsv1alpha1.GatewayInfo{ + { + GatewayIP: "17.16.10.10", + }, + }, + } + clusterBInfoNew := clusterBInfo + clusterBInfoNew.GatewayInfos = []mcsv1alpha1.GatewayInfo{ + { + GatewayIP: "17.16.10.10", + }, + { + GatewayIP: "17.16.11.11", + }, + } + ciResImportA := &mcsv1alpha1.ResourceImport{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "default", + Name: "cluster-a-default-clusterinfo", + }, + Spec: mcsv1alpha1.ResourceImportSpec{ + Kind: common.ClusterInfoKind, + Name: "node-1", + Namespace: "default", + ClusterInfo: &clusterAInfo, + }, + } + ciResImportB := &mcsv1alpha1.ResourceImport{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "default", + Name: "cluster-b-default-clusterinfo", + }, + Spec: mcsv1alpha1.ResourceImportSpec{ + Kind: common.ClusterInfoKind, + Name: "node-2", + Namespace: "default", + ClusterInfo: &clusterBInfoNew, + }, + } + ciResImportC := &mcsv1alpha1.ResourceImport{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "default", + Name: "cluster-c-default-clusterinfo", + }, + Spec: mcsv1alpha1.ResourceImportSpec{ + Kind: common.ClusterInfoKind, + Name: "node-3", + Namespace: "default", + }, + } + ciImportA := mcsv1alpha1.ClusterInfoImport{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "default", + Name: "cluster-a-default-clusterinfo", + }, + Spec: clusterAInfo, + } + ciImportB := mcsv1alpha1.ClusterInfoImport{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "default", + Name: "cluster-b-default-clusterinfo", + }, + Spec: clusterBInfo, + } + ciImportC := mcsv1alpha1.ClusterInfoImport{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "default", + Name: "cluster-c-default-clusterinfo", + }, + Spec: mcsv1alpha1.ClusterInfo{ + ClusterID: "cluster-c", + ServiceCIDR: "10.10.1.0/16", + GatewayInfos: []mcsv1alpha1.GatewayInfo{ + { + GatewayIP: "172.168.10.11", + }, + }, + }, + } + + tests := []struct { + name string + existingCIResImport *mcsv1alpha1.ResourceImport + existingCIImport *mcsv1alpha1.ClusterInfoImport + expectedCIImport *mcsv1alpha1.ClusterInfoImport + isDelete bool + }{ + { + name: "create ClusterInfoImport successfully", + existingCIResImport: ciResImportA, + expectedCIImport: &ciImportA, + }, + { + name: "update ClusterInfoImport successfully", + existingCIResImport: ciResImportB, + existingCIImport: &ciImportB, + expectedCIImport: &mcsv1alpha1.ClusterInfoImport{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "default", + Name: "cluster-b-default-clusterinfo", + }, + Spec: clusterBInfoNew, + }, + }, + { + name: "delete ClusterInfoImport successfully", + existingCIResImport: ciResImportC, + existingCIImport: &ciImportC, + isDelete: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + remoteMgr := NewRemoteCommonAreaManager("test-clusterset", common.ClusterID("cluster-d"), "default") + remoteMgr.Start() + defer remoteMgr.Stop() + fakeClient := fake.NewClientBuilder().WithScheme(scheme).WithObjects().Build() + if tt.existingCIImport != nil { + fakeClient = fake.NewClientBuilder().WithScheme(scheme).WithObjects(tt.existingCIImport).Build() + } + fakeRemoteClient := fake.NewClientBuilder().WithScheme(scheme).WithObjects(tt.existingCIResImport).Build() + if tt.isDelete { + fakeRemoteClient = fake.NewClientBuilder().WithScheme(scheme).WithObjects().Build() + } + remoteCluster := NewFakeRemoteCommonArea(scheme, remoteMgr, fakeRemoteClient, "leader-cluster", "default") + r := NewResourceImportReconciler(fakeClient, scheme, fakeClient, "cluster-d", "default", remoteCluster) + if tt.isDelete { + r.installedResImports.Add(*ciResImportC) + } + ciResImportName := types.NamespacedName{ + Namespace: tt.existingCIResImport.Namespace, + Name: tt.existingCIResImport.Name, + } + req := ctrl.Request{NamespacedName: ciResImportName} + + if _, err := r.Reconcile(ctx, req); err != nil { + t.Errorf("ClusterInfo Importer should handle ResourceImport events successfully but got error = %v", err) + } else { + gotCIImp := &mcsv1alpha1.ClusterInfoImport{} + err := fakeClient.Get(ctx, ciResImportName, gotCIImp) + isNotFound := apierrors.IsNotFound(err) + if err != nil { + if tt.expectedCIImport == nil && !isNotFound { + t.Errorf("Expected to get not found error but got error = %v", err) + } + if tt.expectedCIImport != nil && isNotFound { + t.Errorf("Expected to get ClusterInfoImport %v but got not found error = %v", tt.expectedCIImport, err) + } + } else if tt.expectedCIImport != nil { + if !reflect.DeepEqual(tt.expectedCIImport.Spec, gotCIImp.Spec) { + t.Errorf("Expected ClusterInfoImport %v but got %v", tt.expectedCIImport.Spec, gotCIImp.Spec) + } + } + } + }) + } + +} diff --git a/multicluster/controllers/multicluster/commonarea/fake_remote_common_area.go b/multicluster/controllers/multicluster/commonarea/fake_remote_common_area.go index af6d3c92e2f..1f9c19bcf99 100644 --- a/multicluster/controllers/multicluster/commonarea/fake_remote_common_area.go +++ b/multicluster/controllers/multicluster/commonarea/fake_remote_common_area.go @@ -67,13 +67,13 @@ func (c *fakeRemoteCommonArea) GetStatus() []multiclusterv1alpha1.ClusterConditi // NewFakeRemoteCommonArea creates a new fakeRemoteCommonArea for unit test purpose only func NewFakeRemoteCommonArea(scheme *runtime.Scheme, - remoteCommonAreaManager *RemoteCommonAreaManager, + remoteCommonAreaManager RemoteCommonAreaManager, fakeClient client.Client, clusterID string, namespace string) RemoteCommonArea { fakeRemoteCommonArea := &fakeRemoteCommonArea{ Client: fakeClient, ClusterID: common.ClusterID(clusterID), Namespace: namespace, } - (*remoteCommonAreaManager).AddRemoteCommonArea(fakeRemoteCommonArea) + remoteCommonAreaManager.AddRemoteCommonArea(fakeRemoteCommonArea) return fakeRemoteCommonArea } diff --git a/multicluster/controllers/multicluster/commonarea/leader_elector.go b/multicluster/controllers/multicluster/commonarea/leader_elector.go index e74182f8f60..206bdf7e640 100644 --- a/multicluster/controllers/multicluster/commonarea/leader_elector.go +++ b/multicluster/controllers/multicluster/commonarea/leader_elector.go @@ -122,6 +122,8 @@ func (r *remoteCommonAreaManager) setElectedLeader(cluster RemoteCommonArea) { } r.electedLeaderCluster = cluster if cluster != nil { - cluster.StartWatching() + if err := cluster.StartWatching(); err != nil { + klog.ErrorS(err, "Failed to start watching events") + } } } diff --git a/multicluster/controllers/multicluster/commonarea/mock_remote_common_area.go b/multicluster/controllers/multicluster/commonarea/mock_remote_common_area.go index 8f409ab8764..2c0a8d274a2 100644 --- a/multicluster/controllers/multicluster/commonarea/mock_remote_common_area.go +++ b/multicluster/controllers/multicluster/commonarea/mock_remote_common_area.go @@ -16,7 +16,6 @@ // Code generated by MockGen. DO NOT EDIT. // Source: controllers/multicluster/commonarea/remote_common_area.go -// package commonarea is a generated GoMock package. package commonarea import ( diff --git a/multicluster/controllers/multicluster/commonarea/mock_remote_common_area_manager.go b/multicluster/controllers/multicluster/commonarea/mock_remote_common_area_manager.go index febf8fe6aed..7686d39904f 100644 --- a/multicluster/controllers/multicluster/commonarea/mock_remote_common_area_manager.go +++ b/multicluster/controllers/multicluster/commonarea/mock_remote_common_area_manager.go @@ -14,9 +14,8 @@ // // Code generated by MockGen. DO NOT EDIT. -// Source: controllers/multicluster/core/remote_common_area_manager.go +// Source: controllers/multicluster/commonarea/remote_common_area_manager.go -// package commonarea is a generated GoMock package. package commonarea import ( @@ -105,6 +104,20 @@ func (mr *MockRemoteCommonAreaManagerMockRecorder) GetMemberClusterStatues() *go return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetMemberClusterStatues", reflect.TypeOf((*MockRemoteCommonAreaManager)(nil).GetMemberClusterStatues)) } +// GetNamespace mocks base method. +func (m *MockRemoteCommonAreaManager) GetNamespace() string { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetNamespace") + ret0, _ := ret[0].(string) + return ret0 +} + +// GetNamespace indicates an expected call of GetNamespace. +func (mr *MockRemoteCommonAreaManagerMockRecorder) GetNamespace() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetNamespace", reflect.TypeOf((*MockRemoteCommonAreaManager)(nil).GetNamespace)) +} + // GetRemoteCommonAreas mocks base method. func (m *MockRemoteCommonAreaManager) GetRemoteCommonAreas() map[common.ClusterID]RemoteCommonArea { m.ctrl.T.Helper() diff --git a/multicluster/controllers/multicluster/commonarea/remote_common_area.go b/multicluster/controllers/multicluster/commonarea/remote_common_area.go index a15dc4a269d..9a072604f20 100644 --- a/multicluster/controllers/multicluster/commonarea/remote_common_area.go +++ b/multicluster/controllers/multicluster/commonarea/remote_common_area.go @@ -147,7 +147,6 @@ func NewRemoteCommonArea(clusterID common.ClusterID, clusterSetID common.Cluster if e != nil { return nil, e } - remote := &remoteCommonArea{ Client: remoteClient, ClusterManager: mgr, @@ -378,6 +377,7 @@ func (r *remoteCommonArea) StartWatching() error { r.ClusterManager.GetScheme(), r.localClusterClient, string(r.remoteCommonAreaManager.GetLocalClusterID()), + r.remoteCommonAreaManager.GetNamespace(), r, ) @@ -409,6 +409,17 @@ func (r *remoteCommonArea) StopWatching() { } r.managerStopFunc() r.managerStopFunc = nil + + // Reset ClusterManager so this common area can be started again when it's reconnected. + mgr, err := ctrl.NewManager(r.config, ctrl.Options{ + Scheme: r.scheme, + MetricsBindAddress: "0", + Namespace: r.Namespace, + }) + if err != nil { + klog.ErrorS(err, "Error to reset manager for RemoteCommonArea", "Cluster", r.ClusterID) + } + r.ClusterManager = mgr } func (r *remoteCommonArea) GetStatus() []multiclusterv1alpha1.ClusterCondition { diff --git a/multicluster/controllers/multicluster/commonarea/remote_common_area_manager.go b/multicluster/controllers/multicluster/commonarea/remote_common_area_manager.go index 8654942cbe2..f35a76c4842 100644 --- a/multicluster/controllers/multicluster/commonarea/remote_common_area_manager.go +++ b/multicluster/controllers/multicluster/commonarea/remote_common_area_manager.go @@ -47,6 +47,8 @@ type RemoteCommonAreaManager interface { GetElectedLeaderClusterID() common.ClusterID // GetLocalClusterID returns local cluster ID GetLocalClusterID() common.ClusterID + // GetNamespace returns local Namespace where the RemoteCommonAreaManager is running. + GetNamespace() string GetMemberClusterStatues() []multiclusterv1alpha1.ClusterStatus } @@ -89,14 +91,18 @@ type remoteCommonAreaManager struct { // stopFunc is to stop all background processing when RemoteCommonAreaManager is stopped. stopFunc context.CancelFunc + + // namespace is the Namespace where this remoteCommonAreaManager running from. + namespace string } -func NewRemoteCommonAreaManager(clusterSetID common.ClusterSetID, clusterID common.ClusterID) RemoteCommonAreaManager { +func NewRemoteCommonAreaManager(clusterSetID common.ClusterSetID, clusterID common.ClusterID, namespace string) RemoteCommonAreaManager { klog.InfoS("Creating NewRemoteCommonAreaManager", "ClusterSet", clusterSetID) return &remoteCommonAreaManager{ clusterSetID: clusterSetID, clusterID: clusterID, eventChan: make(chan clusterEvent), + namespace: namespace, remoteCommonAreas: make(map[common.ClusterID]RemoteCommonArea), } } @@ -204,6 +210,10 @@ func (r *remoteCommonAreaManager) GetLocalClusterID() common.ClusterID { return r.clusterID } +func (r *remoteCommonAreaManager) GetNamespace() string { + return r.namespace +} + func (r *remoteCommonAreaManager) GetMemberClusterStatues() []multiclusterv1alpha1.ClusterStatus { statues := make([]multiclusterv1alpha1.ClusterStatus, 0) diff --git a/multicluster/controllers/multicluster/commonarea/remote_common_area_manager_test.go b/multicluster/controllers/multicluster/commonarea/remote_common_area_manager_test.go index 766ca783f55..251b303483d 100644 --- a/multicluster/controllers/multicluster/commonarea/remote_common_area_manager_test.go +++ b/multicluster/controllers/multicluster/commonarea/remote_common_area_manager_test.go @@ -38,7 +38,7 @@ var ( func TestAddMember(t *testing.T) { - remoteCommonAreaManagerUnderTest := NewRemoteCommonAreaManager(common.ClusterSetID("clusterSetA"), common.ClusterID("memberA")) + remoteCommonAreaManagerUnderTest := NewRemoteCommonAreaManager(common.ClusterSetID("clusterSetA"), common.ClusterID("memberA"), "kube-system") remoteCommonAreaManagerUnderTest.Start() mockCtrl := gomock.NewController(t) @@ -86,7 +86,7 @@ func TestAddMember(t *testing.T) { func TestLeaderElection(t *testing.T) { - remoteCommonAreaManagerUnderTest := NewRemoteCommonAreaManager("clusterSetA", "memberA") + remoteCommonAreaManagerUnderTest := NewRemoteCommonAreaManager("clusterSetA", "memberA", "kube-system") remoteCommonAreaManagerUnderTest.Start() mockCtrl := gomock.NewController(t) diff --git a/multicluster/controllers/multicluster/commonarea/resourceimport_controller.go b/multicluster/controllers/multicluster/commonarea/resourceimport_controller.go index 4764743a3d7..fb4eabf79eb 100644 --- a/multicluster/controllers/multicluster/commonarea/resourceimport_controller.go +++ b/multicluster/controllers/multicluster/commonarea/resourceimport_controller.go @@ -60,16 +60,19 @@ type ResourceImportReconciler struct { Scheme *runtime.Scheme localClusterClient client.Client localClusterID string + namespace string remoteCommonArea RemoteCommonArea installedResImports cache.Indexer } -func NewResourceImportReconciler(client client.Client, scheme *runtime.Scheme, localClusterClient client.Client, localClusterID string, remoteCommonArea RemoteCommonArea) *ResourceImportReconciler { +func NewResourceImportReconciler(client client.Client, scheme *runtime.Scheme, localClusterClient client.Client, + localClusterID string, namespace string, remoteCommonArea RemoteCommonArea) *ResourceImportReconciler { return &ResourceImportReconciler{ Client: client, Scheme: scheme, localClusterClient: localClusterClient, localClusterID: localClusterID, + namespace: namespace, remoteCommonArea: remoteCommonArea, installedResImports: cache.NewIndexer(resImportIndexerKeyFunc, cache.Indexers{ resImportIndexer: resImportIndexerFunc, @@ -137,8 +140,12 @@ func (r *ResourceImportReconciler) Reconcile(ctx context.Context, req ctrl.Reque return r.handleResImpDeleteForClusterNetworkPolicy(ctx, &resImp) } return r.handleResImpUpdateForClusterNetworkPolicy(ctx, &resImp) + case common.ClusterInfoKind: + if isDeleted { + return r.handleResImpDeleteForClusterInfo(ctx, req, &resImp) + } + return r.handleResImpUpdateForClusterInfo(ctx, req, &resImp) } - // TODO: handle for other ResImport Kinds return ctrl.Result{}, nil } @@ -210,7 +217,6 @@ func (r *ResourceImportReconciler) handleResImpUpdateForService(ctx context.Cont klog.ErrorS(err, "Failed to update imported Service", "service", svcName.String()) return ctrl.Result{}, err } - r.installedResImports.Update(*resImp) } if !apiequality.Semantic.DeepEqual(svcImp.Spec, svcImpObj.Spec) { @@ -221,8 +227,8 @@ func (r *ResourceImportReconciler) handleResImpUpdateForService(ctx context.Cont klog.ErrorS(err, "Failed to update ServiceImport", "serviceimport", svcImpName.String()) return ctrl.Result{}, err } - r.installedResImports.Update(*resImp) } + r.installedResImports.Update(*resImp) return ctrl.Result{}, nil } @@ -240,10 +246,7 @@ func (r *ResourceImportReconciler) handleResImpDeleteForService(ctx context.Cont return ctrl.Result{}, client.IgnoreNotFound(err) } err = r.localClusterClient.Delete(ctx, svcImp, &client.DeleteOptions{}) - if err != nil { - return ctrl.Result{}, client.IgnoreNotFound(err) - } - return ctrl.Result{}, nil + return ctrl.Result{}, client.IgnoreNotFound(err) } svc := &corev1.Service{} @@ -324,8 +327,8 @@ func (r *ResourceImportReconciler) handleResImpUpdateForEndpoints(ctx context.Co klog.ErrorS(err, "Failed to update MCS Endpoints", "endpoints", epNamespaced.String()) return ctrl.Result{}, err } - r.installedResImports.Update(*resImp) } + r.installedResImports.Update(*resImp) return ctrl.Result{}, nil } diff --git a/multicluster/controllers/multicluster/commonarea/resourceimport_controller_test.go b/multicluster/controllers/multicluster/commonarea/resourceimport_controller_test.go index 0e4619eb996..d9f0bb2528f 100644 --- a/multicluster/controllers/multicluster/commonarea/resourceimport_controller_test.go +++ b/multicluster/controllers/multicluster/commonarea/resourceimport_controller_test.go @@ -119,12 +119,13 @@ func init() { } func TestResourceImportReconciler_handleCreateEvent(t *testing.T) { - remoteMgr := NewRemoteCommonAreaManager("test-clusterset", common.ClusterID(localClusterID)) - go remoteMgr.Start() + remoteMgr := NewRemoteCommonAreaManager("test-clusterset", common.ClusterID(localClusterID), "kube-system") + remoteMgr.Start() + defer remoteMgr.Stop() fakeClient := fake.NewClientBuilder().WithScheme(scheme).Build() fakeRemoteClient := fake.NewClientBuilder().WithScheme(scheme).WithObjects(svcResImport, epResImport).Build() - remoteCluster := NewFakeRemoteCommonArea(scheme, &remoteMgr, fakeRemoteClient, "leader-cluster", "default") + remoteCluster := NewFakeRemoteCommonArea(scheme, remoteMgr, fakeRemoteClient, "leader-cluster", "default") tests := []struct { name string @@ -143,7 +144,7 @@ func TestResourceImportReconciler_handleCreateEvent(t *testing.T) { }, } - r := NewResourceImportReconciler(fakeClient, scheme, fakeClient, localClusterID, remoteCluster) + r := NewResourceImportReconciler(fakeClient, scheme, fakeClient, localClusterID, "default", remoteCluster) for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if _, err := r.Reconcile(ctx, tt.req); err != nil { @@ -174,8 +175,9 @@ func TestResourceImportReconciler_handleCreateEvent(t *testing.T) { } func TestResourceImportReconciler_handleDeleteEvent(t *testing.T) { - remoteMgr := NewRemoteCommonAreaManager("test-clusterset", common.ClusterID(localClusterID)) - go remoteMgr.Start() + remoteMgr := NewRemoteCommonAreaManager("test-clusterset", common.ClusterID(localClusterID), "kube-system") + remoteMgr.Start() + defer remoteMgr.Stop() existSvc := &corev1.Service{ ObjectMeta: metav1.ObjectMeta{ @@ -198,7 +200,7 @@ func TestResourceImportReconciler_handleDeleteEvent(t *testing.T) { fakeClient := fake.NewClientBuilder().WithScheme(scheme).WithObjects(existSvc, existEp, existSvcImp).Build() fakeRemoteClient := fake.NewClientBuilder().WithScheme(scheme).Build() - remoteCluster := NewFakeRemoteCommonArea(scheme, &remoteMgr, fakeRemoteClient, "leader-cluster", "default") + remoteCluster := NewFakeRemoteCommonArea(scheme, remoteMgr, fakeRemoteClient, "leader-cluster", "default") tests := []struct { name string @@ -217,7 +219,7 @@ func TestResourceImportReconciler_handleDeleteEvent(t *testing.T) { }, } - r := NewResourceImportReconciler(fakeClient, scheme, fakeClient, localClusterID, remoteCluster) + r := NewResourceImportReconciler(fakeClient, scheme, fakeClient, localClusterID, "default", remoteCluster) r.installedResImports.Add(*svcResImport) r.installedResImports.Add(*epResImport) @@ -248,8 +250,9 @@ func TestResourceImportReconciler_handleDeleteEvent(t *testing.T) { } func TestResourceImportReconciler_handleUpdateEvent(t *testing.T) { - remoteMgr := NewRemoteCommonAreaManager("test-clusterset", common.ClusterID(localClusterID)) - go remoteMgr.Start() + remoteMgr := NewRemoteCommonAreaManager("test-clusterset", common.ClusterID(localClusterID), "kube-system") + remoteMgr.Start() + defer remoteMgr.Stop() nginxPorts := []corev1.ServicePort{ { @@ -392,7 +395,7 @@ func TestResourceImportReconciler_handleUpdateEvent(t *testing.T) { existEp, existMCSvcConflicts, existMCEpConflicts, svcWithoutAutoAnnotation, epWithoutAutoAnnotation).Build() fakeRemoteClient := fake.NewClientBuilder().WithScheme(scheme).WithObjects(updatedEpResImport, updatedSvcResImport, svcResImportWithConflicts, epResImportWithConflicts).Build() - remoteCluster := NewFakeRemoteCommonArea(scheme, &remoteMgr, fakeRemoteClient, "leader-cluster", "default") + remoteCluster := NewFakeRemoteCommonArea(scheme, remoteMgr, fakeRemoteClient, "leader-cluster", "default") tests := []struct { name string @@ -445,7 +448,7 @@ func TestResourceImportReconciler_handleUpdateEvent(t *testing.T) { }, } - r := NewResourceImportReconciler(fakeClient, scheme, fakeClient, localClusterID, remoteCluster) + r := NewResourceImportReconciler(fakeClient, scheme, fakeClient, localClusterID, "default", remoteCluster) r.installedResImports.Add(*svcResImport) r.installedResImports.Add(*epResImport) diff --git a/multicluster/controllers/multicluster/controller_utils.go b/multicluster/controllers/multicluster/controller_utils.go index 6d248526609..e421da37d53 100644 --- a/multicluster/controllers/multicluster/controller_utils.go +++ b/multicluster/controllers/multicluster/controller_utils.go @@ -17,7 +17,11 @@ package multicluster import ( "context" "fmt" + "regexp" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/intstr" "k8s.io/klog/v2" "sigs.k8s.io/controller-runtime/pkg/client" @@ -25,7 +29,7 @@ import ( "antrea.io/antrea/multicluster/controllers/multicluster/common" ) -func validateLocalClusterClaim(c client.Client, clusterSet *multiclusterv1alpha1.ClusterSet) (clusterId common.ClusterID, clusterSetId common.ClusterSetID, err error) { +func validateLocalClusterClaim(c client.Client, clusterSet *multiclusterv1alpha1.ClusterSet) (clusterID common.ClusterID, clusterSetID common.ClusterSetID, err error) { configNamespace := clusterSet.GetNamespace() clusterClaimList := &multiclusterv1alpha1.ClusterClaimList{} @@ -44,10 +48,10 @@ func validateLocalClusterClaim(c client.Client, clusterSet *multiclusterv1alpha1 klog.InfoS("Processing ClusterClaim", "Name", clusterClaim.Name, "Value", clusterClaim.Value) if clusterClaim.Name == multiclusterv1alpha1.WellKnownClusterClaimClusterSet { wellKnownClusterSetClaimIDExist = true - clusterSetId = common.ClusterSetID(clusterClaim.Value) + clusterSetID = common.ClusterSetID(clusterClaim.Value) } else if clusterClaim.Name == multiclusterv1alpha1.WellKnownClusterClaimID { wellKnownClusterClaimIDExist = true - clusterId = common.ClusterID(clusterClaim.Value) + clusterID = common.ClusterID(clusterClaim.Value) } } @@ -63,25 +67,25 @@ func validateLocalClusterClaim(c client.Client, clusterSet *multiclusterv1alpha1 return } - if clusterSet.Name != string(clusterSetId) { + if clusterSet.Name != string(clusterSetID) { err = fmt.Errorf("ClusterSet Name=%s is not same as ClusterClaim Value=%s for Name=%s", - clusterSet.Name, clusterSetId, multiclusterv1alpha1.WellKnownClusterClaimClusterSet) + clusterSet.Name, clusterSetID, multiclusterv1alpha1.WellKnownClusterClaimClusterSet) return } return } -func validateConfigExists(clusterId common.ClusterID, clusters []multiclusterv1alpha1.MemberCluster) (err error) { +func validateConfigExists(clusterID common.ClusterID, clusters []multiclusterv1alpha1.MemberCluster) (err error) { configExists := false for _, cluster := range clusters { - if string(clusterId) == cluster.ClusterID { + if string(clusterID) == cluster.ClusterID { configExists = true break } } if !configExists { - err = fmt.Errorf("validating cluster %s exists in %v failed", clusterId, clusters) + err = fmt.Errorf("validating cluster %s exists in %v failed", clusterID, clusters) return } return @@ -96,3 +100,53 @@ func validateClusterSetNamespace(clusterSet *multiclusterv1alpha1.ClusterSet) (e } return } + +// findServiceCIDRByInvalidServiceCreation creates an invalid Service to get returned error, and analyzes +// the error message to get Service CIDR. +// TODO: add dual-stack support. +func findServiceCIDRByInvalidServiceCreation(ctx context.Context, k8sClient client.Client, namespace string) (string, error) { + invalidSvcSpec := &corev1.Service{ + ObjectMeta: metav1.ObjectMeta{ + Name: "invalid-svc", + Namespace: namespace, + }, + Spec: corev1.ServiceSpec{ + ClusterIP: "0.0.0.0", + Ports: []corev1.ServicePort{ + { + Port: 443, + TargetPort: intstr.IntOrString{ + IntVal: 443, + }, + }, + }, + }, + } + + err := k8sClient.Create(ctx, invalidSvcSpec, &client.CreateOptions{}) + // Creating invalid Service didn't fail as expected + if err == nil { + return "", fmt.Errorf("could not determine the Service ClusterIP range via Service creation - " + + "expected a specific error but none was returned") + } + + return parseServiceCIDRFromError(err.Error()) +} + +// TODO: add dual-stack support. +func parseServiceCIDRFromError(msg string) (string, error) { + // Expected error message is like below: + // `The Service "invalid-svc" is invalid: spec.clusterIPs: Invalid value: []string{"0.0.0.0"}: + // failed to allocate IP 0.0.0.0: provided IP is not in the valid range. The range of valid IPs is 10.19.0.0/18` + // The CIDR string should be parsed from the error message is: + // 10.19.0.0/18 + re := regexp.MustCompile(".*valid IPs is (.*)$") + + match := re.FindStringSubmatch(msg) + if match == nil { + return "", fmt.Errorf("could not determine the ClusterIP range via Service creation - the expected error "+ + "was not returned. The actual error was %q", msg) + } + + return match[1], nil +} diff --git a/multicluster/controllers/multicluster/gateway_controller.go b/multicluster/controllers/multicluster/gateway_controller.go new file mode 100644 index 00000000000..d87f40ed717 --- /dev/null +++ b/multicluster/controllers/multicluster/gateway_controller.go @@ -0,0 +1,260 @@ +/* +Copyright 2022 Antrea Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package multicluster + +import ( + "context" + "fmt" + "reflect" + "sort" + + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + "k8s.io/klog/v2" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller" + + mcsv1alpha1 "antrea.io/antrea/multicluster/apis/multicluster/v1alpha1" + "antrea.io/antrea/multicluster/controllers/multicluster/common" + "antrea.io/antrea/multicluster/controllers/multicluster/commonarea" +) + +type ( + // GatewayReconciler is for member cluster only. + GatewayReconciler struct { + client.Client + Scheme *runtime.Scheme + commonAreaGetter RemoteCommonAreaGetter + namespace string + localClusterID string + serviceCIDR string + leaderNamespace string + } +) + +// NewGatewayReconciler creates a GatewayReconciler which will watch Gateway events +// and create a ClusterInfo kind of ResourceExport in the leader cluster. +func NewGatewayReconciler( + client client.Client, + scheme *runtime.Scheme, + namespace string, + serviceCIDR string, + commonAreaGetter RemoteCommonAreaGetter) *GatewayReconciler { + reconciler := &GatewayReconciler{ + Client: client, + Scheme: scheme, + namespace: namespace, + serviceCIDR: serviceCIDR, + commonAreaGetter: commonAreaGetter, + } + return reconciler +} + +//+kubebuilder:rbac:groups=multicluster.crd.antrea.io,resources=gateways,verbs=get;list;watch;create;update;patch;delete +//+kubebuilder:rbac:groups=multicluster.crd.antrea.io,resources=gateways/status,verbs=get;update;patch +//+kubebuilder:rbac:groups=multicluster.crd.antrea.io,resources=gateways/finalizers,verbs=update +//+kubebuilder:rbac:groups=multicluster.crd.antrea.io,resources=clusterinfoimports,verbs=get;list;watch;create;update;patch;delete +//+kubebuilder:rbac:groups=multicluster.crd.antrea.io,resources=clusterinfoimports/status,verbs=get;update;patch +//+kubebuilder:rbac:groups=multicluster.crd.antrea.io,resources=clusterinfoimports/finalizers,verbs=update + +func (r *GatewayReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + klog.V(2).InfoS("Reconciling Gateway", "gateway", req.NamespacedName) + var err error + var commonArea commonarea.RemoteCommonArea + commonArea, r.localClusterID, err = r.commonAreaGetter.GetRemoteCommonAreaAndLocalID() + if commonArea == nil { + return ctrl.Result{Requeue: true}, err + } + r.leaderNamespace = commonArea.GetNamespace() + err = r.getServiceCIDR(ctx) + if err != nil { + return ctrl.Result{}, err + } + + resExportName := newClusterInfoResourceExportName(r.localClusterID) + resExportNamespacedName := types.NamespacedName{ + Name: resExportName, + Namespace: r.leaderNamespace, + } + resExport := &mcsv1alpha1.ResourceExport{ + ObjectMeta: metav1.ObjectMeta{ + Name: resExportName, + Namespace: r.leaderNamespace, + }, + } + + createOrUpdate := func(gwIP string, gwInfo *mcsv1alpha1.GatewayInfo) error { + existingResExport := &mcsv1alpha1.ResourceExport{} + if err := commonArea.Get(ctx, resExportNamespacedName, existingResExport); err != nil { + if !apierrors.IsNotFound(err) { + return err + } + if err = r.createResourceExport(ctx, req, commonArea, gwIP); err != nil { + return err + } + return nil + } + if err = r.updateResourceExport(ctx, req, commonArea, existingResExport, gwInfo); err != nil { + return err + } + return nil + } + + gw := &mcsv1alpha1.Gateway{} + if err := r.Client.Get(ctx, req.NamespacedName, gw); err != nil { + if !apierrors.IsNotFound(err) { + return ctrl.Result{}, err + } + gwInfo, err := r.getLastCreatedGateway() + if err != nil { + klog.ErrorS(err, "Failed to get Gateways") + return ctrl.Result{}, err + } + if gwInfo == nil { + // When the last Gateway is deleted, we will remove the ClusterInfo kind of ResourceExport + if err := commonArea.Delete(ctx, resExport, &client.DeleteOptions{}); err != nil { + return ctrl.Result{}, client.IgnoreNotFound(err) + } + return ctrl.Result{}, nil + } + // When there are still Gateways exist, we should create or update existing ResourceExport + // with the latest Gateway in remaining Gateways. + if err := createOrUpdate(gwInfo.GatewayIP, gwInfo); err != nil { + return ctrl.Result{}, err + } + return ctrl.Result{}, nil + } + if err := createOrUpdate(gw.GatewayIP, nil); err != nil { + return ctrl.Result{}, err + } + return ctrl.Result{}, nil +} + +func (r *GatewayReconciler) getLastCreatedGateway() (*mcsv1alpha1.GatewayInfo, error) { + gws := &mcsv1alpha1.GatewayList{} + if err := r.Client.List(ctx, gws, &client.ListOptions{}); err != nil { + return nil, err + } + if len(gws.Items) == 0 { + return nil, nil + } + + // Sort Gateways by CreationTimestamp, the last created Gateway will be the first element. + sort.Slice(gws.Items, func(i, j int) bool { + return !gws.Items[i].CreationTimestamp.Before(&gws.Items[j].CreationTimestamp) + }) + + // Make sure we only return the last created Gateway for now. + return &mcsv1alpha1.GatewayInfo{GatewayIP: gws.Items[0].GatewayIP}, nil +} + +func (r *GatewayReconciler) updateResourceExport(ctx context.Context, req ctrl.Request, + commonArea commonarea.RemoteCommonArea, existingResExport *mcsv1alpha1.ResourceExport, gwInfo *mcsv1alpha1.GatewayInfo) error { + resExportSpec := mcsv1alpha1.ResourceExportSpec{ + Kind: common.ClusterInfoKind, + ClusterID: r.localClusterID, + Name: r.localClusterID, + Namespace: r.namespace, + } + var err error + if gwInfo == nil { + gwInfo, err = r.getLastCreatedGateway() + if err != nil { + return err + } + } + resExportSpec.ClusterInfo = &mcsv1alpha1.ClusterInfo{ + ClusterID: r.localClusterID, + ServiceCIDR: r.serviceCIDR, + GatewayInfos: []mcsv1alpha1.GatewayInfo{*gwInfo}, + } + if reflect.DeepEqual(existingResExport.Spec, resExportSpec) { + klog.V(2).InfoS("Skip updating ClusterInfo kind of ResourceExport due to no change", "clusterinfo", klog.KObj(existingResExport), + "gateway", req.NamespacedName) + return nil + } + klog.V(2).InfoS("Updating ClusterInfo kind of ResourceExport", "clusterinfo", klog.KObj(existingResExport), + "gateway", req.NamespacedName) + existingResExport.Spec = resExportSpec + if err := commonArea.Update(ctx, existingResExport, &client.UpdateOptions{}); err != nil { + return err + } + return nil +} + +func (r *GatewayReconciler) createResourceExport(ctx context.Context, req ctrl.Request, + commonArea commonarea.RemoteCommonArea, gatewayIP string) error { + resExportSpec := mcsv1alpha1.ResourceExportSpec{ + Kind: common.ClusterInfoKind, + ClusterID: r.localClusterID, + Name: r.localClusterID, + Namespace: r.namespace, + } + resExportSpec.ClusterInfo = &mcsv1alpha1.ClusterInfo{ + ClusterID: r.localClusterID, + ServiceCIDR: r.serviceCIDR, + GatewayInfos: []mcsv1alpha1.GatewayInfo{ + { + GatewayIP: gatewayIP, + }, + }, + } + resExport := &mcsv1alpha1.ResourceExport{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: r.leaderNamespace, + Name: newClusterInfoResourceExportName(r.localClusterID), + }, + Spec: resExportSpec, + } + resExport.Finalizers = []string{common.ResourceExportFinalizer} + if err := commonArea.Create(ctx, resExport, &client.CreateOptions{}); err != nil { + return err + } + klog.InfoS("Created a ClusterInfo kind of ResourceExport", "clusterinfo", klog.KObj(resExport)) + return nil +} + +// SetupWithManager sets up the controller with the Manager. +func (r *GatewayReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + For(&mcsv1alpha1.Gateway{}). + WithOptions(controller.Options{ + // TODO: add a lock for serviceCIDR if there is any plan to + // increase this concurrent number. + MaxConcurrentReconciles: 1, + }). + Complete(r) +} + +// getServiceCIDR gets Service ClusterIP CIDR used in the member cluster. +func (r *GatewayReconciler) getServiceCIDR(ctx context.Context) error { + if len(r.serviceCIDR) == 0 { + serviceCIDR, err := findServiceCIDRByInvalidServiceCreation(ctx, r.Client, r.namespace) + if err != nil { + return fmt.Errorf("failed to find Service ClusterIP range automatically, you may set the 'serviceCIDR' config as an alternative, err: %v, ", err) + } + r.serviceCIDR = serviceCIDR + } + return nil +} + +func newClusterInfoResourceExportName(clusterID string) string { + return clusterID + "-clusterinfo" +} diff --git a/multicluster/controllers/multicluster/gateway_controller_test.go b/multicluster/controllers/multicluster/gateway_controller_test.go new file mode 100644 index 00000000000..5e506335329 --- /dev/null +++ b/multicluster/controllers/multicluster/gateway_controller_test.go @@ -0,0 +1,235 @@ +/* +Copyright 2022 Antrea Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package multicluster + +import ( + "fmt" + "reflect" + "testing" + + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/client/fake" + + mcsv1alpha1 "antrea.io/antrea/multicluster/apis/multicluster/v1alpha1" + "antrea.io/antrea/multicluster/controllers/multicluster/common" + "antrea.io/antrea/multicluster/controllers/multicluster/commonarea" +) + +var ( + serviceCIDR = "10.96.0.0/12" + clusterID = "cluster-a" + + gwNode1 = mcsv1alpha1.Gateway{ + ObjectMeta: metav1.ObjectMeta{ + Name: "node-1", + Namespace: "default", + }, + GatewayIP: "10.10.10.10", + InternalIP: "172.11.10.1", + } + gwNode2 = mcsv1alpha1.Gateway{ + ObjectMeta: metav1.ObjectMeta{ + Name: "node-2", + Namespace: "default", + }, + GatewayIP: "10.8.8.8", + InternalIP: "172.11.10.1", + } + existingResExport = &mcsv1alpha1.ResourceExport{ + ObjectMeta: metav1.ObjectMeta{ + Name: "cluster-a-clusterinfo", + Namespace: leaderNamespace, + }, + Spec: mcsv1alpha1.ResourceExportSpec{ + Name: clusterID, + Namespace: "default", + Kind: common.ClusterInfoKind, + ClusterInfo: &mcsv1alpha1.ClusterInfo{ + ServiceCIDR: serviceCIDR, + ClusterID: clusterID, + GatewayInfos: []mcsv1alpha1.GatewayInfo{ + { + GatewayIP: "10.10.10.10", + }, + }, + }, + }, + } + existingResExport2 = &mcsv1alpha1.ResourceExport{ + ObjectMeta: metav1.ObjectMeta{ + Name: "cluster-a-clusterinfo", + Namespace: leaderNamespace, + }, + Spec: mcsv1alpha1.ResourceExportSpec{ + Name: clusterID, + Namespace: "default", + Kind: common.ClusterInfoKind, + ClusterInfo: &mcsv1alpha1.ClusterInfo{ + ServiceCIDR: serviceCIDR, + ClusterID: clusterID, + GatewayInfos: []mcsv1alpha1.GatewayInfo{ + { + GatewayIP: "101.101.101.101", + }, + }, + }, + }, + } +) + +func TestGatewayReconciler(t *testing.T) { + gwNode1New := gwNode1 + gwNode1New.GatewayIP = "10.10.10.12" + + tests := []struct { + name string + te mcsv1alpha1.Gateway + namespacedName types.NamespacedName + gateway []mcsv1alpha1.Gateway + resExport *mcsv1alpha1.ResourceExport + expectedInfo []mcsv1alpha1.GatewayInfo + isDelete bool + }{ + { + name: "create a ResourceExport successfully", + namespacedName: types.NamespacedName{ + Namespace: "default", + Name: "node-1", + }, + gateway: []mcsv1alpha1.Gateway{ + gwNode1, + }, + resExport: existingResExport, + expectedInfo: []mcsv1alpha1.GatewayInfo{ + { + GatewayIP: "10.10.10.10", + }, + }, + }, + { + name: "update a ResourceExport successfully by creating a new Gateway", + namespacedName: types.NamespacedName{ + Namespace: "default", + Name: "node-2", + }, + gateway: []mcsv1alpha1.Gateway{ + gwNode1, gwNode2, + }, + resExport: existingResExport, + expectedInfo: []mcsv1alpha1.GatewayInfo{ + { + GatewayIP: "10.8.8.8", + }, + }, + }, + { + name: "update a ResourceExport successfully by deleting a Gateway", + namespacedName: types.NamespacedName{ + Namespace: "default", + Name: "node-2", + }, + gateway: []mcsv1alpha1.Gateway{ + gwNode1, + }, + resExport: existingResExport2, + expectedInfo: []mcsv1alpha1.GatewayInfo{ + { + GatewayIP: "10.10.10.10", + }, + }, + }, + { + name: "update a ResourceExport successfully by updating an existing Gateway", + namespacedName: types.NamespacedName{ + Namespace: "default", + Name: "node-1", + }, + gateway: []mcsv1alpha1.Gateway{ + gwNode1New, + }, + resExport: existingResExport, + expectedInfo: []mcsv1alpha1.GatewayInfo{ + { + GatewayIP: "10.10.10.12", + }, + }, + }, + { + name: "delete a ResourceExport successfully by deleting an existing Gateway", + namespacedName: types.NamespacedName{ + Namespace: "default", + Name: "node-1", + }, + resExport: existingResExport, + isDelete: true, + }, + } + + for _, tt := range tests { + var obj []client.Object + for _, n := range tt.gateway { + node := n + obj = append(obj, &node) + } + fakeClient := fake.NewClientBuilder().WithScheme(scheme).WithObjects(obj...).Build() + fakeRemoteClient := fake.NewClientBuilder().WithScheme(scheme).WithObjects().Build() + if tt.resExport != nil { + fakeRemoteClient = fake.NewClientBuilder().WithScheme(scheme).WithObjects(tt.resExport).Build() + } + remoteMgr := commonarea.NewRemoteCommonAreaManager("test-clusterset", common.ClusterID(localClusterID), "kube-system") + remoteMgr.Start() + defer remoteMgr.Stop() + _ = commonarea.NewFakeRemoteCommonArea(scheme, remoteMgr, fakeRemoteClient, "leader-cluster", leaderNamespace) + mcReconciler := NewMemberClusterSetReconciler(fakeClient, scheme, "default") + mcReconciler.SetRemoteCommonAreaManager(remoteMgr) + commonAreaGatter := mcReconciler + r := NewGatewayReconciler(fakeClient, scheme, "default", "10.96.0.0/12", commonAreaGatter) + t.Run(tt.name, func(t *testing.T) { + req := ctrl.Request{NamespacedName: tt.namespacedName} + if _, err := r.Reconcile(ctx, req); err != nil { + t.Errorf("Gateway Reconciler should handle ResourceExports events successfully but got error = %v", err) + } else { + gws := &mcsv1alpha1.GatewayList{} + _ = fakeClient.List(ctx, gws, &client.ListOptions{}) + fmt.Printf("output list: %v", gws) + ciExport := mcsv1alpha1.ResourceExport{} + ciExportName := types.NamespacedName{ + Namespace: leaderNamespace, + Name: newClusterInfoResourceExportName(localClusterID), + } + err := fakeRemoteClient.Get(ctx, ciExportName, &ciExport) + if err == nil { + if !reflect.DeepEqual(ciExport.Spec.ClusterInfo.GatewayInfos, tt.expectedInfo) { + t.Errorf("Expected GatewayInfos are %v but got %v", tt.expectedInfo, ciExport.Spec.ClusterInfo.GatewayInfos) + } + } else { + if tt.isDelete { + if !apierrors.IsNotFound(err) { + t.Errorf("Gateway Reconciler expects not found error but got error = %v", err) + } + } else { + t.Errorf("Expected a ClusterInfo kind of ResourceExport but got error = %v", err) + } + } + } + }) + } +} diff --git a/multicluster/controllers/multicluster/leader_clusterset_controller.go b/multicluster/controllers/multicluster/leader_clusterset_controller.go index b433f6c7ac1..f50d10bd1fd 100644 --- a/multicluster/controllers/multicluster/leader_clusterset_controller.go +++ b/multicluster/controllers/multicluster/leader_clusterset_controller.go @@ -63,8 +63,8 @@ type LeaderClusterSetReconciler struct { func (r *LeaderClusterSetReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { clusterSet := &multiclusterv1alpha1.ClusterSet{} err := r.Get(ctx, req.NamespacedName, clusterSet) - defer r.mutex.Unlock() r.mutex.Lock() + defer r.mutex.Unlock() if err != nil { if !errors.IsNotFound(err) { return ctrl.Result{}, err @@ -85,21 +85,21 @@ func (r *LeaderClusterSetReconciler) Reconcile(ctx context.Context, req ctrl.Req // Handle create or update // If create, make sure the local ClusterClaim is part of the leader config if r.clusterSetConfig == nil { - clusterId, clusterSetId, err := validateLocalClusterClaim(r.Client, clusterSet) + clusterID, clusterSetID, err := validateLocalClusterClaim(r.Client, clusterSet) if err != nil { return ctrl.Result{}, err } - if err = validateConfigExists(clusterId, clusterSet.Spec.Leaders); err != nil { - err = fmt.Errorf("local cluster %s is not defined as leader in ClusterSet", clusterId) + if err = validateConfigExists(clusterID, clusterSet.Spec.Leaders); err != nil { + err = fmt.Errorf("local cluster %s is not defined as leader in ClusterSet", clusterID) return ctrl.Result{}, err } if err = validateClusterSetNamespace(clusterSet); err != nil { return ctrl.Result{}, err } - r.clusterID = clusterId - r.clusterSetID = clusterSetId + r.clusterID = clusterID + r.clusterSetID = clusterSetID } else { - // Make sure clusterSetId has not changed + // Make sure clusterSetID has not changed if string(r.clusterSetID) != req.Name { return ctrl.Result{}, fmt.Errorf("ClusterSet Name %s cannot be changed to %s", r.clusterSetID, req.Name) diff --git a/multicluster/controllers/multicluster/member_clusterset_controller.go b/multicluster/controllers/multicluster/member_clusterset_controller.go index d02985cdc9c..3ddf067ea07 100644 --- a/multicluster/controllers/multicluster/member_clusterset_controller.go +++ b/multicluster/controllers/multicluster/member_clusterset_controller.go @@ -18,13 +18,14 @@ package multicluster import ( "context" + "errors" "fmt" "sync" "time" "go.uber.org/multierr" v1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/api/errors" + apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/types" @@ -38,18 +39,33 @@ import ( "antrea.io/antrea/multicluster/controllers/multicluster/commonarea" ) +type RemoteCommonAreaGetter interface { + GetRemoteCommonAreaAndLocalID() (commonarea.RemoteCommonArea, string, error) +} + // MemberClusterSetReconciler reconciles a ClusterSet object in the member cluster deployment. type MemberClusterSetReconciler struct { client.Client Scheme *runtime.Scheme Namespace string - mutex sync.Mutex + mutex sync.RWMutex clusterSetConfig *multiclusterv1alpha1.ClusterSet clusterSetID common.ClusterSetID clusterID common.ClusterID - RemoteCommonAreaManager commonarea.RemoteCommonAreaManager + remoteCommonAreaManager commonarea.RemoteCommonAreaManager +} + +func NewMemberClusterSetReconciler(client client.Client, + scheme *runtime.Scheme, + namespace string, +) *MemberClusterSetReconciler { + return &MemberClusterSetReconciler{ + Client: client, + Scheme: scheme, + Namespace: namespace, + } } //+kubebuilder:rbac:groups=multicluster.crd.antrea.io,resources=clustersets,verbs=get;list;watch;create;update;patch;delete @@ -64,15 +80,15 @@ func (r *MemberClusterSetReconciler) Reconcile(ctx context.Context, req ctrl.Req } clusterSet := &multiclusterv1alpha1.ClusterSet{} err := r.Get(ctx, req.NamespacedName, clusterSet) - defer r.mutex.Unlock() r.mutex.Lock() + defer r.mutex.Unlock() if err != nil { - if !errors.IsNotFound(err) { + if !apierrors.IsNotFound(err) { return ctrl.Result{}, err } klog.InfoS("Received ClusterSet delete", "config", klog.KObj(clusterSet)) - stopErr := r.RemoteCommonAreaManager.Stop() - r.RemoteCommonAreaManager = nil + stopErr := r.remoteCommonAreaManager.Stop() + r.remoteCommonAreaManager = nil r.clusterSetConfig = nil r.clusterID = common.InvalidClusterID r.clusterSetID = common.InvalidClusterSetID @@ -85,16 +101,16 @@ func (r *MemberClusterSetReconciler) Reconcile(ctx context.Context, req ctrl.Req // Handle create or update if r.clusterSetConfig == nil { // If create, make sure the local ClusterClaim is part of the member config - clusterId, clusterSetId, err := validateLocalClusterClaim(r.Client, clusterSet) + clusterID, clusterSetID, err := validateLocalClusterClaim(r.Client, clusterSet) if err != nil { return ctrl.Result{}, err } - if err = validateConfigExists(clusterId, clusterSet.Spec.Members); err != nil { - err = fmt.Errorf("local cluster %s is not defined as member in ClusterSet", clusterId) + if err = validateConfigExists(clusterID, clusterSet.Spec.Members); err != nil { + err = fmt.Errorf("local cluster %s is not defined as member in ClusterSet", clusterID) return ctrl.Result{}, err } - r.clusterID = clusterId - r.clusterSetID = clusterSetId + r.clusterID = clusterID + r.clusterSetID = clusterSetID } else { if string(r.clusterSetID) != clusterSet.Name { return ctrl.Result{}, fmt.Errorf("ClusterSet Name %s cannot be changed to %s", @@ -131,12 +147,12 @@ func (r *MemberClusterSetReconciler) SetupWithManager(mgr ctrl.Manager) error { } func (r *MemberClusterSetReconciler) updateMultiClusterSetOnMemberCluster(clusterSet *multiclusterv1alpha1.ClusterSet) error { - if r.RemoteCommonAreaManager == nil { - r.RemoteCommonAreaManager = commonarea.NewRemoteCommonAreaManager(r.clusterSetID, r.clusterID) - err := r.RemoteCommonAreaManager.Start() + if r.remoteCommonAreaManager == nil { + r.remoteCommonAreaManager = commonarea.NewRemoteCommonAreaManager(r.clusterSetID, r.clusterID, r.Namespace) + err := r.remoteCommonAreaManager.Start() if err != nil { klog.ErrorS(err, "Error starting RemoteCommonAreaManager") - r.RemoteCommonAreaManager = nil + r.remoteCommonAreaManager = nil r.clusterSetID = common.InvalidClusterSetID r.clusterID = common.InvalidClusterID r.clusterSetConfig = nil @@ -144,7 +160,7 @@ func (r *MemberClusterSetReconciler) updateMultiClusterSetOnMemberCluster(cluste } } - currentLeaders := r.RemoteCommonAreaManager.GetRemoteCommonAreas() + currentLeaders := r.remoteCommonAreaManager.GetRemoteCommonAreas() newLeaders := clusterSet.Spec.Leaders var addedLeaders []*multiclusterv1alpha1.MemberCluster @@ -176,7 +192,7 @@ func (r *MemberClusterSetReconciler) updateMultiClusterSetOnMemberCluster(cluste secret, err := r.getSecretForLeader(secretName, clusterSet.GetNamespace()) if err == nil { _, err = commonarea.NewRemoteCommonArea(clusterID, r.clusterSetID, url, secret, r.Scheme, - r.Client, r.RemoteCommonAreaManager, clusterSet.Spec.Namespace) + r.Client, r.remoteCommonAreaManager, clusterSet.Spec.Namespace) } if err != nil { klog.ErrorS(err, "Unable to create RemoteCommonArea", "Cluster", clusterID) @@ -188,7 +204,7 @@ func (r *MemberClusterSetReconciler) updateMultiClusterSetOnMemberCluster(cluste removedLeaders = currentLeaders for _, remoteCommonArea := range removedLeaders { - r.RemoteCommonAreaManager.RemoveRemoteCommonArea(remoteCommonArea) + r.remoteCommonAreaManager.RemoveRemoteCommonArea(remoteCommonArea) klog.InfoS("Deleted RemoteCommonArea", "Cluster", remoteCommonArea.GetClusterID()) } @@ -227,7 +243,7 @@ func (r *MemberClusterSetReconciler) updateStatus() { status := multiclusterv1alpha1.ClusterSetStatus{} status.TotalClusters = int32(len(r.clusterSetConfig.Spec.Members) + len(r.clusterSetConfig.Spec.Leaders)) status.ObservedGeneration = r.clusterSetConfig.Generation - status.ClusterStatuses = r.RemoteCommonAreaManager.GetMemberClusterStatues() + status.ClusterStatuses = r.remoteCommonAreaManager.GetMemberClusterStatues() overallCondition := multiclusterv1alpha1.ClusterSetCondition{ Type: multiclusterv1alpha1.ClusterSetReady, @@ -290,3 +306,35 @@ func (r *MemberClusterSetReconciler) updateStatus() { klog.ErrorS(err, "Failed to update Status of ClusterSet", "Name", namespacedName) } } + +// SetRemoteCommonAreaManager is for testing only +func (r *MemberClusterSetReconciler) SetRemoteCommonAreaManager(mgr commonarea.RemoteCommonAreaManager) commonarea.RemoteCommonAreaManager { + r.remoteCommonAreaManager = mgr + return r.remoteCommonAreaManager +} + +func (r *MemberClusterSetReconciler) GetRemoteCommonAreaAndLocalID() (commonarea.RemoteCommonArea, string, error) { + r.mutex.RLock() + defer r.mutex.RUnlock() + var remoteCommonArea commonarea.RemoteCommonArea + if r.remoteCommonAreaManager == nil { + return nil, "", errors.New("ClusterSet has not been initialized, no available Common Area") + } + + remoteCommonAreas := r.remoteCommonAreaManager.GetRemoteCommonAreas() + if len(remoteCommonAreas) <= 0 { + return nil, "", errors.New("ClusterSet has not been set up properly, no available Common Area") + } + + for _, c := range remoteCommonAreas { + if c.IsConnected() { + remoteCommonArea = c + break + } + } + if remoteCommonArea != nil { + localClusterID := string(r.remoteCommonAreaManager.GetLocalClusterID()) + return remoteCommonArea, localClusterID, nil + } + return nil, "", errors.New("no connected remote common area") +} diff --git a/multicluster/controllers/multicluster/node_controller.go b/multicluster/controllers/multicluster/node_controller.go new file mode 100644 index 00000000000..6136c420787 --- /dev/null +++ b/multicluster/controllers/multicluster/node_controller.go @@ -0,0 +1,173 @@ +/* +Copyright 2022 Antrea Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package multicluster + +import ( + "context" + "fmt" + "net" + + corev1 "k8s.io/api/core/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + "k8s.io/klog/v2" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller" + + mcsv1alpha1 "antrea.io/antrea/multicluster/apis/multicluster/v1alpha1" + "antrea.io/antrea/multicluster/controllers/multicluster/common" +) + +type ( + // NodeReconciler is for member cluster only. + // It will create a Gateway object if a Node has an annotation `multicluster.antrea.io/gateway:true` + // and update corresponding Gateway if any subnets changes. + NodeReconciler struct { + client.Client + Scheme *runtime.Scheme + namespace string + precedence mcsv1alpha1.Precedence + } +) + +// NewNodeReconciler creates a NodeReconciler to watch Node object changes and create a +// corresponding Gateway if the Node has the annotation `multicluster.antrea.io/gateway:true`. +func NewNodeReconciler( + client client.Client, + scheme *runtime.Scheme, + namespace string, + precedence mcsv1alpha1.Precedence) *NodeReconciler { + if string(precedence) == "" { + precedence = mcsv1alpha1.PrecedencePrivate + } + reconciler := &NodeReconciler{ + Client: client, + Scheme: scheme, + namespace: namespace, + precedence: precedence, + } + return reconciler +} + +//+kubebuilder:rbac:groups=multicluster.crd.antrea.io,resources=gateways,verbs=get;list;watch;create;update;patch;delete +//+kubebuilder:rbac:groups="",resources=nodes,verbs=get;list;watch; +//+kubebuilder:rbac:groups=multicluster.crd.antrea.io,resources=gateways/status,verbs=get;update;patch +//+kubebuilder:rbac:groups=multicluster.crd.antrea.io,resources=gateways/finalizers,verbs=update + +func (r *NodeReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + klog.V(2).InfoS("Reconciling Node", "node", req.Name) + gw := &mcsv1alpha1.Gateway{ + ObjectMeta: metav1.ObjectMeta{ + Name: req.Name, + Namespace: r.namespace, + }, + } + // When the Node is annotated with 'multicluster.antrea.io/gateway=true' as a Gateway: + // - Delete the Gateway if the Node is deleted + // - Update the Gateway if Node's InternalIP or GatewayIP is updated + // - Create a new Gateway if there is no existing Gateway + node := &corev1.Node{} + if err := r.Client.Get(ctx, req.NamespacedName, node); err != nil { + if apierrors.IsNotFound(err) { + err := r.Client.Delete(ctx, gw, &client.DeleteOptions{}) + return ctrl.Result{}, client.IgnoreNotFound(err) + } + klog.ErrorS(err, "Failed to get Node", "node", req.Name) + return ctrl.Result{}, err + } + + _, isGW := node.Annotations[common.GatewayAnnotation] + var err error + gwNamespacedName := types.NamespacedName{ + Name: node.Name, + Namespace: r.namespace, + } + + // TODO: cache might be stale. Need to revisit here and other reconcilers to + // check if we can improve this with 'Owns' or other methods. + var gwIP, internalIP string + if isGW { + if internalIP, gwIP, err = r.getGatawayNodeIP(node); err != nil { + klog.ErrorS(err, "There is no valid Gateway IP for Node, will retry later when there is any new Node update", "node", node.Name) + return ctrl.Result{}, nil + } + } + if err := r.Client.Get(ctx, gwNamespacedName, gw); err != nil { + if apierrors.IsNotFound(err) && isGW { + gw.GatewayIP = gwIP + gw.InternalIP = internalIP + if err := r.Client.Create(ctx, gw, &client.CreateOptions{}); err != nil { + return ctrl.Result{}, err + } + return ctrl.Result{}, nil + } + return ctrl.Result{}, client.IgnoreNotFound(err) + } + + if !isGW { + err := r.Client.Delete(ctx, gw, &client.DeleteOptions{}) + return ctrl.Result{}, client.IgnoreNotFound(err) + } + + gw.GatewayIP = gwIP + gw.InternalIP = internalIP + if err := r.Client.Update(ctx, gw, &client.UpdateOptions{}); err != nil { + return ctrl.Result{}, err + } + return ctrl.Result{}, nil +} + +func (r *NodeReconciler) getGatawayNodeIP(node *corev1.Node) (string, string, error) { + var gatewayIP, internalIP string + for _, addr := range node.Status.Addresses { + if addr.Type == corev1.NodeInternalIP { + if r.precedence == mcsv1alpha1.PrecedencePrivate { + gatewayIP = addr.Address + } + internalIP = addr.Address + } + if r.precedence == mcsv1alpha1.PrecedencePublic && addr.Type == corev1.NodeExternalIP { + gatewayIP = addr.Address + } + } + + if ip, ok := node.Annotations[common.GatewayIPAnnotation]; ok { + parsedIP := net.ParseIP(ip) + if parsedIP == nil { + return "", "", fmt.Errorf("the Gateway IP annotation %s on Node %s is not a valid IP address", ip, node.Name) + } + gatewayIP = ip + } + + if gatewayIP == "" || internalIP == "" { + return "", "", fmt.Errorf("no valid IP address for Gateway Node %s", node.Name) + } + return internalIP, gatewayIP, nil +} + +// SetupWithManager sets up the controller with the Manager. +func (r *NodeReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + For(&corev1.Node{}). + WithOptions(controller.Options{ + MaxConcurrentReconciles: 1, + }). + Complete(r) +} diff --git a/multicluster/controllers/multicluster/node_controller_test.go b/multicluster/controllers/multicluster/node_controller_test.go new file mode 100644 index 00000000000..b3ed403f0ed --- /dev/null +++ b/multicluster/controllers/multicluster/node_controller_test.go @@ -0,0 +1,145 @@ +/* +Copyright 2022 Antrea Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package multicluster + +import ( + "testing" + + "github.com/stretchr/testify/assert" + corev1 "k8s.io/api/core/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/client/fake" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + + mcsv1alpha1 "antrea.io/antrea/multicluster/apis/multicluster/v1alpha1" + "antrea.io/antrea/multicluster/controllers/multicluster/common" +) + +func TestNodeReconciler(t *testing.T) { + node1 := &corev1.Node{ + ObjectMeta: metav1.ObjectMeta{ + Name: "node-1", + Annotations: map[string]string{ + common.GatewayAnnotation: "true", + }, + }, + Status: corev1.NodeStatus{ + Addresses: []corev1.NodeAddress{ + { + Type: corev1.NodeExternalIP, + Address: "10.10.10.10", + }, + { + Type: corev1.NodeInternalIP, + Address: "172.11.10.1", + }, + }, + }, + } + node1NoValidUpdate := *node1 + node1NoValidUpdate.Labels = map[string]string{"hostname.k8s.io": "node-1"} + node1NoAnnotation := *node1 + node1NoAnnotation.Annotations = map[string]string{} + node1WithIPAnnotation := *node1 + node1WithIPAnnotation.Annotations = map[string]string{ + common.GatewayAnnotation: "true", + common.GatewayIPAnnotation: "11.11.10.10", + } + + tests := []struct { + name string + nodes []*corev1.Node + req reconcile.Request + existingGW *mcsv1alpha1.Gateway + expectedGW *mcsv1alpha1.Gateway + isDelete bool + expectedErr string + }{ + { + name: "create a Gateway successfully", + nodes: []*corev1.Node{node1}, + req: reconcile.Request{NamespacedName: types.NamespacedName{Namespace: "", Name: node1.Name}}, + expectedGW: &gwNode1, + }, + { + name: "update a Gateway successfully by changing GatewayIP", + nodes: []*corev1.Node{&node1WithIPAnnotation}, + req: reconcile.Request{NamespacedName: types.NamespacedName{Namespace: "", Name: node1.Name}}, + existingGW: &gwNode1, + expectedGW: &mcsv1alpha1.Gateway{ + ObjectMeta: metav1.ObjectMeta{ + Name: "node-1", + Namespace: "default", + }, + GatewayIP: "11.11.10.10", + InternalIP: "172.11.10.1", + }, + }, + { + name: "remove a Gateway Node to delete a Gateway successfully", + nodes: []*corev1.Node{}, + req: reconcile.Request{NamespacedName: types.NamespacedName{Namespace: "", Name: node1.Name}}, + existingGW: &gwNode1, + isDelete: true, + }, + { + name: "remove a Gateway Node's annotation to delete a Gateway successfully", + nodes: []*corev1.Node{&node1NoAnnotation}, + req: reconcile.Request{NamespacedName: types.NamespacedName{Namespace: "", Name: node1.Name}}, + existingGW: &gwNode1, + isDelete: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + var obj []client.Object + for _, n := range tt.nodes { + obj = append(obj, n) + } + if tt.existingGW != nil { + obj = append(obj, tt.existingGW) + } + fakeClient := fake.NewClientBuilder().WithScheme(scheme).WithObjects(obj...).Build() + r := NewNodeReconciler(fakeClient, scheme, "default", mcsv1alpha1.PrecedencePublic) + if _, err := r.Reconcile(ctx, tt.req); err != nil { + if tt.expectedErr != "" { + assert.Contains(t, err.Error(), tt.expectedErr) + } else { + t.Errorf("Node Reconciler should handle Node events successfully but got error = %v", err) + } + } else { + newGW := &mcsv1alpha1.Gateway{} + gwNamespcedName := types.NamespacedName{Name: "node-1", Namespace: "default"} + err := fakeClient.Get(ctx, gwNamespcedName, newGW) + if err != nil { + if tt.isDelete { + if !apierrors.IsNotFound(err) { + t.Errorf("Expected to get not found error but got err: %v", err) + } + } else { + t.Errorf("Expected to get Gateway but got err: %v", err) + } + } else if tt.expectedGW.GatewayIP != newGW.GatewayIP || tt.expectedGW.InternalIP != newGW.InternalIP { + t.Errorf("Expected Gateway %v but got: %v", tt.expectedGW, newGW) + } + } + }) + } +} diff --git a/multicluster/controllers/multicluster/resourceexport_controller.go b/multicluster/controllers/multicluster/resourceexport_controller.go index 5ebede40dbc..b31321aaadc 100644 --- a/multicluster/controllers/multicluster/resourceexport_controller.go +++ b/multicluster/controllers/multicluster/resourceexport_controller.go @@ -56,11 +56,11 @@ const ( ) func NewResourceExportReconciler( - Client client.Client, - Scheme *runtime.Scheme) *ResourceExportReconciler { + client client.Client, + scheme *runtime.Scheme) *ResourceExportReconciler { reconciler := &ResourceExportReconciler{ - Client: Client, - Scheme: Scheme, + Client: client, + Scheme: scheme, } return reconciler } @@ -87,16 +87,18 @@ func (r *ResourceExportReconciler) Reconcile(ctx context.Context, req ctrl.Reque klog.V(2).InfoS("Reconciling Endpoint type of ResourceExport", "resourceexport", req.NamespacedName) case common.AntreaClusterNetworkPolicyKind: klog.V(2).InfoS("Reconciling AntreaClusterNetworkPolicy type of ResourceExport", "resourceexport", req.NamespacedName) + case common.ClusterInfoKind: + return r.handleClusterInfo(ctx, req, resExport) default: klog.InfoS("It's not expected kind, skip reconciling ResourceExport", "resourceexport", req.NamespacedName) return ctrl.Result{}, nil } // We are using Finalizers to implement asynchronous pre-delete hooks. - // When ResourceExport is deleted, it will have non-zero DeletionTimestamp - // but controller can still get the deleted ResourceExport object, so we can - // clean up any external resources like ResourceImport. - // More details about using Finalizers, please refer to https://book.kubebuilder.io/reference/using-finalizers.html. + // When a ResourceExport is deleted, it will have non-zero DeletionTimestamp + // but controller can still get the deleted ResourceExport object, so it can + // clean up any replicated resources like ResourceImport. + // For more details about using Finalizers, please refer to https://book.kubebuilder.io/reference/using-finalizers.html. if !resExport.DeletionTimestamp.IsZero() { if common.StringExistsInSlice(resExport.Finalizers, common.ResourceExportFinalizer) { err := r.handleDeleteEvent(ctx, &resExport) @@ -494,6 +496,7 @@ func SvcPortsConverter(svcPort []corev1.ServicePort) []mcs.ServicePort { var mcsSP []mcs.ServicePort for _, v := range svcPort { mcsSP = append(mcsSP, mcs.ServicePort{ + Name: v.Name, Port: v.Port, Protocol: v.Protocol, }) diff --git a/multicluster/controllers/multicluster/resourceexport_controller_test.go b/multicluster/controllers/multicluster/resourceexport_controller_test.go index fd1ff1c61d6..01de2c2380e 100644 --- a/multicluster/controllers/multicluster/resourceexport_controller_test.go +++ b/multicluster/controllers/multicluster/resourceexport_controller_test.go @@ -82,7 +82,7 @@ var ( ) func TestResourceExportReconciler_handleServiceExportDeleteEvent(t *testing.T) { - existResExport := &mcsv1alpha1.ResourceExport{ + existingResExport := &mcsv1alpha1.ResourceExport{ ObjectMeta: metav1.ObjectMeta{ Namespace: "default", Name: "cluster-a-default-nginx-service", @@ -103,7 +103,7 @@ func TestResourceExportReconciler_handleServiceExportDeleteEvent(t *testing.T) { }, } namespacedName := types.NamespacedName{Namespace: "default", Name: "default-nginx-service"} - fakeClient := fake.NewClientBuilder().WithScheme(scheme).WithObjects(existResExport, existResImport).Build() + fakeClient := fake.NewClientBuilder().WithScheme(scheme).WithObjects(existingResExport, existResImport).Build() r := NewResourceExportReconciler(fakeClient, scheme) if _, err := r.Reconcile(ctx, svcResReq); err != nil { t.Errorf("ResourceExport Reconciler should handle ResourceExport delete event successfully but got error = %v", err) @@ -117,7 +117,7 @@ func TestResourceExportReconciler_handleServiceExportDeleteEvent(t *testing.T) { } func TestResourceExportReconciler_handleEndpointsExportDeleteEvent(t *testing.T) { - existResExport1 := &mcsv1alpha1.ResourceExport{ + existingResExport1 := &mcsv1alpha1.ResourceExport{ ObjectMeta: metav1.ObjectMeta{ Namespace: "default", Name: "cluster-a-default-nginx-endpoints", @@ -134,7 +134,7 @@ func TestResourceExportReconciler_handleEndpointsExportDeleteEvent(t *testing.T) }, }, } - existResExport2 := &mcsv1alpha1.ResourceExport{ + existingResExport2 := &mcsv1alpha1.ResourceExport{ ObjectMeta: metav1.ObjectMeta{ Namespace: "default", Name: "cluster-b-default-nginx-endpoints", @@ -166,7 +166,7 @@ func TestResourceExportReconciler_handleEndpointsExportDeleteEvent(t *testing.T) } expectedSubsets := epNginxSubset2 namespacedName := types.NamespacedName{Namespace: "default", Name: "default-nginx-endpoints"} - fakeClient := fake.NewClientBuilder().WithScheme(scheme).WithObjects(existResExport1, existResExport2, existResImport).Build() + fakeClient := fake.NewClientBuilder().WithScheme(scheme).WithObjects(existingResExport1, existingResExport2, existResImport).Build() r := NewResourceExportReconciler(fakeClient, scheme) if _, err := r.Reconcile(ctx, epResReq); err != nil { t.Errorf("ResourceExport Reconciler should handle Endpoints ResourceExport delete event successfully but got error = %v", err) @@ -182,7 +182,7 @@ func TestResourceExportReconciler_handleEndpointsExportDeleteEvent(t *testing.T) } func TestResourceExportReconciler_handleServiceExportCreateEvent(t *testing.T) { - existResExport := &mcsv1alpha1.ResourceExport{ + existingResExport := &mcsv1alpha1.ResourceExport{ ObjectMeta: metav1.ObjectMeta{ Namespace: "default", Name: "cluster-a-default-nginx-service", @@ -203,13 +203,13 @@ func TestResourceExportReconciler_handleServiceExportCreateEvent(t *testing.T) { Kind: common.ServiceImportKind, ServiceImport: &mcs.ServiceImport{ Spec: mcs.ServiceImportSpec{ - Ports: SvcPortsConverter(existResExport.Spec.Service.ServiceSpec.Ports), + Ports: SvcPortsConverter(existingResExport.Spec.Service.ServiceSpec.Ports), Type: mcs.ClusterSetIP, }, }, } namespacedName := types.NamespacedName{Namespace: "default", Name: "default-nginx-service"} - fakeClient := fake.NewClientBuilder().WithScheme(scheme).WithObjects(existResExport).Build() + fakeClient := fake.NewClientBuilder().WithScheme(scheme).WithObjects(existingResExport).Build() r := NewResourceExportReconciler(fakeClient, scheme) if _, err := r.Reconcile(ctx, svcResReq); err != nil { t.Errorf("ResourceExport Reconciler should handle Service ResourceExport create event successfully but got error = %v", err) @@ -372,7 +372,7 @@ func TestResourceExportReconciler_handleSingleServiceUpdateEvent(t *testing.T) { ServiceImport: &mcs.ServiceImport{ Spec: mcs.ServiceImportSpec{ Ports: SvcPortsConverter([]corev1.ServicePort{{ - Name: "8080tcp", + Name: "http", Port: 8080, Protocol: corev1.ProtocolTCP, }}), @@ -400,7 +400,7 @@ func TestResourceExportReconciler_handleSingleServiceUpdateEvent(t *testing.T) { // When there are multiple Service ResourceExports mapping to ResourceImport // one ResourceExport update with ports conflicts should return error func TestResourceExportReconciler_handleServiceUpdateEvent(t *testing.T) { - existResExport2 := &mcsv1alpha1.ResourceExport{ + existingResExport2 := &mcsv1alpha1.ResourceExport{ ObjectMeta: metav1.ObjectMeta{ Namespace: "default", Name: "cluster-b-default-nginx-service", @@ -418,7 +418,7 @@ func TestResourceExportReconciler_handleServiceUpdateEvent(t *testing.T) { } fakeClient := fake.NewClientBuilder().WithScheme(scheme). - WithObjects(newResExport, existResExport2, existResImport).Build() + WithObjects(newResExport, existingResExport2, existResImport).Build() r := NewResourceExportReconciler(fakeClient, scheme) if _, err := r.Reconcile(ctx, svcResReq); err != nil { if !assert.Contains(t, err.Error(), "don't match existing") { @@ -434,3 +434,148 @@ func TestResourceExportReconciler_handleServiceUpdateEvent(t *testing.T) { } } } + +func TestResourceExportReconciler_handleClusterInfoKind(t *testing.T) { + clusterAInfo := mcsv1alpha1.ClusterInfo{ + ClusterID: "cluster-a", + ServiceCIDR: "10.168.1.0/24", + GatewayInfos: []mcsv1alpha1.GatewayInfo{ + { + GatewayIP: "172.17.0.2", + }, + }, + } + clusterBInfo := mcsv1alpha1.ClusterInfo{ + ClusterID: "cluster-b", + ServiceCIDR: "110.16.1.0/24", + GatewayInfos: []mcsv1alpha1.GatewayInfo{ + { + GatewayIP: "12.17.0.2", + }, + }, + } + clusterBInfoNew := mcsv1alpha1.ClusterInfo{ + ClusterID: "cluster-b", + ServiceCIDR: "110.16.1.0/24", + GatewayInfos: []mcsv1alpha1.GatewayInfo{ + { + GatewayIP: "120.11.0.12", + }, + }, + } + clusterACIResExport := mcsv1alpha1.ResourceExport{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "default", + Name: "cluster-a-default-clusterinfo", + }, + Spec: mcsv1alpha1.ResourceExportSpec{ + Kind: common.ClusterInfoKind, + ClusterID: "cluster-a", + Name: "cluster-a", + Namespace: "default", + ClusterInfo: &clusterAInfo, + }, + } + clusterBCIResExport := mcsv1alpha1.ResourceExport{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "default", + Name: "cluster-b-default-clusterinfo", + }, + Spec: mcsv1alpha1.ResourceExportSpec{ + Kind: common.ClusterInfoKind, + ClusterID: "cluster-b", + Name: "node-2", + Namespace: "default", + ClusterInfo: &clusterBInfoNew, + }, + } + existResImport := mcsv1alpha1.ResourceImport{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "default", + Name: "cluster-b-default-clusterinfo", + }, + Spec: mcsv1alpha1.ResourceImportSpec{ + Kind: common.ClusterInfoKind, + Name: "node-2", + Namespace: "default", + ClusterInfo: &clusterBInfo, + }, + } + deletedTime := metav1.Now() + cluster3ResExportToDel := mcsv1alpha1.ResourceExport{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "default", + Name: "cluster-c-default-clusterinfo", + Finalizers: []string{common.ResourceExportFinalizer}, + DeletionTimestamp: &deletedTime, + }, + Spec: mcsv1alpha1.ResourceExportSpec{ + Kind: common.ClusterInfoKind, + ClusterID: "cluster-c", + Name: "cluster-c", + Namespace: "default", + }, + } + existResImportToDel := mcsv1alpha1.ResourceImport{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "default", + Name: "cluster-c-default-clusterinfo", + }, + Spec: mcsv1alpha1.ResourceImportSpec{ + Kind: common.ClusterInfoKind, + Name: "cluster-c", + Namespace: "default", + ClusterInfo: &clusterBInfo, + }, + } + tests := []struct { + name string + ciRes mcsv1alpha1.ResourceExport + expectedInfo mcsv1alpha1.ClusterInfo + isDelete bool + }{ + { + name: "create a ClusterInfo kind of ResourceImport successfully", + ciRes: clusterACIResExport, + expectedInfo: clusterAInfo, + }, + { + name: "update a ClusterInfo kind of ResourceImport successfully", + ciRes: clusterBCIResExport, + expectedInfo: clusterBInfoNew, + }, + { + name: "delete a ClusterInfo kind of ResourceImport successfully", + ciRes: cluster3ResExportToDel, + isDelete: true, + }, + } + fakeClient := fake.NewClientBuilder().WithScheme(scheme).WithObjects(&clusterACIResExport, &clusterBCIResExport, + &existResImport, &existResImportToDel, &cluster3ResExportToDel).Build() + r := NewResourceExportReconciler(fakeClient, scheme) + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + namespacedName := types.NamespacedName{Namespace: tt.ciRes.Namespace, Name: tt.ciRes.Name} + req := ctrl.Request{NamespacedName: namespacedName} + if _, err := r.Reconcile(ctx, req); err != nil { + t.Errorf("ResourceExport Reconciler should handle Resourcexports events successfully but got error = %v", err) + } else { + teImport := mcsv1alpha1.ResourceImport{} + err := fakeClient.Get(ctx, namespacedName, &teImport) + if err == nil { + if tt.isDelete { + t.Error("Expected not found err but got nil err") + } else if !reflect.DeepEqual(*teImport.Spec.ClusterInfo, tt.expectedInfo) { + t.Errorf("Expected ClusterInfo %v but got %v", tt.expectedInfo, teImport.Spec.ClusterInfo) + } + } else { + teExport := mcsv1alpha1.ResourceExport{} + err := fakeClient.Get(ctx, namespacedName, &teExport) + if !apierrors.IsNotFound(err) { + t.Errorf("ResourceExport should be deleted successfully but got = %v", err) + } + } + } + }) + } +} diff --git a/multicluster/controllers/multicluster/serviceexport_controller.go b/multicluster/controllers/multicluster/serviceexport_controller.go index 44a3f48ce6f..06f16d28a37 100644 --- a/multicluster/controllers/multicluster/serviceexport_controller.go +++ b/multicluster/controllers/multicluster/serviceexport_controller.go @@ -20,8 +20,6 @@ import ( "context" "reflect" "sort" - "strconv" - "strings" corev1 "k8s.io/api/core/v1" apiequality "k8s.io/apimachinery/pkg/api/equality" @@ -64,13 +62,13 @@ type ( // ServiceExportReconciler reconciles a ServiceExport object in the member cluster. ServiceExportReconciler struct { client.Client - Scheme *runtime.Scheme - remoteCommonAreaManager *commonarea.RemoteCommonAreaManager - installedSvcs cache.Indexer - installedEps cache.Indexer - leaderNamespace string - leaderClusterID string - localClusterID string + Scheme *runtime.Scheme + commonAreaGetter RemoteCommonAreaGetter + installedSvcs cache.Indexer + installedEps cache.Indexer + leaderNamespace string + leaderClusterID string + localClusterID string } ) @@ -88,13 +86,13 @@ const ( ) func NewServiceExportReconciler( - Client client.Client, - Scheme *runtime.Scheme, - remoteCommonAreaManager *commonarea.RemoteCommonAreaManager) *ServiceExportReconciler { + client client.Client, + scheme *runtime.Scheme, + commonAreaGetter RemoteCommonAreaGetter) *ServiceExportReconciler { reconciler := &ServiceExportReconciler{ - Client: Client, - Scheme: Scheme, - remoteCommonAreaManager: remoteCommonAreaManager, + Client: client, + Scheme: scheme, + commonAreaGetter: commonAreaGetter, installedSvcs: cache.NewIndexer(svcInfoKeyFunc, cache.Indexers{ svcIndexerByType: svcIndexerByTypeFunc, }), @@ -162,66 +160,58 @@ func (r *ServiceExportReconciler) Reconcile(ctx context.Context, req ctrl.Reques klog.InfoS("Skip reconciling, no corresponding ServiceExport") return ctrl.Result{}, nil } - - if *r.remoteCommonAreaManager == nil { - klog.InfoS("ClusterSet has not been initialized properly, no remote cluster manager") - return ctrl.Result{Requeue: true}, nil - } - r.localClusterID = string((*r.remoteCommonAreaManager).GetLocalClusterID()) - if len(r.localClusterID) == 0 { - klog.InfoS("localClusterID is not initialized, skip reconcile") - return ctrl.Result{Requeue: true}, nil + var commonArea commonarea.RemoteCommonArea + commonArea, r.localClusterID, err = r.commonAreaGetter.GetRemoteCommonAreaAndLocalID() + if commonArea == nil { + return ctrl.Result{Requeue: true}, err } + r.leaderNamespace = commonArea.GetNamespace() + r.leaderClusterID = string(commonArea.GetClusterID()) + var svcExport k8smcsv1alpha1.ServiceExport svcObj, svcInstalled, _ := r.installedSvcs.GetByKey(req.String()) epObj, epInstalled, _ := r.installedEps.GetByKey(req.String()) svcResExportName := getResourceExportName(r.localClusterID, req, "service") epResExportName := getResourceExportName(r.localClusterID, req, "endpoints") - remoteCluster, err := getRemoteCommonArea(r.remoteCommonAreaManager) - if err != nil { - return ctrl.Result{}, err - } - - r.leaderNamespace = remoteCluster.GetNamespace() - r.leaderClusterID = string(remoteCluster.GetClusterID()) - - svc := &corev1.Service{} - if err := r.Client.Get(ctx, req.NamespacedName, &svcExport); err != nil { - klog.V(2).ErrorS(err, "Unable to fetch ServiceExport", "serviceexport", req.String()) - if !apierrors.IsNotFound(err) { - return ctrl.Result{}, err - } + cleanup := func() error { if svcInstalled { - err = r.handleServiceDeleteEvent(ctx, req, remoteCluster) + err = r.handleServiceDeleteEvent(ctx, req, commonArea) if err != nil { - return ctrl.Result{}, err + return err } r.installedSvcs.Delete(svcObj) } - if epInstalled { - err = r.handleEndpointDeleteEvent(ctx, req, remoteCluster) + err = r.handleEndpointDeleteEvent(ctx, req, commonArea) if err != nil { - return ctrl.Result{}, err + return err } r.installedEps.Delete(epObj) } + return nil + } + + if err := r.Client.Get(ctx, req.NamespacedName, &svcExport); err != nil { + if !apierrors.IsNotFound(err) { + klog.ErrorS(err, "Unable to fetch ServiceExport", "serviceexport", req.String()) + return ctrl.Result{}, err + } + if err := cleanup(); err != nil { + return ctrl.Result{}, err + } return ctrl.Result{}, nil } // if corresponding Service doesn't exist, update ServiceExport's status reason to not_found_service, // and clean up remote ResourceExport if it's an installed Service. + svc := &corev1.Service{} err = r.Client.Get(ctx, req.NamespacedName, svc) if err != nil { if apierrors.IsNotFound(err) { - if svcInstalled { - err = r.handleServiceDeleteEvent(ctx, req, remoteCluster) - if err != nil { - return ctrl.Result{}, err - } - r.installedSvcs.Delete(svcObj) + if err := cleanup(); err != nil { + return ctrl.Result{}, err } err = r.updateSvcExportStatus(ctx, req, notFound) if err != nil { @@ -272,7 +262,7 @@ func (r *ServiceExportReconciler) Reconcile(ctx context.Context, req ctrl.Reques if err != nil { klog.ErrorS(err, "Failed to get Endpoints", "endpoints", req.String()) if apierrors.IsNotFound(err) && epInstalled { - err = r.handleEndpointDeleteEvent(ctx, req, remoteCluster) + err = r.handleEndpointDeleteEvent(ctx, req, commonArea) if err != nil { return ctrl.Result{}, err } @@ -314,7 +304,7 @@ func (r *ServiceExportReconciler) Reconcile(ctx context.Context, req ctrl.Reques if !svcNoChange { klog.InfoS("Service has new changes, update ResourceExport", "service", req.String(), "resourceexport", svcExportNSName) - err := r.serviceHandler(ctx, req, svc, svcResExportName, re, remoteCluster) + err := r.serviceHandler(ctx, req, svc, svcResExportName, re, commonArea) if err != nil { klog.ErrorS(err, "Failed to handle Service change", "service", req.String()) return ctrl.Result{}, err @@ -324,7 +314,7 @@ func (r *ServiceExportReconciler) Reconcile(ctx context.Context, req ctrl.Reques if !epNoChange { klog.InfoS("Endpoints have new change, update ResourceExport", "endpoints", req.String(), "resourceexport", epExportNSName) - err := r.endpointsHandler(ctx, req, ep, epResExportName, re, remoteCluster) + err := r.endpointsHandler(ctx, req, ep, epResExportName, re, commonArea) if err != nil { klog.ErrorS(err, "Failed to handle Endpoints change", "endpoints", req.String()) return ctrl.Result{}, err @@ -339,7 +329,7 @@ func (r *ServiceExportReconciler) Reconcile(ctx context.Context, req ctrl.Reques } func (r *ServiceExportReconciler) handleServiceDeleteEvent(ctx context.Context, req ctrl.Request, - remoteCluster commonarea.RemoteCommonArea) error { + commonArea commonarea.RemoteCommonArea) error { svcResExportName := getResourceExportName(r.localClusterID, req, "service") svcResExport := &mcsv1alpha1.ResourceExport{ ObjectMeta: metav1.ObjectMeta{ @@ -349,19 +339,19 @@ func (r *ServiceExportReconciler) handleServiceDeleteEvent(ctx context.Context, } // clean up Service kind of ResourceExport in remote leader cluster - svcResExportNamespaced := common.NamespacedName(r.leaderNamespace, svcResExportName) - err := remoteCluster.Delete(ctx, svcResExport, &client.DeleteOptions{}) + svcResExportNamespacedName := common.NamespacedName(r.leaderNamespace, svcResExportName) + err := commonArea.Delete(ctx, svcResExport, &client.DeleteOptions{}) if err != nil && !apierrors.IsNotFound(err) { klog.ErrorS(err, "Failed to delete ResourceExport in remote cluster", "resourceexport", - svcResExportNamespaced, "clusterID", r.leaderClusterID) + svcResExportNamespacedName, "clusterID", r.leaderClusterID) return err } - klog.V(2).InfoS("Clean up ResourceExport in remote cluster", "resourceexport", svcResExportNamespaced) + klog.V(2).InfoS("Clean up ResourceExport in remote cluster", "resourceexport", svcResExportNamespacedName) return nil } func (r *ServiceExportReconciler) handleEndpointDeleteEvent(ctx context.Context, req ctrl.Request, - remoteCluster commonarea.RemoteCommonArea) error { + commonArea commonarea.RemoteCommonArea) error { epResExportName := getResourceExportName(r.localClusterID, req, "endpoints") epResExport := &mcsv1alpha1.ResourceExport{ ObjectMeta: metav1.ObjectMeta{ @@ -371,15 +361,15 @@ func (r *ServiceExportReconciler) handleEndpointDeleteEvent(ctx context.Context, } // clean up Endpoints kind of ResourceExport in remote leader cluster - epResExportNamespaced := common.NamespacedName(r.leaderNamespace, epResExportName) - err := remoteCluster.Delete(ctx, epResExport, &client.DeleteOptions{}) + epResExportNamespacedName := common.NamespacedName(r.leaderNamespace, epResExportName) + err := commonArea.Delete(ctx, epResExport, &client.DeleteOptions{}) if err != nil && !apierrors.IsNotFound(err) { klog.ErrorS(err, "Failed to delete ResourceExport in remote cluster", "resourceexport", - epResExportNamespaced, "clusterID", r.leaderClusterID) + epResExportNamespacedName, "clusterID", r.leaderClusterID) return err } - klog.V(2).InfoS("Clean up ResourceExport in remote cluster", "resourceexport", epResExportNamespaced) + klog.V(2).InfoS("Clean up ResourceExport in remote cluster", "resourceexport", epResExportNamespacedName) return nil } @@ -448,16 +438,19 @@ func (r *ServiceExportReconciler) updateSvcExportStatus(ctx context.Context, req func (r *ServiceExportReconciler) SetupWithManager(mgr ctrl.Manager) error { return ctrl.NewControllerManagedBy(mgr). For(&k8smcsv1alpha1.ServiceExport{}). - Watches(&source.Kind{Type: &corev1.Service{}}, handler.EnqueueRequestsFromMapFunc(objMapFunc)). - Watches(&source.Kind{Type: &corev1.Endpoints{}}, handler.EnqueueRequestsFromMapFunc(objMapFunc)). + Watches(&source.Kind{Type: &corev1.Service{}}, handler.EnqueueRequestsFromMapFunc(serviceAndEndpointMapFunc)). + Watches(&source.Kind{Type: &corev1.Endpoints{}}, handler.EnqueueRequestsFromMapFunc(serviceAndEndpointMapFunc)). WithOptions(controller.Options{ MaxConcurrentReconciles: common.DefaultWorkerCount, }). Complete(r) } -// objMapFunc simply maps all object events to ServiceExport -func objMapFunc(a client.Object) []reconcile.Request { +// serviceAndEndpointMapFunc simply maps all Service and Endpoints events to ServiceExports. +// When there are any Service/Endpoints changes, it might be reflected in ResourceExport +// in Leader cluster as well, so ServiceExportReconciler also needs to watch Service +// and Endpoints events. +func serviceAndEndpointMapFunc(a client.Object) []reconcile.Request { return []reconcile.Request{ { NamespacedName: types.NamespacedName{ @@ -486,16 +479,16 @@ func (r *ServiceExportReconciler) serviceHandler( svcType: string(svc.Spec.Type), } r.refreshResourceExport(resName, kind, svc, nil, &re) - existResExport := &mcsv1alpha1.ResourceExport{} + existingResExport := &mcsv1alpha1.ResourceExport{} resNamespaced := types.NamespacedName{Namespace: rc.GetNamespace(), Name: resName} - err := rc.Get(ctx, resNamespaced, existResExport) + err := rc.Get(ctx, resNamespaced, existingResExport) if err != nil { if !apierrors.IsNotFound(err) { klog.ErrorS(err, "Failed to get ResourceExport", "resourceexport", resNamespaced.String()) return err } } - if err = r.updateOrCreateResourceExport(resName, ctx, req, &re, existResExport, rc); err != nil { + if err = r.updateOrCreateResourceExport(resName, ctx, req, &re, existingResExport, rc); err != nil { return err } r.installedSvcs.Add(sinfo) @@ -520,16 +513,16 @@ func (r *ServiceExportReconciler) endpointsHandler( labels: ep.Labels, } r.refreshResourceExport(resName, kind, nil, ep, &re) - existResExport := &mcsv1alpha1.ResourceExport{} + existingResExport := &mcsv1alpha1.ResourceExport{} resNamespaced := types.NamespacedName{Namespace: rc.GetNamespace(), Name: resName} - err := rc.Get(ctx, resNamespaced, existResExport) + err := rc.Get(ctx, resNamespaced, existingResExport) if err != nil { if !apierrors.IsNotFound(err) { klog.ErrorS(err, "Failed to get ResourceExport", "resourceexport", resNamespaced.String()) return err } } - if err = r.updateOrCreateResourceExport(resName, ctx, req, &re, existResExport, rc); err != nil { + if err = r.updateOrCreateResourceExport(resName, ctx, req, &re, existingResExport, rc); err != nil { return err } r.installedEps.Add(epInfo) @@ -544,15 +537,8 @@ func (r *ServiceExportReconciler) refreshResourceExport(resName, kind string, switch kind { case common.ServiceKind: re.ObjectMeta.Name = resName - newSvcSpec := svc.Spec.DeepCopy() - var renamedPorts []corev1.ServicePort - for _, p := range svc.Spec.Ports { - p.Name = strings.ToLower(string(p.Protocol)) + strconv.Itoa(int(p.Port)) - renamedPorts = append(renamedPorts, p) - } - newSvcSpec.Ports = renamedPorts re.Spec.Service = &mcsv1alpha1.ServiceExport{ - ServiceSpec: *newSvcSpec, + ServiceSpec: svc.Spec, } re.Labels[common.SourceKind] = common.ServiceKind case common.EndpointsKind: @@ -569,11 +555,16 @@ func (r *ServiceExportReconciler) updateOrCreateResourceExport(resName string, ctx context.Context, req ctrl.Request, newResExport *mcsv1alpha1.ResourceExport, - existResExport *mcsv1alpha1.ResourceExport, + existingResExport *mcsv1alpha1.ResourceExport, rc commonarea.RemoteCommonArea) error { - createResExport := reflect.DeepEqual(*existResExport, mcsv1alpha1.ResourceExport{}) + createResExport := reflect.DeepEqual(*existingResExport, mcsv1alpha1.ResourceExport{}) resNamespaced := types.NamespacedName{Namespace: rc.GetNamespace(), Name: resName} if createResExport { + // We are using Finalizers to implement asynchronous pre-delete hooks. + // When a ServiceExport is deleted, the corresponding ResourceExport will have non-zero + // DeletionTimestamp, so Leader controller can still get the deleted ResourceExport object, + // then it can clean up any external resources like ResourceImport. + // For more details about using Finalizers, please refer to https://book.kubebuilder.io/reference/using-finalizers.html. newResExport.Finalizers = []string{common.ResourceExportFinalizer} klog.InfoS("Creating ResourceExport", "resourceexport", resNamespaced.String()) err := rc.Create(ctx, newResExport, &client.CreateOptions{}) @@ -582,8 +573,8 @@ func (r *ServiceExportReconciler) updateOrCreateResourceExport(resName string, return err } } else { - newResExport.ObjectMeta.ResourceVersion = existResExport.ObjectMeta.ResourceVersion - newResExport.Finalizers = existResExport.Finalizers + newResExport.ObjectMeta.ResourceVersion = existingResExport.ObjectMeta.ResourceVersion + newResExport.Finalizers = existingResExport.Finalizers err := rc.Update(ctx, newResExport, &client.UpdateOptions{}) if err != nil { klog.ErrorS(err, "Failed to update ResourceExport", "resourceexport", resNamespaced.String()) diff --git a/multicluster/controllers/multicluster/serviceexport_controller_test.go b/multicluster/controllers/multicluster/serviceexport_controller_test.go index 38623cbc1d2..0378bc122c5 100644 --- a/multicluster/controllers/multicluster/serviceexport_controller_test.go +++ b/multicluster/controllers/multicluster/serviceexport_controller_test.go @@ -24,6 +24,7 @@ import ( apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" + ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client/fake" "sigs.k8s.io/controller-runtime/pkg/reconcile" @@ -35,26 +36,26 @@ import ( ) var ( - leaderNamespace string - localClusterID string + nginxReq = ctrl.Request{NamespacedName: types.NamespacedName{ + Namespace: "default", + Name: "nginx", + }} ) func TestServiceExportReconciler_handleDeleteEvent(t *testing.T) { - localClusterID = "cluster-a" - leaderNamespace = "default" - remoteMgr := commonarea.NewRemoteCommonAreaManager("test-clusterset", common.ClusterID(localClusterID)) - go remoteMgr.Start() - + remoteMgr := commonarea.NewRemoteCommonAreaManager("test-clusterset", common.ClusterID(localClusterID), "kube-system") + remoteMgr.Start() + defer remoteMgr.Stop() existSvcResExport := &mcsv1alpha1.ResourceExport{ ObjectMeta: metav1.ObjectMeta{ Namespace: leaderNamespace, - Name: getResourceExportName(localClusterID, req, "service"), + Name: getResourceExportName(localClusterID, nginxReq, "service"), }, } existEpResExport := &mcsv1alpha1.ResourceExport{ ObjectMeta: metav1.ObjectMeta{ Namespace: leaderNamespace, - Name: getResourceExportName(localClusterID, req, "endpoints"), + Name: getResourceExportName(localClusterID, nginxReq, "endpoints"), }, } exportedSvcNginx := svcNginx.DeepCopy() @@ -62,8 +63,10 @@ func TestServiceExportReconciler_handleDeleteEvent(t *testing.T) { fakeClient := fake.NewClientBuilder().WithScheme(scheme).WithObjects(exportedSvcNginx).Build() fakeRemoteClient := fake.NewClientBuilder().WithScheme(scheme).WithObjects(existSvcResExport, existEpResExport).Build() - _ = commonarea.NewFakeRemoteCommonArea(scheme, &remoteMgr, fakeRemoteClient, "leader-cluster", "default") - r := NewServiceExportReconciler(fakeClient, scheme, &remoteMgr) + _ = commonarea.NewFakeRemoteCommonArea(scheme, remoteMgr, fakeRemoteClient, "leader-cluster", "default") + mcReconciler := NewMemberClusterSetReconciler(fakeClient, scheme, "default") + mcReconciler.SetRemoteCommonAreaManager(remoteMgr) + r := NewServiceExportReconciler(fakeClient, scheme, mcReconciler) r.installedSvcs.Add(&svcInfo{ name: svcNginx.Name, namespace: svcNginx.Namespace, @@ -72,7 +75,7 @@ func TestServiceExportReconciler_handleDeleteEvent(t *testing.T) { name: epNginx.Name, namespace: epNginx.Namespace, }) - if _, err := r.Reconcile(ctx, req); err != nil { + if _, err := r.Reconcile(ctx, nginxReq); err != nil { t.Errorf("ServiceExport Reconciler should handle delete event successfully but got error = %v", err) } else { epResource := &mcsv1alpha1.ResourceExport{} @@ -81,7 +84,7 @@ func TestServiceExportReconciler_handleDeleteEvent(t *testing.T) { Name: "cluster-a-default-nginx-endpoints", }, epResource) if !apierrors.IsNotFound(err) { - t.Errorf("expect not found error but got error = %v", err) + t.Errorf("Expected not found error but got error = %v", err) } svcResource := &mcsv1alpha1.ResourceExport{} err = fakeRemoteClient.Get(ctx, types.NamespacedName{ @@ -89,16 +92,15 @@ func TestServiceExportReconciler_handleDeleteEvent(t *testing.T) { Name: "cluster-a-default-nginx-service", }, svcResource) if !apierrors.IsNotFound(err) { - t.Errorf("expect not found error but got error = %v", err) + t.Errorf("Expected not found error but got error = %v", err) } } } func TestServiceExportReconciler_ExportNotFoundService(t *testing.T) { - localClusterID = "cluster-a" - leaderNamespace = "default" - remoteMgr := commonarea.NewRemoteCommonAreaManager("test-clusterset", common.ClusterID(localClusterID)) - go remoteMgr.Start() + remoteMgr := commonarea.NewRemoteCommonAreaManager("test-clusterset", common.ClusterID(localClusterID), "kube-system") + remoteMgr.Start() + defer remoteMgr.Stop() existSvcExport := &k8smcsv1alpha1.ServiceExport{ ObjectMeta: metav1.ObjectMeta{ @@ -109,10 +111,12 @@ func TestServiceExportReconciler_ExportNotFoundService(t *testing.T) { fakeClient := fake.NewClientBuilder().WithScheme(scheme).WithObjects(existSvcExport).Build() fakeRemoteClient := fake.NewClientBuilder().WithScheme(scheme).Build() + _ = commonarea.NewFakeRemoteCommonArea(scheme, remoteMgr, fakeRemoteClient, "leader-cluster", "default") - _ = commonarea.NewFakeRemoteCommonArea(scheme, &remoteMgr, fakeRemoteClient, "leader-cluster", "default") - r := NewServiceExportReconciler(fakeClient, scheme, &remoteMgr) - if _, err := r.Reconcile(ctx, req); err != nil { + mcReconciler := NewMemberClusterSetReconciler(fakeClient, scheme, "default") + mcReconciler.SetRemoteCommonAreaManager(remoteMgr) + r := NewServiceExportReconciler(fakeClient, scheme, mcReconciler) + if _, err := r.Reconcile(ctx, nginxReq); err != nil { t.Errorf("ServiceExport Reconciler should update ServiceExport status to 'not_found_service' but got error = %v", err) } else { newSvcExport := &k8smcsv1alpha1.ServiceExport{} @@ -137,10 +141,9 @@ func checkAnnotation(t *testing.T, svcExport *k8smcsv1alpha1.ServiceExport) { } func TestServiceExportReconciler_ExportMCSService(t *testing.T) { - localClusterID = "cluster-a" - leaderNamespace = "default" - remoteMgr := commonarea.NewRemoteCommonAreaManager("test-clusterset", common.ClusterID(localClusterID)) - go remoteMgr.Start() + remoteMgr := commonarea.NewRemoteCommonAreaManager("test-clusterset", common.ClusterID(localClusterID), "kube-system") + remoteMgr.Start() + defer remoteMgr.Stop() mcsSvc := svcNginx.DeepCopy() mcsSvc.Annotations = map[string]string{common.AntreaMCServiceAnnotation: "true"} @@ -154,9 +157,11 @@ func TestServiceExportReconciler_ExportMCSService(t *testing.T) { fakeClient := fake.NewClientBuilder().WithScheme(scheme).WithObjects(mcsSvc, existSvcExport).Build() fakeRemoteClient := fake.NewClientBuilder().WithScheme(scheme).Build() - _ = commonarea.NewFakeRemoteCommonArea(scheme, &remoteMgr, fakeRemoteClient, "leader-cluster", "default") - r := NewServiceExportReconciler(fakeClient, scheme, &remoteMgr) - if _, err := r.Reconcile(ctx, req); err != nil { + _ = commonarea.NewFakeRemoteCommonArea(scheme, remoteMgr, fakeRemoteClient, "leader-cluster", "default") + mcReconciler := NewMemberClusterSetReconciler(fakeClient, scheme, "default") + mcReconciler.SetRemoteCommonAreaManager(remoteMgr) + r := NewServiceExportReconciler(fakeClient, scheme, mcReconciler) + if _, err := r.Reconcile(ctx, nginxReq); err != nil { t.Errorf("ServiceExport Reconciler should update ServiceExport status to 'imported_service' but got error = %v", err) } else { newSvcExport := &k8smcsv1alpha1.ServiceExport{} @@ -174,10 +179,9 @@ func TestServiceExportReconciler_ExportMCSService(t *testing.T) { } func TestServiceExportReconciler_handleServiceExportCreateEvent(t *testing.T) { - localClusterID = "cluster-a" - leaderNamespace = "default" - remoteMgr := commonarea.NewRemoteCommonAreaManager("test-clusterset", common.ClusterID(localClusterID)) - go remoteMgr.Start() + remoteMgr := commonarea.NewRemoteCommonAreaManager("test-clusterset", common.ClusterID(localClusterID), "kube-system") + remoteMgr.Start() + defer remoteMgr.Stop() existSvcExport := &k8smcsv1alpha1.ServiceExport{ ObjectMeta: metav1.ObjectMeta{ @@ -189,9 +193,11 @@ func TestServiceExportReconciler_handleServiceExportCreateEvent(t *testing.T) { fakeClient := fake.NewClientBuilder().WithScheme(scheme).WithObjects(svcNginx, epNginx, existSvcExport).Build() fakeRemoteClient := fake.NewClientBuilder().WithScheme(scheme).Build() - _ = commonarea.NewFakeRemoteCommonArea(scheme, &remoteMgr, fakeRemoteClient, "leader-cluster", "default") - r := NewServiceExportReconciler(fakeClient, scheme, &remoteMgr) - if _, err := r.Reconcile(ctx, req); err != nil { + _ = commonarea.NewFakeRemoteCommonArea(scheme, remoteMgr, fakeRemoteClient, "leader-cluster", "default") + mcReconciler := NewMemberClusterSetReconciler(fakeClient, scheme, "default") + mcReconciler.SetRemoteCommonAreaManager(remoteMgr) + r := NewServiceExportReconciler(fakeClient, scheme, mcReconciler) + if _, err := r.Reconcile(ctx, nginxReq); err != nil { t.Errorf("ServiceExport Reconciler should create ResourceExports but got error = %v", err) } else { svcResExport := &mcsv1alpha1.ResourceExport{} @@ -211,10 +217,9 @@ func TestServiceExportReconciler_handleServiceExportCreateEvent(t *testing.T) { } func TestServiceExportReconciler_handleServiceUpdateEvent(t *testing.T) { - localClusterID = "cluster-a" - leaderNamespace = "default" - remoteMgr := commonarea.NewRemoteCommonAreaManager("test-clusterset", common.ClusterID(localClusterID)) - go remoteMgr.Start() + remoteMgr := commonarea.NewRemoteCommonAreaManager("test-clusterset", common.ClusterID(localClusterID), "kube-system") + remoteMgr.Start() + defer remoteMgr.Stop() existSvcExport := &k8smcsv1alpha1.ServiceExport{ ObjectMeta: metav1.ObjectMeta{ @@ -247,15 +252,15 @@ func TestServiceExportReconciler_handleServiceUpdateEvent(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Namespace: leaderNamespace, Labels: map[string]string{ - common.SourceName: req.Name, - common.SourceNamespace: req.Namespace, + common.SourceName: nginxReq.Name, + common.SourceNamespace: nginxReq.Namespace, common.SourceClusterID: localClusterID, }, }, Spec: mcsv1alpha1.ResourceExportSpec{ ClusterID: localClusterID, - Name: req.Name, - Namespace: req.Namespace, + Name: nginxReq.Name, + Namespace: nginxReq.Namespace, }, } existSvcRe := re.DeepCopy() @@ -270,11 +275,13 @@ func TestServiceExportReconciler_handleServiceUpdateEvent(t *testing.T) { fakeClient := fake.NewClientBuilder().WithScheme(scheme).WithObjects(newSvcNginx, newEpNginx, existSvcExport).Build() fakeRemoteClient := fake.NewClientBuilder().WithScheme(scheme).WithObjects(existSvcRe, existEpRe).Build() - _ = commonarea.NewFakeRemoteCommonArea(scheme, &remoteMgr, fakeRemoteClient, "leader-cluster", "default") - r := NewServiceExportReconciler(fakeClient, scheme, &remoteMgr) + _ = commonarea.NewFakeRemoteCommonArea(scheme, remoteMgr, fakeRemoteClient, "leader-cluster", "default") + mcReconciler := NewMemberClusterSetReconciler(fakeClient, scheme, "default") + mcReconciler.SetRemoteCommonAreaManager(remoteMgr) + r := NewServiceExportReconciler(fakeClient, scheme, mcReconciler) r.installedSvcs.Add(sinfo) r.installedEps.Add(epInfo) - if _, err := r.Reconcile(ctx, req); err != nil { + if _, err := r.Reconcile(ctx, nginxReq); err != nil { t.Errorf("ServiceExport Reconciler should update ResourceExports but got error = %v", err) } else { svcResExport := &mcsv1alpha1.ResourceExport{} @@ -285,7 +292,7 @@ func TestServiceExportReconciler_handleServiceUpdateEvent(t *testing.T) { ports := svcResExport.Spec.Service.ServiceSpec.Ports expectedPorts := []corev1.ServicePort{ { - Name: "tcp8080", + Name: "http", Protocol: corev1.ProtocolTCP, Port: 8080, }, @@ -320,7 +327,7 @@ func TestServiceExportReconciler_handleServiceUpdateEvent(t *testing.T) { } } -func Test_objMapFunc(t *testing.T) { +func Test_serviceAndEndpointMapFunc(t *testing.T) { tests := []struct { name string obj client.Object @@ -363,8 +370,8 @@ func Test_objMapFunc(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - if got := objMapFunc(tt.obj); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Test_objMapFunc() = %v, want %v", got, tt.want) + if got := serviceAndEndpointMapFunc(tt.obj); !reflect.DeepEqual(got, tt.want) { + t.Errorf("Test_serviceAndEndpointMapFunc() = %v, want %v", got, tt.want) } }) } diff --git a/multicluster/controllers/multicluster/stale_controller.go b/multicluster/controllers/multicluster/stale_controller.go index 96ab549cea6..1cf1c4d9131 100644 --- a/multicluster/controllers/multicluster/stale_controller.go +++ b/multicluster/controllers/multicluster/stale_controller.go @@ -17,7 +17,6 @@ limitations under the License. package multicluster import ( - "errors" "time" corev1 "k8s.io/api/core/v1" @@ -36,26 +35,31 @@ import ( crdv1alpha1 "antrea.io/antrea/pkg/apis/crd/v1alpha1" ) -// StaleController will clean up ServiceImport and MC Service if no corresponding ResourceImport -// in the leader cluster and remove any ResourceExport in the leader cluster if no correspoding -// ServiceExport in the member cluster. It will only run in the member cluster. -type StaleController struct { +// StaleResCleanupController will clean up ServiceImport, MC Service, ACNP, ClusterInfoImport resources +// if no corresponding ResourceImports in the leader cluster and remove stale ResourceExports +// in the leader cluster if no corresponding ServiceExport or Gateway in the member cluster. +// It will only run in the member cluster. +type StaleResCleanupController struct { client.Client - Scheme *runtime.Scheme - remoteCommonAreaManager *commonarea.RemoteCommonAreaManager + Scheme *runtime.Scheme + localClusterID string + commonAreaGetter RemoteCommonAreaGetter + namespace string // queue only ever has one item, but it has nice error handling backoff/retry semantics queue workqueue.RateLimitingInterface } -func NewStaleController( +func NewStaleResCleanupController( Client client.Client, Scheme *runtime.Scheme, - remoteCommonAreaManager *commonarea.RemoteCommonAreaManager) *StaleController { - reconciler := &StaleController{ - Client: Client, - Scheme: Scheme, - remoteCommonAreaManager: remoteCommonAreaManager, - queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "StaleController"), + namespace string, + commonAreaGetter RemoteCommonAreaGetter) *StaleResCleanupController { + reconciler := &StaleResCleanupController{ + Client: Client, + Scheme: Scheme, + namespace: namespace, + commonAreaGetter: commonAreaGetter, + queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "StaleResCleanupController"), } return reconciler } @@ -65,33 +69,49 @@ func NewStaleController( //+kubebuilder:rbac:groups=multicluster.crd.antrea.io,resources=resourceimports,verbs=get;list;watch; //+kubebuilder:rbac:groups=multicluster.crd.antrea.io,resources=resourceexports,verbs=get;list;watch;delete -func (c *StaleController) cleanup() error { - if *c.remoteCommonAreaManager == nil { - return errors.New("ClusterSet has not been initialized properly, no available remote common area") - } - remoteCluster, err := getRemoteCommonArea(c.remoteCommonAreaManager) +func (c *StaleResCleanupController) cleanup() error { + var err error + var commonArea commonarea.RemoteCommonArea + commonArea, c.localClusterID, err = c.commonAreaGetter.GetRemoteCommonAreaAndLocalID() if err != nil { return err } - localClusterID := string((*c.remoteCommonAreaManager).GetLocalClusterID()) - if len(localClusterID) == 0 { - return errors.New("localClusterID is not initialized, retry later") - } + resImpList := &mcsv1alpha1.ResourceImportList{} - if err := remoteCluster.List(ctx, resImpList, &client.ListOptions{Namespace: remoteCluster.GetNamespace()}); err != nil { + if err := commonArea.List(ctx, resImpList, &client.ListOptions{Namespace: commonArea.GetNamespace()}); err != nil { return err } - if err := c.cleanupStaleServiceResources(remoteCluster, localClusterID, resImpList); err != nil { + if err := c.cleanupStaleServiceResources(commonArea, resImpList); err != nil { return err } + if err := c.cleanupACNPResources(resImpList); err != nil { return err } + if err := c.cleanupClusterInfoImport(resImpList); err != nil { + return err + } + + // Clean up stale ResourceExports in the leader cluster. + resExpList := &mcsv1alpha1.ResourceExportList{} + if err := commonArea.List(ctx, resExpList, &client.ListOptions{Namespace: commonArea.GetNamespace()}); err != nil { + return err + } + + if len(resExpList.Items) == 0 { + return nil + } + if err := c.cleanupServiceResourceExport(commonArea, resExpList); err != nil { + return err + } + if err := c.cleanupClusterInfoResourceExport(commonArea, resExpList); err != nil { + return err + } return nil } -func (c *StaleController) cleanupStaleServiceResources(remoteCluster commonarea.RemoteCommonArea, - localClusterID string, resImpList *mcsv1alpha1.ResourceImportList) error { +func (c *StaleResCleanupController) cleanupStaleServiceResources(commonArea commonarea.RemoteCommonArea, + resImpList *mcsv1alpha1.ResourceImportList) error { svcImpList := &k8smcsv1alpha1.ServiceImportList{} if err := c.List(ctx, svcImpList, &client.ListOptions{}); err != nil { return err @@ -102,87 +122,43 @@ func (c *StaleController) cleanupStaleServiceResources(remoteCluster commonarea. return err } - svcImpItems := svcImpList.Items - var mcsSvcItems []corev1.Service + svcImpItems := map[string]k8smcsv1alpha1.ServiceImport{} + for _, svcImp := range svcImpList.Items { + svcImpItems[svcImp.Namespace+"/"+svcImp.Name] = svcImp + } + + mcsSvcItems := map[string]corev1.Service{} for _, svc := range svcList.Items { if _, ok := svc.Annotations[common.AntreaMCServiceAnnotation]; ok { - mcsSvcItems = append(mcsSvcItems, svc) + mcsSvcItems[svc.Namespace+"/"+svc.Name] = svc } } for _, resImp := range resImpList.Items { - for k, svc := range mcsSvcItems { - if resImp.Spec.Kind == common.ServiceImportKind && svc.Name == common.AntreaMCSPrefix+resImp.Spec.Name && svc.Namespace == resImp.Spec.Namespace { - // Set the valid Service item as empty Service, then all left non-empty items should be removed. - mcsSvcItems[k] = corev1.Service{} - } - } - for n, svcImp := range svcImpItems { - if svcImp.Name == resImp.Spec.Name && svcImp.Namespace == resImp.Spec.Namespace { - svcImpItems[n] = k8smcsv1alpha1.ServiceImport{} - } - } - } - - for _, svc := range mcsSvcItems { - s := svc - if s.Name != "" { - klog.InfoS("Cleaning up stale Service", "service", klog.KObj(&s)) - if err := c.Client.Delete(ctx, &s, &client.DeleteOptions{}); err != nil && !apierrors.IsNotFound(err) { - return err - } + if resImp.Spec.Kind == common.ServiceImportKind { + delete(mcsSvcItems, resImp.Spec.Namespace+"/"+common.AntreaMCSPrefix+resImp.Spec.Name) + delete(svcImpItems, resImp.Spec.Namespace+"/"+resImp.Spec.Name) } } - for _, svcImp := range svcImpItems { - si := svcImp - if si.Name != "" { - klog.InfoS("Cleaning up stale ServiceImport", "serviceimport", klog.KObj(&si)) - if err := c.Client.Delete(ctx, &si, &client.DeleteOptions{}); err != nil && !apierrors.IsNotFound(err) { - return err - } - } - } - - // clean up any ResourceExport if no corresponding ServiceExport locally - resExpList := &mcsv1alpha1.ResourceExportList{} - labelSelector := metav1.LabelSelector{ - MatchLabels: map[string]string{ - common.SourceClusterID: localClusterID, - }, - } - selector, _ := metav1.LabelSelectorAsSelector(&labelSelector) - if err := remoteCluster.List(ctx, resExpList, &client.ListOptions{Namespace: remoteCluster.GetNamespace(), LabelSelector: selector}); err != nil { - return err - } - svcExpList := &k8smcsv1alpha1.ServiceExportList{} - if err := c.List(ctx, svcExpList, &client.ListOptions{}); err != nil { - return err - } - resExpItems := resExpList.Items - svcExpItems := svcExpList.Items - for k, re := range resExpItems { - for _, se := range svcExpItems { - if re.Spec.Name == se.Name && re.Spec.Namespace == se.Namespace { - // Set the valid ResourceExport item as empty ResourceExport, then all left non-empty items should be removed. - resExpItems[k] = mcsv1alpha1.ResourceExport{} - } + for _, staleSvc := range mcsSvcItems { + svc := staleSvc + klog.InfoS("Cleaning up stale Service", "service", klog.KObj(&svc)) + if err := c.Client.Delete(ctx, &svc, &client.DeleteOptions{}); err != nil && !apierrors.IsNotFound(err) { + return err } } - - for _, r := range resExpItems { - re := r - if re.Name != "" { - klog.InfoS("Cleaning up ResourceExport", "ResourceExport", klog.KObj(&re)) - if err := remoteCluster.Delete(ctx, &re, &client.DeleteOptions{}); err != nil && !apierrors.IsNotFound(err) { - return err - } + for _, staleSvcImp := range svcImpItems { + svcImp := staleSvcImp + klog.InfoS("Cleaning up stale ServiceImport", "serviceimport", klog.KObj(&svcImp)) + if err := c.Client.Delete(ctx, &svcImp, &client.DeleteOptions{}); err != nil && !apierrors.IsNotFound(err) { + return err } } return nil } -func (c *StaleController) cleanupACNPResources(resImpList *mcsv1alpha1.ResourceImportList) error { +func (c *StaleResCleanupController) cleanupACNPResources(resImpList *mcsv1alpha1.ResourceImportList) error { acnpList := &crdv1alpha1.ClusterNetworkPolicyList{} if err := c.List(ctx, acnpList, &client.ListOptions{}); err != nil { return err @@ -196,9 +172,7 @@ func (c *StaleController) cleanupACNPResources(resImpList *mcsv1alpha1.ResourceI for _, resImp := range resImpList.Items { if resImp.Spec.Kind == common.AntreaClusterNetworkPolicyKind { acnpNameFromResImp := common.AntreaMCSPrefix + resImp.Spec.Name - if _, ok := staleMCACNPItems[acnpNameFromResImp]; ok { - delete(staleMCACNPItems, acnpNameFromResImp) - } + delete(staleMCACNPItems, acnpNameFromResImp) } } for _, stalePolicy := range staleMCACNPItems { @@ -211,19 +185,104 @@ func (c *StaleController) cleanupACNPResources(resImpList *mcsv1alpha1.ResourceI return nil } -// Enqueue will be called after StaleController is initialized. -func (c *StaleController) Enqueue() { +func (c *StaleResCleanupController) cleanupClusterInfoImport(resImpList *mcsv1alpha1.ResourceImportList) error { + ciImpList := &mcsv1alpha1.ClusterInfoImportList{} + if err := c.List(ctx, ciImpList, &client.ListOptions{}); err != nil { + return err + } + + staleCIImps := map[string]mcsv1alpha1.ClusterInfoImport{} + for _, item := range ciImpList.Items { + staleCIImps[item.Name] = item + } + for _, resImp := range resImpList.Items { + if resImp.Spec.Kind == common.ClusterInfoKind { + delete(staleCIImps, resImp.Name) + } + } + for _, staleCIImp := range staleCIImps { + ciImp := staleCIImp + klog.InfoS("Cleaning up stale ClusterInfoImport", "clusterinfoimport", klog.KObj(&ciImp)) + if err := c.Client.Delete(ctx, &ciImp, &client.DeleteOptions{}); err != nil && !apierrors.IsNotFound(err) { + return err + } + } + return nil +} + +// cleanupServiceResourceExport removes any Service/Endpoint kind of ResourceExports when there is no +// corresponding ServiceExport in the local cluster. +func (c *StaleResCleanupController) cleanupServiceResourceExport(commonArea commonarea.RemoteCommonArea, + resExpList *mcsv1alpha1.ResourceExportList) error { + svcExpList := &k8smcsv1alpha1.ServiceExportList{} + if err := c.List(ctx, svcExpList, &client.ListOptions{}); err != nil { + return err + } + allResExpItems := resExpList.Items + svcExpItems := svcExpList.Items + staleResExpItems := map[string]mcsv1alpha1.ResourceExport{} + + for _, resExp := range allResExpItems { + if resExp.Spec.Kind == common.ServiceKind && resExp.Labels[common.SourceClusterID] == c.localClusterID { + staleResExpItems[resExp.Spec.Namespace+"/"+resExp.Spec.Name+"service"] = resExp + } + if resExp.Spec.Kind == common.EndpointsKind && resExp.Labels[common.SourceClusterID] == c.localClusterID { + staleResExpItems[resExp.Spec.Namespace+"/"+resExp.Spec.Name+"endpoint"] = resExp + } + } + + for _, se := range svcExpItems { + delete(staleResExpItems, se.Namespace+"/"+se.Name+"service") + delete(staleResExpItems, se.Namespace+"/"+se.Name+"endpoint") + } + + for _, r := range staleResExpItems { + re := r + klog.InfoS("Cleaning up ResourceExport", "ResourceExport", klog.KObj(&re)) + if err := commonArea.Delete(ctx, &re, &client.DeleteOptions{}); err != nil && !apierrors.IsNotFound(err) { + return err + } + } + return nil +} + +// cleanupClusterInfoResourceExport removes any ClusterInfo kind of ResourceExports when there is no +// Gateway in the local cluster. +func (c *StaleResCleanupController) cleanupClusterInfoResourceExport(commonArea commonarea.RemoteCommonArea, + resExpList *mcsv1alpha1.ResourceExportList) error { + var gws mcsv1alpha1.GatewayList + if err := c.Client.List(ctx, &gws, &client.ListOptions{}); err != nil { + return err + } + + if len(gws.Items) == 0 { + ciExport := &mcsv1alpha1.ResourceExport{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: commonArea.GetNamespace(), + Name: newClusterInfoResourceExportName(c.localClusterID), + }, + } + klog.InfoS("Cleaning up stale ClusterInfo kind of ResourceExport", "resourceexport", klog.KObj(ciExport)) + if err := commonArea.Delete(ctx, ciExport, &client.DeleteOptions{}); err != nil && !apierrors.IsNotFound(err) { + return err + } + } + return nil +} + +// Enqueue will be called after StaleResCleanupController is initialized. +func (c *StaleResCleanupController) Enqueue() { // The key can be anything as we only have single item. c.queue.Add("key") } -// Run starts the StaleController and blocks until stopCh is closed. +// Run starts the StaleResCleanupController and blocks until stopCh is closed. // it will run only once to clean up stale resources if no error happens. -func (c *StaleController) Run(stopCh <-chan struct{}) { +func (c *StaleResCleanupController) Run(stopCh <-chan struct{}) { defer c.queue.ShutDown() - klog.InfoS("Starting StaleController") - defer klog.InfoS("Shutting down StaleController") + klog.InfoS("Starting StaleResCleanupController") + defer klog.InfoS("Shutting down StaleResCleanupController") if err := c.RunOnce(); err != nil { c.Enqueue() @@ -233,12 +292,12 @@ func (c *StaleController) Run(stopCh <-chan struct{}) { <-stopCh } -func (c *StaleController) runWorker() { +func (c *StaleResCleanupController) runWorker() { for c.processNextWorkItem() { } } -func (c *StaleController) processNextWorkItem() bool { +func (c *StaleResCleanupController) processNextWorkItem() bool { key, quit := c.queue.Get() if quit { return false @@ -251,37 +310,15 @@ func (c *StaleController) processNextWorkItem() bool { return true } - klog.ErrorS(err, "Error removing stale ServiceImport or multi-cluster Service, requeuing it") + klog.ErrorS(err, "Error removing stale resources, requeuing it") c.queue.AddRateLimited(key) return true } -func (c *StaleController) RunOnce() error { +func (c *StaleResCleanupController) RunOnce() error { err := c.cleanup() if err != nil { return err } return nil } - -// We should have only one remote common area at this moment, -// so check and return the first common area. -func getRemoteCommonArea(remoteMgr *commonarea.RemoteCommonAreaManager) (commonarea.RemoteCommonArea, error) { - var remoteCommonArea commonarea.RemoteCommonArea - remoteCommonAreas := (*remoteMgr).GetRemoteCommonAreas() - if len(remoteCommonAreas) <= 0 { - return nil, errors.New("ClusterSet has not been initialized properly, no remote common area manager") - } - - for _, c := range remoteCommonAreas { - if c.IsConnected() { - remoteCommonArea = c - break - } - } - if remoteCommonArea != nil { - return remoteCommonArea, nil - } else { - return nil, errors.New("no connected remote common area") - } -} diff --git a/multicluster/controllers/multicluster/stale_controller_test.go b/multicluster/controllers/multicluster/stale_controller_test.go index 7c5f644d567..ddedf75d35f 100644 --- a/multicluster/controllers/multicluster/stale_controller_test.go +++ b/multicluster/controllers/multicluster/stale_controller_test.go @@ -35,9 +35,9 @@ import ( ) func TestStaleController_CleanupService(t *testing.T) { - localClusterID = "cluster-a" - remoteMgr := commonarea.NewRemoteCommonAreaManager("test-clusterset", common.ClusterID(localClusterID)) - go remoteMgr.Start() + remoteMgr := commonarea.NewRemoteCommonAreaManager("test-clusterset", common.ClusterID(localClusterID), "kube-system") + remoteMgr.Start() + defer remoteMgr.Stop() mcSvcNginx := svcNginx.DeepCopy() mcSvcNginx.Name = "antrea-mc-nginx" @@ -69,11 +69,11 @@ func TestStaleController_CleanupService(t *testing.T) { }, } tests := []struct { - name string - existSvcList *corev1.ServiceList - existSvcImpList *k8smcsv1alpha1.ServiceImportList - existResImpList *mcsv1alpha1.ResourceImportList - wantErr bool + name string + existSvcList *corev1.ServiceList + existSvcImpList *k8smcsv1alpha1.ServiceImportList + existingResImpList *mcsv1alpha1.ResourceImportList + wantErr bool }{ { name: "clean up MC Serivce and ServiceImport successfully", @@ -85,7 +85,7 @@ func TestStaleController_CleanupService(t *testing.T) { mcSvcImpNginx, mcSvcImpNonNginx, }, }, - existResImpList: &mcsv1alpha1.ResourceImportList{ + existingResImpList: &mcsv1alpha1.ResourceImportList{ Items: []mcsv1alpha1.ResourceImport{ svcResImport, }, @@ -95,10 +95,11 @@ func TestStaleController_CleanupService(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { fakeClient := fake.NewClientBuilder().WithScheme(scheme).WithLists(tt.existSvcList, tt.existSvcImpList).Build() - fakeRemoteClient := fake.NewClientBuilder().WithScheme(scheme).WithLists(tt.existResImpList).Build() - _ = commonarea.NewFakeRemoteCommonArea(scheme, &remoteMgr, fakeRemoteClient, "leader-cluster", "default") - - c := NewStaleController(fakeClient, scheme, &remoteMgr) + fakeRemoteClient := fake.NewClientBuilder().WithScheme(scheme).WithLists(tt.existingResImpList).Build() + _ = commonarea.NewFakeRemoteCommonArea(scheme, remoteMgr, fakeRemoteClient, "leader-cluster", "default") + mcReconciler := NewMemberClusterSetReconciler(fakeClient, scheme, "default") + mcReconciler.SetRemoteCommonAreaManager(remoteMgr) + c := NewStaleResCleanupController(fakeClient, scheme, "default", mcReconciler) if err := c.cleanup(); err != nil { t.Errorf("StaleController.cleanup() should clean up all stale Service and ServiceImport but got err = %v", err) } @@ -128,9 +129,9 @@ func TestStaleController_CleanupService(t *testing.T) { } func TestStaleController_CleanupACNP(t *testing.T) { - localClusterID = "cluster-a" - remoteMgr := commonarea.NewRemoteCommonAreaManager("test-clusterset", common.ClusterID(localClusterID)) - go remoteMgr.Start() + remoteMgr := commonarea.NewRemoteCommonAreaManager("test-clusterset", common.ClusterID(localClusterID), "kube-system") + remoteMgr.Start() + defer remoteMgr.Stop() acnpImportName := "acnp-for-isolation" acnpResImportName := leaderNamespace + "-" + acnpImportName @@ -171,7 +172,7 @@ func TestStaleController_CleanupACNP(t *testing.T) { tests := []struct { name string existingACNPList *v1alpha1.ClusterNetworkPolicyList - existResImpList *mcsv1alpha1.ResourceImportList + existingResImpList *mcsv1alpha1.ResourceImportList expectedACNPRemaining sets.String }{ { @@ -181,7 +182,7 @@ func TestStaleController_CleanupACNP(t *testing.T) { acnp1, acnp2, acnp3, }, }, - existResImpList: &mcsv1alpha1.ResourceImportList{ + existingResImpList: &mcsv1alpha1.ResourceImportList{ Items: []mcsv1alpha1.ResourceImport{ acnpResImport, }, @@ -192,10 +193,12 @@ func TestStaleController_CleanupACNP(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { fakeClient := fake.NewClientBuilder().WithScheme(scheme).WithLists(tt.existingACNPList).Build() - fakeRemoteClient := fake.NewClientBuilder().WithScheme(scheme).WithLists(tt.existResImpList).Build() - _ = commonarea.NewFakeRemoteCommonArea(scheme, &remoteMgr, fakeRemoteClient, "leader-cluster", "default") + fakeRemoteClient := fake.NewClientBuilder().WithScheme(scheme).WithLists(tt.existingResImpList).Build() + _ = commonarea.NewFakeRemoteCommonArea(scheme, remoteMgr, fakeRemoteClient, "leader-cluster", "default") - c := NewStaleController(fakeClient, scheme, &remoteMgr) + mcReconciler := NewMemberClusterSetReconciler(fakeClient, scheme, "default") + mcReconciler.SetRemoteCommonAreaManager(remoteMgr) + c := NewStaleResCleanupController(fakeClient, scheme, "default", mcReconciler) if err := c.cleanup(); err != nil { t.Errorf("StaleController.cleanup() should clean up all stale ACNPs but got err = %v", err) } @@ -216,42 +219,71 @@ func TestStaleController_CleanupACNP(t *testing.T) { } func TestStaleController_CleanupResourceExport(t *testing.T) { - localClusterID = "cluster-a" - remoteMgr := commonarea.NewRemoteCommonAreaManager("test-clusterset", common.ClusterID(localClusterID)) - go remoteMgr.Start() + remoteMgr := commonarea.NewRemoteCommonAreaManager("test-clusterset", common.ClusterID(localClusterID), "kube-system") + remoteMgr.Start() + defer remoteMgr.Stop() svcExpNginx := k8smcsv1alpha1.ServiceExport{ ObjectMeta: metav1.ObjectMeta{ Namespace: "default", - Name: "nginx", + Name: "keep-nginx", }, } toDeleteSvcResExport := mcsv1alpha1.ResourceExport{ ObjectMeta: metav1.ObjectMeta{ Namespace: "default", - Name: "cluster-a-default-tobedeleted-service", + Name: "cluster-a-default-nginx-service", + Labels: map[string]string{ + common.SourceClusterID: "cluster-a", + }, + }, + Spec: mcsv1alpha1.ResourceExportSpec{ + Name: "nginx", + Namespace: "default", + Kind: common.ServiceKind, + }, + } + toDeleteEPResExport := mcsv1alpha1.ResourceExport{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "default", + Name: "cluster-a-default-nginx-endpoint", Labels: map[string]string{ common.SourceClusterID: "cluster-a", }, }, + Spec: mcsv1alpha1.ResourceExportSpec{ + Name: "nginx", + Namespace: "default", + Kind: common.EndpointsKind, + }, + } + toDeleteCIResExport := mcsv1alpha1.ResourceExport{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "default", + Name: "cluster-a-clusterinfo", + }, Spec: mcsv1alpha1.ResourceExportSpec{ Name: "tobedeleted", Namespace: "default", + ClusterID: "cluster-a", + Kind: common.ClusterInfoKind, }, } toKeepSvcResExport := mcsv1alpha1.ResourceExport{ ObjectMeta: metav1.ObjectMeta{ Namespace: "default", - Name: "cluster-a-default-nginx-service", + Name: "cluster-a-default-keep-nginx-service", Labels: map[string]string{ common.SourceClusterID: "cluster-a", }, }, Spec: mcsv1alpha1.ResourceExportSpec{ - Name: "nginx", + Name: "keep-nginx", Namespace: "default", + Kind: common.ServiceKind, }, } + svcResExportFromOther := mcsv1alpha1.ResourceExport{ ObjectMeta: metav1.ObjectMeta{ Namespace: "default", @@ -263,6 +295,7 @@ func TestStaleController_CleanupResourceExport(t *testing.T) { Spec: mcsv1alpha1.ResourceExportSpec{ Name: "nginx", Namespace: "default", + Kind: common.ServiceKind, }, } tests := []struct { @@ -282,6 +315,8 @@ func TestStaleController_CleanupResourceExport(t *testing.T) { existResExpList: &mcsv1alpha1.ResourceExportList{ Items: []mcsv1alpha1.ResourceExport{ toDeleteSvcResExport, + toDeleteEPResExport, + toDeleteCIResExport, toKeepSvcResExport, svcResExportFromOther, }, @@ -292,9 +327,11 @@ func TestStaleController_CleanupResourceExport(t *testing.T) { t.Run(tt.name, func(t *testing.T) { fakeClient := fake.NewClientBuilder().WithScheme(scheme).WithLists(tt.existSvcExpList).Build() fakeRemoteClient := fake.NewClientBuilder().WithScheme(scheme).WithLists(tt.existResExpList).Build() - _ = commonarea.NewFakeRemoteCommonArea(scheme, &remoteMgr, fakeRemoteClient, "leader-cluster", "default") + _ = commonarea.NewFakeRemoteCommonArea(scheme, remoteMgr, fakeRemoteClient, "leader-cluster", "default") - c := NewStaleController(fakeClient, scheme, &remoteMgr) + mcReconciler := NewMemberClusterSetReconciler(fakeClient, scheme, "default") + mcReconciler.SetRemoteCommonAreaManager(remoteMgr) + c := NewStaleResCleanupController(fakeClient, scheme, "default", mcReconciler) if err := c.cleanup(); err != nil { t.Errorf("StaleController.cleanup() should clean up all stale ResourceExports but got err = %v", err) } @@ -315,3 +352,84 @@ func TestStaleController_CleanupResourceExport(t *testing.T) { }) } } + +func TestStaleController_CleanupClusterInfoImport(t *testing.T) { + remoteMgr := commonarea.NewRemoteCommonAreaManager("test-clusterset", common.ClusterID(localClusterID), "kube-system") + remoteMgr.Start() + defer remoteMgr.Stop() + ci := mcsv1alpha1.ClusterInfo{ + ClusterID: "cluster-a", + ServiceCIDR: "10.10.1.0/16", + } + ciResImportA := mcsv1alpha1.ResourceImport{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "antrea-mcs", + Name: "cluster-a-default-clusterinfo", + }, + Spec: mcsv1alpha1.ResourceImportSpec{ + Kind: common.ClusterInfoKind, + Name: "node-1", + Namespace: "default", + ClusterInfo: &ci, + }, + } + ciImportA := mcsv1alpha1.ClusterInfoImport{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "default", + Name: "cluster-a-default-clusterinfo", + }, + Spec: ci, + } + ciImportB := mcsv1alpha1.ClusterInfoImport{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "default", + Name: "cluster-b-default-clusterinfo", + }, + Spec: ci, + } + tests := []struct { + name string + existCIImpList *mcsv1alpha1.ClusterInfoImportList + existingResImpList *mcsv1alpha1.ResourceImportList + wantErr bool + }{ + { + name: "clean up ClusterInfoImport successfully", + existCIImpList: &mcsv1alpha1.ClusterInfoImportList{ + Items: []mcsv1alpha1.ClusterInfoImport{ + ciImportA, ciImportB, + }, + }, + existingResImpList: &mcsv1alpha1.ResourceImportList{ + Items: []mcsv1alpha1.ResourceImport{ + ciResImportA, + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + fakeClient := fake.NewClientBuilder().WithScheme(scheme).WithLists(tt.existCIImpList).Build() + fakeRemoteClient := fake.NewClientBuilder().WithScheme(scheme).WithLists(tt.existingResImpList).Build() + _ = commonarea.NewFakeRemoteCommonArea(scheme, remoteMgr, fakeRemoteClient, "leader-cluster", "antrea-mcs") + + mcReconciler := NewMemberClusterSetReconciler(fakeClient, scheme, "default") + mcReconciler.SetRemoteCommonAreaManager(remoteMgr) + c := NewStaleResCleanupController(fakeClient, scheme, "default", mcReconciler) + if err := c.cleanup(); err != nil { + t.Errorf("StaleController.cleanup() should clean up all stale ClusterInfoImport but got err = %v", err) + } + ctx := context.TODO() + ciImpList := &mcsv1alpha1.ClusterInfoImportList{} + err := fakeClient.List(ctx, ciImpList, &client.ListOptions{}) + ciImpLen := len(ciImpList.Items) + if err == nil { + if ciImpLen != 1 { + t.Errorf("Should only one valid ClusterInfoImport left but got %v", ciImpLen) + } + } else { + t.Errorf("Should list ClusterInfoImport successfully but got err = %v", err) + } + }) + } +} diff --git a/multicluster/controllers/multicluster/test_data.go b/multicluster/controllers/multicluster/test_data.go index 160db53e4c8..e45d8ea282a 100644 --- a/multicluster/controllers/multicluster/test_data.go +++ b/multicluster/controllers/multicluster/test_data.go @@ -22,10 +22,8 @@ import ( corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/types" utilruntime "k8s.io/apimachinery/pkg/util/runtime" k8sscheme "k8s.io/client-go/kubernetes/scheme" - ctrl "sigs.k8s.io/controller-runtime" k8smcsapi "sigs.k8s.io/mcs-api/pkg/apis/v1alpha1" mcsv1alpha1 "antrea.io/antrea/multicluster/apis/multicluster/v1alpha1" @@ -33,6 +31,9 @@ import ( ) var ( + localClusterID = "cluster-a" + leaderNamespace = "default" + svcPort80 = corev1.ServicePort{ Name: "http", Protocol: corev1.ProtocolTCP, @@ -103,10 +104,6 @@ var ( }, Subsets: epNginxSubset, } - req = ctrl.Request{NamespacedName: types.NamespacedName{ - Namespace: "default", - Name: "nginx", - }} ctx = context.Background() scheme = runtime.NewScheme() diff --git a/multicluster/hack/update-codegen.sh b/multicluster/hack/update-codegen.sh index d83426fd2c1..4152e69907a 100755 --- a/multicluster/hack/update-codegen.sh +++ b/multicluster/hack/update-codegen.sh @@ -19,7 +19,7 @@ set -o nounset set -o pipefail ANTREA_ROOT="$( cd "$( dirname "${BASH_SOURCE[0]}" )/../../" && pwd )" -IMAGE_NAME="antrea/codegen:kubernetes-1.21.0" +IMAGE_NAME="antrea/codegen:kubernetes-1.24.0" function docker_run() { docker pull ${IMAGE_NAME} diff --git a/multicluster/hack/verify-tools.sh b/multicluster/hack/verify-tools.sh index 062afb34e8f..a4230caebc3 100755 --- a/multicluster/hack/verify-tools.sh +++ b/multicluster/hack/verify-tools.sh @@ -22,7 +22,7 @@ WORKDIR=$1 os=$(echo $(uname) | tr '[:upper:]' '[:lower:]') if ! which kind > /dev/null; then if [[ ${os} == 'darwin' || ${os} == 'linux' ]]; then - curl -Lo ./kind https://github.com/kubernetes-sigs/kind/releases/download/v0.11.1/kind-${os}-amd64 + curl -Lo ./kind https://github.com/kubernetes-sigs/kind/releases/download/v0.12.0/kind-${os}-amd64 chmod +x ./kind if [[ "$WORKDIR" != "" ]];then mv kind "$WORKDIR" diff --git a/multicluster/pkg/client/clientset/versioned/clientset.go b/multicluster/pkg/client/clientset/versioned/clientset.go index bb259f94f38..f0e2c32ab2d 100644 --- a/multicluster/pkg/client/clientset/versioned/clientset.go +++ b/multicluster/pkg/client/clientset/versioned/clientset.go @@ -19,6 +19,7 @@ package versioned import ( "fmt" + "net/http" multiclusterv1alpha1 "antrea.io/antrea/multicluster/pkg/client/clientset/versioned/typed/multicluster/v1alpha1" discovery "k8s.io/client-go/discovery" @@ -54,22 +55,45 @@ func (c *Clientset) Discovery() discovery.DiscoveryInterface { // NewForConfig creates a new Clientset for the given config. // If config's RateLimiter is not set and QPS and Burst are acceptable, // NewForConfig will generate a rate-limiter in configShallowCopy. +// NewForConfig is equivalent to NewForConfigAndClient(c, httpClient), +// where httpClient was generated with rest.HTTPClientFor(c). func NewForConfig(c *rest.Config) (*Clientset, error) { configShallowCopy := *c + + if configShallowCopy.UserAgent == "" { + configShallowCopy.UserAgent = rest.DefaultKubernetesUserAgent() + } + + // share the transport between all clients + httpClient, err := rest.HTTPClientFor(&configShallowCopy) + if err != nil { + return nil, err + } + + return NewForConfigAndClient(&configShallowCopy, httpClient) +} + +// NewForConfigAndClient creates a new Clientset for the given config and http client. +// Note the http client provided takes precedence over the configured transport values. +// If config's RateLimiter is not set and QPS and Burst are acceptable, +// NewForConfigAndClient will generate a rate-limiter in configShallowCopy. +func NewForConfigAndClient(c *rest.Config, httpClient *http.Client) (*Clientset, error) { + configShallowCopy := *c if configShallowCopy.RateLimiter == nil && configShallowCopy.QPS > 0 { if configShallowCopy.Burst <= 0 { return nil, fmt.Errorf("burst is required to be greater than 0 when RateLimiter is not set and QPS is set to greater than 0") } configShallowCopy.RateLimiter = flowcontrol.NewTokenBucketRateLimiter(configShallowCopy.QPS, configShallowCopy.Burst) } + var cs Clientset var err error - cs.multiclusterV1alpha1, err = multiclusterv1alpha1.NewForConfig(&configShallowCopy) + cs.multiclusterV1alpha1, err = multiclusterv1alpha1.NewForConfigAndClient(&configShallowCopy, httpClient) if err != nil { return nil, err } - cs.DiscoveryClient, err = discovery.NewDiscoveryClientForConfig(&configShallowCopy) + cs.DiscoveryClient, err = discovery.NewDiscoveryClientForConfigAndClient(&configShallowCopy, httpClient) if err != nil { return nil, err } @@ -79,11 +103,11 @@ func NewForConfig(c *rest.Config) (*Clientset, error) { // NewForConfigOrDie creates a new Clientset for the given config and // panics if there is an error in the config. func NewForConfigOrDie(c *rest.Config) *Clientset { - var cs Clientset - cs.multiclusterV1alpha1 = multiclusterv1alpha1.NewForConfigOrDie(c) - - cs.DiscoveryClient = discovery.NewDiscoveryClientForConfigOrDie(c) - return &cs + cs, err := NewForConfig(c) + if err != nil { + panic(err) + } + return cs } // New creates a new Clientset for the given RESTClient. diff --git a/multicluster/pkg/client/clientset/versioned/fake/clientset_generated.go b/multicluster/pkg/client/clientset/versioned/fake/clientset_generated.go index 3d7e46650e0..5b65267ec52 100644 --- a/multicluster/pkg/client/clientset/versioned/fake/clientset_generated.go +++ b/multicluster/pkg/client/clientset/versioned/fake/clientset_generated.go @@ -73,7 +73,10 @@ func (c *Clientset) Tracker() testing.ObjectTracker { return c.tracker } -var _ clientset.Interface = &Clientset{} +var ( + _ clientset.Interface = &Clientset{} + _ testing.FakeClient = &Clientset{} +) // MulticlusterV1alpha1 retrieves the MulticlusterV1alpha1Client func (c *Clientset) MulticlusterV1alpha1() multiclusterv1alpha1.MulticlusterV1alpha1Interface { diff --git a/multicluster/pkg/client/clientset/versioned/typed/multicluster/v1alpha1/clusterinfoimport.go b/multicluster/pkg/client/clientset/versioned/typed/multicluster/v1alpha1/clusterinfoimport.go new file mode 100644 index 00000000000..270ca3b4102 --- /dev/null +++ b/multicluster/pkg/client/clientset/versioned/typed/multicluster/v1alpha1/clusterinfoimport.go @@ -0,0 +1,194 @@ +/* +Copyright 2021 Antrea Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +// Code generated by client-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + "context" + "time" + + v1alpha1 "antrea.io/antrea/multicluster/apis/multicluster/v1alpha1" + scheme "antrea.io/antrea/multicluster/pkg/client/clientset/versioned/scheme" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + rest "k8s.io/client-go/rest" +) + +// ClusterInfoImportsGetter has a method to return a ClusterInfoImportInterface. +// A group's client should implement this interface. +type ClusterInfoImportsGetter interface { + ClusterInfoImports(namespace string) ClusterInfoImportInterface +} + +// ClusterInfoImportInterface has methods to work with ClusterInfoImport resources. +type ClusterInfoImportInterface interface { + Create(ctx context.Context, clusterInfoImport *v1alpha1.ClusterInfoImport, opts v1.CreateOptions) (*v1alpha1.ClusterInfoImport, error) + Update(ctx context.Context, clusterInfoImport *v1alpha1.ClusterInfoImport, opts v1.UpdateOptions) (*v1alpha1.ClusterInfoImport, error) + UpdateStatus(ctx context.Context, clusterInfoImport *v1alpha1.ClusterInfoImport, opts v1.UpdateOptions) (*v1alpha1.ClusterInfoImport, error) + Delete(ctx context.Context, name string, opts v1.DeleteOptions) error + DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error + Get(ctx context.Context, name string, opts v1.GetOptions) (*v1alpha1.ClusterInfoImport, error) + List(ctx context.Context, opts v1.ListOptions) (*v1alpha1.ClusterInfoImportList, error) + Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) + Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.ClusterInfoImport, err error) + ClusterInfoImportExpansion +} + +// clusterInfoImports implements ClusterInfoImportInterface +type clusterInfoImports struct { + client rest.Interface + ns string +} + +// newClusterInfoImports returns a ClusterInfoImports +func newClusterInfoImports(c *MulticlusterV1alpha1Client, namespace string) *clusterInfoImports { + return &clusterInfoImports{ + client: c.RESTClient(), + ns: namespace, + } +} + +// Get takes name of the clusterInfoImport, and returns the corresponding clusterInfoImport object, and an error if there is any. +func (c *clusterInfoImports) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.ClusterInfoImport, err error) { + result = &v1alpha1.ClusterInfoImport{} + err = c.client.Get(). + Namespace(c.ns). + Resource("clusterinfoimports"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(ctx). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of ClusterInfoImports that match those selectors. +func (c *clusterInfoImports) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.ClusterInfoImportList, err error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + result = &v1alpha1.ClusterInfoImportList{} + err = c.client.Get(). + Namespace(c.ns). + Resource("clusterinfoimports"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Do(ctx). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested clusterInfoImports. +func (c *clusterInfoImports) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + opts.Watch = true + return c.client.Get(). + Namespace(c.ns). + Resource("clusterinfoimports"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Watch(ctx) +} + +// Create takes the representation of a clusterInfoImport and creates it. Returns the server's representation of the clusterInfoImport, and an error, if there is any. +func (c *clusterInfoImports) Create(ctx context.Context, clusterInfoImport *v1alpha1.ClusterInfoImport, opts v1.CreateOptions) (result *v1alpha1.ClusterInfoImport, err error) { + result = &v1alpha1.ClusterInfoImport{} + err = c.client.Post(). + Namespace(c.ns). + Resource("clusterinfoimports"). + VersionedParams(&opts, scheme.ParameterCodec). + Body(clusterInfoImport). + Do(ctx). + Into(result) + return +} + +// Update takes the representation of a clusterInfoImport and updates it. Returns the server's representation of the clusterInfoImport, and an error, if there is any. +func (c *clusterInfoImports) Update(ctx context.Context, clusterInfoImport *v1alpha1.ClusterInfoImport, opts v1.UpdateOptions) (result *v1alpha1.ClusterInfoImport, err error) { + result = &v1alpha1.ClusterInfoImport{} + err = c.client.Put(). + Namespace(c.ns). + Resource("clusterinfoimports"). + Name(clusterInfoImport.Name). + VersionedParams(&opts, scheme.ParameterCodec). + Body(clusterInfoImport). + Do(ctx). + Into(result) + return +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *clusterInfoImports) UpdateStatus(ctx context.Context, clusterInfoImport *v1alpha1.ClusterInfoImport, opts v1.UpdateOptions) (result *v1alpha1.ClusterInfoImport, err error) { + result = &v1alpha1.ClusterInfoImport{} + err = c.client.Put(). + Namespace(c.ns). + Resource("clusterinfoimports"). + Name(clusterInfoImport.Name). + SubResource("status"). + VersionedParams(&opts, scheme.ParameterCodec). + Body(clusterInfoImport). + Do(ctx). + Into(result) + return +} + +// Delete takes name of the clusterInfoImport and deletes it. Returns an error if one occurs. +func (c *clusterInfoImports) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + return c.client.Delete(). + Namespace(c.ns). + Resource("clusterinfoimports"). + Name(name). + Body(&opts). + Do(ctx). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *clusterInfoImports) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + var timeout time.Duration + if listOpts.TimeoutSeconds != nil { + timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second + } + return c.client.Delete(). + Namespace(c.ns). + Resource("clusterinfoimports"). + VersionedParams(&listOpts, scheme.ParameterCodec). + Timeout(timeout). + Body(&opts). + Do(ctx). + Error() +} + +// Patch applies the patch and returns the patched clusterInfoImport. +func (c *clusterInfoImports) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.ClusterInfoImport, err error) { + result = &v1alpha1.ClusterInfoImport{} + err = c.client.Patch(pt). + Namespace(c.ns). + Resource("clusterinfoimports"). + Name(name). + SubResource(subresources...). + VersionedParams(&opts, scheme.ParameterCodec). + Body(data). + Do(ctx). + Into(result) + return +} diff --git a/multicluster/pkg/client/clientset/versioned/typed/multicluster/v1alpha1/fake/fake_clusterclaim.go b/multicluster/pkg/client/clientset/versioned/typed/multicluster/v1alpha1/fake/fake_clusterclaim.go index d25958f8608..b9badd55a6e 100644 --- a/multicluster/pkg/client/clientset/versioned/typed/multicluster/v1alpha1/fake/fake_clusterclaim.go +++ b/multicluster/pkg/client/clientset/versioned/typed/multicluster/v1alpha1/fake/fake_clusterclaim.go @@ -104,7 +104,7 @@ func (c *FakeClusterClaims) Update(ctx context.Context, clusterClaim *v1alpha1.C // Delete takes name of the clusterClaim and deletes it. Returns an error if one occurs. func (c *FakeClusterClaims) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { _, err := c.Fake. - Invokes(testing.NewDeleteAction(clusterclaimsResource, c.ns, name), &v1alpha1.ClusterClaim{}) + Invokes(testing.NewDeleteActionWithOptions(clusterclaimsResource, c.ns, name, opts), &v1alpha1.ClusterClaim{}) return err } diff --git a/multicluster/pkg/client/clientset/versioned/typed/multicluster/v1alpha1/fake/fake_clusterinfoimport.go b/multicluster/pkg/client/clientset/versioned/typed/multicluster/v1alpha1/fake/fake_clusterinfoimport.go new file mode 100644 index 00000000000..0039686e969 --- /dev/null +++ b/multicluster/pkg/client/clientset/versioned/typed/multicluster/v1alpha1/fake/fake_clusterinfoimport.go @@ -0,0 +1,141 @@ +/* +Copyright 2021 Antrea Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + + v1alpha1 "antrea.io/antrea/multicluster/apis/multicluster/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + testing "k8s.io/client-go/testing" +) + +// FakeClusterInfoImports implements ClusterInfoImportInterface +type FakeClusterInfoImports struct { + Fake *FakeMulticlusterV1alpha1 + ns string +} + +var clusterinfoimportsResource = schema.GroupVersionResource{Group: "multicluster.crd.antrea.io", Version: "v1alpha1", Resource: "clusterinfoimports"} + +var clusterinfoimportsKind = schema.GroupVersionKind{Group: "multicluster.crd.antrea.io", Version: "v1alpha1", Kind: "ClusterInfoImport"} + +// Get takes name of the clusterInfoImport, and returns the corresponding clusterInfoImport object, and an error if there is any. +func (c *FakeClusterInfoImports) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.ClusterInfoImport, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(clusterinfoimportsResource, c.ns, name), &v1alpha1.ClusterInfoImport{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.ClusterInfoImport), err +} + +// List takes label and field selectors, and returns the list of ClusterInfoImports that match those selectors. +func (c *FakeClusterInfoImports) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.ClusterInfoImportList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(clusterinfoimportsResource, clusterinfoimportsKind, c.ns, opts), &v1alpha1.ClusterInfoImportList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1alpha1.ClusterInfoImportList{ListMeta: obj.(*v1alpha1.ClusterInfoImportList).ListMeta} + for _, item := range obj.(*v1alpha1.ClusterInfoImportList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested clusterInfoImports. +func (c *FakeClusterInfoImports) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(clusterinfoimportsResource, c.ns, opts)) + +} + +// Create takes the representation of a clusterInfoImport and creates it. Returns the server's representation of the clusterInfoImport, and an error, if there is any. +func (c *FakeClusterInfoImports) Create(ctx context.Context, clusterInfoImport *v1alpha1.ClusterInfoImport, opts v1.CreateOptions) (result *v1alpha1.ClusterInfoImport, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(clusterinfoimportsResource, c.ns, clusterInfoImport), &v1alpha1.ClusterInfoImport{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.ClusterInfoImport), err +} + +// Update takes the representation of a clusterInfoImport and updates it. Returns the server's representation of the clusterInfoImport, and an error, if there is any. +func (c *FakeClusterInfoImports) Update(ctx context.Context, clusterInfoImport *v1alpha1.ClusterInfoImport, opts v1.UpdateOptions) (result *v1alpha1.ClusterInfoImport, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(clusterinfoimportsResource, c.ns, clusterInfoImport), &v1alpha1.ClusterInfoImport{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.ClusterInfoImport), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeClusterInfoImports) UpdateStatus(ctx context.Context, clusterInfoImport *v1alpha1.ClusterInfoImport, opts v1.UpdateOptions) (*v1alpha1.ClusterInfoImport, error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceAction(clusterinfoimportsResource, "status", c.ns, clusterInfoImport), &v1alpha1.ClusterInfoImport{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.ClusterInfoImport), err +} + +// Delete takes name of the clusterInfoImport and deletes it. Returns an error if one occurs. +func (c *FakeClusterInfoImports) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteActionWithOptions(clusterinfoimportsResource, c.ns, name, opts), &v1alpha1.ClusterInfoImport{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeClusterInfoImports) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(clusterinfoimportsResource, c.ns, listOpts) + + _, err := c.Fake.Invokes(action, &v1alpha1.ClusterInfoImportList{}) + return err +} + +// Patch applies the patch and returns the patched clusterInfoImport. +func (c *FakeClusterInfoImports) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.ClusterInfoImport, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(clusterinfoimportsResource, c.ns, name, pt, data, subresources...), &v1alpha1.ClusterInfoImport{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.ClusterInfoImport), err +} diff --git a/multicluster/pkg/client/clientset/versioned/typed/multicluster/v1alpha1/fake/fake_clusterset.go b/multicluster/pkg/client/clientset/versioned/typed/multicluster/v1alpha1/fake/fake_clusterset.go index 8df9394bbb3..d7fd8011150 100644 --- a/multicluster/pkg/client/clientset/versioned/typed/multicluster/v1alpha1/fake/fake_clusterset.go +++ b/multicluster/pkg/client/clientset/versioned/typed/multicluster/v1alpha1/fake/fake_clusterset.go @@ -116,7 +116,7 @@ func (c *FakeClusterSets) UpdateStatus(ctx context.Context, clusterSet *v1alpha1 // Delete takes name of the clusterSet and deletes it. Returns an error if one occurs. func (c *FakeClusterSets) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { _, err := c.Fake. - Invokes(testing.NewDeleteAction(clustersetsResource, c.ns, name), &v1alpha1.ClusterSet{}) + Invokes(testing.NewDeleteActionWithOptions(clustersetsResource, c.ns, name, opts), &v1alpha1.ClusterSet{}) return err } diff --git a/multicluster/pkg/client/clientset/versioned/typed/multicluster/v1alpha1/fake/fake_gateway.go b/multicluster/pkg/client/clientset/versioned/typed/multicluster/v1alpha1/fake/fake_gateway.go new file mode 100644 index 00000000000..a9141f04549 --- /dev/null +++ b/multicluster/pkg/client/clientset/versioned/typed/multicluster/v1alpha1/fake/fake_gateway.go @@ -0,0 +1,129 @@ +/* +Copyright 2021 Antrea Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + + v1alpha1 "antrea.io/antrea/multicluster/apis/multicluster/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + testing "k8s.io/client-go/testing" +) + +// FakeGateways implements GatewayInterface +type FakeGateways struct { + Fake *FakeMulticlusterV1alpha1 + ns string +} + +var gatewaysResource = schema.GroupVersionResource{Group: "multicluster.crd.antrea.io", Version: "v1alpha1", Resource: "gateways"} + +var gatewaysKind = schema.GroupVersionKind{Group: "multicluster.crd.antrea.io", Version: "v1alpha1", Kind: "Gateway"} + +// Get takes name of the gateway, and returns the corresponding gateway object, and an error if there is any. +func (c *FakeGateways) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.Gateway, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(gatewaysResource, c.ns, name), &v1alpha1.Gateway{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.Gateway), err +} + +// List takes label and field selectors, and returns the list of Gateways that match those selectors. +func (c *FakeGateways) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.GatewayList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(gatewaysResource, gatewaysKind, c.ns, opts), &v1alpha1.GatewayList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1alpha1.GatewayList{ListMeta: obj.(*v1alpha1.GatewayList).ListMeta} + for _, item := range obj.(*v1alpha1.GatewayList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested gateways. +func (c *FakeGateways) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(gatewaysResource, c.ns, opts)) + +} + +// Create takes the representation of a gateway and creates it. Returns the server's representation of the gateway, and an error, if there is any. +func (c *FakeGateways) Create(ctx context.Context, gateway *v1alpha1.Gateway, opts v1.CreateOptions) (result *v1alpha1.Gateway, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(gatewaysResource, c.ns, gateway), &v1alpha1.Gateway{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.Gateway), err +} + +// Update takes the representation of a gateway and updates it. Returns the server's representation of the gateway, and an error, if there is any. +func (c *FakeGateways) Update(ctx context.Context, gateway *v1alpha1.Gateway, opts v1.UpdateOptions) (result *v1alpha1.Gateway, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(gatewaysResource, c.ns, gateway), &v1alpha1.Gateway{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.Gateway), err +} + +// Delete takes name of the gateway and deletes it. Returns an error if one occurs. +func (c *FakeGateways) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteActionWithOptions(gatewaysResource, c.ns, name, opts), &v1alpha1.Gateway{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeGateways) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(gatewaysResource, c.ns, listOpts) + + _, err := c.Fake.Invokes(action, &v1alpha1.GatewayList{}) + return err +} + +// Patch applies the patch and returns the patched gateway. +func (c *FakeGateways) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.Gateway, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(gatewaysResource, c.ns, name, pt, data, subresources...), &v1alpha1.Gateway{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.Gateway), err +} diff --git a/multicluster/pkg/client/clientset/versioned/typed/multicluster/v1alpha1/fake/fake_memberclusterannounce.go b/multicluster/pkg/client/clientset/versioned/typed/multicluster/v1alpha1/fake/fake_memberclusterannounce.go index 4bee9d1dd23..aa1d81e165f 100644 --- a/multicluster/pkg/client/clientset/versioned/typed/multicluster/v1alpha1/fake/fake_memberclusterannounce.go +++ b/multicluster/pkg/client/clientset/versioned/typed/multicluster/v1alpha1/fake/fake_memberclusterannounce.go @@ -104,7 +104,7 @@ func (c *FakeMemberClusterAnnounces) Update(ctx context.Context, memberClusterAn // Delete takes name of the memberClusterAnnounce and deletes it. Returns an error if one occurs. func (c *FakeMemberClusterAnnounces) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { _, err := c.Fake. - Invokes(testing.NewDeleteAction(memberclusterannouncesResource, c.ns, name), &v1alpha1.MemberClusterAnnounce{}) + Invokes(testing.NewDeleteActionWithOptions(memberclusterannouncesResource, c.ns, name, opts), &v1alpha1.MemberClusterAnnounce{}) return err } diff --git a/multicluster/pkg/client/clientset/versioned/typed/multicluster/v1alpha1/fake/fake_multicluster_client.go b/multicluster/pkg/client/clientset/versioned/typed/multicluster/v1alpha1/fake/fake_multicluster_client.go index 30ac2ac7dae..1c74e66da6f 100644 --- a/multicluster/pkg/client/clientset/versioned/typed/multicluster/v1alpha1/fake/fake_multicluster_client.go +++ b/multicluster/pkg/client/clientset/versioned/typed/multicluster/v1alpha1/fake/fake_multicluster_client.go @@ -31,10 +31,18 @@ func (c *FakeMulticlusterV1alpha1) ClusterClaims(namespace string) v1alpha1.Clus return &FakeClusterClaims{c, namespace} } +func (c *FakeMulticlusterV1alpha1) ClusterInfoImports(namespace string) v1alpha1.ClusterInfoImportInterface { + return &FakeClusterInfoImports{c, namespace} +} + func (c *FakeMulticlusterV1alpha1) ClusterSets(namespace string) v1alpha1.ClusterSetInterface { return &FakeClusterSets{c, namespace} } +func (c *FakeMulticlusterV1alpha1) Gateways(namespace string) v1alpha1.GatewayInterface { + return &FakeGateways{c, namespace} +} + func (c *FakeMulticlusterV1alpha1) MemberClusterAnnounces(namespace string) v1alpha1.MemberClusterAnnounceInterface { return &FakeMemberClusterAnnounces{c, namespace} } diff --git a/multicluster/pkg/client/clientset/versioned/typed/multicluster/v1alpha1/fake/fake_resourceexport.go b/multicluster/pkg/client/clientset/versioned/typed/multicluster/v1alpha1/fake/fake_resourceexport.go index eb9f9a734a4..48c6aee465d 100644 --- a/multicluster/pkg/client/clientset/versioned/typed/multicluster/v1alpha1/fake/fake_resourceexport.go +++ b/multicluster/pkg/client/clientset/versioned/typed/multicluster/v1alpha1/fake/fake_resourceexport.go @@ -116,7 +116,7 @@ func (c *FakeResourceExports) UpdateStatus(ctx context.Context, resourceExport * // Delete takes name of the resourceExport and deletes it. Returns an error if one occurs. func (c *FakeResourceExports) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { _, err := c.Fake. - Invokes(testing.NewDeleteAction(resourceexportsResource, c.ns, name), &v1alpha1.ResourceExport{}) + Invokes(testing.NewDeleteActionWithOptions(resourceexportsResource, c.ns, name, opts), &v1alpha1.ResourceExport{}) return err } diff --git a/multicluster/pkg/client/clientset/versioned/typed/multicluster/v1alpha1/fake/fake_resourceexportfilter.go b/multicluster/pkg/client/clientset/versioned/typed/multicluster/v1alpha1/fake/fake_resourceexportfilter.go index 60aa67b4124..c30fe1960e0 100644 --- a/multicluster/pkg/client/clientset/versioned/typed/multicluster/v1alpha1/fake/fake_resourceexportfilter.go +++ b/multicluster/pkg/client/clientset/versioned/typed/multicluster/v1alpha1/fake/fake_resourceexportfilter.go @@ -116,7 +116,7 @@ func (c *FakeResourceExportFilters) UpdateStatus(ctx context.Context, resourceEx // Delete takes name of the resourceExportFilter and deletes it. Returns an error if one occurs. func (c *FakeResourceExportFilters) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { _, err := c.Fake. - Invokes(testing.NewDeleteAction(resourceexportfiltersResource, c.ns, name), &v1alpha1.ResourceExportFilter{}) + Invokes(testing.NewDeleteActionWithOptions(resourceexportfiltersResource, c.ns, name, opts), &v1alpha1.ResourceExportFilter{}) return err } diff --git a/multicluster/pkg/client/clientset/versioned/typed/multicluster/v1alpha1/fake/fake_resourceimport.go b/multicluster/pkg/client/clientset/versioned/typed/multicluster/v1alpha1/fake/fake_resourceimport.go index 4d034c72dea..65b5b9c3e67 100644 --- a/multicluster/pkg/client/clientset/versioned/typed/multicluster/v1alpha1/fake/fake_resourceimport.go +++ b/multicluster/pkg/client/clientset/versioned/typed/multicluster/v1alpha1/fake/fake_resourceimport.go @@ -116,7 +116,7 @@ func (c *FakeResourceImports) UpdateStatus(ctx context.Context, resourceImport * // Delete takes name of the resourceImport and deletes it. Returns an error if one occurs. func (c *FakeResourceImports) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { _, err := c.Fake. - Invokes(testing.NewDeleteAction(resourceimportsResource, c.ns, name), &v1alpha1.ResourceImport{}) + Invokes(testing.NewDeleteActionWithOptions(resourceimportsResource, c.ns, name, opts), &v1alpha1.ResourceImport{}) return err } diff --git a/multicluster/pkg/client/clientset/versioned/typed/multicluster/v1alpha1/fake/fake_resourceimportfilter.go b/multicluster/pkg/client/clientset/versioned/typed/multicluster/v1alpha1/fake/fake_resourceimportfilter.go index 52757098b4a..cb8af950f4f 100644 --- a/multicluster/pkg/client/clientset/versioned/typed/multicluster/v1alpha1/fake/fake_resourceimportfilter.go +++ b/multicluster/pkg/client/clientset/versioned/typed/multicluster/v1alpha1/fake/fake_resourceimportfilter.go @@ -116,7 +116,7 @@ func (c *FakeResourceImportFilters) UpdateStatus(ctx context.Context, resourceIm // Delete takes name of the resourceImportFilter and deletes it. Returns an error if one occurs. func (c *FakeResourceImportFilters) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { _, err := c.Fake. - Invokes(testing.NewDeleteAction(resourceimportfiltersResource, c.ns, name), &v1alpha1.ResourceImportFilter{}) + Invokes(testing.NewDeleteActionWithOptions(resourceimportfiltersResource, c.ns, name, opts), &v1alpha1.ResourceImportFilter{}) return err } diff --git a/multicluster/pkg/client/clientset/versioned/typed/multicluster/v1alpha1/gateway.go b/multicluster/pkg/client/clientset/versioned/typed/multicluster/v1alpha1/gateway.go new file mode 100644 index 00000000000..58521e96ef0 --- /dev/null +++ b/multicluster/pkg/client/clientset/versioned/typed/multicluster/v1alpha1/gateway.go @@ -0,0 +1,177 @@ +/* +Copyright 2021 Antrea Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +// Code generated by client-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + "context" + "time" + + v1alpha1 "antrea.io/antrea/multicluster/apis/multicluster/v1alpha1" + scheme "antrea.io/antrea/multicluster/pkg/client/clientset/versioned/scheme" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + rest "k8s.io/client-go/rest" +) + +// GatewaysGetter has a method to return a GatewayInterface. +// A group's client should implement this interface. +type GatewaysGetter interface { + Gateways(namespace string) GatewayInterface +} + +// GatewayInterface has methods to work with Gateway resources. +type GatewayInterface interface { + Create(ctx context.Context, gateway *v1alpha1.Gateway, opts v1.CreateOptions) (*v1alpha1.Gateway, error) + Update(ctx context.Context, gateway *v1alpha1.Gateway, opts v1.UpdateOptions) (*v1alpha1.Gateway, error) + Delete(ctx context.Context, name string, opts v1.DeleteOptions) error + DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error + Get(ctx context.Context, name string, opts v1.GetOptions) (*v1alpha1.Gateway, error) + List(ctx context.Context, opts v1.ListOptions) (*v1alpha1.GatewayList, error) + Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) + Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.Gateway, err error) + GatewayExpansion +} + +// gateways implements GatewayInterface +type gateways struct { + client rest.Interface + ns string +} + +// newGateways returns a Gateways +func newGateways(c *MulticlusterV1alpha1Client, namespace string) *gateways { + return &gateways{ + client: c.RESTClient(), + ns: namespace, + } +} + +// Get takes name of the gateway, and returns the corresponding gateway object, and an error if there is any. +func (c *gateways) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.Gateway, err error) { + result = &v1alpha1.Gateway{} + err = c.client.Get(). + Namespace(c.ns). + Resource("gateways"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(ctx). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of Gateways that match those selectors. +func (c *gateways) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.GatewayList, err error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + result = &v1alpha1.GatewayList{} + err = c.client.Get(). + Namespace(c.ns). + Resource("gateways"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Do(ctx). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested gateways. +func (c *gateways) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + opts.Watch = true + return c.client.Get(). + Namespace(c.ns). + Resource("gateways"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Watch(ctx) +} + +// Create takes the representation of a gateway and creates it. Returns the server's representation of the gateway, and an error, if there is any. +func (c *gateways) Create(ctx context.Context, gateway *v1alpha1.Gateway, opts v1.CreateOptions) (result *v1alpha1.Gateway, err error) { + result = &v1alpha1.Gateway{} + err = c.client.Post(). + Namespace(c.ns). + Resource("gateways"). + VersionedParams(&opts, scheme.ParameterCodec). + Body(gateway). + Do(ctx). + Into(result) + return +} + +// Update takes the representation of a gateway and updates it. Returns the server's representation of the gateway, and an error, if there is any. +func (c *gateways) Update(ctx context.Context, gateway *v1alpha1.Gateway, opts v1.UpdateOptions) (result *v1alpha1.Gateway, err error) { + result = &v1alpha1.Gateway{} + err = c.client.Put(). + Namespace(c.ns). + Resource("gateways"). + Name(gateway.Name). + VersionedParams(&opts, scheme.ParameterCodec). + Body(gateway). + Do(ctx). + Into(result) + return +} + +// Delete takes name of the gateway and deletes it. Returns an error if one occurs. +func (c *gateways) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + return c.client.Delete(). + Namespace(c.ns). + Resource("gateways"). + Name(name). + Body(&opts). + Do(ctx). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *gateways) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + var timeout time.Duration + if listOpts.TimeoutSeconds != nil { + timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second + } + return c.client.Delete(). + Namespace(c.ns). + Resource("gateways"). + VersionedParams(&listOpts, scheme.ParameterCodec). + Timeout(timeout). + Body(&opts). + Do(ctx). + Error() +} + +// Patch applies the patch and returns the patched gateway. +func (c *gateways) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.Gateway, err error) { + result = &v1alpha1.Gateway{} + err = c.client.Patch(pt). + Namespace(c.ns). + Resource("gateways"). + Name(name). + SubResource(subresources...). + VersionedParams(&opts, scheme.ParameterCodec). + Body(data). + Do(ctx). + Into(result) + return +} diff --git a/multicluster/pkg/client/clientset/versioned/typed/multicluster/v1alpha1/generated_expansion.go b/multicluster/pkg/client/clientset/versioned/typed/multicluster/v1alpha1/generated_expansion.go index f666a0a8999..8c9d1e0ca65 100644 --- a/multicluster/pkg/client/clientset/versioned/typed/multicluster/v1alpha1/generated_expansion.go +++ b/multicluster/pkg/client/clientset/versioned/typed/multicluster/v1alpha1/generated_expansion.go @@ -19,8 +19,12 @@ package v1alpha1 type ClusterClaimExpansion interface{} +type ClusterInfoImportExpansion interface{} + type ClusterSetExpansion interface{} +type GatewayExpansion interface{} + type MemberClusterAnnounceExpansion interface{} type ResourceExportExpansion interface{} diff --git a/multicluster/pkg/client/clientset/versioned/typed/multicluster/v1alpha1/multicluster_client.go b/multicluster/pkg/client/clientset/versioned/typed/multicluster/v1alpha1/multicluster_client.go index e3b1c38e45f..725e7b2f815 100644 --- a/multicluster/pkg/client/clientset/versioned/typed/multicluster/v1alpha1/multicluster_client.go +++ b/multicluster/pkg/client/clientset/versioned/typed/multicluster/v1alpha1/multicluster_client.go @@ -18,6 +18,8 @@ limitations under the License. package v1alpha1 import ( + "net/http" + v1alpha1 "antrea.io/antrea/multicluster/apis/multicluster/v1alpha1" "antrea.io/antrea/multicluster/pkg/client/clientset/versioned/scheme" rest "k8s.io/client-go/rest" @@ -26,7 +28,9 @@ import ( type MulticlusterV1alpha1Interface interface { RESTClient() rest.Interface ClusterClaimsGetter + ClusterInfoImportsGetter ClusterSetsGetter + GatewaysGetter MemberClusterAnnouncesGetter ResourceExportsGetter ResourceExportFiltersGetter @@ -43,10 +47,18 @@ func (c *MulticlusterV1alpha1Client) ClusterClaims(namespace string) ClusterClai return newClusterClaims(c, namespace) } +func (c *MulticlusterV1alpha1Client) ClusterInfoImports(namespace string) ClusterInfoImportInterface { + return newClusterInfoImports(c, namespace) +} + func (c *MulticlusterV1alpha1Client) ClusterSets(namespace string) ClusterSetInterface { return newClusterSets(c, namespace) } +func (c *MulticlusterV1alpha1Client) Gateways(namespace string) GatewayInterface { + return newGateways(c, namespace) +} + func (c *MulticlusterV1alpha1Client) MemberClusterAnnounces(namespace string) MemberClusterAnnounceInterface { return newMemberClusterAnnounces(c, namespace) } @@ -68,12 +80,28 @@ func (c *MulticlusterV1alpha1Client) ResourceImportFilters(namespace string) Res } // NewForConfig creates a new MulticlusterV1alpha1Client for the given config. +// NewForConfig is equivalent to NewForConfigAndClient(c, httpClient), +// where httpClient was generated with rest.HTTPClientFor(c). func NewForConfig(c *rest.Config) (*MulticlusterV1alpha1Client, error) { config := *c if err := setConfigDefaults(&config); err != nil { return nil, err } - client, err := rest.RESTClientFor(&config) + httpClient, err := rest.HTTPClientFor(&config) + if err != nil { + return nil, err + } + return NewForConfigAndClient(&config, httpClient) +} + +// NewForConfigAndClient creates a new MulticlusterV1alpha1Client for the given config and http client. +// Note the http client provided takes precedence over the configured transport values. +func NewForConfigAndClient(c *rest.Config, h *http.Client) (*MulticlusterV1alpha1Client, error) { + config := *c + if err := setConfigDefaults(&config); err != nil { + return nil, err + } + client, err := rest.RESTClientForConfigAndClient(&config, h) if err != nil { return nil, err } diff --git a/multicluster/pkg/client/informers/externalversions/generic.go b/multicluster/pkg/client/informers/externalversions/generic.go index 838bedf070a..10017104303 100644 --- a/multicluster/pkg/client/informers/externalversions/generic.go +++ b/multicluster/pkg/client/informers/externalversions/generic.go @@ -54,8 +54,12 @@ func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource // Group=multicluster.crd.antrea.io, Version=v1alpha1 case v1alpha1.SchemeGroupVersion.WithResource("clusterclaims"): return &genericInformer{resource: resource.GroupResource(), informer: f.Multicluster().V1alpha1().ClusterClaims().Informer()}, nil + case v1alpha1.SchemeGroupVersion.WithResource("clusterinfoimports"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Multicluster().V1alpha1().ClusterInfoImports().Informer()}, nil case v1alpha1.SchemeGroupVersion.WithResource("clustersets"): return &genericInformer{resource: resource.GroupResource(), informer: f.Multicluster().V1alpha1().ClusterSets().Informer()}, nil + case v1alpha1.SchemeGroupVersion.WithResource("gateways"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Multicluster().V1alpha1().Gateways().Informer()}, nil case v1alpha1.SchemeGroupVersion.WithResource("memberclusterannounces"): return &genericInformer{resource: resource.GroupResource(), informer: f.Multicluster().V1alpha1().MemberClusterAnnounces().Informer()}, nil case v1alpha1.SchemeGroupVersion.WithResource("resourceexports"): diff --git a/multicluster/pkg/client/informers/externalversions/multicluster/v1alpha1/clusterinfoimport.go b/multicluster/pkg/client/informers/externalversions/multicluster/v1alpha1/clusterinfoimport.go new file mode 100644 index 00000000000..68487a9906b --- /dev/null +++ b/multicluster/pkg/client/informers/externalversions/multicluster/v1alpha1/clusterinfoimport.go @@ -0,0 +1,89 @@ +/* +Copyright 2021 Antrea Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +// Code generated by informer-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + "context" + time "time" + + multiclusterv1alpha1 "antrea.io/antrea/multicluster/apis/multicluster/v1alpha1" + versioned "antrea.io/antrea/multicluster/pkg/client/clientset/versioned" + internalinterfaces "antrea.io/antrea/multicluster/pkg/client/informers/externalversions/internalinterfaces" + v1alpha1 "antrea.io/antrea/multicluster/pkg/client/listers/multicluster/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" +) + +// ClusterInfoImportInformer provides access to a shared informer and lister for +// ClusterInfoImports. +type ClusterInfoImportInformer interface { + Informer() cache.SharedIndexInformer + Lister() v1alpha1.ClusterInfoImportLister +} + +type clusterInfoImportInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc + namespace string +} + +// NewClusterInfoImportInformer constructs a new informer for ClusterInfoImport type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewClusterInfoImportInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredClusterInfoImportInformer(client, namespace, resyncPeriod, indexers, nil) +} + +// NewFilteredClusterInfoImportInformer constructs a new informer for ClusterInfoImport type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFilteredClusterInfoImportInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options v1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.MulticlusterV1alpha1().ClusterInfoImports(namespace).List(context.TODO(), options) + }, + WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.MulticlusterV1alpha1().ClusterInfoImports(namespace).Watch(context.TODO(), options) + }, + }, + &multiclusterv1alpha1.ClusterInfoImport{}, + resyncPeriod, + indexers, + ) +} + +func (f *clusterInfoImportInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredClusterInfoImportInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *clusterInfoImportInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&multiclusterv1alpha1.ClusterInfoImport{}, f.defaultInformer) +} + +func (f *clusterInfoImportInformer) Lister() v1alpha1.ClusterInfoImportLister { + return v1alpha1.NewClusterInfoImportLister(f.Informer().GetIndexer()) +} diff --git a/multicluster/pkg/client/informers/externalversions/multicluster/v1alpha1/gateway.go b/multicluster/pkg/client/informers/externalversions/multicluster/v1alpha1/gateway.go new file mode 100644 index 00000000000..1b3ae8773bc --- /dev/null +++ b/multicluster/pkg/client/informers/externalversions/multicluster/v1alpha1/gateway.go @@ -0,0 +1,89 @@ +/* +Copyright 2021 Antrea Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +// Code generated by informer-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + "context" + time "time" + + multiclusterv1alpha1 "antrea.io/antrea/multicluster/apis/multicluster/v1alpha1" + versioned "antrea.io/antrea/multicluster/pkg/client/clientset/versioned" + internalinterfaces "antrea.io/antrea/multicluster/pkg/client/informers/externalversions/internalinterfaces" + v1alpha1 "antrea.io/antrea/multicluster/pkg/client/listers/multicluster/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" +) + +// GatewayInformer provides access to a shared informer and lister for +// Gateways. +type GatewayInformer interface { + Informer() cache.SharedIndexInformer + Lister() v1alpha1.GatewayLister +} + +type gatewayInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc + namespace string +} + +// NewGatewayInformer constructs a new informer for Gateway type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewGatewayInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredGatewayInformer(client, namespace, resyncPeriod, indexers, nil) +} + +// NewFilteredGatewayInformer constructs a new informer for Gateway type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFilteredGatewayInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options v1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.MulticlusterV1alpha1().Gateways(namespace).List(context.TODO(), options) + }, + WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.MulticlusterV1alpha1().Gateways(namespace).Watch(context.TODO(), options) + }, + }, + &multiclusterv1alpha1.Gateway{}, + resyncPeriod, + indexers, + ) +} + +func (f *gatewayInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredGatewayInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *gatewayInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&multiclusterv1alpha1.Gateway{}, f.defaultInformer) +} + +func (f *gatewayInformer) Lister() v1alpha1.GatewayLister { + return v1alpha1.NewGatewayLister(f.Informer().GetIndexer()) +} diff --git a/multicluster/pkg/client/informers/externalversions/multicluster/v1alpha1/interface.go b/multicluster/pkg/client/informers/externalversions/multicluster/v1alpha1/interface.go index ff4c3100c97..6fef614477f 100644 --- a/multicluster/pkg/client/informers/externalversions/multicluster/v1alpha1/interface.go +++ b/multicluster/pkg/client/informers/externalversions/multicluster/v1alpha1/interface.go @@ -25,8 +25,12 @@ import ( type Interface interface { // ClusterClaims returns a ClusterClaimInformer. ClusterClaims() ClusterClaimInformer + // ClusterInfoImports returns a ClusterInfoImportInformer. + ClusterInfoImports() ClusterInfoImportInformer // ClusterSets returns a ClusterSetInformer. ClusterSets() ClusterSetInformer + // Gateways returns a GatewayInformer. + Gateways() GatewayInformer // MemberClusterAnnounces returns a MemberClusterAnnounceInformer. MemberClusterAnnounces() MemberClusterAnnounceInformer // ResourceExports returns a ResourceExportInformer. @@ -55,11 +59,21 @@ func (v *version) ClusterClaims() ClusterClaimInformer { return &clusterClaimInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} } +// ClusterInfoImports returns a ClusterInfoImportInformer. +func (v *version) ClusterInfoImports() ClusterInfoImportInformer { + return &clusterInfoImportInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} +} + // ClusterSets returns a ClusterSetInformer. func (v *version) ClusterSets() ClusterSetInformer { return &clusterSetInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} } +// Gateways returns a GatewayInformer. +func (v *version) Gateways() GatewayInformer { + return &gatewayInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} +} + // MemberClusterAnnounces returns a MemberClusterAnnounceInformer. func (v *version) MemberClusterAnnounces() MemberClusterAnnounceInformer { return &memberClusterAnnounceInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} diff --git a/multicluster/pkg/client/listers/multicluster/v1alpha1/clusterinfoimport.go b/multicluster/pkg/client/listers/multicluster/v1alpha1/clusterinfoimport.go new file mode 100644 index 00000000000..73b81011982 --- /dev/null +++ b/multicluster/pkg/client/listers/multicluster/v1alpha1/clusterinfoimport.go @@ -0,0 +1,98 @@ +/* +Copyright 2021 Antrea Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +// Code generated by lister-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + v1alpha1 "antrea.io/antrea/multicluster/apis/multicluster/v1alpha1" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/tools/cache" +) + +// ClusterInfoImportLister helps list ClusterInfoImports. +// All objects returned here must be treated as read-only. +type ClusterInfoImportLister interface { + // List lists all ClusterInfoImports in the indexer. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*v1alpha1.ClusterInfoImport, err error) + // ClusterInfoImports returns an object that can list and get ClusterInfoImports. + ClusterInfoImports(namespace string) ClusterInfoImportNamespaceLister + ClusterInfoImportListerExpansion +} + +// clusterInfoImportLister implements the ClusterInfoImportLister interface. +type clusterInfoImportLister struct { + indexer cache.Indexer +} + +// NewClusterInfoImportLister returns a new ClusterInfoImportLister. +func NewClusterInfoImportLister(indexer cache.Indexer) ClusterInfoImportLister { + return &clusterInfoImportLister{indexer: indexer} +} + +// List lists all ClusterInfoImports in the indexer. +func (s *clusterInfoImportLister) List(selector labels.Selector) (ret []*v1alpha1.ClusterInfoImport, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*v1alpha1.ClusterInfoImport)) + }) + return ret, err +} + +// ClusterInfoImports returns an object that can list and get ClusterInfoImports. +func (s *clusterInfoImportLister) ClusterInfoImports(namespace string) ClusterInfoImportNamespaceLister { + return clusterInfoImportNamespaceLister{indexer: s.indexer, namespace: namespace} +} + +// ClusterInfoImportNamespaceLister helps list and get ClusterInfoImports. +// All objects returned here must be treated as read-only. +type ClusterInfoImportNamespaceLister interface { + // List lists all ClusterInfoImports in the indexer for a given namespace. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*v1alpha1.ClusterInfoImport, err error) + // Get retrieves the ClusterInfoImport from the indexer for a given namespace and name. + // Objects returned here must be treated as read-only. + Get(name string) (*v1alpha1.ClusterInfoImport, error) + ClusterInfoImportNamespaceListerExpansion +} + +// clusterInfoImportNamespaceLister implements the ClusterInfoImportNamespaceLister +// interface. +type clusterInfoImportNamespaceLister struct { + indexer cache.Indexer + namespace string +} + +// List lists all ClusterInfoImports in the indexer for a given namespace. +func (s clusterInfoImportNamespaceLister) List(selector labels.Selector) (ret []*v1alpha1.ClusterInfoImport, err error) { + err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { + ret = append(ret, m.(*v1alpha1.ClusterInfoImport)) + }) + return ret, err +} + +// Get retrieves the ClusterInfoImport from the indexer for a given namespace and name. +func (s clusterInfoImportNamespaceLister) Get(name string) (*v1alpha1.ClusterInfoImport, error) { + obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(v1alpha1.Resource("clusterinfoimport"), name) + } + return obj.(*v1alpha1.ClusterInfoImport), nil +} diff --git a/multicluster/pkg/client/listers/multicluster/v1alpha1/expansion_generated.go b/multicluster/pkg/client/listers/multicluster/v1alpha1/expansion_generated.go index 80cd468ef4e..b2b18cd2ec9 100644 --- a/multicluster/pkg/client/listers/multicluster/v1alpha1/expansion_generated.go +++ b/multicluster/pkg/client/listers/multicluster/v1alpha1/expansion_generated.go @@ -25,6 +25,14 @@ type ClusterClaimListerExpansion interface{} // ClusterClaimNamespaceLister. type ClusterClaimNamespaceListerExpansion interface{} +// ClusterInfoImportListerExpansion allows custom methods to be added to +// ClusterInfoImportLister. +type ClusterInfoImportListerExpansion interface{} + +// ClusterInfoImportNamespaceListerExpansion allows custom methods to be added to +// ClusterInfoImportNamespaceLister. +type ClusterInfoImportNamespaceListerExpansion interface{} + // ClusterSetListerExpansion allows custom methods to be added to // ClusterSetLister. type ClusterSetListerExpansion interface{} @@ -33,6 +41,14 @@ type ClusterSetListerExpansion interface{} // ClusterSetNamespaceLister. type ClusterSetNamespaceListerExpansion interface{} +// GatewayListerExpansion allows custom methods to be added to +// GatewayLister. +type GatewayListerExpansion interface{} + +// GatewayNamespaceListerExpansion allows custom methods to be added to +// GatewayNamespaceLister. +type GatewayNamespaceListerExpansion interface{} + // MemberClusterAnnounceListerExpansion allows custom methods to be added to // MemberClusterAnnounceLister. type MemberClusterAnnounceListerExpansion interface{} diff --git a/multicluster/pkg/client/listers/multicluster/v1alpha1/gateway.go b/multicluster/pkg/client/listers/multicluster/v1alpha1/gateway.go new file mode 100644 index 00000000000..796f1a87979 --- /dev/null +++ b/multicluster/pkg/client/listers/multicluster/v1alpha1/gateway.go @@ -0,0 +1,98 @@ +/* +Copyright 2021 Antrea Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +// Code generated by lister-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + v1alpha1 "antrea.io/antrea/multicluster/apis/multicluster/v1alpha1" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/tools/cache" +) + +// GatewayLister helps list Gateways. +// All objects returned here must be treated as read-only. +type GatewayLister interface { + // List lists all Gateways in the indexer. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*v1alpha1.Gateway, err error) + // Gateways returns an object that can list and get Gateways. + Gateways(namespace string) GatewayNamespaceLister + GatewayListerExpansion +} + +// gatewayLister implements the GatewayLister interface. +type gatewayLister struct { + indexer cache.Indexer +} + +// NewGatewayLister returns a new GatewayLister. +func NewGatewayLister(indexer cache.Indexer) GatewayLister { + return &gatewayLister{indexer: indexer} +} + +// List lists all Gateways in the indexer. +func (s *gatewayLister) List(selector labels.Selector) (ret []*v1alpha1.Gateway, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*v1alpha1.Gateway)) + }) + return ret, err +} + +// Gateways returns an object that can list and get Gateways. +func (s *gatewayLister) Gateways(namespace string) GatewayNamespaceLister { + return gatewayNamespaceLister{indexer: s.indexer, namespace: namespace} +} + +// GatewayNamespaceLister helps list and get Gateways. +// All objects returned here must be treated as read-only. +type GatewayNamespaceLister interface { + // List lists all Gateways in the indexer for a given namespace. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*v1alpha1.Gateway, err error) + // Get retrieves the Gateway from the indexer for a given namespace and name. + // Objects returned here must be treated as read-only. + Get(name string) (*v1alpha1.Gateway, error) + GatewayNamespaceListerExpansion +} + +// gatewayNamespaceLister implements the GatewayNamespaceLister +// interface. +type gatewayNamespaceLister struct { + indexer cache.Indexer + namespace string +} + +// List lists all Gateways in the indexer for a given namespace. +func (s gatewayNamespaceLister) List(selector labels.Selector) (ret []*v1alpha1.Gateway, err error) { + err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { + ret = append(ret, m.(*v1alpha1.Gateway)) + }) + return ret, err +} + +// Get retrieves the Gateway from the indexer for a given namespace and name. +func (s gatewayNamespaceLister) Get(name string) (*v1alpha1.Gateway, error) { + obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(v1alpha1.Resource("gateway"), name) + } + return obj.(*v1alpha1.Gateway), nil +} diff --git a/multicluster/test/e2e/antreapolicy_test.go b/multicluster/test/e2e/antreapolicy_test.go index 70d56ea5565..59ad973a561 100644 --- a/multicluster/test/e2e/antreapolicy_test.go +++ b/multicluster/test/e2e/antreapolicy_test.go @@ -20,9 +20,9 @@ import ( "time" log "github.com/sirupsen/logrus" - v1 "k8s.io/api/core/v1" antreae2e "antrea.io/antrea/test/e2e" + "antrea.io/antrea/test/e2e/utils" ) const ( @@ -33,10 +33,11 @@ const ( ) var ( - allPodsPerCluster []antreae2e.Pod - perNamespacePods, perClusterNamespaces []string - podsByNamespace map[string][]antreae2e.Pod - clusterK8sUtilsMap map[string]*antreae2e.KubernetesUtils + allPodsPerCluster []antreae2e.Pod + perNamespacePods []string + perClusterNamespaces map[string]string + podsByNamespace map[string][]antreae2e.Pod + clusterK8sUtilsMap map[string]*antreae2e.KubernetesUtils ) func failOnError(err error, t *testing.T) { @@ -52,7 +53,10 @@ func failOnError(err error, t *testing.T) { // initializeForPolicyTest creates three Pods in three test Namespaces for each test cluster. func initializeForPolicyTest(t *testing.T, data *MCTestData) { perNamespacePods = []string{"a", "b", "c"} - perClusterNamespaces = []string{"x", "y", "z"} + perClusterNamespaces = make(map[string]string) + perClusterNamespaces["x"] = "x" + perClusterNamespaces["y"] = "y" + perClusterNamespaces["z"] = "z" allPodsPerCluster = []antreae2e.Pod{} podsByNamespace = make(map[string][]antreae2e.Pod) @@ -91,6 +95,8 @@ func (data *MCTestData) testAntreaPolicyCopySpanNSIsolation(t *testing.T) { setup := func() { err := data.deployACNPResourceExport(acnpIsolationResourceExport) failOnError(err, t) + // Sleep 5s to wait resource export/import process to finish resource exchange. + time.Sleep(5 * time.Second) } teardown := func() { err := data.deleteACNPResourceExport(acnpIsolationResourceExport) @@ -102,7 +108,7 @@ func (data *MCTestData) testAntreaPolicyCopySpanNSIsolation(t *testing.T) { Name: "Port 80", Reachability: reachability, Ports: []int32{80}, - Protocol: v1.ProtocolTCP, + Protocol: utils.ProtocolTCP, } testCaseList := []*antreae2e.TestCase{ { @@ -132,7 +138,7 @@ func executeTestsOnAllMemberClusters(t *testing.T, testList []*antreae2e.TestCas } start := time.Now() k8sUtils.Validate(allPodsPerCluster, reachability, step.Ports, step.Protocol) - step.Duration = time.Now().Sub(start) + step.Duration = time.Since(start) _, wrong, _ := step.Reachability.Summary() if wrong != 0 { t.Errorf("Failure in cluster %s -- %d wrong results", clusterName, wrong) @@ -146,22 +152,18 @@ func executeTestsOnAllMemberClusters(t *testing.T, testList []*antreae2e.TestCas } func (data *MCTestData) deployACNPResourceExport(reFileName string) error { - var rc int - var err error log.Infof("Creating ResourceExport %s in the leader cluster", reFileName) - rc, _, _, err = provider.RunCommandOnNode(leaderCluster, fmt.Sprintf("kubectl apply -f %s", reFileName)) - if err != nil || rc != 0 { - return fmt.Errorf("error when deploying the ACNP ResourceExport in leader cluster: %v", err) + rc, _, stderr, err := provider.RunCommandOnNode(leaderCluster, fmt.Sprintf("kubectl apply -f %s", reFileName)) + if err != nil || rc != 0 || stderr != "" { + return fmt.Errorf("error when deploying the ACNP ResourceExport in leader cluster: %v, stderr: %v", err, stderr) } return nil } func (data *MCTestData) deleteACNPResourceExport(reFileName string) error { - var rc int - var err error - rc, _, _, err = provider.RunCommandOnNode(leaderCluster, fmt.Sprintf("kubectl delete -f %s", reFileName)) - if err != nil || rc != 0 { - return fmt.Errorf("error when deleting the ACNP ResourceExport in leader cluster: %v", err) + rc, _, stderr, err := provider.RunCommandOnNode(leaderCluster, fmt.Sprintf("kubectl delete -f %s", reFileName)) + if err != nil || rc != 0 || stderr != "" { + return fmt.Errorf("error when deleting the ACNP ResourceExport in leader cluster: %v, stderr: %v", err, stderr) } return nil } diff --git a/multicluster/test/e2e/framework.go b/multicluster/test/e2e/framework.go index 258f34542b2..1fd0a862f9b 100644 --- a/multicluster/test/e2e/framework.go +++ b/multicluster/test/e2e/framework.go @@ -220,6 +220,26 @@ func randName(prefix string) string { return prefix + randSeq(nameSuffixLength) } +func (data *MCTestData) probeServiceFromPodInCluster( + cluster string, + podName string, + containerName string, + podNamespace string, + serviceIP string, +) error { + cmd := []string{ + "/bin/sh", + "-c", + fmt.Sprintf("curl --connect-timeout 5 -s %s", serviceIP), + } + log.Tracef("Running: kubectl exec %s -c %s -n %s -- %s", podName, containerName, podNamespace, strings.Join(cmd, " ")) + stdout, stderr, err := data.runCommandFromPod(cluster, podNamespace, podName, containerName, cmd) + if err != nil || stderr != "" { + return fmt.Errorf("%s -> %s: error when running command: err - %v /// stdout - %s /// stderr - %s", podName, serviceIP, err, stdout, stderr) + } + return nil +} + func (data *MCTestData) probeFromPodInCluster( cluster string, podNamespace string, diff --git a/multicluster/test/e2e/main_test.go b/multicluster/test/e2e/main_test.go index de51f8bf44f..ad3a13cf0a0 100644 --- a/multicluster/test/e2e/main_test.go +++ b/multicluster/test/e2e/main_test.go @@ -104,4 +104,7 @@ func TestConnectivity(t *testing.T) { testMCAntreaPolicy(t, data) tearDownForPolicyTest() }) + // Wait 5 seconds to let both member and leader controllers clean up all resources, + // otherwise, Namespace deletion may stuck into termininating status. + time.Sleep(5 * time.Second) } diff --git a/multicluster/test/e2e/service_test.go b/multicluster/test/e2e/service_test.go index d58c1e9ad8b..af2a8a99de7 100644 --- a/multicluster/test/e2e/service_test.go +++ b/multicluster/test/e2e/service_test.go @@ -31,11 +31,10 @@ func testServiceExport(t *testing.T, data *MCTestData) { data.testServiceExport(t) } -// testServiceExport is used to test the service between clusters by following steps -// we create a nginx in on cluster(east), and try to curl it in another cluster(west). -// If we got status code 200, it means that the resources is exported by the east cluster -// and imported by the west cluster. -// TODO(yang): reorg test function contents +// testServiceExport is used to test the connectivity of Multicluster Service between +// member clusters. We create a nginx Pod and Service in one member cluster, and try to +// curl it from a Pod in another cluster. If we get status code 200, it means that the +// resources are exported and imported successfully in each member cluster. func (data *MCTestData) testServiceExport(t *testing.T) { podName := randName("test-nginx-") clientPodName := "test-service-client" @@ -72,36 +71,57 @@ func (data *MCTestData) testServiceExport(t *testing.T) { defer data.deleteServiceExport(eastCluster) time.Sleep(importServiceDelay) + // Create a Pod in east cluster and verify the MC Service connectivity from it. + if err := data.createPod(eastCluster, clientPodName, multiClusterTestNamespace, "client", agnhostImage, + []string{"sleep", strconv.Itoa(3600)}, nil, nil, nil, false, nil); err != nil { + t.Fatalf("Error when creating client Pod in east cluster: %v", err) + } + defer deletePodWrapper(t, data, eastCluster, multiClusterTestNamespace, clientPodName) + _, err := data.podWaitFor(defaultTimeout, eastCluster, clientPodName, multiClusterTestNamespace, func(pod *corev1.Pod) (bool, error) { + return pod.Status.Phase == corev1.PodRunning, nil + }) + if err != nil { + t.Fatalf("Error when waiting for Pod '%s' in east cluster: %v", clientPodName, err) + } + svc, err := data.getService(eastCluster, multiClusterTestNamespace, fmt.Sprintf("antrea-mc-%s", westClusterTestService)) if err != nil { t.Fatalf("Error when getting the imported service %s: %v", fmt.Sprintf("antrea-mc-%s", westClusterTestService), err) } eastIP := svc.Spec.ClusterIP - if err := data.probeFromCluster(eastCluster, eastIP); err != nil { + if err := data.probeServiceFromPodInCluster(eastCluster, clientPodName, "client", multiClusterTestNamespace, eastIP); err != nil { t.Fatalf("Error when probing service from %s", eastCluster) } + + // Create a Pod in west cluster and verify the MC Service connectivity from it. + if err := data.createPod(westCluster, clientPodName, multiClusterTestNamespace, "client", agnhostImage, + []string{"sleep", strconv.Itoa(3600)}, nil, nil, nil, false, nil); err != nil { + t.Fatalf("Error when creating client Pod in west cluster: %v", err) + } + defer deletePodWrapper(t, data, westCluster, multiClusterTestNamespace, clientPodName) + _, err = data.podWaitFor(defaultTimeout, westCluster, clientPodName, multiClusterTestNamespace, func(pod *corev1.Pod) (bool, error) { + return pod.Status.Phase == corev1.PodRunning, nil + }) + if err != nil { + t.Fatalf("Error when waiting for Pod '%s' in west cluster: %v", clientPodName, err) + } + svc, err = data.getService(westCluster, multiClusterTestNamespace, fmt.Sprintf("antrea-mc-%s", eastClusterTestService)) if err != nil { t.Fatalf("Error when getting the imported service %s: %v", fmt.Sprintf("antrea-mc-%s", eastClusterTestService), err) } westIP := svc.Spec.ClusterIP - if err := data.probeFromCluster(westCluster, westIP); err != nil { + if err := data.probeServiceFromPodInCluster(westCluster, clientPodName, "client", multiClusterTestNamespace, westIP); err != nil { t.Fatalf("Error when probing service from %s", westCluster) } - if err := data.createPod(eastCluster, clientPodName, multiClusterTestNamespace, "client", agnhostImage, - []string{"sleep", strconv.Itoa(3600)}, nil, nil, nil, false, nil); err != nil { - t.Fatalf("Error when creating client Pod in east cluster: %v", err) - } - defer deletePodWrapper(t, data, eastCluster, multiClusterTestNamespace, clientPodName) - _, err = data.podWaitFor(defaultTimeout, eastCluster, clientPodName, multiClusterTestNamespace, func(pod *corev1.Pod) (bool, error) { - return pod.Status.Phase == corev1.PodRunning, nil - }) - if err != nil { - t.Fatalf("Error when waiting for Pod '%s' in east cluster: %v", clientPodName, err) - } + // Verify that ACNP works fine with new Multicluster Service. + data.verifyMCServiceACNP(t, clientPodName, eastIP) +} +func (data *MCTestData) verifyMCServiceACNP(t *testing.T, clientPodName, eastIP string) { + var err error anpBuilder := &e2euttils.AntreaNetworkPolicySpecBuilder{} anpBuilder = anpBuilder.SetName(multiClusterTestNamespace, "block-west-exported-service"). SetPriority(1.0). @@ -115,7 +135,7 @@ func (data *MCTestData) testServiceExport(t *testing.T) { } defer data.deleteANP(eastCluster, multiClusterTestNamespace, anpBuilder.Name) - connectivity := data.probeFromPodInCluster(eastCluster, multiClusterTestNamespace, clientPodName, "client", westIP, "westClusterServiceIP", 80, corev1.ProtocolTCP) + connectivity := data.probeFromPodInCluster(eastCluster, multiClusterTestNamespace, clientPodName, "client", eastIP, fmt.Sprintf("antrea-mc-%s", westClusterTestService), 80, corev1.ProtocolTCP) if connectivity == antreae2e.Error { t.Errorf("Failure -- could not complete probeFromPodInCluster: %v", err) } else if connectivity != antreae2e.Dropped { @@ -124,33 +144,18 @@ func (data *MCTestData) testServiceExport(t *testing.T) { } func (data *MCTestData) deployServiceExport(clusterName string) error { - var rc int - var err error - rc, _, _, err = provider.RunCommandOnNode(clusterName, fmt.Sprintf("kubectl apply -f %s", serviceExportYML)) - if err != nil || rc != 0 { - return fmt.Errorf("error when deploying the ServiceExport: %v", err) + rc, _, stderr, err := provider.RunCommandOnNode(clusterName, fmt.Sprintf("kubectl apply -f %s", serviceExportYML)) + if err != nil || rc != 0 || stderr != "" { + return fmt.Errorf("error when deploying the ServiceExport: %v, stderr: %v", err, stderr) } return nil } func (data *MCTestData) deleteServiceExport(clusterName string) error { - var rc int - var err error - rc, _, _, err = provider.RunCommandOnNode(clusterName, fmt.Sprintf("kubectl delete -f %s", serviceExportYML)) - if err != nil || rc != 0 { - return fmt.Errorf("error when deleting the ServiceExport: %v", err) - } - - return nil -} - -func (data *MCTestData) probeFromCluster(clusterName string, url string) error { - var rc int - var err error - rc, _, _, err = provider.RunCommandOnNode(clusterName, fmt.Sprintf("curl --connect-timeout 5 -s %s", url)) - if err != nil || rc != 0 { - return fmt.Errorf("error when curl the url %s: %v", url, err) + rc, _, stderr, err := provider.RunCommandOnNode(clusterName, fmt.Sprintf("kubectl delete -f %s", serviceExportYML)) + if err != nil || rc != 0 || stderr != "" { + return fmt.Errorf("error when deleting the ServiceExport: %v, stderr: %v", err, stderr) } return nil diff --git a/multicluster/test/integration/serviceexport_controller_test.go b/multicluster/test/integration/serviceexport_controller_test.go index 3f678efbf56..439a2c9e6c2 100644 --- a/multicluster/test/integration/serviceexport_controller_test.go +++ b/multicluster/test/integration/serviceexport_controller_test.go @@ -230,4 +230,69 @@ var _ = Describe("ServiceExport controller", func() { return apierrors.IsNotFound(err) }, timeout, interval).Should(BeTrue()) }) + + It("Should update existing ServiceExport status when corresponding Service is removed", func() { + By("By deleting a Service") + svc := &corev1.Service{ + ObjectMeta: metav1.ObjectMeta{ + Name: "nginx-svc-deleted", + Namespace: testNamespace, + }, + Spec: svcSpec, + } + ep := &corev1.Endpoints{ + ObjectMeta: metav1.ObjectMeta{ + Name: "nginx-svc-deleted", + Namespace: testNamespace, + }, + Subsets: []corev1.EndpointSubset{ + { + Addresses: []corev1.EndpointAddress{ + { + IP: "192.168.170.11", + Hostname: "pod1", + }, + }, + Ports: epPorts, + }, + }, + } + svcResExportName := LocalClusterID + "-" + svc.Namespace + "-" + svc.Name + "-service" + epResExportName := LocalClusterID + "-" + ep.Namespace + "-" + ep.Name + "-endpoints" + + svcExportDeletedService := &k8smcsv1alpha1.ServiceExport{ + ObjectMeta: metav1.ObjectMeta{ + Name: "nginx-svc-deleted", + Namespace: testNamespace, + }, + } + Expect(k8sClient.Create(ctx, svc)).Should(Succeed()) + Expect(k8sClient.Create(ctx, ep)).Should(Succeed()) + Expect(k8sClient.Create(ctx, svcExportDeletedService)).Should(Succeed()) + time.Sleep(2 * time.Second) + + err := k8sClient.Delete(ctx, svc) + Expect(err).ToNot(HaveOccurred()) + time.Sleep(2 * time.Second) + + latestsvcExportDeletedService := &k8smcsv1alpha1.ServiceExport{} + err = k8sClient.Get(ctx, types.NamespacedName{ + Namespace: svcExportDeletedService.Namespace, + Name: svcExportDeletedService.Name, + }, latestsvcExportDeletedService) + Expect(err).ToNot(HaveOccurred()) + conditions := latestsvcExportDeletedService.Status.Conditions + Expect(len(conditions)).Should(Equal(1)) + Expect(*conditions[0].Message).Should(Equal("the Service does not exist")) + + resExp := &mcsv1alpha1.ResourceExport{} + Eventually(func() bool { + err = k8sClient.Get(ctx, types.NamespacedName{Namespace: LeaderNamespace, Name: svcResExportName}, resExp) + return apierrors.IsNotFound(err) + }, timeout, interval).Should(BeTrue()) + Eventually(func() bool { + err = k8sClient.Get(ctx, types.NamespacedName{Namespace: LeaderNamespace, Name: epResExportName}, resExp) + return apierrors.IsNotFound(err) + }, timeout, interval).Should(BeTrue()) + }) }) diff --git a/multicluster/test/integration/stale_controller_test.go b/multicluster/test/integration/stale_controller_test.go index 390adf485aa..3048be8dccd 100644 --- a/multicluster/test/integration/stale_controller_test.go +++ b/multicluster/test/integration/stale_controller_test.go @@ -32,7 +32,7 @@ import ( // This file contains test cases for below basic scenarios: // * Clean up MC Service and ServiceImport if no corresponding ResourceImport. -// * Clean up ResourceExport if no correspoding exported Service. +// * Clean up ResourceExport if no corresponding exported Service. var _ = Describe("Stale controller", func() { svcSpec := corev1.ServiceSpec{ @@ -41,14 +41,33 @@ var _ = Describe("Stale controller", func() { ctx := context.Background() It("Should clean up MC Service and ServiceImport if no corresponding ResourceImport in leader cluster", func() { By("By claim a Service and ServiceImport without ResourceImport in leader cluster") + svcImpNoDelete := &k8smcsv1alpha1.ServiceImport{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: testNSForStale, + Name: "nginxnodelete", + }, + Spec: k8smcsv1alpha1.ServiceImportSpec{ + Type: k8smcsv1alpha1.ClusterSetIP, + Ports: []k8smcsv1alpha1.ServicePort{ + { + Name: "http", + Protocol: corev1.ProtocolTCP, + Port: 80, + }, + }, + }, + } + resImport := &mcsv1alpha1.ResourceImport{ ObjectMeta: metav1.ObjectMeta{ Name: "resourceimportexist", Namespace: LeaderNamespace, }, Spec: mcsv1alpha1.ResourceImportSpec{ - Name: "nginxnodelete", - Namespace: testNSForStale, + Name: "nginxnodelete", + Namespace: testNSForStale, + Kind: common.ServiceImportKind, + ServiceImport: svcImpNoDelete, }, } err := k8sClient.Create(ctx, resImport, &client.CreateOptions{}) @@ -106,28 +125,16 @@ var _ = Describe("Stale controller", func() { Spec: svcSpec, } - svcImpNoDelete := &k8smcsv1alpha1.ServiceImport{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: testNSForStale, - Name: "nginxnodelete", - }, - Spec: k8smcsv1alpha1.ServiceImportSpec{ - Type: k8smcsv1alpha1.ClusterSetIP, - Ports: []k8smcsv1alpha1.ServicePort{ - { - Name: "http", - Protocol: corev1.ProtocolTCP, - Port: 80, - }, - }, - }, - } - Expect(k8sClient.Create(ctx, svcToDelete)).Should(Succeed()) Expect(k8sClient.Create(ctx, svcImpToDelete)).Should(Succeed()) Expect(k8sClient.Create(ctx, svcNoDelete)).Should(Succeed()) - Expect(k8sClient.Create(ctx, mcSvcNoDelete)).Should(Succeed()) - Expect(k8sClient.Create(ctx, svcImpNoDelete)).Should(Succeed()) + // ResourceImport controller will watch ResourceImport creation event, + // it may create corresponding Service and ServiceImport already, so we + // skip it if it's 409 AlreadyExists error. + err = k8sClient.Create(ctx, mcSvcNoDelete) + Expect(err == nil || apierrors.IsAlreadyExists(err)).Should(BeTrue()) + err = k8sClient.Create(ctx, svcImpNoDelete) + Expect(err == nil || apierrors.IsAlreadyExists(err)).Should(BeTrue()) Eventually(func() bool { latestSvc := &corev1.Service{} diff --git a/multicluster/test/integration/suite_test.go b/multicluster/test/integration/suite_test.go index 8ae58eff64e..781bbe0d767 100644 --- a/multicluster/test/integration/suite_test.go +++ b/multicluster/test/integration/suite_test.go @@ -37,10 +37,10 @@ import ( "sigs.k8s.io/controller-runtime/pkg/log/zap" mcsscheme "sigs.k8s.io/mcs-api/pkg/client/clientset/versioned/scheme" - // mcsv1alpha1 "antrea.io/antrea/multicluster/apis/multicluster/v1alpha1" mcsv1alpha1 "antrea.io/antrea/multicluster/apis/multicluster/v1alpha1" multiclustercontrollers "antrea.io/antrea/multicluster/controllers/multicluster" antreamcscheme "antrea.io/antrea/multicluster/pkg/client/clientset/versioned/scheme" + antreascheme "antrea.io/antrea/pkg/client/clientset/versioned/scheme" "antrea.io/antrea/pkg/signals" //+kubebuilder:scaffold:imports ) @@ -97,7 +97,9 @@ var _ = BeforeSuite(func() { By("bootstrapping test environment") useExistingCluster := true testEnv = &envtest.Environment{ - CRDDirectoryPaths: []string{filepath.Join("..", "..", "config", "crd", "bases"), filepath.Join("..", "..", "config", "crd", "k8smcs")}, + CRDDirectoryPaths: []string{filepath.Join("..", "..", "config", "crd", "bases"), + filepath.Join("..", "..", "config", "crd", "k8smcs"), + filepath.Join("..", "..", "..", "build", "charts", "antrea", "templates", "crds", "clusternetworkpolicy.yaml")}, ErrorIfCRDPathMissing: true, UseExistingCluster: &useExistingCluster, } @@ -114,6 +116,8 @@ var _ = BeforeSuite(func() { Expect(err).NotTo(HaveOccurred()) err = k8sscheme.AddToScheme(scheme) Expect(err).NotTo(HaveOccurred()) + err = antreascheme.AddToScheme(scheme) + Expect(err).NotTo(HaveOccurred()) //+kubebuilder:scaffold:scheme k8sClient, err = client.New(cfg, client.Options{Scheme: scheme}) @@ -131,11 +135,11 @@ var _ = BeforeSuite(func() { k8sClient.Create(ctx, leaderNS) k8sClient.Create(ctx, testNS) k8sClient.Create(ctx, testNSStale) - clusterSetReconciler := &multiclustercontrollers.MemberClusterSetReconciler{ - Client: k8sManager.GetClient(), - Scheme: k8sManager.GetScheme(), - Namespace: LeaderNamespace, - } + clusterSetReconciler := multiclustercontrollers.NewMemberClusterSetReconciler( + k8sManager.GetClient(), + k8sManager.GetScheme(), + LeaderNamespace, + ) err = clusterSetReconciler.SetupWithManager(k8sManager) Expect(err).ToNot(HaveOccurred()) @@ -143,7 +147,7 @@ var _ = BeforeSuite(func() { svcExportReconciler := multiclustercontrollers.NewServiceExportReconciler( k8sManager.GetClient(), k8sManager.GetScheme(), - &clusterSetReconciler.RemoteCommonAreaManager) + clusterSetReconciler) err = svcExportReconciler.SetupWithManager(k8sManager) Expect(err).ToNot(HaveOccurred()) @@ -152,14 +156,15 @@ var _ = BeforeSuite(func() { By("Creating StaleController") stopCh := signals.RegisterSignalHandlers() - staleController := multiclustercontrollers.NewStaleController( + staleController := multiclustercontrollers.NewStaleResCleanupController( k8sManager.GetClient(), k8sManager.GetScheme(), - &clusterSetReconciler.RemoteCommonAreaManager) + "default", + clusterSetReconciler) go staleController.Run(stopCh) // Make sure to trigger clean up process every 5 seconds - // otherwise staleController will only run once before test case is ready to run. + // otherwise staleResCleanupController will only run once before test case is ready to run. go func() { for { staleController.Enqueue() diff --git a/pkg/agent/agent.go b/pkg/agent/agent.go index 494b3af1412..c37fabd3e1b 100644 --- a/pkg/agent/agent.go +++ b/pkg/agent/agent.go @@ -85,21 +85,18 @@ type Initializer struct { ovsBridge string hostGateway string // name of gateway port on the OVS bridge mtu int - serviceCIDR *net.IPNet // K8s Service ClusterIP CIDR - serviceCIDRv6 *net.IPNet // K8s Service ClusterIP CIDR in IPv6 networkConfig *config.NetworkConfig nodeConfig *config.NodeConfig wireGuardConfig *config.WireGuardConfig egressConfig *config.EgressConfig + serviceConfig *config.ServiceConfig enableProxy bool connectUplinkToBridge bool // networkReadyCh should be closed once the Node's network is ready. // The CNI server will wait for it before handling any CNI Add requests. - proxyAll bool - nodePortAddressesIPv4 []net.IP - nodePortAddressesIPv6 []net.IP - networkReadyCh chan<- struct{} - stopCh <-chan struct{} + proxyAll bool + networkReadyCh chan<- struct{} + stopCh <-chan struct{} } func NewInitializer( @@ -111,17 +108,14 @@ func NewInitializer( ovsBridge string, hostGateway string, mtu int, - serviceCIDR *net.IPNet, - serviceCIDRv6 *net.IPNet, networkConfig *config.NetworkConfig, wireGuardConfig *config.WireGuardConfig, egressConfig *config.EgressConfig, + serviceConfig *config.ServiceConfig, networkReadyCh chan<- struct{}, stopCh <-chan struct{}, enableProxy bool, proxyAll bool, - nodePortAddressesIPv4 []net.IP, - nodePortAddressesIPv6 []net.IP, connectUplinkToBridge bool, ) *Initializer { return &Initializer{ @@ -133,17 +127,14 @@ func NewInitializer( ovsBridge: ovsBridge, hostGateway: hostGateway, mtu: mtu, - serviceCIDR: serviceCIDR, - serviceCIDRv6: serviceCIDRv6, networkConfig: networkConfig, wireGuardConfig: wireGuardConfig, egressConfig: egressConfig, + serviceConfig: serviceConfig, networkReadyCh: networkReadyCh, stopCh: stopCh, enableProxy: enableProxy, proxyAll: proxyAll, - nodePortAddressesIPv4: nodePortAddressesIPv4, - nodePortAddressesIPv6: nodePortAddressesIPv6, connectUplinkToBridge: connectUplinkToBridge, } } @@ -434,60 +425,12 @@ func (i *Initializer) initOpenFlowPipeline() error { roundInfo := getRoundInfo(i.ovsBridgeClient) // Set up all basic flows. - ofConnCh, err := i.ofClient.Initialize(roundInfo, i.nodeConfig, i.networkConfig) + ofConnCh, err := i.ofClient.Initialize(roundInfo, i.nodeConfig, i.networkConfig, i.egressConfig, i.serviceConfig) if err != nil { klog.Errorf("Failed to initialize openflow client: %v", err) return err } - // On Windows platform, host network flows are needed for host traffic. - if err := i.initHostNetworkFlows(); err != nil { - klog.Errorf("Failed to install openflow entries for host network: %v", err) - return err - } - - // Install OpenFlow entries to enable Pod traffic to external IP - // addresses. - if err := i.ofClient.InstallExternalFlows(i.egressConfig.ExceptCIDRs); err != nil { - klog.Errorf("Failed to install openflow entries for external connectivity: %v", err) - return err - } - - // Set up flow entries for gateway interface, including classifier, skip spoof guard check, - // L3 forwarding and L2 forwarding - if err := i.ofClient.InstallGatewayFlows(); err != nil { - klog.Errorf("Failed to setup openflow entries for gateway: %v", err) - return err - } - - if i.networkConfig.TrafficEncapMode.SupportsEncap() { - // Set up flow entries for the default tunnel port interface. - if err := i.ofClient.InstallDefaultTunnelFlows(); err != nil { - klog.Errorf("Failed to setup openflow entries for tunnel interface: %v", err) - return err - } - } - - if !i.enableProxy { - // Set up flow entries to enable Service connectivity. Upstream kube-proxy is leveraged to - // provide load-balancing, and the flows installed by this method ensure that traffic sent - // from local Pods to any Service address can be forwarded to the host gateway interface - // correctly. Otherwise packets might be dropped by egress rules before they are DNATed to - // backend Pods. - if err := i.ofClient.InstallClusterServiceCIDRFlows([]*net.IPNet{i.serviceCIDR, i.serviceCIDRv6}); err != nil { - klog.Errorf("Failed to setup OpenFlow entries for Service CIDRs: %v", err) - return err - } - } else { - // Set up flow entries to enable Service connectivity. The agent proxy handles - // ClusterIP Services while the upstream kube-proxy is leveraged to handle - // any other kinds of Services. - if err := i.ofClient.InstallDefaultServiceFlows(i.nodePortAddressesIPv4, i.nodePortAddressesIPv6); err != nil { - klog.Errorf("Failed to setup default OpenFlow entries for ClusterIP Services: %v", err) - return err - } - } - go func() { // Delete stale flows from previous round. We need to wait long enough to ensure // that all the flow which are still required have received an updated cookie (with diff --git a/pkg/agent/agent_linux.go b/pkg/agent/agent_linux.go index af324f839fc..5bf791feadd 100644 --- a/pkg/agent/agent_linux.go +++ b/pkg/agent/agent_linux.go @@ -125,15 +125,6 @@ func (i *Initializer) prepareOVSBridge() error { return nil } -// initHostNetworkFlows installs Openflow flows between bridge local port and uplink port to support -// host networking. -func (i *Initializer) initHostNetworkFlows() error { - if err := i.ofClient.InstallBridgeUplinkFlows(); err != nil { - return err - } - return nil -} - // getTunnelLocalIP returns local_ip of tunnel port. // On linux platform, local_ip option is not needed. func (i *Initializer) getTunnelPortLocalIP() net.IP { diff --git a/pkg/agent/agent_windows.go b/pkg/agent/agent_windows.go index 3ecb469e307..2053be1f070 100644 --- a/pkg/agent/agent_windows.go +++ b/pkg/agent/agent_windows.go @@ -191,15 +191,6 @@ func (i *Initializer) prepareOVSBridge() error { return nil } -// initHostNetworkFlows installs Openflow flows between bridge local port and uplink port to support -// host networking. -func (i *Initializer) initHostNetworkFlows() error { - if err := i.ofClient.InstallBridgeUplinkFlows(); err != nil { - return err - } - return nil -} - // getTunnelLocalIP returns local_ip of tunnel port func (i *Initializer) getTunnelPortLocalIP() net.IP { return i.nodeConfig.NodeTransportIPv4Addr.IP @@ -261,9 +252,9 @@ func (i *Initializer) restoreHostRoutes() error { } func GetTransportIPNetDeviceByName(ifaceName string, ovsBridgeName string) (*net.IPNet, *net.IPNet, *net.Interface, error) { - // Find transport Interface in the order: ifaceName -> "vEthernet (ifaceName)" -> br-int. Return immediately if - // an interface using the specified name exists. Using "vEthernet (ifaceName)" or br-int is for restart agent case. - for _, name := range []string{ifaceName, util.VirtualAdapterName(ifaceName), ovsBridgeName} { + // Find transport Interface in the order: ifaceName -> br-int. Return immediately if + // an interface using the specified name exists. Using br-int is for restart agent case. + for _, name := range []string{ifaceName, ovsBridgeName} { ipNet, _, link, err := util.GetIPNetDeviceByName(name) if err == nil { return ipNet, nil, link, nil diff --git a/pkg/agent/apiserver/apiserver.go b/pkg/agent/apiserver/apiserver.go index 763df749281..0862aeae431 100644 --- a/pkg/agent/apiserver/apiserver.go +++ b/pkg/agent/apiserver/apiserver.go @@ -40,6 +40,7 @@ import ( "antrea.io/antrea/pkg/agent/apiserver/handlers/ovsflows" "antrea.io/antrea/pkg/agent/apiserver/handlers/ovstracing" "antrea.io/antrea/pkg/agent/apiserver/handlers/podinterface" + "antrea.io/antrea/pkg/agent/apiserver/handlers/serviceexternalip" agentquerier "antrea.io/antrea/pkg/agent/querier" systeminstall "antrea.io/antrea/pkg/apis/system/install" systemv1beta1 "antrea.io/antrea/pkg/apis/system/v1beta1" @@ -72,7 +73,7 @@ func (s *agentAPIServer) Run(stopCh <-chan struct{}) error { return s.GenericAPIServer.PrepareRun().Run(stopCh) } -func installHandlers(aq agentquerier.AgentQuerier, npq querier.AgentNetworkPolicyInfoQuerier, s *genericapiserver.GenericAPIServer) { +func installHandlers(aq agentquerier.AgentQuerier, npq querier.AgentNetworkPolicyInfoQuerier, seipq querier.ServiceExternalIPStatusQuerier, s *genericapiserver.GenericAPIServer) { s.Handler.NonGoRestfulMux.HandleFunc("/loglevel", loglevel.HandleFunc()) s.Handler.NonGoRestfulMux.HandleFunc("/featuregates", featuregates.HandleFunc()) s.Handler.NonGoRestfulMux.HandleFunc("/agentinfo", agentinfo.HandleFunc(aq)) @@ -82,6 +83,7 @@ func installHandlers(aq agentquerier.AgentQuerier, npq querier.AgentNetworkPolic s.Handler.NonGoRestfulMux.HandleFunc("/addressgroups", addressgroup.HandleFunc(npq)) s.Handler.NonGoRestfulMux.HandleFunc("/ovsflows", ovsflows.HandleFunc(aq)) s.Handler.NonGoRestfulMux.HandleFunc("/ovstracing", ovstracing.HandleFunc(aq)) + s.Handler.NonGoRestfulMux.HandleFunc("/serviceexternalip", serviceexternalip.HandleFunc(seipq)) } func installAPIGroup(s *genericapiserver.GenericAPIServer, aq agentquerier.AgentQuerier, npq querier.AgentNetworkPolicyInfoQuerier, v4Enabled, v6Enabled bool) error { @@ -95,8 +97,8 @@ func installAPIGroup(s *genericapiserver.GenericAPIServer, aq agentquerier.Agent } // New creates an APIServer for running in antrea agent. -func New(aq agentquerier.AgentQuerier, npq querier.AgentNetworkPolicyInfoQuerier, bindPort int, - enableMetrics bool, kubeconfig string, cipherSuites []uint16, tlsMinVersion uint16, v4Enabled, v6Enabled bool) (*agentAPIServer, error) { +func New(aq agentquerier.AgentQuerier, npq querier.AgentNetworkPolicyInfoQuerier, seipq querier.ServiceExternalIPStatusQuerier, + bindPort int, enableMetrics bool, kubeconfig string, cipherSuites []uint16, tlsMinVersion uint16, v4Enabled, v6Enabled bool) (*agentAPIServer, error) { cfg, err := newConfig(npq, bindPort, enableMetrics, kubeconfig) if err != nil { return nil, err @@ -110,7 +112,7 @@ func New(aq agentquerier.AgentQuerier, npq querier.AgentNetworkPolicyInfoQuerier if err := installAPIGroup(s, aq, npq, v4Enabled, v6Enabled); err != nil { return nil, err } - installHandlers(aq, npq, s) + installHandlers(aq, npq, seipq, s) return &agentAPIServer{GenericAPIServer: s}, nil } diff --git a/pkg/agent/apiserver/handlers/serviceexternalip/handler.go b/pkg/agent/apiserver/handlers/serviceexternalip/handler.go new file mode 100644 index 00000000000..c397f24f505 --- /dev/null +++ b/pkg/agent/apiserver/handlers/serviceexternalip/handler.go @@ -0,0 +1,70 @@ +// Copyright 2022 Antrea Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package serviceexternalip + +import ( + "encoding/json" + "net/http" + + "antrea.io/antrea/pkg/antctl/transform/common" + "antrea.io/antrea/pkg/features" + "antrea.io/antrea/pkg/querier" +) + +// HandleFunc creates a http.HandlerFunc which uses an ServiceExternalIPStatusQuerier +// to query Service external IP status. +func HandleFunc(sq querier.ServiceExternalIPStatusQuerier) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + name := r.URL.Query().Get("name") + ns := r.URL.Query().Get("namespace") + if !features.DefaultFeatureGate.Enabled(features.ServiceExternalIP) { + http.Error(w, "ServiceExternalIP is not enabled", http.StatusServiceUnavailable) + return + } + result := sq.GetServiceExternalIPStatus() + var response []Response + for _, r := range result { + if (len(name) == 0 || name == r.ServiceName) && (len(ns) == 0 || ns == r.Namespace) { + response = append(response, Response{r}) + } + } + if len(name) > 0 && len(response) == 0 { + w.WriteHeader(http.StatusNotFound) + return + } + if err := json.NewEncoder(w).Encode(response); err != nil { + http.Error(w, "Failed to encode response: "+err.Error(), http.StatusInternalServerError) + } + } +} + +// Response describes the response struct of serviceexternalip command. +type Response struct { + querier.ServiceExternalIPInfo +} + +var _ common.TableOutput = (*Response)(nil) + +func (r Response) GetTableHeader() []string { + return []string{"NAMESPACE", "NAME", "EXTERNAL-IP-POOL", "EXTERNAL-IP", "ASSIGNED-NODE"} +} + +func (r Response) GetTableRow(_ int) []string { + return []string{r.Namespace, r.ServiceName, r.ExternalIPPool, r.ExternalIP, r.AssignedNode} +} + +func (r Response) SortRows() bool { + return true +} diff --git a/pkg/agent/client.go b/pkg/agent/client.go index 67ffec3c91e..f49e8aa8b11 100644 --- a/pkg/agent/client.go +++ b/pkg/agent/client.go @@ -15,6 +15,7 @@ package agent import ( + "context" "fmt" "io/ioutil" "net" @@ -76,8 +77,8 @@ func (p *antreaClientProvider) RunOnce() error { // Run starts the caContentProvider, which watches the ConfigMap and notifies changes // by calling Enqueue. -func (p *antreaClientProvider) Run(stopCh <-chan struct{}) { - p.caContentProvider.Run(1, stopCh) +func (p *antreaClientProvider) Run(ctx context.Context) { + p.caContentProvider.Run(ctx, 1) } // Enqueue implements dynamiccertificates.Listener. It will be called by caContentProvider diff --git a/pkg/agent/cniserver/interface_configuration_linux.go b/pkg/agent/cniserver/interface_configuration_linux.go index 2d86a771a3c..d165876bbb9 100644 --- a/pkg/agent/cniserver/interface_configuration_linux.go +++ b/pkg/agent/cniserver/interface_configuration_linux.go @@ -47,10 +47,11 @@ const ( type ifConfigurator struct { ovsDatapathType ovsconfig.OVSDatapathType isOvsHardwareOffloadEnabled bool + disableTXChecksumOffload bool } -func newInterfaceConfigurator(ovsDatapathType ovsconfig.OVSDatapathType, isOvsHardwareOffloadEnabled bool) (*ifConfigurator, error) { - return &ifConfigurator{ovsDatapathType: ovsDatapathType, isOvsHardwareOffloadEnabled: isOvsHardwareOffloadEnabled}, nil +func newInterfaceConfigurator(ovsDatapathType ovsconfig.OVSDatapathType, isOvsHardwareOffloadEnabled bool, disableTXChecksumOffload bool) (*ifConfigurator, error) { + return &ifConfigurator{ovsDatapathType: ovsDatapathType, isOvsHardwareOffloadEnabled: isOvsHardwareOffloadEnabled, disableTXChecksumOffload: disableTXChecksumOffload}, nil } func renameLink(curName, newName string) error { @@ -260,9 +261,10 @@ func (ic *ifConfigurator) configureContainerLinkVeth( } containerIface.Mac = containerVeth.HardwareAddr.String() hostIface.Mac = hostVeth.HardwareAddr.String() + // Disable TX checksum offloading when it's configured explicitly or the datapath is netdev. // OVS netdev datapath doesn't support TX checksum offloading, i.e. if packet // arrives with bad/no checksum it will be sent to the output port with same bad/no checksum. - if ic.ovsDatapathType == ovsconfig.OVSDatapathNetdev { + if ic.disableTXChecksumOffload || ic.ovsDatapathType == ovsconfig.OVSDatapathNetdev { if err := ethtool.EthtoolTXHWCsumOff(containerVeth.Name); err != nil { return fmt.Errorf("error when disabling TX checksum offload on container veth: %v", err) } diff --git a/pkg/agent/cniserver/interface_configuration_windows.go b/pkg/agent/cniserver/interface_configuration_windows.go index f38ae221e18..40042db1256 100644 --- a/pkg/agent/cniserver/interface_configuration_windows.go +++ b/pkg/agent/cniserver/interface_configuration_windows.go @@ -48,7 +48,8 @@ type ifConfigurator struct { epCache *sync.Map } -func newInterfaceConfigurator(ovsDatapathType ovsconfig.OVSDatapathType, isOvsHardwareOffloadEnabled bool) (*ifConfigurator, error) { +// disableTXChecksumOffload is ignored on Windows. +func newInterfaceConfigurator(ovsDatapathType ovsconfig.OVSDatapathType, isOvsHardwareOffloadEnabled bool, disableTXChecksumOffload bool) (*ifConfigurator, error) { hnsNetwork, err := hcsshim.GetHNSNetworkByName(util.LocalHNSNetwork) if err != nil { return nil, err diff --git a/pkg/agent/cniserver/ipam/antrea_ipam.go b/pkg/agent/cniserver/ipam/antrea_ipam.go index d37faa22395..d9cd90f7309 100644 --- a/pkg/agent/cniserver/ipam/antrea_ipam.go +++ b/pkg/agent/cniserver/ipam/antrea_ipam.go @@ -26,13 +26,13 @@ import ( "k8s.io/apimachinery/pkg/util/wait" "k8s.io/klog/v2" - argtypes "antrea.io/antrea/pkg/agent/cniserver/types" + "antrea.io/antrea/pkg/agent/cniserver/types" crdv1a2 "antrea.io/antrea/pkg/apis/crd/v1alpha2" "antrea.io/antrea/pkg/ipam/poolallocator" ) const ( - AntreaIPAMType = "antrea-ipam" + AntreaIPAMType = "antrea" ) // Antrea IPAM driver would allocate IP addresses according to object IPAM annotation, @@ -58,13 +58,17 @@ const ( // Resource needs to be unique since it is used as identifier in Del. // Therefore Container ID is used, while Pod/Namespace are shown for visibility. -// TODO: Consider multi-interface case -func getAllocationOwner(args *invoke.Args, k8sArgs *argtypes.K8sArgs, reservedOwner *crdv1a2.IPAddressOwner) crdv1a2.IPAddressOwner { +func getAllocationOwner(args *invoke.Args, k8sArgs *types.K8sArgs, reservedOwner *crdv1a2.IPAddressOwner, secondary bool) crdv1a2.IPAddressOwner { podOwner := &crdv1a2.PodOwner{ Name: string(k8sArgs.K8S_POD_NAME), Namespace: string(k8sArgs.K8S_POD_NAMESPACE), ContainerID: args.ContainerID, } + if secondary { + // Add interface name for secondary network to uniquely identify + // the secondary network interface. + podOwner.IFName = args.IfName + } if reservedOwner != nil { owner := *reservedOwner owner.Pod = podOwner @@ -107,6 +111,23 @@ func generateIPConfig(ip net.IP, prefixLength int, gwIP net.IP) (*current.IPConf return &ipConfig, &defaultRoute } +func parseStaticAddresses(ipamConfig *types.IPAMConfig) error { + for i := range ipamConfig.Addresses { + ip, addr, err := net.ParseCIDR(ipamConfig.Addresses[i].Address) + if err != nil { + return fmt.Errorf("invalid address %s", ipamConfig.Addresses[i].Address) + } + ipamConfig.Addresses[i].IPNet = *addr + ipamConfig.Addresses[i].IPNet.IP = ip + if ip.To4() != nil { + ipamConfig.Addresses[i].Version = "4" + } else { + ipamConfig.Addresses[i].Version = "6" + } + } + return nil +} + func (d *AntreaIPAM) setController(controller *AntreaIPAMController) { d.controllerMutex.Lock() defer d.controllerMutex.Unlock() @@ -115,7 +136,7 @@ func (d *AntreaIPAM) setController(controller *AntreaIPAMController) { // Add allocates next available IP address from associated IP Pool // Allocated IP and associated resource are stored in IP Pool status -func (d *AntreaIPAM) Add(args *invoke.Args, k8sArgs *argtypes.K8sArgs, networkConfig []byte) (bool, *IPAMResult, error) { +func (d *AntreaIPAM) Add(args *invoke.Args, k8sArgs *types.K8sArgs, networkConfig []byte) (bool, *IPAMResult, error) { mine, allocator, ips, reservedOwner, err := d.owns(k8sArgs) if err != nil { return true, nil, err @@ -125,9 +146,9 @@ func (d *AntreaIPAM) Add(args *invoke.Args, k8sArgs *argtypes.K8sArgs, networkCo return false, nil, nil } - owner := getAllocationOwner(args, k8sArgs, reservedOwner) + owner := getAllocationOwner(args, k8sArgs, reservedOwner, false) var ip net.IP - var subnetInfo crdv1a2.SubnetInfo + var subnetInfo *crdv1a2.SubnetInfo if reservedOwner != nil { ip, subnetInfo, err = allocator.AllocateReservedOrNext(crdv1a2.IPAddressPhaseAllocated, owner) } else if len(ips) == 0 { @@ -142,7 +163,7 @@ func (d *AntreaIPAM) Add(args *invoke.Args, k8sArgs *argtypes.K8sArgs, networkCo klog.V(4).InfoS("IP allocation successful", "IP", ip.String(), "Pod", string(k8sArgs.K8S_POD_NAME)) - result := IPAMResult{Result: current.Result{CNIVersion: current.ImplementedSpecVersion}, VLANID: subnetInfo.VLAN & 0xfff} + result := IPAMResult{Result: current.Result{CNIVersion: current.ImplementedSpecVersion}, VLANID: subnetInfo.VLAN} gwIP := net.ParseIP(subnetInfo.Gateway) ipConfig, defaultRoute := generateIPConfig(ip, int(subnetInfo.PrefixLength), gwIP) @@ -153,23 +174,20 @@ func (d *AntreaIPAM) Add(args *invoke.Args, k8sArgs *argtypes.K8sArgs, networkCo } // Del deletes IP associated with resource from IP Pool status -func (d *AntreaIPAM) Del(args *invoke.Args, k8sArgs *argtypes.K8sArgs, networkConfig []byte) (bool, error) { - mine, allocator, _, _, err := d.owns(k8sArgs) - if mine == mineFalse || mine == mineUnknown { - // pass this request to next driver - return false, nil - } +func (d *AntreaIPAM) Del(args *invoke.Args, k8sArgs *types.K8sArgs, networkConfig []byte) (bool, error) { + owner := getAllocationOwner(args, k8sArgs, nil, false) + foundAllocation, err := d.del(owner.Pod) if err != nil { + // Let the invoker retry at error. return true, err } - owner := getAllocationOwner(args, k8sArgs, nil) - err = allocator.ReleaseContainerIfPresent(owner.Pod.ContainerID) - return true, err + // If no allocation found, pass CNI DEL to the next driver. + return foundAllocation, nil } // Check verifues IP associated with resource is tracked in IP Pool status -func (d *AntreaIPAM) Check(args *invoke.Args, k8sArgs *argtypes.K8sArgs, networkConfig []byte) (bool, error) { +func (d *AntreaIPAM) Check(args *invoke.Args, k8sArgs *types.K8sArgs, networkConfig []byte) (bool, error) { mine, allocator, _, _, err := d.owns(k8sArgs) if err != nil { return true, err @@ -179,16 +197,119 @@ func (d *AntreaIPAM) Check(args *invoke.Args, k8sArgs *argtypes.K8sArgs, network return false, nil } - owner := getAllocationOwner(args, k8sArgs, nil) - found, err := allocator.HasContainer(owner.Pod.ContainerID) + ip, err := allocator.GetContainerIP(args.ContainerID, "") if err != nil { return true, err } - if !found { + if ip == nil { return true, fmt.Errorf("no IP Address association found for container %s", string(k8sArgs.K8S_POD_NAME)) } + return true, nil +} + +func (d *AntreaIPAM) secondaryNetworkAdd(args *invoke.Args, k8sArgs *types.K8sArgs, networkConfig *types.NetworkConfig) (*current.Result, error) { + ipamConf := networkConfig.IPAM + numPools := len(ipamConf.IPPools) + + if err := parseStaticAddresses(ipamConf); err != nil { + return nil, fmt.Errorf("failed to parse static addresses in the IPAM config: %v", err) + } + if numPools == 0 && len(ipamConf.Addresses) == 0 { + return nil, fmt.Errorf("at least one Antrea IPPool or static address must be specified") + } + + result := ¤t.Result{} + if numPools > 0 { + if err := d.waitForControllerReady(); err != nil { + // Return error to let the invoker retry. + return nil, err + } + + owner := getAllocationOwner(args, k8sArgs, nil, true) + var allocatorsToRelease []*poolallocator.IPPoolAllocator + defer func() { + for _, allocator := range allocatorsToRelease { + // Try to release the allocated IPs after an error. + allocator.ReleaseContainer(owner.Pod.ContainerID, owner.Pod.IFName) + } + }() + + for _, p := range ipamConf.IPPools { + allocator, err := d.controller.getPoolAllocatorByName(p) + if err != nil { + return nil, err + } + + var ip net.IP + var subnetInfo *crdv1a2.SubnetInfo + ip, subnetInfo, err = allocator.AllocateNext(crdv1a2.IPAddressPhaseAllocated, owner) + if err != nil { + return nil, err + } + if numPools > 1 { + allocatorsToRelease = append(allocatorsToRelease, allocator) + } + + gwIP := net.ParseIP(subnetInfo.Gateway) + ipConfig, _ := generateIPConfig(ip, int(subnetInfo.PrefixLength), gwIP) + // CNI spec 0.2.0 and below support only one v4 and one v6 address. But we + // assume the CNI version >= 0.3.0, and so do not check the number of + // addresses. + result.IPs = append(result.IPs, ipConfig) + } + // No failed allocation, so do not release allocated IPs. + allocatorsToRelease = nil + } + + // Add static addresses. + for _, a := range ipamConf.Addresses { + result.IPs = append(result.IPs, ¤t.IPConfig{ + Address: a.IPNet, + Gateway: a.Gateway, + Version: a.Version}) + } + // Copy routes and DNS from the input IPAM configuration. + result.Routes = ipamConf.Routes + result.DNS = ipamConf.DNS + return result, nil +} + +func (d *AntreaIPAM) secondaryNetworkDel(args *invoke.Args, k8sArgs *types.K8sArgs, networkConfig *types.NetworkConfig) error { + owner := getAllocationOwner(args, k8sArgs, nil, true) + _, err := d.del(owner.Pod) + return err +} + +func (d *AntreaIPAM) secondaryNetworkCheck(args *invoke.Args, k8sArgs *types.K8sArgs, networkConfig *types.NetworkConfig) error { + return fmt.Errorf("CNI CHECK is not implemented for secondary network") +} + +func (d *AntreaIPAM) del(podOwner *crdv1a2.PodOwner) (foundAllocation bool, err error) { + if err := d.waitForControllerReady(); err != nil { + // Return error to let the invoker retry. + return false, err + } + // The Pod resource might have been removed; and for a secondary we + // would rely on the passed IPPool for CNI DEL. So, search IPPools with + // the matched PodOwner. + allocators, err := d.controller.getPoolAllocatorsByOwner(podOwner) + if err != nil { + return false, err + } + + if len(allocators) == 0 { + return false, nil + } + // Multiple allocators can be returned if the network interface has IPs + // allocated from more than one IPPools. + for _, a := range allocators { + err = a.ReleaseContainer(podOwner.ContainerID, podOwner.IFName) + if err != nil { + return true, err + } + } return true, nil } @@ -203,18 +324,10 @@ func (d *AntreaIPAM) Check(args *invoke.Args, k8sArgs *argtypes.K8sArgs, network // mineTrue + timeout error // mineTrue + IPPoolNotFound error // mineTrue + nil error -func (d *AntreaIPAM) owns(k8sArgs *argtypes.K8sArgs) (mineType, *poolallocator.IPPoolAllocator, []net.IP, *crdv1a2.IPAddressOwner, error) { +func (d *AntreaIPAM) owns(k8sArgs *types.K8sArgs) (mineType, *poolallocator.IPPoolAllocator, []net.IP, *crdv1a2.IPAddressOwner, error) { // Wait controller ready to avoid inappropriate behavior on CNI request - if err := wait.PollImmediate(500*time.Millisecond, 5*time.Second, func() (bool, error) { - d.controllerMutex.RLock() - defer d.controllerMutex.RUnlock() - if d.controller == nil { - klog.Warningf("Antrea IPAM driver is not ready.") - return false, nil - } - return true, nil - }); err != nil { - // return mineTrue to make this request failed and kubelet will retry + if err := d.waitForControllerReady(); err != nil { + // Return mineTrue to make this request failed and kubelet will retry. return mineTrue, nil, nil, nil, err } @@ -227,17 +340,29 @@ func (d *AntreaIPAM) owns(k8sArgs *argtypes.K8sArgs) (mineType, *poolallocator.I return d.controller.getPoolAllocatorByPod(namespace, podName) } -func init() { - // Antrea driver must come first - // NOTE: this is global variable that requires follow-up setup post agent Init - antreaIPAMDriver = &AntreaIPAM{} +func (d *AntreaIPAM) waitForControllerReady() error { + err := wait.PollImmediate(500*time.Millisecond, 5*time.Second, func() (bool, error) { + d.controllerMutex.RLock() + defer d.controllerMutex.RUnlock() + if d.controller == nil { + klog.Warningf("Antrea IPAM driver is not ready.") + return false, nil + } + return true, nil + }) - if err := RegisterIPAMDriver(AntreaIPAMType, antreaIPAMDriver); err != nil { - klog.Errorf("Failed to register IPAM plugin on type %s", AntreaIPAMType) + if err != nil { + return fmt.Errorf("Antrea IPAM driver not ready: %v", err) } + return nil +} + +func init() { + // Antrea driver must come first. + // NOTE: this is global variable that requires follow-up setup post agent initialization. + antreaIPAMDriver = &AntreaIPAM{} + RegisterIPAMDriver(AntreaIPAMType, antreaIPAMDriver) // Host local plugin is fallback driver - if err := RegisterIPAMDriver(AntreaIPAMType, &IPAMDelegator{pluginType: ipamHostLocal}); err != nil { - klog.Errorf("Failed to register IPAM plugin on type %s", ipamHostLocal) - } + RegisterIPAMDriver(AntreaIPAMType, &IPAMDelegator{pluginType: ipamHostLocal}) } diff --git a/pkg/agent/cniserver/ipam/antrea_ipam_controller.go b/pkg/agent/cniserver/ipam/antrea_ipam_controller.go index 3de98391dab..f57a8aa435f 100644 --- a/pkg/agent/cniserver/ipam/antrea_ipam_controller.go +++ b/pkg/agent/cniserver/ipam/antrea_ipam_controller.go @@ -19,10 +19,10 @@ import ( "net" "strings" + "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/util/sets" "k8s.io/client-go/informers" coreinformers "k8s.io/client-go/informers/core/v1" - clientset "k8s.io/client-go/kubernetes" corelisters "k8s.io/client-go/listers/core/v1" "k8s.io/client-go/tools/cache" "k8s.io/klog/v2" @@ -48,7 +48,6 @@ const ( // this controller can be used to store annotations for other objects, // such as Statefulsets. type AntreaIPAMController struct { - kubeClient clientset.Interface crdClient clientsetversioned.Interface ipPoolInformer crdinformers.IPPoolInformer ipPoolLister crdlisters.IPPoolLister @@ -58,47 +57,24 @@ type AntreaIPAMController struct { podLister corelisters.PodLister } -func NewAntreaIPAMController(kubeClient clientset.Interface, - crdClient clientsetversioned.Interface, - informerFactory informers.SharedInformerFactory, - podInformer cache.SharedIndexInformer, - crdInformerFactory externalversions.SharedInformerFactory) *AntreaIPAMController { - - namespaceInformer := informerFactory.Core().V1().Namespaces() - ipPoolInformer := crdInformerFactory.Crd().V1alpha2().IPPools() - ipPoolInformer.Informer().AddIndexers(cache.Indexers{podIndex: podIndexFunc}) - - c := AntreaIPAMController{ - kubeClient: kubeClient, - crdClient: crdClient, - ipPoolInformer: ipPoolInformer, - ipPoolLister: ipPoolInformer.Lister(), - namespaceInformer: namespaceInformer, - namespaceLister: namespaceInformer.Lister(), - podInformer: podInformer, - podLister: corelisters.NewPodLister(podInformer.GetIndexer()), - } - - return &c -} - func podIndexFunc(obj interface{}) ([]string, error) { ipPool, ok := obj.(*crdv1a2.IPPool) if !ok { return nil, fmt.Errorf("obj is not IPPool: %+v", obj) } podNames := sets.NewString() - for _, IPAddress := range ipPool.Status.IPAddresses { - if IPAddress.Owner.Pod != nil { - podNames.Insert(k8s.NamespacedName(IPAddress.Owner.Pod.Namespace, IPAddress.Owner.Pod.Name)) + for _, ipAddress := range ipPool.Status.IPAddresses { + if ipAddress.Owner.Pod != nil { + podNames.Insert(k8s.NamespacedName(ipAddress.Owner.Pod.Namespace, ipAddress.Owner.Pod.Name)) } } return podNames.UnsortedList(), nil } -func InitializeAntreaIPAMController(kubeClient clientset.Interface, crdClient clientsetversioned.Interface, informerFactory informers.SharedInformerFactory, podInformer cache.SharedIndexInformer, crdInformerFactory externalversions.SharedInformerFactory) (*AntreaIPAMController, error) { - antreaIPAMController := NewAntreaIPAMController(kubeClient, crdClient, informerFactory, podInformer, crdInformerFactory) - +func InitializeAntreaIPAMController(crdClient clientsetversioned.Interface, + informerFactory informers.SharedInformerFactory, + crdInformerFactory externalversions.SharedInformerFactory, + podInformer cache.SharedIndexInformer, ipamAnnotations bool) (*AntreaIPAMController, error) { // Order of init causes antreaIPAMDriver to be initialized first // After controller is initialized by agent init, we need to make it // know to the driver @@ -106,6 +82,30 @@ func InitializeAntreaIPAMController(kubeClient clientset.Interface, crdClient cl return nil, fmt.Errorf("Antrea IPAM driver failed to initialize") } + var antreaIPAMController *AntreaIPAMController + ipPoolInformer := crdInformerFactory.Crd().V1alpha2().IPPools() + ipPoolInformer.Informer().AddIndexers(cache.Indexers{podIndex: podIndexFunc}) + + // Create podInformer/Lister and namespaceInformer/Lister if need to read the AntreaIPAM + // annotation on Pods and Namespaces. + if ipamAnnotations { + namespaceInformer := informerFactory.Core().V1().Namespaces() + antreaIPAMController = &AntreaIPAMController{ + crdClient: crdClient, + ipPoolInformer: ipPoolInformer, + ipPoolLister: ipPoolInformer.Lister(), + namespaceInformer: namespaceInformer, + namespaceLister: namespaceInformer.Lister(), + podInformer: podInformer, + podLister: corelisters.NewPodLister(podInformer.GetIndexer()), + } + } else { + antreaIPAMController = &AntreaIPAMController{ + crdClient: crdClient, + ipPoolInformer: ipPoolInformer, + ipPoolLister: ipPoolInformer.Lister(), + } + } return antreaIPAMController, nil } @@ -117,7 +117,11 @@ func (c *AntreaIPAMController) Run(stopCh <-chan struct{}) { }() klog.InfoS("Starting", "controller", controllerName) - if !cache.WaitForNamedCacheSync(controllerName, stopCh, c.namespaceInformer.Informer().HasSynced, c.ipPoolInformer.Informer().HasSynced, c.podInformer.HasSynced) { + cacheSyncs := []cache.InformerSynced{c.ipPoolInformer.Informer().HasSynced} + if c.podInformer != nil && c.namespaceInformer != nil { + cacheSyncs = append(cacheSyncs, c.podInformer.HasSynced, c.namespaceInformer.Informer().HasSynced) + } + if !cache.WaitForNamedCacheSync(controllerName, stopCh, cacheSyncs...) { return } antreaIPAMDriver.setController(c) @@ -125,27 +129,12 @@ func (c *AntreaIPAMController) Run(stopCh <-chan struct{}) { <-stopCh } +// Look up IPPools from the Pod annotation. func (c *AntreaIPAMController) getIPPoolsByPod(namespace, name string) ([]string, []net.IP, *crdv1a2.IPAddressOwner, error) { - // Find IPPool by Pod var ips []net.IP var reservedOwner *crdv1a2.IPAddressOwner pod, err := c.podLister.Pods(namespace).Get(name) if err != nil { - // For CNI DEL case, getting Pod may fail. Try to get information from allocated IPs of all IPPools. - klog.ErrorS(err, "Getting pod failed", "namespace", namespace, "name", name) - ipPools, _ := c.ipPoolInformer.Informer().GetIndexer().ByIndex(podIndex, k8s.NamespacedName(namespace, name)) - for _, item := range ipPools { - ipPool := item.(*crdv1a2.IPPool) - if ipPool.Spec.IPVersion != 4 { - continue - } - for _, IPAddress := range ipPool.Status.IPAddresses { - if IPAddress.Owner.Pod != nil && IPAddress.Owner.Pod.Namespace == namespace && IPAddress.Owner.Pod.Name == name { - // reservedOwner is nil, since this is not needed for CNI DEL case - return []string{ipPool.Name}, []net.IP{net.ParseIP(IPAddress.IPAddress)}, nil, nil - } - } - } return nil, nil, nil, err } @@ -204,16 +193,58 @@ ownerReferenceLoop: return strings.Split(annotations, annotation.AntreaIPAMAnnotationDelimiter), ips, reservedOwner, ipErr } +// Look up IPPools from the Pod annotation. func (c *AntreaIPAMController) getPoolAllocatorByPod(namespace, podName string) (mineType, *poolallocator.IPPoolAllocator, []net.IP, *crdv1a2.IPAddressOwner, error) { poolNames, ips, reservedOwner, err := c.getIPPoolsByPod(namespace, podName) if err != nil { return mineUnknown, nil, nil, nil, err - } else if len(poolNames) < 1 { + } else if len(poolNames) == 0 { return mineFalse, nil, nil, nil, nil } - // Only one pool is supported as of today - // TODO - support a pool for each IP version - ipPool := poolNames[0] - allocator, err := poolallocator.NewIPPoolAllocator(ipPool, c.crdClient, c.ipPoolLister) + + var allocator *poolallocator.IPPoolAllocator + for _, p := range poolNames { + allocator, err = poolallocator.NewIPPoolAllocator(p, c.crdClient, c.ipPoolLister) + if err != nil { + if !errors.IsNotFound(err) { + err = fmt.Errorf("failed to get IPPool %s: %v", p, err) + break + } + klog.InfoS("IPPool not found", "pool", p) + err = nil + } else if allocator.IPVersion == crdv1a2.IPv4 { + // Support IPv6 / dual stack in future. + break + } + } + if err == nil && allocator == nil { + err = fmt.Errorf("no valid IPPool found") + } + return mineTrue, allocator, ips, reservedOwner, err } + +// Look up IPPools by matching PodOwnder. +func (c *AntreaIPAMController) getPoolAllocatorsByOwner(podOwner *crdv1a2.PodOwner) ([]*poolallocator.IPPoolAllocator, error) { + var allocators []*poolallocator.IPPoolAllocator + ipPools, _ := c.ipPoolInformer.Informer().GetIndexer().ByIndex(podIndex, + k8s.NamespacedName(podOwner.Namespace, podOwner.Name)) + for _, item := range ipPools { + ipPool := item.(*crdv1a2.IPPool) + for _, ipAddress := range ipPool.Status.IPAddresses { + savedPod := ipAddress.Owner.Pod + if savedPod != nil && savedPod.ContainerID == podOwner.ContainerID && savedPod.IFName == podOwner.IFName { + allocator, err := poolallocator.NewIPPoolAllocator(ipPool.Name, c.crdClient, c.ipPoolLister) + if err != nil { + return nil, err + } + allocators = append(allocators, allocator) + } + } + } + return allocators, nil +} + +func (c *AntreaIPAMController) getPoolAllocatorByName(poolName string) (*poolallocator.IPPoolAllocator, error) { + return poolallocator.NewIPPoolAllocator(poolName, c.crdClient, c.ipPoolLister) +} diff --git a/pkg/agent/cniserver/ipam/antrea_ipam_test.go b/pkg/agent/cniserver/ipam/antrea_ipam_test.go index 53724d361b2..3808ceb3621 100644 --- a/pkg/agent/cniserver/ipam/antrea_ipam_test.go +++ b/pkg/agent/cniserver/ipam/antrea_ipam_test.go @@ -110,7 +110,7 @@ func createIPPools(crdClient *fakepoolclient.IPPoolClientset) { ObjectMeta: metav1.ObjectMeta{Name: testPear}, Spec: crdv1a2.IPPoolSpec{ IPRanges: []crdv1a2.SubnetIPRange{subnetRangePear}, - IPVersion: 4, + IPVersion: crdv1a2.IPv4, }, Status: crdv1a2.IPPoolStatus{IPAddresses: []crdv1a2.IPAddressState{{ IPAddress: "10.2.3.198", @@ -322,7 +322,7 @@ func TestAntreaIPAMDriver(t *testing.T) { listOptions, ) - antreaIPAMController, err := InitializeAntreaIPAMController(k8sClient, crdClient, informerFactory, localPodInformer, crdInformerFactory) + antreaIPAMController, err := InitializeAntreaIPAMController(crdClient, informerFactory, crdInformerFactory, localPodInformer, true) require.NoError(t, err, "Expected no error in initialization for Antrea IPAM Controller") informerFactory.Start(stopCh) go localPodInformer.Run(stopCh) @@ -338,7 +338,7 @@ func TestAntreaIPAMDriver(t *testing.T) { // Test the driver singleton that was assigned to global variable testDriver := antreaIPAMDriver - networkConfig := []byte("'name': 'testCfg', 'cniVersion': '0.4.0', 'type': 'antrea', 'ipam': {'type': 'antrea-ipam'}}") + networkConfig := []byte("'name': 'testCfg', 'cniVersion': '0.4.0', 'type': 'antrea', 'ipam': {'type': 'antrea'}}") cniArgsMap := make(map[string]*invoke.Args) k8sArgsMap := make(map[string]*argtypes.K8sArgs) @@ -516,15 +516,15 @@ func TestAntreaIPAMDriver(t *testing.T) { } owns, err = testDriver.Del(cniArgsBadContainer, k8sArgsMap["orange1"], networkConfig) - assert.True(t, owns) + assert.False(t, owns) require.NoError(t, err, "expected no error in Del call") // Make sure repeated Add works for Pod that was previously released testAdd("apple1", "10.2.2.100", "10.2.2.1", "ffffff00", false) testAdd("apple-sts-0", "10.2.2.102", "10.2.2.1", "ffffff00", true) - // Make sure repeated call for previous container results in error - testAddError("apple2") + // Make sure repeated call for previous container gets identical result + testAdd("apple2", "10.2.2.101", "10.2.2.1", "ffffff00", false) // Make sure repeated Add works for pod that was previously released testAdd("pear3", "10.2.3.199", "10.2.3.1", "ffffff00", false) diff --git a/pkg/agent/cniserver/ipam/ipam_delegator.go b/pkg/agent/cniserver/ipam/ipam_delegator.go index 10aeb827bb8..815809d9f11 100644 --- a/pkg/agent/cniserver/ipam/ipam_delegator.go +++ b/pkg/agent/cniserver/ipam/ipam_delegator.go @@ -125,7 +125,5 @@ func delegateNoResult(delegatePlugin string, networkConfig []byte, args *invoke. } func init() { - if err := RegisterIPAMDriver(ipamHostLocal, &IPAMDelegator{pluginType: ipamHostLocal}); err != nil { - klog.Errorf("Failed to register IPAM plugin on type %s", ipamHostLocal) - } + RegisterIPAMDriver(ipamHostLocal, &IPAMDelegator{pluginType: ipamHostLocal}) } diff --git a/pkg/agent/cniserver/ipam/ipam_service.go b/pkg/agent/cniserver/ipam/ipam_service.go index b64c335a7c6..209305545f3 100644 --- a/pkg/agent/cniserver/ipam/ipam_service.go +++ b/pkg/agent/cniserver/ipam/ipam_service.go @@ -21,7 +21,7 @@ import ( "github.com/containernetworking/cni/pkg/invoke" "github.com/containernetworking/cni/pkg/types/current" - argtypes "antrea.io/antrea/pkg/agent/cniserver/types" + "antrea.io/antrea/pkg/agent/cniserver/types" cnipb "antrea.io/antrea/pkg/apis/cni/v1beta1" ) @@ -33,17 +33,8 @@ import ( // Otherwise IPAM should be handled by host-local plugin. var ipamDrivers map[string][]IPAMDriver -type Range struct { - Subnet string `json:"subnet"` - Gateway string `json:"gateway,omitempty"` -} - -type RangeSet []Range - -type IPAMConfig struct { - Type string `json:"type,omitempty"` - Ranges []RangeSet `json:"ranges,omitempty"` -} +// A cache of IPAM results. +var ipamResults = sync.Map{} type IPAMResult struct { current.Result @@ -51,19 +42,16 @@ type IPAMResult struct { } type IPAMDriver interface { - Add(args *invoke.Args, k8sArgs *argtypes.K8sArgs, networkConfig []byte) (bool, *IPAMResult, error) - Del(args *invoke.Args, k8sArgs *argtypes.K8sArgs, networkConfig []byte) (bool, error) - Check(args *invoke.Args, k8sArgs *argtypes.K8sArgs, networkConfig []byte) (bool, error) + Add(args *invoke.Args, k8sArgs *types.K8sArgs, networkConfig []byte) (bool, *IPAMResult, error) + Del(args *invoke.Args, k8sArgs *types.K8sArgs, networkConfig []byte) (bool, error) + Check(args *invoke.Args, k8sArgs *types.K8sArgs, networkConfig []byte) (bool, error) } -var ipamResults = sync.Map{} - -func RegisterIPAMDriver(ipamType string, ipamDriver IPAMDriver) error { +func RegisterIPAMDriver(ipamType string, ipamDriver IPAMDriver) { if ipamDrivers == nil { ipamDrivers = make(map[string][]IPAMDriver) } ipamDrivers[ipamType] = append(ipamDrivers[ipamType], ipamDriver) - return nil } func argsFromEnv(cniArgs *cnipb.CniCmdArgs) *invoke.Args { @@ -75,20 +63,20 @@ func argsFromEnv(cniArgs *cnipb.CniCmdArgs) *invoke.Args { } } -func ExecIPAMAdd(cniArgs *cnipb.CniCmdArgs, k8sArgs *argtypes.K8sArgs, ipamType string, resultKey string) (*IPAMResult, error) { - // Return the cached IPAM result for the same Pod. This cache helps to ensure CNIAdd is idempotent. There are two - // usages of CNIAdd message on Windows: 1) add container network configuration, and 2) query Pod network status. - // kubelet on Windows sends CNIAdd messages to query Pod status periodically before the sandbox container is ready. - // The cache here is to ensure only one IP address is allocated to one Pod. - // TODO: A risk of IP re-allocation exists if agent restarts before kubelet queries Pod status and after the - // container networking configurations is added. +func ExecIPAMAdd(cniArgs *cnipb.CniCmdArgs, k8sArgs *types.K8sArgs, ipamType string, resultKey string) (*IPAMResult, error) { + // Return the cached IPAM result for the same Pod. This cache helps to ensure CNI ADD is + // idempotent. There are two usages of CNI ADD on Windows: 1) add container network + // configuration, and 2) query Pod network status. kubelet on Windows excutess CNI ADD + // to query Pod status periodically before the sandbox container is ready. The cache here + // is to ensure only one IP address is allocated to one Pod. + // TODO: A risk of IP re-allocation exists if agent restarts before kubelet queries Pod + // status and after the container network configuration is added. obj, ok := GetIPFromCache(resultKey) if ok { return obj, nil } args := argsFromEnv(cniArgs) - drivers := ipamDrivers[ipamType] for _, driver := range drivers { owns, result, err := driver.Add(args, k8sArgs, cniArgs.NetworkConfiguration) @@ -106,7 +94,7 @@ func ExecIPAMAdd(cniArgs *cnipb.CniCmdArgs, k8sArgs *argtypes.K8sArgs, ipamType return nil, fmt.Errorf("No suitable IPAM driver found") } -func ExecIPAMDelete(cniArgs *cnipb.CniCmdArgs, k8sArgs *argtypes.K8sArgs, ipamType string, resultKey string) error { +func ExecIPAMDelete(cniArgs *cnipb.CniCmdArgs, k8sArgs *types.K8sArgs, ipamType string, resultKey string) error { args := argsFromEnv(cniArgs) drivers := ipamDrivers[ipamType] for _, driver := range drivers { @@ -124,7 +112,7 @@ func ExecIPAMDelete(cniArgs *cnipb.CniCmdArgs, k8sArgs *argtypes.K8sArgs, ipamTy return fmt.Errorf("No suitable IPAM driver found") } -func ExecIPAMCheck(cniArgs *cnipb.CniCmdArgs, k8sArgs *argtypes.K8sArgs, ipamType string) error { +func ExecIPAMCheck(cniArgs *cnipb.CniCmdArgs, k8sArgs *types.K8sArgs, ipamType string) error { args := argsFromEnv(cniArgs) drivers := ipamDrivers[ipamType] for _, driver := range drivers { @@ -153,3 +141,30 @@ func IsIPAMTypeValid(ipamType string) bool { _, valid := ipamDrivers[ipamType] return valid } + +// Antrea IPAM for secondary network. +func SecondaryNetworkAdd(cniArgs *cnipb.CniCmdArgs, k8sArgs *types.K8sArgs, networkConfig *types.NetworkConfig) (*current.Result, error) { + args := argsFromEnv(cniArgs) + return getAntreaIPAMDriver().secondaryNetworkAdd(args, k8sArgs, networkConfig) + +} + +func SecondaryNetworkDel(cniArgs *cnipb.CniCmdArgs, k8sArgs *types.K8sArgs, networkConfig *types.NetworkConfig) error { + args := argsFromEnv(cniArgs) + return getAntreaIPAMDriver().secondaryNetworkDel(args, k8sArgs, networkConfig) + +} + +func SecondaryNetworkCheck(cniArgs *cnipb.CniCmdArgs, k8sArgs *types.K8sArgs, networkConfig *types.NetworkConfig) error { + args := argsFromEnv(cniArgs) + return getAntreaIPAMDriver().secondaryNetworkCheck(args, k8sArgs, networkConfig) + +} + +func getAntreaIPAMDriver() *AntreaIPAM { + drivers, ok := ipamDrivers[AntreaIPAMType] + if !ok { + return nil + } + return drivers[0].(*AntreaIPAM) +} diff --git a/pkg/agent/cniserver/pod_configuration.go b/pkg/agent/cniserver/pod_configuration.go index dd4d251225e..f33d20c4717 100644 --- a/pkg/agent/cniserver/pod_configuration.go +++ b/pkg/agent/cniserver/pod_configuration.go @@ -27,10 +27,12 @@ import ( "k8s.io/klog/v2" "antrea.io/antrea/pkg/agent/cniserver/ipam" + "antrea.io/antrea/pkg/agent/cniserver/types" "antrea.io/antrea/pkg/agent/interfacestore" "antrea.io/antrea/pkg/agent/openflow" "antrea.io/antrea/pkg/agent/route" "antrea.io/antrea/pkg/agent/secondarynetwork/cnipodcache" + agenttypes "antrea.io/antrea/pkg/agent/types" "antrea.io/antrea/pkg/agent/util" "antrea.io/antrea/pkg/ovs/ovsconfig" "antrea.io/antrea/pkg/util/channel" @@ -80,8 +82,9 @@ func newPodConfigurator( isOvsHardwareOffloadEnabled bool, podUpdateNotifier channel.Notifier, podInfoStore cnipodcache.CNIPodInfoStore, + disableTXChecksumOffload bool, ) (*podConfigurator, error) { - ifConfigurator, err := newInterfaceConfigurator(ovsDatapathType, isOvsHardwareOffloadEnabled) + ifConfigurator, err := newInterfaceConfigurator(ovsDatapathType, isOvsHardwareOffloadEnabled, disableTXChecksumOffload) if err != nil { return nil, err } @@ -311,6 +314,7 @@ func (pc *podConfigurator) removeInterfaces(containerID string) error { if err := pc.routeClient.DeleteLocalAntreaFlexibleIPAMPodRule(containerConfig.IPs); err != nil { return err } + return nil } @@ -394,7 +398,7 @@ func (pc *podConfigurator) validateOVSInterfaceConfig(containerID string, contai return fmt.Errorf("container %s interface not found from local cache", containerID) } -func parsePrevResult(conf *NetworkConfig) error { +func parsePrevResult(conf *types.NetworkConfig) error { if conf.RawPrevResult == nil { return nil } @@ -494,7 +498,13 @@ func (pc *podConfigurator) connectInterfaceToOVSCommon(ovsPortName string, conta // Add containerConfig into local cache pc.ifaceStore.AddInterface(containerConfig) // Notify the Pod update event to required components. - pc.podUpdateNotifier.Notify(k8s.NamespacedName(containerConfig.PodNamespace, containerConfig.PodName)) + event := agenttypes.PodUpdate{ + PodName: containerConfig.PodName, + PodNamespace: containerConfig.PodNamespace, + IsAdd: true, + ContainerID: containerConfig.ContainerID, + } + pc.podUpdateNotifier.Notify(event) return nil } @@ -517,6 +527,13 @@ func (pc *podConfigurator) disconnectInterfaceFromOVS(containerConfig *interface } // Remove container configuration from cache. pc.ifaceStore.DeleteInterface(containerConfig) + event := agenttypes.PodUpdate{ + PodName: containerConfig.PodName, + PodNamespace: containerConfig.PodNamespace, + IsAdd: false, + ContainerID: containerConfig.ContainerID, + } + pc.podUpdateNotifier.Notify(event) klog.Infof("Removed interfaces for container %s", containerID) return nil } diff --git a/pkg/agent/cniserver/pod_configuration_windows.go b/pkg/agent/cniserver/pod_configuration_windows.go index a2dc2834081..16f824f847e 100644 --- a/pkg/agent/cniserver/pod_configuration_windows.go +++ b/pkg/agent/cniserver/pod_configuration_windows.go @@ -24,6 +24,7 @@ import ( "k8s.io/klog/v2" "antrea.io/antrea/pkg/agent/interfacestore" + "antrea.io/antrea/pkg/agent/types" "antrea.io/antrea/pkg/agent/util" "antrea.io/antrea/pkg/util/k8s" ) @@ -49,7 +50,13 @@ func (pc *podConfigurator) connectInterfaceToOVSAsync(ifConfig *interfacestore.I // Update interface config with the ofPort. ifConfig.OVSPortConfig.OFPort = ofPort // Notify the Pod update event to required components. - pc.podUpdateNotifier.Notify(k8s.NamespacedName(ifConfig.PodNamespace, ifConfig.PodName)) + event := types.PodUpdate{ + PodName: ifConfig.PodName, + PodNamespace: ifConfig.PodNamespace, + IsAdd: true, + ContainerID: ifConfig.ContainerID, + } + pc.podUpdateNotifier.Notify(event) return nil }) } diff --git a/pkg/agent/cniserver/server.go b/pkg/agent/cniserver/server.go index dd2c88788e4..0a589a1ee8c 100644 --- a/pkg/agent/cniserver/server.go +++ b/pkg/agent/cniserver/server.go @@ -34,7 +34,7 @@ import ( "k8s.io/klog/v2" "antrea.io/antrea/pkg/agent/cniserver/ipam" - argtypes "antrea.io/antrea/pkg/agent/cniserver/types" + "antrea.io/antrea/pkg/agent/cniserver/types" "antrea.io/antrea/pkg/agent/config" "antrea.io/antrea/pkg/agent/interfacestore" "antrea.io/antrea/pkg/agent/openflow" @@ -48,6 +48,8 @@ import ( ) const ( + antreaCNIType = "antrea" + // networkReadyTimeout is the maximum time the CNI server will wait for network ready when processing CNI Add // requests. If timeout occurs, tryAgainLaterResponse will be returned. // The default runtime request timeout of kubelet is 2 minutes. @@ -100,52 +102,36 @@ func (arbitrator *containerAccessArbitrator) unlockContainer(containerKey string } type CNIServer struct { - cniSocket string - supportedCNIVersions map[string]bool - serverVersion string - nodeConfig *config.NodeConfig - hostProcPathPrefix string - kubeClient clientset.Interface - containerAccess *containerAccessArbitrator - podConfigurator *podConfigurator - isChaining bool - antreaIPAM bool - routeClient route.Interface - secondaryNetworkEnabled bool + cniSocket string + supportedCNIVersions map[string]bool + serverVersion string + nodeConfig *config.NodeConfig + hostProcPathPrefix string + kubeClient clientset.Interface + containerAccess *containerAccessArbitrator + podConfigurator *podConfigurator + routeClient route.Interface + isChaining bool + enableBridgingMode bool + // Enable AntreaIPAM for secondary networks implementd by other CNIs. + enableSecondaryNetworkIPAM bool + disableTXChecksumOffload bool + secondaryNetworkEnabled bool // networkReadyCh notifies that the network is ready so new Pods can be created. Therefore, CmdAdd waits for it. networkReadyCh <-chan struct{} } var supportedCNIVersionSet map[string]bool -type RuntimeDNS struct { - Nameservers []string `json:"servers,omitempty"` - Search []string `json:"searches,omitempty"` -} - -type RuntimeConfig struct { - DNS RuntimeDNS `json:"dns"` -} - -type NetworkConfig struct { - CNIVersion string `json:"cniVersion,omitempty"` - Name string `json:"name,omitempty"` - Type string `json:"type,omitempty"` - DeviceID string `json:"deviceID"` // PCI address of a VF - MTU int `json:"mtu,omitempty"` - DNS cnitypes.DNS `json:"dns"` - IPAM ipam.IPAMConfig `json:"ipam,omitempty"` - // Options to be passed in by the runtime. - RuntimeConfig RuntimeConfig `json:"runtimeConfig"` - - RawPrevResult map[string]interface{} `json:"prevResult,omitempty"` - PrevResult cnitypes.Result `json:"-"` -} - type CNIConfig struct { - *NetworkConfig + *types.NetworkConfig + // AntreaIPAM for an interface not managed by Antrea CNI. + secondaryNetworkIPAM bool + // CniCmdArgs received from the CNI plugin. IPAM data in CniCmdArgs can be updated with the + // Node's Pod CIDRs for NodeIPAM. *cnipb.CniCmdArgs - *argtypes.K8sArgs + // K8s CNI_ARGS passed to the CNI plugin. + *types.K8sArgs } // updateResultIfaceConfig processes the result from the IPAM plugin and does the following: @@ -197,23 +183,20 @@ func resultToResponse(result *current.Result) *cnipb.CniCmdResponse { } func (s *CNIServer) loadNetworkConfig(request *cnipb.CniCmdRequest) (*CNIConfig, error) { - cniConfig := &CNIConfig{} - cniConfig.CniCmdArgs = request.CniArgs - if err := json.Unmarshal(request.CniArgs.NetworkConfiguration, cniConfig); err != nil { - return cniConfig, err + cniConfig := CNIConfig{} + if err := json.Unmarshal(request.CniArgs.NetworkConfiguration, &cniConfig); err != nil { + return nil, err } - cniConfig.K8sArgs = &argtypes.K8sArgs{} + cniConfig.K8sArgs = &types.K8sArgs{} if err := cnitypes.LoadArgs(request.CniArgs.Args, cniConfig.K8sArgs); err != nil { - return cniConfig, err - } - if !s.isChaining { - s.updateLocalIPAMSubnet(cniConfig) + return nil, err } if cniConfig.MTU == 0 { cniConfig.MTU = s.nodeConfig.NodeMTU } + cniConfig.CniCmdArgs = request.CniArgs klog.V(3).Infof("Load network configurations: %v", cniConfig) - return cniConfig, nil + return &cniConfig, nil } func (s *CNIServer) isCNIVersionSupported(reqVersion string) bool { @@ -221,44 +204,72 @@ func (s *CNIServer) isCNIVersionSupported(reqVersion string) bool { return exist } -func (s *CNIServer) checkRequestMessage(request *cnipb.CniCmdRequest) (*CNIConfig, *cnipb.CniCmdResponse) { +func (s *CNIServer) valiateCNIAndIPAMType(cniConfig *CNIConfig) *cnipb.CniCmdResponse { + var ipamType string + if cniConfig.IPAM != nil { + ipamType = cniConfig.IPAM.Type + } + if cniConfig.Type == antreaCNIType { + if s.isChaining { + return nil + } + if !ipam.IsIPAMTypeValid(ipamType) { + klog.Errorf("Unsupported IPAM type %s", ipamType) + return s.unsupportedFieldResponse("ipam/type", ipamType) + } + if s.enableBridgingMode { + // When the bridging mode is enabled, Antrea ignores IPAM type from request. + cniConfig.IPAM.Type = ipam.AntreaIPAMType + + } + return nil + } + + if !s.enableSecondaryNetworkIPAM { + return s.unsupportedFieldResponse("type", cniConfig.Type) + } + if ipamType != ipam.AntreaIPAMType { + klog.Errorf("Unsupported IPAM type %s", ipamType) + return s.unsupportedFieldResponse("ipam/type", ipamType) + } + // IPAM for an interface not managed by Antrea CNI. + cniConfig.secondaryNetworkIPAM = true + return nil +} + +func (s *CNIServer) validateRequestMessage(request *cnipb.CniCmdRequest) (*CNIConfig, *cnipb.CniCmdResponse) { cniConfig, err := s.loadNetworkConfig(request) if err != nil { klog.Errorf("Failed to parse network configuration: %v", err) return nil, s.decodingFailureResponse("network config") } + cniVersion := cniConfig.CNIVersion // Check if CNI version in the request is supported if !s.isCNIVersionSupported(cniVersion) { klog.Errorf(fmt.Sprintf("Unsupported CNI version [%s], supported CNI versions %s", cniVersion, version.All.SupportedVersions())) - return cniConfig, s.incompatibleCniVersionResponse(cniVersion) - } - if s.isChaining { - return cniConfig, nil - } - // Find IPAM Service according configuration - ipamType := cniConfig.IPAM.Type - isValid := ipam.IsIPAMTypeValid(ipamType) - if !isValid { - klog.Errorf("Unsupported IPAM type %s", ipamType) - return cniConfig, s.unsupportedFieldResponse("ipam/type", ipamType) + return nil, s.incompatibleCniVersionResponse(cniVersion) } - if s.antreaIPAM { - // With AnteaIPAM feature enabled, Antrea ignores IPAM type from request - cniConfig.IPAM.Type = ipam.AntreaIPAMType + if resp := s.valiateCNIAndIPAMType(cniConfig); resp != nil { + return nil, resp + } + if !s.isChaining && !cniConfig.secondaryNetworkIPAM { + s.updateLocalIPAMSubnet(cniConfig) } return cniConfig, nil } +// updateLocalIPAMSubnet updates CNIConfig.CniCmdArgs with this Node's Pod CIDRs, which will be +// passed to the IPAM driver. func (s *CNIServer) updateLocalIPAMSubnet(cniConfig *CNIConfig) { if (s.nodeConfig.GatewayConfig.IPv4 != nil) && (s.nodeConfig.PodIPv4CIDR != nil) { cniConfig.NetworkConfig.IPAM.Ranges = append(cniConfig.NetworkConfig.IPAM.Ranges, - ipam.RangeSet{ipam.Range{Subnet: s.nodeConfig.PodIPv4CIDR.String(), Gateway: s.nodeConfig.GatewayConfig.IPv4.String()}}) + types.RangeSet{types.Range{Subnet: s.nodeConfig.PodIPv4CIDR.String(), Gateway: s.nodeConfig.GatewayConfig.IPv4.String()}}) } if (s.nodeConfig.GatewayConfig.IPv6 != nil) && (s.nodeConfig.PodIPv6CIDR != nil) { cniConfig.NetworkConfig.IPAM.Ranges = append(cniConfig.NetworkConfig.IPAM.Ranges, - ipam.RangeSet{ipam.Range{Subnet: s.nodeConfig.PodIPv6CIDR.String(), Gateway: s.nodeConfig.GatewayConfig.IPv6.String()}}) + types.RangeSet{types.Range{Subnet: s.nodeConfig.PodIPv6CIDR.String(), Gateway: s.nodeConfig.GatewayConfig.IPv6.String()}}) } cniConfig.NetworkConfiguration, _ = json.Marshal(cniConfig.NetworkConfig) } @@ -336,7 +347,7 @@ func buildVersionSet() map[string]bool { return versionSet } -func (s *CNIServer) parsePrevResultFromRequest(networkConfig *NetworkConfig) (*current.Result, *cnipb.CniCmdResponse) { +func (s *CNIServer) parsePrevResultFromRequest(networkConfig *types.NetworkConfig) (*current.Result, *cnipb.CniCmdResponse) { if networkConfig.PrevResult == nil && networkConfig.RawPrevResult == nil { klog.Errorf("Previous network configuration not specified") return nil, s.unsupportedFieldResponse("prevResult", "") @@ -358,7 +369,7 @@ func (s *CNIServer) parsePrevResultFromRequest(networkConfig *NetworkConfig) (*c // validatePrevResult validates container and host interfaces configuration // the return value is nil if prevResult is valid -func (s *CNIServer) validatePrevResult(cfgArgs *cnipb.CniCmdArgs, k8sCNIArgs *argtypes.K8sArgs, prevResult *current.Result, sriovVFDeviceID string) *cnipb.CniCmdResponse { +func (s *CNIServer) validatePrevResult(cfgArgs *cnipb.CniCmdArgs, prevResult *current.Result, sriovVFDeviceID string) *cnipb.CniCmdResponse { containerID := cfgArgs.ContainerId netNS := s.hostNetNsPath(cfgArgs.Netns) @@ -384,13 +395,48 @@ func (s *CNIServer) GetPodConfigurator() *podConfigurator { return s.podConfigurator } +// Antrea IPAM for secondary network. +func (s *CNIServer) ipamAdd(cniConfig *CNIConfig) (*cnipb.CniCmdResponse, error) { + ipamResult, err := ipam.SecondaryNetworkAdd(cniConfig.CniCmdArgs, cniConfig.K8sArgs, cniConfig.NetworkConfig) + if err != nil { + return s.ipamFailureResponse(err), nil + } + klog.InfoS("Allocated IP addresses", "container", cniConfig.ContainerId, "result", ipamResult) + return resultToResponse(ipamResult), nil +} + +func (s *CNIServer) ipamDel(cniConfig *CNIConfig) (*cnipb.CniCmdResponse, error) { + if err := ipam.SecondaryNetworkDel(cniConfig.CniCmdArgs, cniConfig.K8sArgs, cniConfig.NetworkConfig); err != nil { + return s.ipamFailureResponse(err), nil + } + return &cnipb.CniCmdResponse{CniResult: []byte("")}, nil +} + +func (s *CNIServer) ipamCheck(cniConfig *CNIConfig) (*cnipb.CniCmdResponse, error) { + if err := ipam.SecondaryNetworkCheck(cniConfig.CniCmdArgs, cniConfig.K8sArgs, cniConfig.NetworkConfig); err != nil { + return s.ipamFailureResponse(err), nil + } + // CNI CHECK is not implemented for secondary network IPAM, and so the func will always + // return an error, but never reach here. + return &cnipb.CniCmdResponse{CniResult: []byte("")}, nil +} + func (s *CNIServer) CmdAdd(ctx context.Context, request *cnipb.CniCmdRequest) (*cnipb.CniCmdResponse, error) { klog.Infof("Received CmdAdd request %v", request) - cniConfig, response := s.checkRequestMessage(request) + cniConfig, response := s.validateRequestMessage(request) if response != nil { return response, nil } + infraContainer := cniConfig.getInfraContainer() + if cniConfig.secondaryNetworkIPAM { + klog.InfoS("Antrea IPAM add", "CNI", cniConfig.Type, "network", cniConfig.Name) + s.containerAccess.lockContainer(infraContainer) + resp, err := s.ipamAdd(cniConfig) + s.containerAccess.unlockContainer(infraContainer) + return resp, err + } + select { case <-time.After(networkReadyTimeout): klog.Errorf("Cannot process CmdAdd request for container %v because network is not ready", cniConfig.ContainerId) @@ -418,7 +464,7 @@ func (s *CNIServer) CmdAdd(ctx context.Context, request *cnipb.CniCmdRequest) (* } }() - infraContainer := cniConfig.getInfraContainer() + // Serialize CNI calls for one Pod. s.containerAccess.lockContainer(infraContainer) defer s.containerAccess.unlockContainer(infraContainer) @@ -446,16 +492,17 @@ func (s *CNIServer) CmdAdd(ctx context.Context, request *cnipb.CniCmdRequest) (* return s.ipamFailureResponse(err), nil } } - klog.Infof("Requested ip addresses for container %v: %v", cniConfig.ContainerId, ipamResult) + klog.InfoS("Allocated IP addresses", "container", cniConfig.ContainerId, "result", ipamResult) result.IPs = ipamResult.IPs result.Routes = ipamResult.Routes result.VLANID = ipamResult.VLANID // Ensure interface gateway setting and mapping relations between result.Interfaces and result.IPs updateResultIfaceConfig(&result.Result, s.nodeConfig.GatewayConfig.IPv4, s.nodeConfig.GatewayConfig.IPv6) + updateResultDNSConfig(&result.Result, cniConfig) + // Setup pod interfaces and connect to ovs bridge podName := string(cniConfig.K8S_POD_NAME) podNamespace := string(cniConfig.K8S_POD_NAMESPACE) - updateResultDNSConfig(&result.Result, cniConfig) if err = s.podConfigurator.configureInterfaces( podName, podNamespace, @@ -491,7 +538,7 @@ func (s *CNIServer) CmdDel(_ context.Context, request *cnipb.CniCmdRequest) ( *cnipb.CniCmdResponse, error) { klog.Infof("Received CmdDel request %v", request) - cniConfig, response := s.checkRequestMessage(request) + cniConfig, response := s.validateRequestMessage(request) if response != nil { return response, nil } @@ -500,6 +547,11 @@ func (s *CNIServer) CmdDel(_ context.Context, request *cnipb.CniCmdRequest) ( s.containerAccess.lockContainer(infraContainer) defer s.containerAccess.unlockContainer(infraContainer) + if cniConfig.secondaryNetworkIPAM { + klog.InfoS("Antrea IPAM del", "CNI", cniConfig.Type, "network", cniConfig.Name) + return s.ipamDel(cniConfig) + } + if s.isChaining { return s.interceptDel(cniConfig) } @@ -532,7 +584,7 @@ func (s *CNIServer) CmdCheck(_ context.Context, request *cnipb.CniCmdRequest) ( *cnipb.CniCmdResponse, error) { klog.Infof("Received CmdCheck request %v", request) - cniConfig, response := s.checkRequestMessage(request) + cniConfig, response := s.validateRequestMessage(request) if response != nil { return response, nil } @@ -541,6 +593,11 @@ func (s *CNIServer) CmdCheck(_ context.Context, request *cnipb.CniCmdRequest) ( s.containerAccess.lockContainer(infraContainer) defer s.containerAccess.unlockContainer(infraContainer) + if cniConfig.secondaryNetworkIPAM { + klog.InfoS("Antrea IPAM check", "CNI", cniConfig.Type, "network", cniConfig.Name) + return s.ipamCheck(cniConfig) + } + if s.isChaining { return s.interceptCheck(cniConfig) } @@ -554,7 +611,7 @@ func (s *CNIServer) CmdCheck(_ context.Context, request *cnipb.CniCmdRequest) ( if valid, _ := version.GreaterThanOrEqualTo(cniVersion, "0.4.0"); valid { if prevResult, response := s.parsePrevResultFromRequest(cniConfig.NetworkConfig); response != nil { return response, nil - } else if response := s.validatePrevResult(cniConfig.CniCmdArgs, cniConfig.K8sArgs, prevResult, cniConfig.DeviceID); response != nil { + } else if response := s.validatePrevResult(cniConfig.CniCmdArgs, prevResult, cniConfig.DeviceID); response != nil { return response, nil } } @@ -566,23 +623,24 @@ func New( cniSocket, hostProcPathPrefix string, nodeConfig *config.NodeConfig, kubeClient clientset.Interface, - isChaining bool, - antreaIPAM bool, routeClient route.Interface, + isChaining, enableBridgingMode, enableSecondaryNetworkIPAM, disableTXChecksumOffload bool, networkReadyCh <-chan struct{}, ) *CNIServer { return &CNIServer{ - cniSocket: cniSocket, - supportedCNIVersions: supportedCNIVersionSet, - serverVersion: cni.AntreaCNIVersion, - nodeConfig: nodeConfig, - hostProcPathPrefix: hostProcPathPrefix, - kubeClient: kubeClient, - containerAccess: newContainerAccessArbitrator(), - isChaining: isChaining, - antreaIPAM: antreaIPAM, - routeClient: routeClient, - networkReadyCh: networkReadyCh, + cniSocket: cniSocket, + supportedCNIVersions: supportedCNIVersionSet, + serverVersion: cni.AntreaCNIVersion, + nodeConfig: nodeConfig, + hostProcPathPrefix: hostProcPathPrefix, + kubeClient: kubeClient, + containerAccess: newContainerAccessArbitrator(), + routeClient: routeClient, + isChaining: isChaining, + enableBridgingMode: enableBridgingMode, + disableTXChecksumOffload: disableTXChecksumOffload, + enableSecondaryNetworkIPAM: enableSecondaryNetworkIPAM, + networkReadyCh: networkReadyCh, } } @@ -604,7 +662,7 @@ func (s *CNIServer) Initialize( s.podConfigurator, err = newPodConfigurator( ovsBridgeClient, ofClient, s.routeClient, ifaceStore, s.nodeConfig.GatewayConfig.MAC, ovsBridgeClient.GetOVSDatapathType(), ovsBridgeClient.IsHardwareOffloadEnabled(), podUpdateNotifier, - podInfoStore, + podInfoStore, s.disableTXChecksumOffload, ) if err != nil { return fmt.Errorf("error during initialize podConfigurator: %v", err) diff --git a/pkg/agent/cniserver/server_test.go b/pkg/agent/cniserver/server_test.go index ef57bcfc4c1..c2d8dea5e45 100644 --- a/pkg/agent/cniserver/server_test.go +++ b/pkg/agent/cniserver/server_test.go @@ -37,7 +37,7 @@ import ( "antrea.io/antrea/pkg/agent/cniserver/ipam" ipamtest "antrea.io/antrea/pkg/agent/cniserver/ipam/testing" cniservertest "antrea.io/antrea/pkg/agent/cniserver/testing" - argtypes "antrea.io/antrea/pkg/agent/cniserver/types" + types "antrea.io/antrea/pkg/agent/cniserver/types" "antrea.io/antrea/pkg/agent/config" "antrea.io/antrea/pkg/agent/interfacestore" openflowtest "antrea.io/antrea/pkg/agent/openflow/testing" @@ -64,26 +64,29 @@ const ( unsupportedCNIVersion = "0.5.1" ) -var routes = []string{"10.0.0.0/8,10.1.2.1", "0.0.0.0/0,10.1.2.1"} -var dns = []string{"192.168.100.1"} -var ips = []string{"10.1.2.100/24,10.1.2.1,4"} -var args = cniservertest.GenerateCNIArgs(testPodNameA, testPodNamespace, testPodInfraContainerID) -var testNodeConfig *config.NodeConfig -var gwIPv4 net.IP -var gwIPv6 net.IP +var ( + routes = []string{"10.0.0.0/8,10.1.2.1", "0.0.0.0/0,10.1.2.1"} + dns = []string{"192.168.100.1"} + ips = []string{"10.1.2.100/24,10.1.2.1,4"} + args = cniservertest.GenerateCNIArgs(testPodNameA, testPodNamespace, testPodInfraContainerID) + testNodeConfig *config.NodeConfig + gwIPv4 net.IP + gwIPv6 net.IP +) func TestLoadNetConfig(t *testing.T) { assert := assert.New(t) - cniService := newCNIServer(t) - networkCfg := generateNetworkConfiguration("testCfg", supportedCNIVersion, testIpamType) + ipamType := "TestLoadNetConfig" + networkCfg := generateNetworkConfiguration("", supportedCNIVersion, "", ipamType) requestMsg, containerID := newRequest(args, networkCfg, "", t) - netCfg, err := cniService.loadNetworkConfig(requestMsg) + ipam.RegisterIPAMDriver(ipamType, nil) + netCfg, resp := cniService.validateRequestMessage(requestMsg) // just make sure that cniService.nodeConfig matches the testNodeConfig. require.Equal(t, testNodeConfig, cniService.nodeConfig) - assert.Nil(err, "Error while parsing request message, %v", err) + assert.Nil(resp, "Error while parsing request message, %v", resp) assert.Equal(supportedCNIVersion, netCfg.CNIVersion) assert.Equal(containerID, netCfg.ContainerId) assert.Equal(netns, netCfg.Netns) @@ -137,7 +140,7 @@ func TestIPAMService(t *testing.T) { controller := gomock.NewController(t) defer controller.Finish() ipamMock := ipamtest.NewMockIPAMDriver(controller) - _ = ipam.RegisterIPAMDriver(testIpamType, ipamMock) + ipam.RegisterIPAMDriver(testIpamType, ipamMock) cniServer := newCNIServer(t) ifaceStore := interfacestore.NewInterfaceStore() cniServer.podConfigurator = &podConfigurator{ifaceStore: ifaceStore} @@ -147,7 +150,7 @@ func TestIPAMService(t *testing.T) { // Test IPAM_Failure cases cxt := context.Background() - networkCfg := generateNetworkConfiguration("testCfg", "0.4.0", testIpamType) + networkCfg := generateNetworkConfiguration("", "0.4.0", "", testIpamType) requestMsg, _ := newRequest(args, networkCfg, "", t) t.Run("Error on ADD", func(t *testing.T) { @@ -161,7 +164,7 @@ func TestIPAMService(t *testing.T) { t.Run("Error on DEL", func(t *testing.T) { // Prepare cached IPAM result which will be deleted later. ipamMock.EXPECT().Add(gomock.Any(), gomock.Any(), gomock.Any()).Return(true, nil, nil) - cniConfig, _ := cniServer.checkRequestMessage(requestMsg) + cniConfig, _ := cniServer.validateRequestMessage(requestMsg) _, err := ipam.ExecIPAMAdd(cniConfig.CniCmdArgs, cniConfig.K8sArgs, cniConfig.IPAM.Type, cniConfig.getInfraContainer()) require.Nil(t, err, "expected no Add error") ipamMock.EXPECT().Del(gomock.Any(), gomock.Any(), gomock.Any()).Return(true, fmt.Errorf("IPAM delete error")) @@ -186,7 +189,7 @@ func TestIPAMService(t *testing.T) { t.Run("Idempotent Call of IPAM ADD/DEL for the same Pod", func(t *testing.T) { ipamMock.EXPECT().Add(gomock.Any(), gomock.Any(), gomock.Any()).Return(true, nil, nil) ipamMock.EXPECT().Del(gomock.Any(), gomock.Any(), gomock.Any()).Return(true, nil).Times(2) - cniConfig, response := cniServer.checkRequestMessage(requestMsg) + cniConfig, response := cniServer.validateRequestMessage(requestMsg) require.Nil(t, response, "expected no rpc error") ipamResult, err := ipam.ExecIPAMAdd(cniConfig.CniCmdArgs, cniConfig.K8sArgs, cniConfig.IPAM.Type, cniConfig.getInfraContainer()) require.Nil(t, err, "expected no IPAM add error") @@ -202,14 +205,14 @@ func TestIPAMService(t *testing.T) { t.Run("Idempotent Call of IPAM ADD/DEL for the same Pod with different containers", func(t *testing.T) { ipamMock.EXPECT().Add(gomock.Any(), gomock.Any(), gomock.Any()).Return(true, nil, nil).Times(2) ipamMock.EXPECT().Del(gomock.Any(), gomock.Any(), gomock.Any()).Return(true, nil).Times(2) - cniConfig, response := cniServer.checkRequestMessage(requestMsg) + cniConfig, response := cniServer.validateRequestMessage(requestMsg) require.Nil(t, response, "expected no rpc error") _, err := ipam.ExecIPAMAdd(cniConfig.CniCmdArgs, cniConfig.K8sArgs, cniConfig.IPAM.Type, cniConfig.getInfraContainer()) require.Nil(t, err, "expected no IPAM add error") workerContainerID := "test-infra-2222222" args2 := cniservertest.GenerateCNIArgs(testPodNameA, testPodNamespace, workerContainerID) requestMsg2, _ := newRequest(args2, networkCfg, "", t) - cniConfig2, response := cniServer.checkRequestMessage(requestMsg2) + cniConfig2, response := cniServer.validateRequestMessage(requestMsg2) require.Nil(t, response, "expected no rpc error") _, err = ipam.ExecIPAMAdd(cniConfig2.CniCmdArgs, cniConfig.K8sArgs, cniConfig.IPAM.Type, cniConfig2.getInfraContainer()) require.Nil(t, err, "expected no IPAM add error") @@ -227,8 +230,8 @@ func TestIPAMServiceMultiDriver(t *testing.T) { mockDriverA := ipamtest.NewMockIPAMDriver(controller) mockDriverB := ipamtest.NewMockIPAMDriver(controller) - _ = ipam.RegisterIPAMDriver(testIpamType2, mockDriverA) - _ = ipam.RegisterIPAMDriver(testIpamType2, mockDriverB) + ipam.RegisterIPAMDriver(testIpamType2, mockDriverA) + ipam.RegisterIPAMDriver(testIpamType2, mockDriverB) cniServer := newCNIServer(t) ifaceStore := interfacestore.NewInterfaceStore() cniServer.podConfigurator = &podConfigurator{ifaceStore: ifaceStore} @@ -238,7 +241,7 @@ func TestIPAMServiceMultiDriver(t *testing.T) { // Test IPAM_Failure cases cxt := context.Background() - networkCfg := generateNetworkConfiguration("testCfg", "0.4.0", testIpamType2) + networkCfg := generateNetworkConfiguration("", "0.4.0", "", testIpamType2) argsPodA := cniservertest.GenerateCNIArgs(testPodNameA, testPodNamespace, testPodInfraContainerID) argsPodB := cniservertest.GenerateCNIArgs(testPodNameB, testPodNamespace, testPodInfraContainerID) @@ -272,7 +275,7 @@ func TestIPAMServiceMultiDriver(t *testing.T) { t.Run("Error on DEL for first registered driver", func(t *testing.T) { // Prepare cached IPAM result which will be deleted later. mockDriverA.EXPECT().Add(gomock.Any(), gomock.Any(), gomock.Any()).Return(true, ipamResult, nil) - cniConfig, _ := cniServer.checkRequestMessage(requestMsgA) + cniConfig, _ := cniServer.validateRequestMessage(requestMsgA) _, err := ipam.ExecIPAMAdd(cniConfig.CniCmdArgs, cniConfig.K8sArgs, cniConfig.IPAM.Type, cniConfig.getInfraContainer()) require.Nil(t, err, "expected no Add error") @@ -292,7 +295,7 @@ func TestIPAMServiceMultiDriver(t *testing.T) { // Prepare cached IPAM result which will be deleted later. mockDriverA.EXPECT().Add(gomock.Any(), gomock.Any(), gomock.Any()).Return(false, nil, nil) mockDriverB.EXPECT().Add(gomock.Any(), gomock.Any(), gomock.Any()).Return(true, ipamResult, nil) - cniConfig, _ := cniServer.checkRequestMessage(requestMsgB) + cniConfig, _ := cniServer.validateRequestMessage(requestMsgB) _, err := ipam.ExecIPAMAdd(cniConfig.CniCmdArgs, cniConfig.K8sArgs, cniConfig.IPAM.Type, cniConfig.getInfraContainer()) require.Nil(t, err, "expected no Add error") @@ -326,30 +329,122 @@ func TestIPAMServiceMultiDriver(t *testing.T) { }) } -func TestCheckRequestMessage(t *testing.T) { +func TestValidateRequestMessage(t *testing.T) { + hostLocal := "host-local" + ipam.RegisterIPAMDriver(hostLocal, nil) + ipam.RegisterIPAMDriver(ipam.AntreaIPAMType, nil) cniServer := newCNIServer(t) - t.Run("Incompatible CNI version", func(t *testing.T) { - networkCfg := generateNetworkConfiguration("testCfg", unsupportedCNIVersion, testIpamType) - requestMsg, _ := newRequest(args, networkCfg, "", t) - _, response := cniServer.checkRequestMessage(requestMsg) - checkErrorResponse(t, response, cnipb.ErrorCode_INCOMPATIBLE_CNI_VERSION, "") - }) + type testCase struct { + test string + cniVersion string + cniType string + ipamType string + isChaining bool + enableBridgingMode bool + enableSecondaryNetworkIPAM bool + resIPAMType string + resSecondaryNetworkIPAM bool + errorCode cnipb.ErrorCode + } - t.Run("Unknown IPAM type", func(t *testing.T) { - networkCfg := generateNetworkConfiguration("testCfg", supportedCNIVersion, testIpamType) - networkCfg.IPAM.Type = "unknown" - requestMsg, _ := newRequest(args, networkCfg, "", t) - _, response := cniServer.checkRequestMessage(requestMsg) - checkErrorResponse(t, response, cnipb.ErrorCode_UNSUPPORTED_FIELD, "") - }) + testCases := []testCase{ + { + test: "Incompatible CNI version", + cniVersion: unsupportedCNIVersion, + errorCode: cnipb.ErrorCode_INCOMPATIBLE_CNI_VERSION, + }, + { + test: "Unknown CNI type", + cniType: "unknown", + errorCode: cnipb.ErrorCode_UNSUPPORTED_FIELD, + }, + { + test: "Unknown IPAM type", + ipamType: "unknown", + errorCode: cnipb.ErrorCode_UNSUPPORTED_FIELD, + }, + { + test: "host-local", + ipamType: hostLocal, + resIPAMType: hostLocal, + }, + { + test: "antrea-ipam", + ipamType: ipam.AntreaIPAMType, + resIPAMType: ipam.AntreaIPAMType, + }, + { + test: "host-local in bridging mode", + ipamType: hostLocal, + enableBridgingMode: true, + resIPAMType: ipam.AntreaIPAMType, + }, + { + test: "chaining", + ipamType: "unknown", + isChaining: true, + resIPAMType: "unknown", + }, + { + test: "IPAM for other CNI not enabled", + cniType: "unknown", + ipamType: ipam.AntreaIPAMType, + errorCode: cnipb.ErrorCode_UNSUPPORTED_FIELD, + }, + { + test: "IPAM for other CNI with unsupported IPAM type", + cniType: "unknown", + ipamType: hostLocal, + enableSecondaryNetworkIPAM: true, + errorCode: cnipb.ErrorCode_UNSUPPORTED_FIELD, + }, + { + test: "IPAM for other CNI", + cniType: "unknown", + ipamType: ipam.AntreaIPAMType, + resIPAMType: ipam.AntreaIPAMType, + resSecondaryNetworkIPAM: true, + enableSecondaryNetworkIPAM: true, + }, + } + + for _, c := range testCases { + t.Run(c.test, func(t *testing.T) { + cniVersion := c.cniVersion + if cniVersion == "" { + cniVersion = supportedCNIVersion + } + ipamType := c.ipamType + if ipamType == "" { + ipamType = hostLocal + } + + networkCfg := generateNetworkConfiguration("", cniVersion, c.cniType, ipamType) + requestMsg, _ := newRequest(args, networkCfg, "", t) + cniServer.isChaining = c.isChaining + cniServer.enableBridgingMode = c.enableBridgingMode + cniServer.enableSecondaryNetworkIPAM = c.enableSecondaryNetworkIPAM + + resCfg, response := cniServer.validateRequestMessage(requestMsg) + if c.errorCode != 0 { + assert.NotNil(t, response, "Error code %v is expected", c.errorCode) + checkErrorResponse(t, response, c.errorCode, "") + return + } + assert.Nil(t, response, "Unexpected error response: %v", response) + + assert.Equal(t, resCfg.IPAM.Type, c.resIPAMType) + assert.Equal(t, resCfg.secondaryNetworkIPAM, c.resSecondaryNetworkIPAM) + }) + } } func TestValidatePrevResult(t *testing.T) { cniServer := newCNIServer(t) cniVersion := "0.4.0" - networkCfg := generateNetworkConfiguration("testCfg", cniVersion, testIpamType) - k8sPodArgs := &argtypes.K8sArgs{} + networkCfg := generateNetworkConfiguration("", cniVersion, "", testIpamType) + k8sPodArgs := &types.K8sArgs{} cnitypes.LoadArgs(args, k8sPodArgs) networkCfg.PrevResult = nil ips := []string{"10.1.2.100/24,10.1.2.1,4"} @@ -375,7 +470,7 @@ func TestValidatePrevResult(t *testing.T) { cniConfig.Ifname = "invalid_iface" // invalid sriovVFDeviceID := "" prevResult.Interfaces = []*current.Interface{hostIface, containerIface} - response := cniServer.validatePrevResult(cniConfig.CniCmdArgs, k8sPodArgs, prevResult, sriovVFDeviceID) + response := cniServer.validatePrevResult(cniConfig.CniCmdArgs, prevResult, sriovVFDeviceID) checkErrorResponse( t, response, cnipb.ErrorCode_INVALID_NETWORK_CONFIG, "prevResult does not match network configuration", @@ -387,7 +482,7 @@ func TestValidatePrevResult(t *testing.T) { cniConfig.Ifname = "invalid_iface" // invalid sriovVFDeviceID := "0000:03:00.6" prevResult.Interfaces = []*current.Interface{hostIface, containerIface} - response := cniServer.validatePrevResult(cniConfig.CniCmdArgs, k8sPodArgs, prevResult, sriovVFDeviceID) + response := cniServer.validatePrevResult(cniConfig.CniCmdArgs, prevResult, sriovVFDeviceID) checkErrorResponse( t, response, cnipb.ErrorCode_INVALID_NETWORK_CONFIG, "prevResult does not match network configuration", @@ -400,8 +495,8 @@ func TestValidatePrevResult(t *testing.T) { cniConfig.Netns = "invalid_netns" sriovVFDeviceID := "" prevResult.Interfaces = []*current.Interface{hostIface, containerIface} - cniServer.podConfigurator, _ = newPodConfigurator(nil, nil, nil, nil, nil, "", false, channel.NewSubscribableChannel("PodUpdate", 100), nil) - response := cniServer.validatePrevResult(cniConfig.CniCmdArgs, k8sPodArgs, prevResult, sriovVFDeviceID) + cniServer.podConfigurator, _ = newPodConfigurator(nil, nil, nil, nil, nil, "", false, channel.NewSubscribableChannel("PodUpdate", 100), nil, false) + response := cniServer.validatePrevResult(cniConfig.CniCmdArgs, prevResult, sriovVFDeviceID) checkErrorResponse(t, response, cnipb.ErrorCode_CHECK_INTERFACE_FAILURE, "") }) @@ -411,8 +506,8 @@ func TestValidatePrevResult(t *testing.T) { cniConfig.Netns = "invalid_netns" sriovVFDeviceID := "0000:03:00.6" prevResult.Interfaces = []*current.Interface{hostIface, containerIface} - cniServer.podConfigurator, _ = newPodConfigurator(nil, nil, nil, nil, nil, "", true, channel.NewSubscribableChannel("PodUpdate", 100), nil) - response := cniServer.validatePrevResult(cniConfig.CniCmdArgs, k8sPodArgs, prevResult, sriovVFDeviceID) + cniServer.podConfigurator, _ = newPodConfigurator(nil, nil, nil, nil, nil, "", true, channel.NewSubscribableChannel("PodUpdate", 100), nil, false) + response := cniServer.validatePrevResult(cniConfig.CniCmdArgs, prevResult, sriovVFDeviceID) checkErrorResponse(t, response, cnipb.ErrorCode_CHECK_INTERFACE_FAILURE, "") }) } @@ -420,8 +515,8 @@ func TestValidatePrevResult(t *testing.T) { func TestParsePrevResultFromRequest(t *testing.T) { cniServer := newCNIServer(t) - getNetworkCfg := func(cniVersion string) *NetworkConfig { - networkCfg := generateNetworkConfiguration("testCfg", cniVersion, testIpamType) + getNetworkCfg := func(cniVersion string) *types.NetworkConfig { + networkCfg := generateNetworkConfiguration("", cniVersion, "", testIpamType) networkCfg.PrevResult = nil networkCfg.RawPrevResult = nil return networkCfg @@ -531,7 +626,7 @@ func TestRemoveInterface(t *testing.T) { ifaceStore := interfacestore.NewInterfaceStore() routeMock := routetest.NewMockInterface(controller) gwMAC, _ := net.ParseMAC("00:00:11:11:11:11") - podConfigurator, err := newPodConfigurator(mockOVSBridgeClient, mockOFClient, routeMock, ifaceStore, gwMAC, "system", false, channel.NewSubscribableChannel("PodUpdate", 100), nil) + podConfigurator, err := newPodConfigurator(mockOVSBridgeClient, mockOFClient, routeMock, ifaceStore, gwMAC, "system", false, channel.NewSubscribableChannel("PodUpdate", 100), nil, false) require.Nil(t, err, "No error expected in podConfigurator constructor") containerMAC, _ := net.ParseMAC("aa:bb:cc:dd:ee:ff") @@ -550,7 +645,7 @@ func TestRemoveInterface(t *testing.T) { hostIfaceName = util.GenerateContainerInterfaceName(podName, testPodNamespace, containerID) fakePortUUID = uuid.New().String() - netcfg := generateNetworkConfiguration("testCfg", supportedCNIVersion, testIpamType) + netcfg := generateNetworkConfiguration("", supportedCNIVersion, "", testIpamType) cniConfig = &CNIConfig{NetworkConfig: netcfg, CniCmdArgs: &cnipb.CniCmdArgs{}} cniConfig.Ifname = "eth0" cniConfig.ContainerId = containerID @@ -687,16 +782,24 @@ func newCNIServer(t *testing.T) *CNIServer { return cniServer } -func generateNetworkConfiguration(name string, cniVersion string, ipamType string) *NetworkConfig { - netCfg := new(NetworkConfig) - netCfg.Name = name +func generateNetworkConfiguration(name, cniVersion, cniType, ipamType string) *types.NetworkConfig { + netCfg := new(types.NetworkConfig) + if name == "" { + netCfg.Name = "test-network" + } else { + netCfg.Name = name + } netCfg.CNIVersion = cniVersion - netCfg.Type = "antrea" - netCfg.IPAM = ipam.IPAMConfig{Type: ipamType} + if cniType == "" { + netCfg.Type = antreaCNIType + } else { + netCfg.Type = "cniType" + } + netCfg.IPAM = &types.IPAMConfig{Type: ipamType} return netCfg } -func newRequest(args string, netCfg *NetworkConfig, path string, t *testing.T) (*cnipb.CniCmdRequest, string) { +func newRequest(args string, netCfg *types.NetworkConfig, path string, t *testing.T) (*cnipb.CniCmdRequest, string) { containerID := generateUUID(t) networkConfig, err := json.Marshal(netCfg) if err != nil { diff --git a/pkg/agent/cniserver/types/types.go b/pkg/agent/cniserver/types/types.go new file mode 100644 index 00000000000..bb9f6300bc5 --- /dev/null +++ b/pkg/agent/cniserver/types/types.go @@ -0,0 +1,80 @@ +// Copyright 2019 Antrea Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package types + +import ( + "net" + + cnitypes "github.com/containernetworking/cni/pkg/types" +) + +type K8sArgs struct { + cnitypes.CommonArgs + K8S_POD_NAME cnitypes.UnmarshallableString + K8S_POD_NAMESPACE cnitypes.UnmarshallableString + K8S_POD_INFRA_CONTAINER_ID cnitypes.UnmarshallableString +} + +type RuntimeDNS struct { + Nameservers []string `json:"servers,omitempty"` + Search []string `json:"searches,omitempty"` +} + +type RuntimeConfig struct { + DNS RuntimeDNS `json:"dns"` +} + +type Range struct { + Subnet string `json:"subnet"` + Gateway string `json:"gateway,omitempty"` +} + +type RangeSet []Range + +type Address struct { + Address string `json:"address"` + Gateway net.IP `json:"gateway,omitempty"` + IPNet net.IPNet + // IP version. Either "4" or "6". + Version string +} + +type IPAMConfig struct { + Type string `json:"type"` + // IP ranges for NodeIPAM. Can include both v4 and v6 ranges. + Ranges []RangeSet `json:"ranges,omitempty"` + // Routes, Addresses, and DNS are copied from static IPAM + // (https://www.cni.dev/plugins/current/ipam/static). + Routes []*cnitypes.Route `json:"routes,omitempty"` + Addresses []Address `json:"addresses,omitempty"` + DNS cnitypes.DNS `json:"dns,omitempty"` + // Antrea IPPool names for Antrea IPAM. + IPPools []string `json:"ippools,omitempty"` + // Other NodeIPAM config parameters (ResolvConf, IPArgs) are not supported. +} + +type NetworkConfig struct { + CNIVersion string `json:"cniVersion"` + Name string `json:"name"` + Type string `json:"type"` + DeviceID string `json:"deviceID,omitempty"` // PCI address of a VF + MTU int `json:"mtu,omitempty"` + DNS cnitypes.DNS `json:"dns,omitempty"` + IPAM *IPAMConfig `json:"ipam,omitempty"` + // Options to be passed in by the runtime. + RuntimeConfig RuntimeConfig `json:"runtimeConfig,omitempty"` + RawPrevResult map[string]interface{} `json:"prevResult,omitempty"` + PrevResult cnitypes.Result `json:"-"` +} diff --git a/pkg/agent/config/node_config.go b/pkg/agent/config/node_config.go index 01bd20a9628..5b60993e1b7 100644 --- a/pkg/agent/config/node_config.go +++ b/pkg/agent/config/node_config.go @@ -182,3 +182,11 @@ func (nc *NetworkConfig) NeedsTunnelToPeer(peerIP net.IP, localIP *net.IPNet) bo func (nc *NetworkConfig) NeedsDirectRoutingToPeer(peerIP net.IP, localIP *net.IPNet) bool { return (nc.TrafficEncapMode == TrafficEncapModeNoEncap || nc.TrafficEncapMode == TrafficEncapModeHybrid) && localIP.Contains(peerIP) } + +// ServiceConfig includes K8s Service CIDR and available IP addresses for NodePort. +type ServiceConfig struct { + ServiceCIDR *net.IPNet // K8s Service ClusterIP CIDR + ServiceCIDRv6 *net.IPNet // K8s Service ClusterIP CIDR in IPv6 + NodePortAddressesIPv4 []net.IP + NodePortAddressesIPv6 []net.IP +} diff --git a/pkg/agent/controller/egress/egress_controller.go b/pkg/agent/controller/egress/egress_controller.go index 167d0756a7f..a683a8d84e0 100644 --- a/pkg/agent/controller/egress/egress_controller.go +++ b/pkg/agent/controller/egress/egress_controller.go @@ -41,6 +41,7 @@ import ( "antrea.io/antrea/pkg/agent/memberlist" "antrea.io/antrea/pkg/agent/openflow" "antrea.io/antrea/pkg/agent/route" + "antrea.io/antrea/pkg/agent/types" cpv1b2 "antrea.io/antrea/pkg/apis/controlplane/v1beta2" crdv1a2 "antrea.io/antrea/pkg/apis/crd/v1alpha2" clientsetversioned "antrea.io/antrea/pkg/client/clientset/versioned" @@ -217,9 +218,11 @@ func NewEgressController( // processPodUpdate will be called when CNIServer publishes a Pod update event. // It triggers reconciling the effective Egress of the Pod. -func (c *EgressController) processPodUpdate(pod string) { +func (c *EgressController) processPodUpdate(e interface{}) { c.egressBindingsMutex.Lock() defer c.egressBindingsMutex.Unlock() + podEvent := e.(types.PodUpdate) + pod := k8s.NamespacedName(podEvent.PodNamespace, podEvent.PodName) binding, exists := c.egressBindings[pod] if !exists { return diff --git a/pkg/agent/controller/egress/egress_controller_test.go b/pkg/agent/controller/egress/egress_controller_test.go index 9c448dd1cf6..0d241bf7e8e 100644 --- a/pkg/agent/controller/egress/egress_controller_test.go +++ b/pkg/agent/controller/egress/egress_controller_test.go @@ -38,6 +38,7 @@ import ( ipassignertest "antrea.io/antrea/pkg/agent/ipassigner/testing" openflowtest "antrea.io/antrea/pkg/agent/openflow/testing" routetest "antrea.io/antrea/pkg/agent/route/testing" + "antrea.io/antrea/pkg/agent/types" "antrea.io/antrea/pkg/agent/util" cpv1b2 "antrea.io/antrea/pkg/apis/controlplane/v1beta2" crdv1a2 "antrea.io/antrea/pkg/apis/crd/v1alpha2" @@ -582,7 +583,11 @@ func TestPodUpdateShouldSyncEgress(t *testing.T) { c.mockIPAssigner.EXPECT().UnassignIP(fakeLocalEgressIP1) // Mock CNIServer addPodInterface(c.ifaceStore, "ns1", "pendingPod", 10) - c.podUpdateChannel.Notify("ns1/pendingPod") + ev := types.PodUpdate{ + PodName: "pendingPod", + PodNamespace: "ns1", + } + c.podUpdateChannel.Notify(ev) require.NoError(t, wait.PollImmediate(10*time.Millisecond, time.Second, func() (done bool, err error) { return c.queue.Len() == 1, nil })) diff --git a/pkg/agent/controller/networkpolicy/allocator.go b/pkg/agent/controller/networkpolicy/allocator.go index 103412be7b1..0187cf11327 100644 --- a/pkg/agent/controller/networkpolicy/allocator.go +++ b/pkg/agent/controller/networkpolicy/allocator.go @@ -21,11 +21,11 @@ import ( "sync" "time" - "k8s.io/apimachinery/pkg/util/clock" "k8s.io/apimachinery/pkg/util/wait" "k8s.io/client-go/tools/cache" "k8s.io/client-go/util/workqueue" "k8s.io/klog/v2" + "k8s.io/utils/clock" "antrea.io/antrea/pkg/agent/types" ) @@ -106,7 +106,7 @@ func newIDAllocator(asyncRuleDeleteInterval time.Duration, allocatedIDs ...uint3 // newIDAllocatorWithCustomClock creates an ID allocator with a custom clock, // which is useful when writing robust unit tests. -func newIDAllocatorWithCustomClock(clock clock.Clock, asyncRuleDeleteInterval time.Duration, allocatedIDs ...uint32) *idAllocator { +func newIDAllocatorWithCustomClock(clock clock.WithTicker, asyncRuleDeleteInterval time.Duration, allocatedIDs ...uint32) *idAllocator { allocator := newIDAllocator(asyncRuleDeleteInterval, allocatedIDs...) // override regular delaying workqueue with one using a custom clock allocator.deleteQueue = workqueue.NewDelayingQueueWithCustomClock(clock, deleteQueueName) diff --git a/pkg/agent/controller/networkpolicy/allocator_test.go b/pkg/agent/controller/networkpolicy/allocator_test.go index e22df5fd70c..cb99e6fafd4 100644 --- a/pkg/agent/controller/networkpolicy/allocator_test.go +++ b/pkg/agent/controller/networkpolicy/allocator_test.go @@ -21,9 +21,9 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "k8s.io/apimachinery/pkg/util/clock" "k8s.io/apimachinery/pkg/util/sets" "k8s.io/apimachinery/pkg/util/wait" + clock "k8s.io/utils/clock/testing" "antrea.io/antrea/pkg/agent/types" "antrea.io/antrea/pkg/apis/controlplane/v1beta2" diff --git a/pkg/agent/controller/networkpolicy/audit_logging_test.go b/pkg/agent/controller/networkpolicy/audit_logging_test.go index 57438c374f6..36323b616a8 100644 --- a/pkg/agent/controller/networkpolicy/audit_logging_test.go +++ b/pkg/agent/controller/networkpolicy/audit_logging_test.go @@ -130,17 +130,6 @@ func newLogInfo(disposition string) (*logInfo, string) { return testLogInfo, expected } -func sendMultiplePackets(antreaLogger *AntreaPolicyLogger, ob *logInfo, numPackets int, sendInterval time.Duration) { - count := 0 - for range time.Tick(sendInterval) { - count += 1 - antreaLogger.LogDedupPacket(ob) - if count == numPackets { - break - } - } -} - func expectedLogWithCount(msg string, count int) string { return fmt.Sprintf("%s [%d", msg, count) } @@ -164,12 +153,17 @@ func TestDropPacketLog(t *testing.T) { } func TestDropPacketDedupLog(t *testing.T) { - antreaLogger, mockAnpLogger := newTestAntreaPolicyLogger(testBufferLength, &realClock{}) + clock := NewVirtualClock(time.Now()) + defer clock.Stop() + antreaLogger, mockAnpLogger := newTestAntreaPolicyLogger(testBufferLength, clock) ob, expected := newLogInfo("Drop") // Add the additional log info for duplicate packets. expected = expectedLogWithCount(expected, 2) - go sendMultiplePackets(antreaLogger, ob, 2, time.Millisecond) + antreaLogger.LogDedupPacket(ob) + clock.Advance(time.Millisecond) + antreaLogger.LogDedupPacket(ob) + clock.Advance(testBufferLength) actual := <-mockAnpLogger.logged assert.Contains(t, actual, expected) } diff --git a/pkg/agent/controller/networkpolicy/cache.go b/pkg/agent/controller/networkpolicy/cache.go index 32011eaf8cd..e0fc264f260 100644 --- a/pkg/agent/controller/networkpolicy/cache.go +++ b/pkg/agent/controller/networkpolicy/cache.go @@ -28,6 +28,7 @@ import ( "k8s.io/klog/v2" "antrea.io/antrea/pkg/agent/metrics" + agenttypes "antrea.io/antrea/pkg/agent/types" v1beta "antrea.io/antrea/pkg/apis/controlplane/v1beta2" crdv1alpha1 "antrea.io/antrea/pkg/apis/crd/v1alpha1" "antrea.io/antrea/pkg/querier" @@ -361,12 +362,12 @@ func newRuleCache(dirtyRuleHandler func(string), podUpdateSubscriber channel.Sub // done if antrea-controller has computed the Pods' policies and propagated // them to this Node by their labels and NodeName, instead of waiting for their // IPs are reported to kube-apiserver and processed by antrea-controller. -func (c *ruleCache) processPodUpdate(pod string) { - namespace, name := k8s.SplitNamespacedName(pod) +func (c *ruleCache) processPodUpdate(e interface{}) { + podEvent := e.(agenttypes.PodUpdate) member := &v1beta.GroupMember{ Pod: &v1beta.PodReference{ - Name: name, - Namespace: namespace, + Name: podEvent.PodName, + Namespace: podEvent.PodNamespace, }, } c.appliedToSetLock.RLock() diff --git a/pkg/agent/controller/networkpolicy/cache_test.go b/pkg/agent/controller/networkpolicy/cache_test.go index 35878d26cfd..00c01d3ed25 100644 --- a/pkg/agent/controller/networkpolicy/cache_test.go +++ b/pkg/agent/controller/networkpolicy/cache_test.go @@ -25,8 +25,10 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/sets" + "antrea.io/antrea/pkg/agent/types" "antrea.io/antrea/pkg/apis/controlplane/v1beta2" "antrea.io/antrea/pkg/util/channel" + "antrea.io/antrea/pkg/util/k8s" ) var ( @@ -1184,7 +1186,12 @@ func TestRuleCacheProcessPodUpdates(t *testing.T) { stopCh := make(chan struct{}) defer close(stopCh) go podUpdateNotifier.Run(stopCh) - podUpdateNotifier.Notify(tt.podUpdate) + ns, name := k8s.SplitNamespacedName(tt.podUpdate) + e := types.PodUpdate{ + PodNamespace: ns, + PodName: name, + } + podUpdateNotifier.Notify(e) func() { // Drain the channel with 10 ms timeout so we can know it's done. for { diff --git a/pkg/agent/controller/networkpolicy/packetin.go b/pkg/agent/controller/networkpolicy/packetin.go index b93b58ab760..cea0ea60e89 100644 --- a/pkg/agent/controller/networkpolicy/packetin.go +++ b/pkg/agent/controller/networkpolicy/packetin.go @@ -17,6 +17,7 @@ package networkpolicy import ( "errors" "fmt" + "net" "time" "antrea.io/libOpenflow/openflow13" @@ -117,13 +118,11 @@ func (c *Controller) storeDenyConnection(pktIn *ofctrl.PacketIn) error { DestinationPort: packet.DestinationPort, Protocol: packet.IPProto, } - if packet.IsIPv6 { - tuple.SourceAddress = packet.SourceIP.To16() - tuple.DestinationAddress = packet.DestinationIP.To16() - } else { - tuple.SourceAddress = packet.SourceIP.To4() - tuple.DestinationAddress = packet.DestinationIP.To4() - } + // Make deep copy of IP addresses + tuple.SourceAddress = make(net.IP, len(packet.SourceIP)) + tuple.DestinationAddress = make(net.IP, len(packet.DestinationIP)) + copy(tuple.SourceAddress, packet.SourceIP) + copy(tuple.DestinationAddress, packet.DestinationIP) // Generate deny connection and add to deny connection store denyConn := flowexporter.Connection{} diff --git a/pkg/agent/controller/networkpolicy/reconciler_test.go b/pkg/agent/controller/networkpolicy/reconciler_test.go index dc9a4448826..0541264eb44 100644 --- a/pkg/agent/controller/networkpolicy/reconciler_test.go +++ b/pkg/agent/controller/networkpolicy/reconciler_test.go @@ -526,7 +526,7 @@ func TestReconcilerReconcile(t *testing.T) { mockOFClient := openflowtest.NewMockClient(controller) // TODO: mock idAllocator and priorityAssigner for i := 0; i < len(tt.expectedOFRules); i++ { - mockOFClient.EXPECT().InstallPolicyRuleFlows(gomock.Any()) + mockOFClient.EXPECT().InstallPolicyRuleFlows(newPolicyRulesMatcher(tt.expectedOFRules[i])) } r := newTestReconciler(t, controller, ifaceStore, mockOFClient, true, false) if err := r.Reconcile(tt.args); (err != nil) != tt.wantErr { @@ -1966,6 +1966,7 @@ func newPolicyRulesMatcher(ofRule *types.PolicyRule) gomock.Matcher { return policyRuleMatcher{ofPolicyRule: ofRule} } +// Matches checks if predictable fields of *types.PolicyRule match. func (m policyRuleMatcher) Matches(x interface{}) bool { b, ok := x.(*types.PolicyRule) if !ok { @@ -1975,7 +1976,6 @@ func (m policyRuleMatcher) Matches(x interface{}) bool { if !sliceEqual(a.Service, b.Service) || !sliceEqual(a.From, b.From) || !sliceEqual(a.To, b.To) || - a.TableID != b.TableID || a.PolicyRef != b.PolicyRef || a.Direction != b.Direction || a.EnableLogging != b.EnableLogging { diff --git a/pkg/agent/controller/networkpolicy/reject.go b/pkg/agent/controller/networkpolicy/reject.go index aa73b3eb693..365a5c068ef 100644 --- a/pkg/agent/controller/networkpolicy/reject.go +++ b/pkg/agent/controller/networkpolicy/reject.go @@ -16,6 +16,7 @@ package networkpolicy import ( "encoding/binary" + "fmt" "antrea.io/libOpenflow/protocol" "antrea.io/ofnet/ofctrl" @@ -73,6 +74,9 @@ const ( // Service traffic, when AntreaProxy is disabled. The EndpointPod is on a remote // Node and the dstPod of the reject response is on the local Node. RejectNoAPServiceRemoteToLocal + // Unsupported indicates that Antrea couldn't generate packetOut for current + // packetIn. + Unsupported ) // rejectRequest sends reject response to the requesting client, based on the @@ -133,6 +137,19 @@ func (c *Controller) rejectRequest(pktIn *ofctrl.PacketIn) error { return dstFound && dstMAC == gwIfaces[0].MAC.String() } packetOutType := getRejectType(isServiceTraffic(), c.antreaProxyEnabled, srcFound, dstFound) + if packetOutType == Unsupported { + return fmt.Errorf("error when generating reject response for the packet from: %s to %s: neither source nor destination are on this Node", dstIP, srcIP) + } + // When in AntreaIPAM mode, even though srcPod and dstPod are on the same Node, MAC + // will still be re-written in L3ForwardingTable. During rejection, the reject + // response will be directly sent to the dst OF port without go through + // L3ForwardingTable. So we need to re-write MAC here. There is no need to check + // whether AntreaIPAM mode is enabled. Because if AntreaIPAM mode is disabled, + // this re-write doesn't change anything. + if packetOutType == RejectPodLocal { + srcMAC = sIface.MAC.String() + dstMAC = dIface.MAC.String() + } inPort, outPort := getRejectOFPorts(packetOutType, sIface, dIface) mutateFunc := getRejectPacketOutMutateFunc(packetOutType) @@ -195,13 +212,19 @@ func getRejectType(isServiceTraffic, antreaProxyEnabled, srcIsLocal, dstIsLocal } return RejectLocalToRemote } - return RejectPodRemoteToLocal + if dstIsLocal { + return RejectPodRemoteToLocal + } + return Unsupported } if !antreaProxyEnabled { if srcIsLocal { return RejectNoAPServiceLocal } - return RejectNoAPServiceRemoteToLocal + if dstIsLocal { + return RejectNoAPServiceRemoteToLocal + } + return Unsupported } if srcIsLocal { if dstIsLocal { @@ -209,7 +232,10 @@ func getRejectType(isServiceTraffic, antreaProxyEnabled, srcIsLocal, dstIsLocal } return RejectLocalToRemote } - return RejectServiceRemoteToLocal + if dstIsLocal { + return RejectServiceRemoteToLocal + } + return Unsupported } // getRejectOFPorts returns the inPort and outPort of a packetOut based on the RejectType. @@ -219,6 +245,7 @@ func getRejectOFPorts(rejectType RejectType, sIface, dIface *interfacestore.Inte switch rejectType { case RejectPodLocal: inPort = uint32(sIface.OFPort) + outPort = uint32(dIface.OFPort) case RejectServiceLocal: inPort = uint32(sIface.OFPort) case RejectPodRemoteToLocal: @@ -247,11 +274,6 @@ func getRejectPacketOutMutateFunc(rejectType RejectType) func(binding.PacketOutB mutatePacketOut = func(packetOutBuilder binding.PacketOutBuilder) binding.PacketOutBuilder { return packetOutBuilder.AddResubmitAction(nil, &tableID) } - case RejectPodLocal: - // When in AntreaIPAM mode, even srcPod and dstPod are on the same Node, MAC will - // still be re-written in L3ForwardingTable. So during rejection, we also need to - // let the reject response go thru L3ForwardingTable to re-write MAC. - fallthrough case RejectLocalToRemote: tableID := openflow.L3ForwardingTable.GetID() mutatePacketOut = func(packetOutBuilder binding.PacketOutBuilder) binding.PacketOutBuilder { diff --git a/pkg/agent/controller/serviceexternalip/controller.go b/pkg/agent/controller/serviceexternalip/controller.go index e458b5e98c0..d6c1b9d0d84 100644 --- a/pkg/agent/controller/serviceexternalip/controller.go +++ b/pkg/agent/controller/serviceexternalip/controller.go @@ -15,14 +15,12 @@ package serviceexternalip import ( - "context" "fmt" "sync" "time" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/errors" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" apimachinerytypes "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/sets" "k8s.io/apimachinery/pkg/util/wait" @@ -36,6 +34,7 @@ import ( "antrea.io/antrea/pkg/agent/ipassigner" "antrea.io/antrea/pkg/agent/memberlist" "antrea.io/antrea/pkg/agent/types" + "antrea.io/antrea/pkg/querier" ) const ( @@ -54,6 +53,7 @@ const ( type externalIPState struct { ip string + ipPool string assignedNode string } @@ -81,6 +81,8 @@ type ServiceExternalIPController struct { assignedIPsMutex sync.Mutex } +var _ querier.ServiceExternalIPStatusQuerier = (*ServiceExternalIPController)(nil) + func NewServiceExternalIPController( nodeName string, nodeTransportInterface string, @@ -302,21 +304,21 @@ func (c *ServiceExternalIPController) getServiceState(service *corev1.Service) ( return state, exist } -func (c *ServiceExternalIPController) saveServiceState(service *corev1.Service, state externalIPState) { +func (c *ServiceExternalIPController) saveServiceState(service *corev1.Service, state *externalIPState) { c.externalIPStatesMutex.Lock() defer c.externalIPStatesMutex.Unlock() name := apimachinerytypes.NamespacedName{ Namespace: service.Namespace, Name: service.Name, } - c.externalIPStates[name] = state + c.externalIPStates[name] = *state } -func (c *ServiceExternalIPController) getServiceExternalIPAndHostname(service *corev1.Service) (string, string) { +func (c *ServiceExternalIPController) getServiceExternalIP(service *corev1.Service) string { if len(service.Status.LoadBalancer.Ingress) == 0 { - return "", "" + return "" } - return service.Status.LoadBalancer.Ingress[0].IP, service.Status.LoadBalancer.Ingress[0].Hostname + return service.Status.LoadBalancer.Ingress[0].IP } func (c *ServiceExternalIPController) syncService(key apimachinerytypes.NamespacedName) error { @@ -337,9 +339,9 @@ func (c *ServiceExternalIPController) syncService(key apimachinerytypes.Namespac return c.deleteService(key) } - state, exist := c.getServiceState(service) - currentExternalIP, currentHostname := c.getServiceExternalIPAndHostname(service) - if exist && state.ip != currentExternalIP { + prevState, exist := c.getServiceState(service) + currentExternalIP := c.getServiceExternalIP(service) + if exist && prevState.ip != currentExternalIP { // External IP of the Service has changed. Delete the previous assigned IP if exists. if err := c.deleteService(key); err != nil { return err @@ -347,58 +349,41 @@ func (c *ServiceExternalIPController) syncService(key apimachinerytypes.Namespac } ipPool := service.ObjectMeta.Annotations[types.ServiceExternalIPPoolAnnotationKey] + state := &externalIPState{ + ip: currentExternalIP, + ipPool: ipPool, + } + defer c.saveServiceState(service, state) + if currentExternalIP == "" || ipPool == "" { return nil } - selectNode := true var filters []func(string) bool if service.Spec.ExternalTrafficPolicy == corev1.ServiceExternalTrafficPolicyTypeLocal { nodes, err := c.nodesHasHealthyServiceEndpoint(service) if err != nil { return err } - // Avoid unnecessary migration caused by Endpoints changes. - if currentHostname != "" && c.cluster.AliveNodes().Has(currentHostname) && nodes.Has(currentHostname) { - selectNode = false - state = externalIPState{ - ip: currentExternalIP, - assignedNode: currentHostname, - } - c.saveServiceState(service, state) - } else { - filters = append(filters, func(s string) bool { - return nodes.Has(s) - }) - } + filters = append(filters, func(s string) bool { + return nodes.Has(s) + }) } - if selectNode { - nodeName, err := c.cluster.SelectNodeForIP(currentExternalIP, ipPool, filters...) - if err != nil { - if err == memberlist.ErrNoNodeAvailable { - // No Node is available for the moment. The Service will be requeued by Endpoints, Node, or Memberlist update events. - klog.InfoS("No Node available", "ip", currentExternalIP, "ipPool", ipPool) - return nil - } - return err - } - klog.InfoS("Select Node for IP", "service", key, "nodeName", nodeName, "currentExternalIP", currentExternalIP, "ipPool", ipPool) - state = externalIPState{ - ip: currentExternalIP, - assignedNode: nodeName, + nodeName, err := c.cluster.SelectNodeForIP(currentExternalIP, ipPool, filters...) + if err != nil { + if err == memberlist.ErrNoNodeAvailable { + // No Node is available at the moment. The Service will be requeued by Endpoints, Node, or Memberlist update events. + klog.InfoS("No Node available", "ip", currentExternalIP, "ipPool", ipPool) + return nil } - c.saveServiceState(service, state) + return err } - // Update the hostname field of Service status and assign the external IP if this Node is selected. + klog.InfoS("Select Node for IP", "service", key, "nodeName", nodeName, "currentExternalIP", currentExternalIP, "ipPool", ipPool) + + state.assignedNode = nodeName + if state.assignedNode == c.nodeName { - if service.Status.LoadBalancer.Ingress[0].Hostname != state.assignedNode { - serviceToUpdate := service.DeepCopy() - serviceToUpdate.Status.LoadBalancer.Ingress[0].Hostname = state.assignedNode - if _, err = c.client.CoreV1().Services(serviceToUpdate.Namespace).UpdateStatus(context.TODO(), serviceToUpdate, v1.UpdateOptions{}); err != nil { - return err - } - } return c.assignIP(currentExternalIP, key) } return c.unassignIP(currentExternalIP, key) @@ -453,3 +438,19 @@ func (c *ServiceExternalIPController) nodesHasHealthyServiceEndpoint(service *co } return nodes, nil } + +func (c *ServiceExternalIPController) GetServiceExternalIPStatus() []querier.ServiceExternalIPInfo { + c.externalIPStatesMutex.RLock() + defer c.externalIPStatesMutex.RUnlock() + info := make([]querier.ServiceExternalIPInfo, 0, len(c.externalIPStates)) + for k, v := range c.externalIPStates { + info = append(info, querier.ServiceExternalIPInfo{ + ServiceName: k.Name, + Namespace: k.Namespace, + ExternalIP: v.ip, + ExternalIPPool: v.ipPool, + AssignedNode: v.assignedNode, + }) + } + return info +} diff --git a/pkg/agent/controller/serviceexternalip/controller_test.go b/pkg/agent/controller/serviceexternalip/controller_test.go index 5c9ff627d55..ea24b84fca2 100644 --- a/pkg/agent/controller/serviceexternalip/controller_test.go +++ b/pkg/agent/controller/serviceexternalip/controller_test.go @@ -33,6 +33,7 @@ import ( ipassignertest "antrea.io/antrea/pkg/agent/ipassigner/testing" "antrea.io/antrea/pkg/agent/memberlist" "antrea.io/antrea/pkg/agent/types" + "antrea.io/antrea/pkg/querier" ) const ( @@ -228,6 +229,7 @@ func TestCreateService(t *testing.T) { expectedExternalIPStates: map[apimachinerytypes.NamespacedName]externalIPState{ keyFor(servicePolicyCluster): { ip: fakeServiceExternalIP1, + ipPool: fakeExternalIPPoolName, assignedNode: fakeNode1, }, }, @@ -244,6 +246,7 @@ func TestCreateService(t *testing.T) { expectedExternalIPStates: map[apimachinerytypes.NamespacedName]externalIPState{ keyFor(servicePolicyCluster): { ip: fakeServiceExternalIP1, + ipPool: fakeExternalIPPoolName, assignedNode: fakeNode2, }, }, @@ -267,6 +270,7 @@ func TestCreateService(t *testing.T) { expectedExternalIPStates: map[apimachinerytypes.NamespacedName]externalIPState{ keyFor(servicePolicyLocal): { ip: fakeServiceExternalIP1, + ipPool: fakeExternalIPPoolName, assignedNode: fakeNode1, }, }, @@ -294,6 +298,7 @@ func TestCreateService(t *testing.T) { expectedExternalIPStates: map[apimachinerytypes.NamespacedName]externalIPState{ keyFor(servicePolicyLocal): { ip: fakeServiceExternalIP1, + ipPool: fakeExternalIPPoolName, assignedNode: fakeNode2, }, }, @@ -317,6 +322,7 @@ func TestCreateService(t *testing.T) { expectedExternalIPStates: map[apimachinerytypes.NamespacedName]externalIPState{ keyFor(servicePolicyLocal): { ip: fakeServiceExternalIP1, + ipPool: fakeExternalIPPoolName, assignedNode: fakeNode2, }, }, @@ -333,17 +339,22 @@ func TestCreateService(t *testing.T) { "2.3.4.6": fakeNode2, }), }, - serviceToCreate: servicePolicyLocal, - healthyNodes: []string{fakeNode1, fakeNode2}, - expectedCalls: func(mockIPAssigner *ipassignertest.MockIPAssigner) {}, - expectedExternalIPStates: map[apimachinerytypes.NamespacedName]externalIPState{}, - expectError: true, + serviceToCreate: servicePolicyLocal, + healthyNodes: []string{fakeNode1, fakeNode2}, + expectedCalls: func(mockIPAssigner *ipassignertest.MockIPAssigner) {}, + expectedExternalIPStates: map[apimachinerytypes.NamespacedName]externalIPState{ + keyFor(servicePolicyLocal): { + ip: fakeServiceExternalIP1, + ipPool: fakeExternalIPPoolName, + }, + }, + expectError: true, }, { name: "new Service created and local Node selected and IP already assigned by other Service", existingEndpoints: nil, previousExternalIPStates: map[apimachinerytypes.NamespacedName]externalIPState{ - keyFor(servicePolicyLocal): {fakeServiceExternalIP1, fakeNode1}, + keyFor(servicePolicyLocal): {fakeServiceExternalIP1, fakeExternalIPPoolName, fakeNode1}, }, serviceToCreate: servicePolicyCluster, healthyNodes: []string{fakeNode1, fakeNode2}, @@ -351,10 +362,12 @@ func TestCreateService(t *testing.T) { expectedExternalIPStates: map[apimachinerytypes.NamespacedName]externalIPState{ keyFor(servicePolicyLocal): { ip: fakeServiceExternalIP1, + ipPool: fakeExternalIPPoolName, assignedNode: fakeNode1, }, keyFor(servicePolicyCluster): { ip: fakeServiceExternalIP1, + ipPool: fakeExternalIPPoolName, assignedNode: fakeNode1, }, }, @@ -405,12 +418,6 @@ func TestUpdateService(t *testing.T) { serviceExternalTrafficPolicyClusterWithSameExternalIP.Name = "svc-same-eip" serviceExternalTrafficPolicyClusterWithSameExternalIP.Status.LoadBalancer.Ingress[0].IP = fakeServiceExternalIP2 - serviceExternalTrafficLocalWithNodeSelected := servicePolicyLocal.DeepCopy() - serviceExternalTrafficLocalWithNodeSelected.Status.LoadBalancer.Ingress[0].Hostname = fakeNode1 - - serviceExternalTrafficLocalUpdatedHostname := servicePolicyLocal.DeepCopy() - serviceExternalTrafficLocalUpdatedHostname.Status.LoadBalancer.Ingress[0].Hostname = fakeNode2 - serviceChangedType := servicePolicyCluster.DeepCopy() serviceChangedType.Spec.Type = corev1.ServiceTypeClusterIP @@ -436,10 +443,10 @@ func TestUpdateService(t *testing.T) { endpoints: nil, serviceToUpdate: serviceExternalTrafficPolicyClusterUpdatedExternalIP, previousExternalIPStates: map[apimachinerytypes.NamespacedName]externalIPState{ - keyFor(serviceExternalTrafficPolicyClusterUpdatedExternalIP): {fakeServiceExternalIP1, fakeNode1}, + keyFor(serviceExternalTrafficPolicyClusterUpdatedExternalIP): {fakeServiceExternalIP1, fakeExternalIPPoolName, fakeNode1}, }, expectedExternalIPStates: map[apimachinerytypes.NamespacedName]externalIPState{ - keyFor(serviceExternalTrafficPolicyClusterUpdatedExternalIP): {fakeServiceExternalIP2, fakeNode1}, + keyFor(serviceExternalTrafficPolicyClusterUpdatedExternalIP): {fakeServiceExternalIP2, fakeExternalIPPoolName, fakeNode1}, }, healthyNodes: []string{fakeNode1, fakeNode2}, expectedCalls: func(mockIPAssigner *ipassignertest.MockIPAssigner) { @@ -453,12 +460,12 @@ func TestUpdateService(t *testing.T) { endpoints: nil, serviceToUpdate: serviceExternalTrafficPolicyClusterUpdatedExternalIP, previousExternalIPStates: map[apimachinerytypes.NamespacedName]externalIPState{ - keyFor(serviceExternalTrafficPolicyClusterWithSameExternalIP): {fakeServiceExternalIP1, fakeNode1}, - keyFor(serviceExternalTrafficPolicyClusterUpdatedExternalIP): {fakeServiceExternalIP1, fakeNode1}, + keyFor(serviceExternalTrafficPolicyClusterWithSameExternalIP): {fakeServiceExternalIP1, fakeExternalIPPoolName, fakeNode1}, + keyFor(serviceExternalTrafficPolicyClusterUpdatedExternalIP): {fakeServiceExternalIP1, fakeExternalIPPoolName, fakeNode1}, }, expectedExternalIPStates: map[apimachinerytypes.NamespacedName]externalIPState{ - keyFor(serviceExternalTrafficPolicyClusterWithSameExternalIP): {fakeServiceExternalIP1, fakeNode1}, - keyFor(serviceExternalTrafficPolicyClusterUpdatedExternalIP): {fakeServiceExternalIP2, fakeNode1}, + keyFor(serviceExternalTrafficPolicyClusterWithSameExternalIP): {fakeServiceExternalIP1, fakeExternalIPPoolName, fakeNode1}, + keyFor(serviceExternalTrafficPolicyClusterUpdatedExternalIP): {fakeServiceExternalIP2, fakeExternalIPPoolName, fakeNode1}, }, healthyNodes: []string{fakeNode1, fakeNode2}, expectedCalls: func(mockIPAssigner *ipassignertest.MockIPAssigner) { @@ -471,10 +478,10 @@ func TestUpdateService(t *testing.T) { endpoints: nil, serviceToUpdate: serviceExternalTrafficPolicyClusterUpdatedExternalIP, previousExternalIPStates: map[apimachinerytypes.NamespacedName]externalIPState{ - keyFor(serviceExternalTrafficPolicyClusterUpdatedExternalIP): {fakeServiceExternalIP1, fakeNode1}, + keyFor(serviceExternalTrafficPolicyClusterUpdatedExternalIP): {fakeServiceExternalIP1, fakeExternalIPPoolName, fakeNode1}, }, expectedExternalIPStates: map[apimachinerytypes.NamespacedName]externalIPState{ - keyFor(serviceExternalTrafficPolicyClusterUpdatedExternalIP): {fakeServiceExternalIP2, fakeNode2}, + keyFor(serviceExternalTrafficPolicyClusterUpdatedExternalIP): {fakeServiceExternalIP2, fakeExternalIPPoolName, fakeNode2}, }, healthyNodes: []string{fakeNode1, fakeNode2}, overrideHashFn: fakeHashFn(true), @@ -488,7 +495,7 @@ func TestUpdateService(t *testing.T) { endpoints: nil, serviceToUpdate: serviceChangedType, previousExternalIPStates: map[apimachinerytypes.NamespacedName]externalIPState{ - keyFor(serviceExternalTrafficPolicyClusterUpdatedExternalIP): {fakeServiceExternalIP1, fakeNode1}, + keyFor(serviceExternalTrafficPolicyClusterUpdatedExternalIP): {fakeServiceExternalIP1, fakeExternalIPPoolName, fakeNode1}, }, expectedExternalIPStates: map[apimachinerytypes.NamespacedName]externalIPState{}, healthyNodes: []string{fakeNode1, fakeNode2}, @@ -502,7 +509,7 @@ func TestUpdateService(t *testing.T) { endpoints: nil, serviceToUpdate: serviceChangedType, previousExternalIPStates: map[apimachinerytypes.NamespacedName]externalIPState{ - keyFor(serviceExternalTrafficPolicyClusterUpdatedExternalIP): {fakeServiceExternalIP1, fakeNode1}, + keyFor(serviceExternalTrafficPolicyClusterUpdatedExternalIP): {fakeServiceExternalIP1, fakeExternalIPPoolName, fakeNode1}, }, expectedExternalIPStates: map[apimachinerytypes.NamespacedName]externalIPState{}, healthyNodes: []string{fakeNode1, fakeNode2}, @@ -523,10 +530,10 @@ func TestUpdateService(t *testing.T) { }, serviceToUpdate: serviceChangedExternalTrafficPolicy, previousExternalIPStates: map[apimachinerytypes.NamespacedName]externalIPState{ - keyFor(serviceChangedExternalTrafficPolicy): {fakeServiceExternalIP1, fakeNode1}, + keyFor(serviceChangedExternalTrafficPolicy): {fakeServiceExternalIP1, fakeExternalIPPoolName, fakeNode1}, }, expectedExternalIPStates: map[apimachinerytypes.NamespacedName]externalIPState{ - keyFor(serviceChangedExternalTrafficPolicy): {fakeServiceExternalIP1, fakeNode2}, + keyFor(serviceChangedExternalTrafficPolicy): {fakeServiceExternalIP1, fakeExternalIPPoolName, fakeNode2}, }, healthyNodes: []string{fakeNode1, fakeNode2}, expectedCalls: func(mockIPAssigner *ipassignertest.MockIPAssigner) { @@ -539,10 +546,10 @@ func TestUpdateService(t *testing.T) { endpoints: nil, serviceToUpdate: servicePolicyCluster, previousExternalIPStates: map[apimachinerytypes.NamespacedName]externalIPState{ - keyFor(servicePolicyCluster): {fakeServiceExternalIP1, fakeNode1}, + keyFor(servicePolicyCluster): {fakeServiceExternalIP1, fakeExternalIPPoolName, fakeNode1}, }, expectedExternalIPStates: map[apimachinerytypes.NamespacedName]externalIPState{ - keyFor(servicePolicyCluster): {fakeServiceExternalIP1, fakeNode2}, + keyFor(servicePolicyCluster): {fakeServiceExternalIP1, fakeExternalIPPoolName, fakeNode2}, }, healthyNodes: []string{fakeNode1, fakeNode2}, overrideHashFn: fakeHashFn(true), @@ -561,59 +568,12 @@ func TestUpdateService(t *testing.T) { "2.3.4.5": fakeNode1, }), }, - serviceToUpdate: serviceExternalTrafficLocalWithNodeSelected, - previousExternalIPStates: map[apimachinerytypes.NamespacedName]externalIPState{ - keyFor(servicePolicyLocal): {fakeServiceExternalIP1, fakeNode1}, - }, - expectedExternalIPStates: map[apimachinerytypes.NamespacedName]externalIPState{ - keyFor(servicePolicyLocal): {fakeServiceExternalIP1, fakeNode2}, - }, - healthyNodes: []string{fakeNode1, fakeNode2}, - expectedCalls: func(mockIPAssigner *ipassignertest.MockIPAssigner) { - mockIPAssigner.EXPECT().UnassignIP(fakeServiceExternalIP1) - }, - expectError: false, - }, - { - name: "should not migrate to other Nodes if selected Node still have healthy endpoints", - endpoints: []*corev1.Endpoints{ - makeEndpoints(servicePolicyLocal.Name, servicePolicyLocal.Namespace, - map[string]string{ - "2.3.4.5": fakeNode1, - "2.3.4.6": fakeNode2, - }, - nil, - ), - }, - overrideHashFn: fakeHashFn(true), - serviceToUpdate: serviceExternalTrafficLocalWithNodeSelected, - previousExternalIPStates: map[apimachinerytypes.NamespacedName]externalIPState{ - keyFor(servicePolicyLocal): {fakeServiceExternalIP1, fakeNode1}, - }, - expectedExternalIPStates: map[apimachinerytypes.NamespacedName]externalIPState{ - keyFor(servicePolicyLocal): {fakeServiceExternalIP1, fakeNode1}, - }, - healthyNodes: []string{fakeNode1, fakeNode2}, - expectedCalls: func(mockIPAssigner *ipassignertest.MockIPAssigner) {}, - expectError: false, - }, - { - name: "other Node could promote itself as the new owner", - endpoints: []*corev1.Endpoints{ - makeEndpoints(servicePolicyLocal.Name, servicePolicyLocal.Namespace, - map[string]string{ - "2.3.4.5": fakeNode1, - "2.3.4.6": fakeNode2, - }, - nil, - ), - }, - serviceToUpdate: serviceExternalTrafficLocalUpdatedHostname, + serviceToUpdate: servicePolicyLocal, previousExternalIPStates: map[apimachinerytypes.NamespacedName]externalIPState{ - keyFor(servicePolicyLocal): {fakeServiceExternalIP1, fakeNode1}, + keyFor(servicePolicyLocal): {fakeServiceExternalIP1, fakeExternalIPPoolName, fakeNode1}, }, expectedExternalIPStates: map[apimachinerytypes.NamespacedName]externalIPState{ - keyFor(servicePolicyLocal): {fakeServiceExternalIP1, fakeNode2}, + keyFor(servicePolicyLocal): {fakeServiceExternalIP1, fakeExternalIPPoolName, fakeNode2}, }, healthyNodes: []string{fakeNode1, fakeNode2}, expectedCalls: func(mockIPAssigner *ipassignertest.MockIPAssigner) { @@ -621,29 +581,6 @@ func TestUpdateService(t *testing.T) { }, expectError: false, }, - { - name: "agent restarts and should not select new Node if current selected Node still healthy and have healthy endpoints", - endpoints: []*corev1.Endpoints{ - makeEndpoints(servicePolicyLocal.Name, servicePolicyLocal.Namespace, - map[string]string{ - "2.3.4.5": fakeNode1, - "2.3.4.6": fakeNode2, - }, - nil, - ), - }, - overrideHashFn: fakeHashFn(true), - serviceToUpdate: serviceExternalTrafficLocalWithNodeSelected, - previousExternalIPStates: map[apimachinerytypes.NamespacedName]externalIPState{}, - expectedExternalIPStates: map[apimachinerytypes.NamespacedName]externalIPState{ - keyFor(servicePolicyLocal): {fakeServiceExternalIP1, fakeNode1}, - }, - healthyNodes: []string{fakeNode1, fakeNode2}, - expectedCalls: func(mockIPAssigner *ipassignertest.MockIPAssigner) { - mockIPAssigner.EXPECT().AssignIP(fakeServiceExternalIP1) - }, - expectError: false, - }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -763,3 +700,66 @@ func TestServiceExternalIPController_nodesHasHealthyServiceEndpoint(t *testing.T }) } } + +func TestServiceExternalIPController_GetServiceExternalIPStatus(t *testing.T) { + tests := []struct { + name string + externalIPStates map[apimachinerytypes.NamespacedName]externalIPState + expectedServiceExternalIPInfo []querier.ServiceExternalIPInfo + }{ + { + name: "no Service available should return empty slice", + externalIPStates: map[apimachinerytypes.NamespacedName]externalIPState{}, + expectedServiceExternalIPInfo: []querier.ServiceExternalIPInfo{}, + }, + { + name: "one Service processed", + externalIPStates: map[apimachinerytypes.NamespacedName]externalIPState{ + keyFor(servicePolicyCluster): {fakeServiceExternalIP1, fakeExternalIPPoolName, fakeNode1}, + }, + expectedServiceExternalIPInfo: []querier.ServiceExternalIPInfo{ + { + + ServiceName: servicePolicyCluster.Name, + Namespace: servicePolicyCluster.Namespace, + ExternalIP: fakeServiceExternalIP1, + ExternalIPPool: fakeExternalIPPoolName, + AssignedNode: fakeNode1, + }, + }, + }, + { + name: "two Services processed", + externalIPStates: map[apimachinerytypes.NamespacedName]externalIPState{ + keyFor(servicePolicyCluster): {fakeServiceExternalIP1, fakeExternalIPPoolName, fakeNode1}, + keyFor(servicePolicyLocal): {fakeServiceExternalIP2, fakeExternalIPPoolName, fakeNode2}, + }, + expectedServiceExternalIPInfo: []querier.ServiceExternalIPInfo{ + { + + ServiceName: servicePolicyCluster.Name, + Namespace: servicePolicyCluster.Namespace, + ExternalIP: fakeServiceExternalIP1, + ExternalIPPool: fakeExternalIPPoolName, + AssignedNode: fakeNode1, + }, + { + + ServiceName: servicePolicyLocal.Name, + Namespace: servicePolicyLocal.Namespace, + ExternalIP: fakeServiceExternalIP2, + ExternalIPPool: fakeExternalIPPoolName, + AssignedNode: fakeNode2, + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + c := newFakeController(t) + c.externalIPStates = tt.externalIPStates + got := c.ServiceExternalIPController.GetServiceExternalIPStatus() + assert.ElementsMatch(t, tt.expectedServiceExternalIPInfo, got) + }) + } +} diff --git a/pkg/agent/flowexporter/connections/connections.go b/pkg/agent/flowexporter/connections/connections.go index c76aadddab6..432909b3c34 100644 --- a/pkg/agent/flowexporter/connections/connections.go +++ b/pkg/agent/flowexporter/connections/connections.go @@ -70,7 +70,20 @@ func (cs *connectionStore) ForAllConnectionsDo(callback flowexporter.ConnectionM for k, v := range cs.connections { err := callback(k, v) if err != nil { - klog.Errorf("Callback execution failed for flow with key: %v, conn: %v, k, v: %v", k, v, err) + klog.ErrorS(err, "Callback execution failed for flow", "key", k, "conn", v) + return err + } + } + return nil +} + +// ForAllConnectionsDoWithoutLock execute the callback for each connection in connection +// map, without grabbing the lock. Caller is expected to grab lock. +func (cs *connectionStore) ForAllConnectionsDoWithoutLock(callback flowexporter.ConnectionMapCallBack) error { + for k, v := range cs.connections { + err := callback(k, v) + if err != nil { + klog.ErrorS(err, "Callback execution failed for flow", "key", k, "conn", v) return err } } diff --git a/pkg/agent/flowexporter/connections/conntrack_connections.go b/pkg/agent/flowexporter/connections/conntrack_connections.go index a573057cb6e..c4aa09361ea 100644 --- a/pkg/agent/flowexporter/connections/conntrack_connections.go +++ b/pkg/agent/flowexporter/connections/conntrack_connections.go @@ -96,29 +96,6 @@ func (cs *ConntrackConnectionStore) Run(stopCh <-chan struct{}) { // TODO: As optimization, only poll invalid/closed connections during every poll, and poll the established connections right before the export. func (cs *ConntrackConnectionStore) Poll() ([]int, error) { klog.V(2).Infof("Polling conntrack") - // Reset IsPresent flag for all connections in connection map before dumping - // flows in conntrack module. If the connection does not exist in conntrack - // table and has been exported, then we will delete it from connection map. - // In addition, if the connection was not exported for a specific time period, - // then we consider it to be stale and delete it. - deleteIfStaleOrResetConn := func(key flowexporter.ConnectionKey, conn *flowexporter.Connection) error { - if !conn.IsPresent { - // Delete the connection if it is ready to delete or it was not exported - // in the time period as specified by the stale connection timeout. - if conn.ReadyToDelete || time.Since(conn.LastExportTime) >= cs.staleConnectionTimeout { - if err := cs.deleteConnWithoutLock(key); err != nil { - return err - } - } - } else { - conn.IsPresent = false - } - return nil - } - - if err := cs.ForAllConnectionsDo(deleteIfStaleOrResetConn); err != nil { - return []int{}, err - } var zones []uint16 var connsLens []int @@ -137,18 +114,53 @@ func (cs *ConntrackConnectionStore) Poll() ([]int, error) { } } var totalConns int + var filteredConnsList []*flowexporter.Connection for _, zone := range zones { - filteredConnsList, totalConnsPerZone, err := cs.connDumper.DumpFlows(zone) + filteredConnsListPerZone, totalConnsPerZone, err := cs.connDumper.DumpFlows(zone) if err != nil { return []int{}, err } totalConns += totalConnsPerZone - // Update only the Connection store. IPFIX records are generated based on Connection store. - for _, conn := range filteredConnsList { - cs.AddOrUpdateConn(conn) - } + filteredConnsList = append(filteredConnsList, filteredConnsListPerZone...) connsLens = append(connsLens, len(filteredConnsList)) } + + // Reset IsPresent flag for all connections in connection map before updating + // the dumped flows information in connection map. If the connection does not + // exist in conntrack table and has been exported, then we will delete it from + // connection map. In addition, if the connection was not exported for a specific + // time period, then we consider it to be stale and delete it. + deleteIfStaleOrResetConn := func(key flowexporter.ConnectionKey, conn *flowexporter.Connection) error { + if !conn.IsPresent { + // Delete the connection if it is ready to delete or it was not exported + // in the time period as specified by the stale connection timeout. + if conn.ReadyToDelete || time.Since(conn.LastExportTime) >= cs.staleConnectionTimeout { + if err := cs.deleteConnWithoutLock(key); err != nil { + return err + } + } + } else { + conn.IsPresent = false + } + return nil + } + + // Hold the lock until we verify whether the connection exist in conntrack table, + // and finish updating the connection store. + cs.AcquireConnStoreLock() + + if err := cs.ForAllConnectionsDoWithoutLock(deleteIfStaleOrResetConn); err != nil { + cs.ReleaseConnStoreLock() + return []int{}, err + } + + // Update only the Connection store. IPFIX records are generated based on Connection store. + for _, conn := range filteredConnsList { + cs.AddOrUpdateConn(conn) + } + + cs.ReleaseConnStoreLock() + metrics.TotalConnectionsInConnTrackTable.Set(float64(totalConns)) maxConns, err := cs.connDumper.GetMaxConnections() if err != nil { @@ -203,13 +215,12 @@ func (cs *ConntrackConnectionStore) addNetworkPolicyMetadata(conn *flowexporter. // AddOrUpdateConn updates the connection if it is already present, i.e., update timestamp, counters etc., // or adds a new connection with the resolved K8s metadata. func (cs *ConntrackConnectionStore) AddOrUpdateConn(conn *flowexporter.Connection) { + conn.IsPresent = true connKey := flowexporter.NewConnectionKey(conn) - cs.mutex.Lock() - defer cs.mutex.Unlock() existingConn, exists := cs.connections[connKey] if exists { - existingConn.IsPresent = true + existingConn.IsPresent = conn.IsPresent if flowexporter.IsConnectionDying(existingConn) { return } diff --git a/pkg/agent/flowexporter/connections/conntrack_connections_test.go b/pkg/agent/flowexporter/connections/conntrack_connections_test.go index f152fd7aec6..b2cfdebf243 100644 --- a/pkg/agent/flowexporter/connections/conntrack_connections_test.go +++ b/pkg/agent/flowexporter/connections/conntrack_connections_test.go @@ -118,6 +118,7 @@ func TestConntrackConnectionStore_AddOrUpdateConn(t *testing.T) { FlowKey: tuple1, Labels: []byte{0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0}, Mark: openflow.ServiceCTMark.GetValue(), + IsPresent: true, IsActive: true, DestinationPodName: "pod1", DestinationPodNamespace: "ns1", diff --git a/pkg/agent/memberlist/cluster_test.go b/pkg/agent/memberlist/cluster_test.go index 938a3194787..33f6c79957a 100644 --- a/pkg/agent/memberlist/cluster_test.go +++ b/pkg/agent/memberlist/cluster_test.go @@ -18,7 +18,6 @@ import ( "context" "fmt" "net" - "reflect" "testing" "time" @@ -152,20 +151,15 @@ func TestCluster_Run(t *testing.T) { go fakeCluster.cluster.Run(stopCh) - assert.NoError(t, wait.Poll(time.Millisecond*100, time.Second, func() (done bool, err error) { - newEIP, _ := fakeCluster.cluster.externalIPPoolLister.Get(eip.Name) - return reflect.DeepEqual(newEIP, eip), nil - })) - tCase.egress.Spec.ExternalIPPool = eip.Name - res, err := fakeCluster.cluster.ShouldSelectIP(tCase.egress.Spec.EgressIP, eip.Name) - // Cluster should hold the same consistent hash ring for each ExternalIPPool. - assert.NoError(t, err) + assert.NoError(t, wait.Poll(100*time.Millisecond, time.Second, func() (done bool, err error) { + res, err := fakeCluster.cluster.ShouldSelectIP(tCase.egress.Spec.EgressIP, eip.Name) + return err == nil && res == tCase.expectEgressSelectResult, nil + }), "select Node result for Egress does not match") allMembers, err := fakeCluster.cluster.allClusterMembers() assert.NoError(t, err) - assert.Equal(t, 1, len(allMembers), "expected Node member num is 1") + assert.Len(t, allMembers, 1, "expected Node member num is 1") assert.Equal(t, 1, fakeCluster.cluster.mList.NumMembers(), "expected alive Node num is 1") - assert.Equal(t, tCase.expectEgressSelectResult, res, "select Node for Egress result not match") }) } } @@ -207,11 +201,6 @@ func TestCluster_RunClusterEvents(t *testing.T) { go fakeCluster.cluster.Run(stopCh) - assert.NoError(t, wait.Poll(time.Millisecond*100, time.Second, func() (done bool, err error) { - newEIP, _ := fakeCluster.cluster.externalIPPoolLister.Get(fakeEIP1.Name) - return reflect.DeepEqual(newEIP, fakeEIP1), nil - })) - // Test updating Node labels. testCasesUpdateNode := []struct { name string @@ -249,18 +238,15 @@ func TestCluster_RunClusterEvents(t *testing.T) { if err != nil { t.Fatalf("Update Node error: %v", err) } - assert.NoError(t, wait.Poll(time.Millisecond*100, time.Second, func() (done bool, err error) { - newNode, _ := fakeCluster.cluster.nodeLister.Get(node.Name) - return reflect.DeepEqual(node, newNode), nil - })) } for _, tCase := range testCasesUpdateNode { t.Run(tCase.name, func(t *testing.T) { localNode.Labels = tCase.newNodeLabels updateNode(localNode) - res, err := fakeCluster.cluster.ShouldSelectIP(tCase.egress.Spec.EgressIP, tCase.egress.Spec.ExternalIPPool) - assert.NoError(t, err) - assert.Equal(t, tCase.expectEgressSelectResult, res, "select Node for Egress result not match") + assert.NoError(t, wait.Poll(100*time.Millisecond, time.Second, func() (done bool, err error) { + res, err := fakeCluster.cluster.ShouldSelectIP(tCase.egress.Spec.EgressIP, tCase.egress.Spec.ExternalIPPool) + return err == nil && res == tCase.expectEgressSelectResult, nil + }), "select Node result for Egress does not match") }) } @@ -300,13 +286,10 @@ func TestCluster_RunClusterEvents(t *testing.T) { if err != nil { t.Fatalf("Update ExternalIPPool error: %v", err) } - assert.NoError(t, wait.Poll(time.Millisecond*100, time.Second, func() (done bool, err error) { - newEIP, _ := fakeCluster.cluster.externalIPPoolLister.Get(fakeEIP1.Name) - return reflect.DeepEqual(fakeEIP1, newEIP), nil - })) - res, err := fakeCluster.cluster.ShouldSelectIP(fakeEgress1.Spec.EgressIP, fakeEgress1.Spec.ExternalIPPool) - assert.NoError(t, err) - assert.Equal(t, tCase.expectEgressSelectResult, res, "select Node for Egress result not match") + assert.NoError(t, wait.Poll(100*time.Millisecond, time.Second, func() (done bool, err error) { + res, err := fakeCluster.cluster.ShouldSelectIP(fakeEgress1.Spec.EgressIP, fakeEgress1.Spec.ExternalIPPool) + return err == nil && res == tCase.expectEgressSelectResult, nil + }), "select Node result for Egress does not match") }) } @@ -326,16 +309,15 @@ func TestCluster_RunClusterEvents(t *testing.T) { Spec: crdv1a2.EgressSpec{ExternalIPPool: fakeEIP2.Name, EgressIP: fakeEgressIP2}, } assert.NoError(t, createExternalIPPool(fakeCluster.crdClient, fakeEIP2)) - assert.NoError(t, wait.Poll(time.Millisecond*100, time.Second, func() (done bool, err error) { - newEIP, _ := fakeCluster.cluster.externalIPPoolLister.Get(fakeEIP2.Name) - return reflect.DeepEqual(newEIP, fakeEIP2), nil - })) + assertEgressSelectResult := func(egress *crdv1a2.Egress, expectedRes bool, hasSyncedErr bool) { - res, err := fakeCluster.cluster.ShouldSelectIP(egress.Spec.EgressIP, egress.Spec.ExternalIPPool) - if !hasSyncedErr { - assert.NoError(t, err) - } - assert.Equal(t, expectedRes, res, "select Node for Egress result not match") + assert.NoErrorf(t, wait.Poll(100*time.Millisecond, time.Second, func() (done bool, err error) { + res, err := fakeCluster.cluster.ShouldSelectIP(egress.Spec.EgressIP, egress.Spec.ExternalIPPool) + if hasSyncedErr { + return err != nil, nil + } + return err == nil && res == expectedRes, nil + }), "select Node result for Egress '%s' does not match", egress.Name) } assertEgressSelectResult(fakeEgress2, true, false) assertEgressSelectResult(fakeEgress1, false, false) @@ -346,10 +328,6 @@ func TestCluster_RunClusterEvents(t *testing.T) { if err != nil { t.Fatalf("Delete ExternalIPPool error: %v", err) } - assert.NoError(t, wait.Poll(time.Millisecond*100, time.Second, func() (done bool, err error) { - newEIP, _ := fakeCluster.cluster.externalIPPoolLister.Get(eipName) - return nil == newEIP, nil - })) } deleteExternalIPPool(fakeEIP2.Name) assertEgressSelectResult(fakeEgress2, false, true) @@ -390,10 +368,6 @@ func TestCluster_RunClusterEvents(t *testing.T) { if err != nil { t.Fatalf("Delete Node error: %v", err) } - assert.NoError(t, wait.Poll(time.Millisecond*100, time.Second, func() (done bool, err error) { - newNode, _ := fakeCluster.cluster.nodeLister.Get(node.Name) - return nil == newNode, nil - })) } deleteNode(localNode) assertEgressSelectResult(fakeEgress2, false, true) diff --git a/pkg/agent/multicast/mcast_controller.go b/pkg/agent/multicast/mcast_controller.go index c11a923371f..01188cba172 100644 --- a/pkg/agent/multicast/mcast_controller.go +++ b/pkg/agent/multicast/mcast_controller.go @@ -28,7 +28,11 @@ import ( "antrea.io/antrea/pkg/agent/config" "antrea.io/antrea/pkg/agent/interfacestore" "antrea.io/antrea/pkg/agent/openflow" + "antrea.io/antrea/pkg/agent/types" + "antrea.io/antrea/pkg/agent/util" + binding "antrea.io/antrea/pkg/ovs/openflow" "antrea.io/antrea/pkg/ovs/ovsconfig" + "antrea.io/antrea/pkg/util/channel" ) type eventType uint8 @@ -59,10 +63,11 @@ type mcastGroupEvent struct { type GroupMemberStatus struct { group net.IP - // localMembers is a set for the local Pod's interface name which has joined in the multicast group. - localMembers sets.String + // localMembers is a map for the local Pod member and its last update time, key is the Pod's interface name, + // and value is its last update time. + localMembers map[string]time.Time lastIGMPReport time.Time - mutex sync.RWMutex + ofGroupID binding.GroupIDType } // eventHandler process the multicast Group membership report or leave messages. @@ -82,7 +87,8 @@ func (c *Controller) addGroupMemberStatus(e *mcastGroupEvent) { status := &GroupMemberStatus{ group: e.group, lastIGMPReport: e.time, - localMembers: sets.NewString(e.iface.InterfaceName), + localMembers: map[string]time.Time{e.iface.InterfaceName: e.time}, + ofGroupID: c.v4GroupAllocator.Allocate(), } c.groupCache.Add(status) c.queue.Add(e.group.String()) @@ -97,29 +103,37 @@ func (c *Controller) addGroupMemberStatus(e *mcastGroupEvent) { // is sent out to check if there are still local members in the group. func (c *Controller) updateGroupMemberStatus(obj interface{}, e *mcastGroupEvent) { status := obj.(*GroupMemberStatus) - status.mutex.Lock() - defer status.mutex.Unlock() newStatus := &GroupMemberStatus{ group: status.group, - localMembers: status.localMembers.Union(nil), + localMembers: make(map[string]time.Time), lastIGMPReport: status.lastIGMPReport, + ofGroupID: status.ofGroupID, } - exist := status.localMembers.Has(e.iface.InterfaceName) + for m, t := range status.localMembers { + newStatus.localMembers[m] = t + } + _, exist := status.localMembers[e.iface.InterfaceName] switch e.eType { case groupJoin: newStatus.lastIGMPReport = e.time + newStatus.localMembers[e.iface.InterfaceName] = e.time + c.groupCache.Update(newStatus) if !exist { - newStatus.localMembers.Insert(e.iface.InterfaceName) klog.InfoS("Added member to multicast group", "group", e.group.String(), "member", e.iface.InterfaceName) + c.queue.Add(newStatus.group.String()) } - c.groupCache.Update(newStatus) - c.queue.Add(newStatus.group.String()) case groupLeave: if exist { - newStatus.localMembers.Delete(e.iface.InterfaceName) + delete(newStatus.localMembers, e.iface.InterfaceName) c.groupCache.Update(newStatus) klog.InfoS("Deleted member from multicast group", "group", e.group.String(), "member", e.iface.InterfaceName) - if len(newStatus.localMembers) == 0 { + _, found := c.ifaceStore.GetInterfaceByName(e.iface.InterfaceName) + // Notify worker immediately about the member leave event if the member doesn't exist on the Node, or there are + // other local members in the multicast group. + if !found || len(newStatus.localMembers) > 0 { + c.queue.Add(newStatus.group.String()) + } else { + // Check if all local members have left the multicast group. klog.InfoS("Check last member in multicast group", "group", e.group.String(), "member", e.iface.InterfaceName) c.checkLastMember(e.group) } @@ -139,62 +153,118 @@ func (c *Controller) checkLastMember(group net.IP) { c.queue.AddAfter(group.String(), igmpMaxResponseTime) } -// clearStaleGroups checks the stale groups which have not been updated for mcastGroupTimeout, and then notifies worker +// clearStaleGroups checks the stale group members which have not been updated for c.mcastGroupTimeout, and then notifies worker // to remove them from groupCache. func (c *Controller) clearStaleGroups() { now := time.Now() for _, obj := range c.groupCache.List() { status := obj.(*GroupMemberStatus) - status.mutex.RLock() diff := now.Sub(status.lastIGMPReport) - status.mutex.RUnlock() - if diff > mcastGroupTimeout { + if diff > c.mcastGroupTimeout { + // Notify worker to remove the group from groupCache if all its members are not updated before mcastGroupTimeout. c.queue.Add(status.group.String()) + } else { + // Create a "leave" event for a local member if it is not updated before mcastGroupTimeout. + for member, lastUpdate := range status.localMembers { + if now.Sub(lastUpdate) > c.mcastGroupTimeout { + ifConfig := &interfacestore.InterfaceConfig{ + InterfaceName: member, + } + event := &mcastGroupEvent{ + group: status.group, + eType: groupLeave, + time: now, + iface: ifConfig, + } + c.groupEventCh <- event + } + } } } } +// removeLocalInterface searches the GroupMemberStatus which the deleted interface has joined, and then triggers a member +// leave event so that Antrea can remove the corresponding interface from local multicast receivers on OVS. This function +// should be called if the removed Pod receiver fails to send IGMP leave message before deletion. +func (c *Controller) removeLocalInterface(e interface{}) { + podEvent := e.(types.PodUpdate) + // Ignore Pod creation event. + if podEvent.IsAdd { + return + } + interfaceName := util.GenerateContainerInterfaceName(podEvent.PodName, podEvent.PodNamespace, podEvent.ContainerID) + ifConfig := &interfacestore.InterfaceConfig{ + InterfaceName: interfaceName, + } + groupStatuses := c.getGroupMemberStatusesByPod(interfaceName) + for _, g := range groupStatuses { + event := &mcastGroupEvent{ + group: g.group, + eType: groupLeave, + time: time.Now(), + iface: ifConfig, + } + c.groupEventCh <- event + } +} + type Controller struct { - ofClient openflow.Client - nodeConfig *config.NodeConfig - igmpSnooper *IGMPSnooper - groupEventCh chan *mcastGroupEvent - groupCache cache.Indexer - queue workqueue.RateLimitingInterface + ofClient openflow.Client + v4GroupAllocator openflow.GroupAllocator + ifaceStore interfacestore.InterfaceStore + nodeConfig *config.NodeConfig + igmpSnooper *IGMPSnooper + groupEventCh chan *mcastGroupEvent + groupCache cache.Indexer + queue workqueue.RateLimitingInterface // installedGroups saves the groups which are configured on both OVS and the host. installedGroups sets.String installedGroupsMutex sync.RWMutex mRouteClient *MRouteClient ovsBridgeClient ovsconfig.OVSBridgeClient + + // queryInterval is the interval to send IGMP query messages. + queryInterval time.Duration + // mcastGroupTimeout is the timeout to detect a group as stale if no IGMP report is received within the time. + mcastGroupTimeout time.Duration } -func NewMulticastController(ofClient openflow.Client, nodeConfig *config.NodeConfig, ifaceStore interfacestore.InterfaceStore, multicastSocket RouteInterface, multicastInterfaces sets.String, ovsBridgeClient ovsconfig.OVSBridgeClient) *Controller { +func NewMulticastController(ofClient openflow.Client, + v4GroupAllocator openflow.GroupAllocator, + nodeConfig *config.NodeConfig, + ifaceStore interfacestore.InterfaceStore, + multicastSocket RouteInterface, + multicastInterfaces sets.String, + ovsBridgeClient ovsconfig.OVSBridgeClient, + podUpdateSubscriber channel.Subscriber, + igmpQueryInterval time.Duration) *Controller { eventCh := make(chan *mcastGroupEvent, workerCount) - groupSnooper := newSnooper(ofClient, ifaceStore, eventCh) + groupSnooper := newSnooper(ofClient, ifaceStore, eventCh, igmpQueryInterval) groupCache := cache.NewIndexer(getGroupEventKey, cache.Indexers{ podInterfaceIndex: podInterfaceIndexFunc, }) multicastRouteClient := newRouteClient(nodeConfig, groupCache, multicastSocket, multicastInterfaces) - return &Controller{ - ofClient: ofClient, - nodeConfig: nodeConfig, - igmpSnooper: groupSnooper, - groupEventCh: eventCh, - groupCache: groupCache, - installedGroups: sets.NewString(), - queue: workqueue.NewNamedRateLimitingQueue(workqueue.NewItemExponentialFailureRateLimiter(minRetryDelay, maxRetryDelay), "multicastgroup"), - mRouteClient: multicastRouteClient, - ovsBridgeClient: ovsBridgeClient, + c := &Controller{ + ofClient: ofClient, + ifaceStore: ifaceStore, + v4GroupAllocator: v4GroupAllocator, + nodeConfig: nodeConfig, + igmpSnooper: groupSnooper, + groupEventCh: eventCh, + groupCache: groupCache, + installedGroups: sets.NewString(), + queue: workqueue.NewNamedRateLimitingQueue(workqueue.NewItemExponentialFailureRateLimiter(minRetryDelay, maxRetryDelay), "multicastgroup"), + mRouteClient: multicastRouteClient, + ovsBridgeClient: ovsBridgeClient, + queryInterval: igmpQueryInterval, + mcastGroupTimeout: igmpQueryInterval * 3, } + podUpdateSubscriber.Subscribe(c.removeLocalInterface) + return c } func (c *Controller) Initialize() error { - err := c.configureOVSMulticast() - if err != nil { - klog.ErrorS(err, "Failed to configure multicast for the OVS bridge") - return err - } - err = c.mRouteClient.Initialize() + err := c.mRouteClient.Initialize() if err != nil { return err } @@ -217,11 +287,10 @@ func (c *Controller) Run(stopCh <-chan struct{}) { if err := c.igmpSnooper.queryIGMP(net.IPv4zero, queryVersions); err != nil { klog.ErrorS(err, "Failed to send IGMP query") } - }, queryInterval, stopCh) + }, c.queryInterval, stopCh) // Periodically check the group member status, and remove the groups in which no members exist - go wait.NonSlidingUntil(c.clearStaleGroups, queryInterval, stopCh) - + go wait.NonSlidingUntil(c.clearStaleGroups, c.queryInterval, stopCh) go c.eventHandler(stopCh) for i := 0; i < int(workerCount); i++ { @@ -298,15 +367,28 @@ func (c *Controller) syncGroup(groupKey string) error { return nil } status := obj.(*GroupMemberStatus) + memberPorts := make([]uint32, 0, len(status.localMembers)) + for memberInterfaceName := range status.localMembers { + obj, found := c.ifaceStore.GetInterfaceByName(memberInterfaceName) + if !found { + klog.InfoS("Failed to find interface from cache", "interface", memberInterfaceName) + continue + } + memberPorts = append(memberPorts, uint32(obj.OFPort)) + } if c.groupHasInstalled(groupKey) { - status.mutex.Lock() - defer status.mutex.Unlock() if c.groupIsStale(status) { // Remove the multicast flow entry if no local Pod is in the group. - if err := c.ofClient.UninstallMulticastFlow(status.group); err != nil { + if err := c.ofClient.UninstallMulticastFlows(status.group); err != nil { klog.ErrorS(err, "Failed to uninstall multicast flows", "group", groupKey) return err } + // Remove the multicast flow entry if no local Pod is in the group. + if err := c.ofClient.UninstallGroup(status.ofGroupID); err != nil { + klog.ErrorS(err, "Failed to uninstall multicast group", "group", groupKey) + return err + } + c.v4GroupAllocator.Release(status.ofGroupID) err := c.mRouteClient.deleteInboundMrouteEntryByGroup(status.group) if err != nil { klog.ErrorS(err, "Cannot delete multicast group", "group", groupKey) @@ -320,10 +402,22 @@ func (c *Controller) syncGroup(groupKey string) error { c.delInstalledGroup(groupKey) c.groupCache.Delete(status) klog.InfoS("Removed multicast group from cache after all members left", "group", groupKey) + return nil } + // Reinstall OpenFlow group because the local Pod receivers have changed. + if err := c.ofClient.InstallMulticastGroup(status.ofGroupID, memberPorts); err != nil { + return err + } + klog.V(2).InfoS("Updated OpenFlow group for local receivers", "group", groupKey, "ofGroup", status.ofGroupID, "localReceivers", memberPorts) return nil } - if err := c.ofClient.InstallMulticastFlow(status.group); err != nil { + // Install OpenFlow group for a new multicast group which has local Pod receivers joined. + if err := c.ofClient.InstallMulticastGroup(status.ofGroupID, memberPorts); err != nil { + return err + } + klog.V(2).InfoS("Installed OpenFlow group for local receivers", "group", groupKey, "ofGroup", status.ofGroupID, "localReceivers", memberPorts) + // Install OpenFlow flow to forward packets to local Pod receivers which are included in the group. + if err := c.ofClient.InstallMulticastFlows(status.group, status.ofGroupID); err != nil { klog.ErrorS(err, "Failed to install multicast flows", "group", status.group) return err } @@ -335,11 +429,11 @@ func (c *Controller) syncGroup(groupKey string) error { return nil } -// groupIsStale returns true if no local members in the group, or there is no IGMP report received after mcastGroupTimeout. +// groupIsStale returns true if no local members in the group, or there is no IGMP report received after c.mcastGroupTimeout. func (c *Controller) groupIsStale(status *GroupMemberStatus) bool { membersCount := len(status.localMembers) diff := time.Now().Sub(status.lastIGMPReport) - if membersCount == 0 || diff > mcastGroupTimeout { + if membersCount == 0 || diff > c.mcastGroupTimeout { return true } return false @@ -388,21 +482,6 @@ func podInterfaceIndexFunc(obj interface{}) ([]string, error) { return podInterfaces, nil } -func (c *Controller) configureOVSMulticast() error { - // Configure bridge to enable multicast snooping. - err := c.ovsBridgeClient.SetBridgeMcastSnooping(true) - if err != nil { - return err - } - // Disable flooding of unregistered multicast packets to all ports. - otherConfig := map[string]interface{}{"mcast-snooping-disable-flood-unregistered": "true"} - err = c.ovsBridgeClient.AddBridgeOtherConfig(otherConfig) - if err != nil { - return err - } - return nil -} - func getGroupEventKey(obj interface{}) (string, error) { groupState := obj.(*GroupMemberStatus) return groupState.group.String(), nil diff --git a/pkg/agent/multicast/mcast_controller_test.go b/pkg/agent/multicast/mcast_controller_test.go index 9918b5ffeb6..1f57b503f30 100644 --- a/pkg/agent/multicast/mcast_controller_test.go +++ b/pkg/agent/multicast/mcast_controller_test.go @@ -36,8 +36,10 @@ import ( "antrea.io/antrea/pkg/agent/interfacestore" ifaceStoretest "antrea.io/antrea/pkg/agent/interfacestore/testing" multicasttest "antrea.io/antrea/pkg/agent/multicast/testing" + "antrea.io/antrea/pkg/agent/openflow" openflowtest "antrea.io/antrea/pkg/agent/openflow/testing" ovsconfigtest "antrea.io/antrea/pkg/ovs/ovsconfig/testing" + "antrea.io/antrea/pkg/util/channel" ) var ( @@ -45,16 +47,21 @@ var ( mockMulticastSocket *multicasttest.MockRouteInterface mockIfaceStore *ifaceStoretest.MockInterfaceStore ovsClient *ovsconfigtest.MockOVSBridgeClient - mgroup = net.ParseIP("224.96.1.3") if1 = &interfacestore.InterfaceConfig{ Type: interfacestore.ContainerInterface, InterfaceName: "if1", IPs: []net.IP{net.ParseIP("192.168.1.1")}, + OVSPortConfig: &interfacestore.OVSPortConfig{ + OFPort: 1, + }, } if2 = &interfacestore.InterfaceConfig{ Type: interfacestore.ContainerInterface, InterfaceName: "if2", IPs: []net.IP{net.ParseIP("192.168.1.2")}, + OVSPortConfig: &interfacestore.OVSPortConfig{ + OFPort: 2, + }, } nodeIf1IP = net.ParseIP("192.168.20.22") externalInterfaceIP = net.ParseIP("192.168.50.23") @@ -63,6 +70,7 @@ var ( ) func TestAddGroupMemberStatus(t *testing.T) { + mgroup := net.ParseIP("224.96.1.3") event := &mcastGroupEvent{ group: mgroup, eType: groupJoin, @@ -82,7 +90,9 @@ func TestAddGroupMemberStatus(t *testing.T) { key, ok := obj.(string) assert.True(t, ok) assert.Equal(t, mgroup.String(), key) - mockOFClient.EXPECT().InstallMulticastFlow(mgroup).Times(1) + mockIfaceStore.EXPECT().GetInterfaceByName(if1.InterfaceName).Return(if1, true) + mockOFClient.EXPECT().InstallMulticastGroup(gomock.Any(), gomock.Any()) + mockOFClient.EXPECT().InstallMulticastFlows(mgroup, gomock.Any()).Times(1) mockMulticastSocket.EXPECT().MulticastInterfaceJoinMgroup(mgroup.To4(), nodeIf1IP.To4(), if1.InterfaceName).Times(1) err = mctrl.syncGroup(key) assert.Nil(t, err) @@ -94,6 +104,7 @@ func TestUpdateGroupMemberStatus(t *testing.T) { err := mctrl.initialize(t) assert.Nil(t, err) igmpMaxResponseTime = time.Second * 1 + mgroup := net.ParseIP("224.96.1.4") event := &mcastGroupEvent{ group: mgroup, eType: groupJoin, @@ -101,7 +112,6 @@ func TestUpdateGroupMemberStatus(t *testing.T) { iface: if1, } mctrl.addGroupMemberStatus(event) - obj, _, _ := mctrl.groupCache.GetByKey(event.group.String()) mockOFClient.EXPECT().SendIGMPQueryPacketOut(igmpQueryDstMac, mcastAllHosts, uint32(openflow13.P_NORMAL), gomock.Any()).Times(len(queryVersions)) for _, e := range []*mcastGroupEvent{ {group: mgroup, eType: groupJoin, time: event.time.Add(time.Second * 20), iface: if1}, @@ -110,6 +120,10 @@ func TestUpdateGroupMemberStatus(t *testing.T) { {group: mgroup, eType: groupLeave, time: event.time.Add(time.Second * 61), iface: if1}, {group: mgroup, eType: groupLeave, time: event.time.Add(time.Second * 62), iface: if2}, } { + obj, _, _ := mctrl.groupCache.GetByKey(event.group.String()) + if e.eType == groupLeave { + mockIfaceStore.EXPECT().GetInterfaceByName(e.iface.InterfaceName).Return(e.iface, true) + } mctrl.updateGroupMemberStatus(obj, e) groupCache := mctrl.groupCache compareGroupStatus(t, groupCache, e) @@ -127,15 +141,22 @@ func TestCheckLastMember(t *testing.T) { workerCount = 1 igmpMaxResponseTime = time.Second * 1 lastProbe := time.Now() + mgroup := net.ParseIP("224.96.1.2") testCheckLastMember := func(ev *mcastGroupEvent, expExist bool) { status := &GroupMemberStatus{ - localMembers: sets.NewString(), + localMembers: map[string]time.Time{}, lastIGMPReport: lastProbe, } if ev != nil { status.group = ev.group + if ev.eType == groupLeave { + mockOFClient.EXPECT().UninstallGroup(gomock.Any()) + mockOFClient.EXPECT().UninstallMulticastFlows(status.group) + } } else { status.group = mgroup + mockOFClient.EXPECT().UninstallGroup(gomock.Any()) + mockOFClient.EXPECT().UninstallMulticastFlows(status.group) } _ = mctrl.groupCache.Add(status) mctrl.addInstalledGroup(status.group.String()) @@ -167,7 +188,8 @@ func TestCheckLastMember(t *testing.T) { } mctrl.queue.Forget(obj) } - mockOFClient.EXPECT().UninstallMulticastFlow(gomock.Any()).Times(2) + mockIfaceStore.EXPECT().GetInterfaceByName(if1.InterfaceName).Return(if1, true).Times(1) + mockOFClient.EXPECT().InstallMulticastGroup(gomock.Any(), gomock.Any()).Times(1) for _, tc := range []struct { ev *mcastGroupEvent exists bool @@ -194,30 +216,31 @@ func TestClearStaleGroups(t *testing.T) { mctrl.worker() wg.Done() }() - now := time.Now() + validUpdateTime := now.Add(-mctrl.queryInterval) validGroups := []*GroupMemberStatus{ { group: net.ParseIP("224.96.1.2"), - localMembers: sets.NewString("p1", "p2"), - lastIGMPReport: now.Add(-queryInterval), + localMembers: map[string]time.Time{"p1": now, "p2": validUpdateTime}, + lastIGMPReport: validUpdateTime, }, { group: net.ParseIP("224.96.1.3"), - localMembers: sets.NewString(), - lastIGMPReport: now.Add(-queryInterval), + localMembers: map[string]time.Time{"p2": validUpdateTime}, + lastIGMPReport: validUpdateTime, }, } + staleUpdateTime := now.Add(-mctrl.mcastGroupTimeout - time.Second) staleGroups := []*GroupMemberStatus{ { group: net.ParseIP("224.96.1.4"), - localMembers: sets.NewString("p1", "p3"), - lastIGMPReport: now.Add(-mcastGroupTimeout - time.Second), + localMembers: map[string]time.Time{"p1": staleUpdateTime, "p3": staleUpdateTime}, + lastIGMPReport: staleUpdateTime, }, { group: net.ParseIP("224.96.1.5"), - localMembers: sets.NewString(), - lastIGMPReport: now.Add(-mcastGroupTimeout - time.Second), + localMembers: map[string]time.Time{}, + lastIGMPReport: staleUpdateTime, }, } for _, g := range validGroups { @@ -225,12 +248,19 @@ func TestClearStaleGroups(t *testing.T) { assert.Nil(t, err) mctrl.addInstalledGroup(g.group.String()) } + fakePort := int32(1) for _, g := range staleGroups { err := mctrl.groupCache.Add(g) assert.Nil(t, err) mctrl.addInstalledGroup(g.group.String()) + for m := range g.localMembers { + mockIface := &interfacestore.InterfaceConfig{InterfaceName: m, OVSPortConfig: &interfacestore.OVSPortConfig{OFPort: fakePort}} + mockIfaceStore.EXPECT().GetInterfaceByName(m).Return(mockIface, true) + fakePort++ + } } - mockOFClient.EXPECT().UninstallMulticastFlow(gomock.Any()).Times(len(staleGroups)) + mockOFClient.EXPECT().UninstallGroup(gomock.Any()).Times(len(staleGroups)) + mockOFClient.EXPECT().UninstallMulticastFlows(gomock.Any()).Times(len(staleGroups)) mockMulticastSocket.EXPECT().MulticastInterfaceLeaveMgroup(gomock.Any(), gomock.Any(), gomock.Any()).Times(len(staleGroups)) mctrl.clearStaleGroups() mctrl.queue.ShutDown() @@ -251,7 +281,9 @@ func TestProcessPacketIn(t *testing.T) { snooper := mockController.igmpSnooper stopCh := make(chan struct{}) defer close(stopCh) - go mockController.eventHandler(stopCh) + go func() { + mockController.eventHandler(stopCh) + }() getIPs := func(ipStrs []string) []net.IP { ips := make([]net.IP, len(ipStrs)) @@ -285,6 +317,7 @@ func TestProcessPacketIn(t *testing.T) { version: 3, }, } { + mockIfaceStore.EXPECT().GetInterfaceByName(tc.iface.InterfaceName).Return(tc.iface, true).AnyTimes() packets := createIGMPReportPacketIn(getIPs(tc.joinedGroups.List()), getIPs(tc.leftGroups.List()), tc.version, uint32(tc.iface.OFPort)) mockOFClient.EXPECT().SendIGMPQueryPacketOut(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes() for _, pkt := range packets { @@ -311,11 +344,11 @@ func compareGroupStatus(t *testing.T, cache cache.Indexer, event *mcastGroupEven assert.Equal(t, event.group, status.group) if event.eType == groupJoin { assert.True(t, status.lastIGMPReport.Equal(event.time) || status.lastIGMPReport.After(event.time)) - exists := status.localMembers.Has(event.iface.InterfaceName) + _, exists := status.localMembers[event.iface.InterfaceName] assert.Truef(t, exists, "member is not added into cache") } else { assert.True(t, status.lastIGMPReport.Before(event.time)) - exists := status.localMembers.Has(event.iface.InterfaceName) + _, exists := status.localMembers[event.iface.InterfaceName] assert.Falsef(t, exists, "member is not removed from cache") } } @@ -329,13 +362,14 @@ func newMockMulticastController(t *testing.T) *Controller { addr := &net.IPNet{IP: nodeIf1IP, Mask: net.IPv4Mask(255, 255, 255, 0)} nodeConfig := &config.NodeConfig{GatewayConfig: &config.GatewayConfig{Name: "antrea-gw0"}, NodeIPv4Addr: addr} mockOFClient.EXPECT().RegisterPacketInHandler(gomock.Any(), gomock.Any(), gomock.Any()).Times(1) - mctrl := NewMulticastController(mockOFClient, nodeConfig, mockIfaceStore, mockMulticastSocket, sets.NewString(), ovsClient) + groupAllocator := openflow.NewGroupAllocator(false) + podUpdateSubscriber := channel.NewSubscribableChannel("PodUpdate", 100) + queryInterval := 5 * time.Second + mctrl := NewMulticastController(mockOFClient, groupAllocator, nodeConfig, mockIfaceStore, mockMulticastSocket, sets.NewString(), ovsClient, podUpdateSubscriber, queryInterval) return mctrl } func (c *Controller) initialize(t *testing.T) error { - ovsClient.EXPECT().SetBridgeMcastSnooping(true).Times(1) - ovsClient.EXPECT().AddBridgeOtherConfig(map[string]interface{}{"mcast-snooping-disable-flood-unregistered": "true"}).Times(1) mockOFClient.EXPECT().InstallMulticastInitialFlows(uint8(0)).Times(1) mockMulticastSocket.EXPECT().AllocateVIFs(gomock.Any(), uint16(0)).Times(1).Return([]uint16{0}, nil) mockMulticastSocket.EXPECT().AllocateVIFs(gomock.Any(), uint16(1)).Times(1).Return([]uint16{1, 2}, nil) diff --git a/pkg/agent/multicast/mcast_discovery.go b/pkg/agent/multicast/mcast_discovery.go index 5f418513ce3..e68da77bdf5 100644 --- a/pkg/agent/multicast/mcast_discovery.go +++ b/pkg/agent/multicast/mcast_discovery.go @@ -34,13 +34,6 @@ const ( IGMPProtocolNumber = 2 ) -const ( - // queryInterval is the interval to send IGMP query messages. - queryInterval = time.Second * 125 - // mcastGroupTimeout is the timeout to detect a group as stale if no IGMP report is received within the time. - mcastGroupTimeout = queryInterval * 3 -) - var ( // igmpMaxResponseTime is the maximum time allowed before sending a responding report which is used for the // "Max Resp Code" field in the IGMP query message. It is also the maximum time to wait for the IGMP report message @@ -52,9 +45,10 @@ var ( ) type IGMPSnooper struct { - ofClient openflow.Client - ifaceStore interfacestore.InterfaceStore - eventCh chan *mcastGroupEvent + ofClient openflow.Client + ifaceStore interfacestore.InterfaceStore + eventCh chan *mcastGroupEvent + queryInterval time.Duration } func (s *IGMPSnooper) HandlePacketIn(pktIn *ofctrl.PacketIn) error { @@ -99,7 +93,7 @@ func (s *IGMPSnooper) parseSrcInterface(pktIn *ofctrl.PacketIn) (*interfacestore func (s *IGMPSnooper) queryIGMP(group net.IP, versions []uint8) error { for _, version := range versions { - igmp, err := generateIGMPQueryPacket(group, version) + igmp, err := generateIGMPQueryPacket(group, version, s.queryInterval) if err != nil { return err } @@ -131,7 +125,7 @@ func (s *IGMPSnooper) processPacketIn(pktIn *ofctrl.PacketIn) error { fallthrough case protocol.IGMPv2Report: mgroup := igmp.(*protocol.IGMPv1or2).GroupAddress - klog.InfoS("Received IGMPv1or2 Report message", "group", mgroup.String(), "interface", iface.InterfaceName, "pod", podName) + klog.V(2).InfoS("Received IGMPv1or2 Report message", "group", mgroup.String(), "interface", iface.InterfaceName, "pod", podName) event := &mcastGroupEvent{ group: mgroup, eType: groupJoin, @@ -143,7 +137,7 @@ func (s *IGMPSnooper) processPacketIn(pktIn *ofctrl.PacketIn) error { msg := igmp.(*protocol.IGMPv3MembershipReport) for _, gr := range msg.GroupRecords { mgroup := gr.MulticastAddress - klog.InfoS("Received IGMPv3 Report message", "group", mgroup.String(), "interface", iface.InterfaceName, "pod", podName, "recordType", gr.Type, "sourceCount", gr.NumberOfSources) + klog.V(2).InfoS("Received IGMPv3 Report message", "group", mgroup.String(), "interface", iface.InterfaceName, "pod", podName, "recordType", gr.Type, "sourceCount", gr.NumberOfSources) evtType := groupJoin if (gr.Type == protocol.IGMPIsIn || gr.Type == protocol.IGMPToIn) && gr.NumberOfSources == 0 { evtType = groupLeave @@ -159,7 +153,7 @@ func (s *IGMPSnooper) processPacketIn(pktIn *ofctrl.PacketIn) error { case protocol.IGMPv2LeaveGroup: mgroup := igmp.(*protocol.IGMPv1or2).GroupAddress - klog.InfoS("Received IGMPv2 Leave message", "group", mgroup.String(), "interface", iface.InterfaceName, "pod", podName) + klog.V(2).InfoS("Received IGMPv2 Leave message", "group", mgroup.String(), "interface", iface.InterfaceName, "pod", podName) event := &mcastGroupEvent{ group: mgroup, eType: groupLeave, @@ -171,7 +165,7 @@ func (s *IGMPSnooper) processPacketIn(pktIn *ofctrl.PacketIn) error { return nil } -func generateIGMPQueryPacket(group net.IP, version uint8) (util.Message, error) { +func generateIGMPQueryPacket(group net.IP, version uint8, queryInterval time.Duration) (util.Message, error) { // The max response time field in IGMP protocol uses a value in units of 1/10 second. // See https://datatracker.ietf.org/doc/html/rfc2236 and https://datatracker.ietf.org/doc/html/rfc3376 respTime := uint8(igmpMaxResponseTime.Seconds() * 10) @@ -242,8 +236,8 @@ func parseIGMPPacket(pkt protocol.Ethernet) (protocol.IGMPMessage, error) { } } -func newSnooper(ofClient openflow.Client, ifaceStore interfacestore.InterfaceStore, eventCh chan *mcastGroupEvent) *IGMPSnooper { - d := &IGMPSnooper{ofClient: ofClient, ifaceStore: ifaceStore, eventCh: eventCh} +func newSnooper(ofClient openflow.Client, ifaceStore interfacestore.InterfaceStore, eventCh chan *mcastGroupEvent, queryInterval time.Duration) *IGMPSnooper { + d := &IGMPSnooper{ofClient: ofClient, ifaceStore: ifaceStore, eventCh: eventCh, queryInterval: queryInterval} ofClient.RegisterPacketInHandler(uint8(openflow.PacketInReasonMC), "MulticastGroupDiscovery", d) return d } diff --git a/pkg/agent/multicast/mcast_route_test.go b/pkg/agent/multicast/mcast_route_test.go index 081171e7c00..b9f4c14d69c 100644 --- a/pkg/agent/multicast/mcast_route_test.go +++ b/pkg/agent/multicast/mcast_route_test.go @@ -21,6 +21,7 @@ import ( "fmt" "net" "testing" + "time" "github.com/golang/mock/gomock" "github.com/stretchr/testify/assert" @@ -76,12 +77,12 @@ func TestProcessIGMPNocacheMsg(t *testing.T) { mRoute.internalInterfaceVIF = uint16(0) status1 := &GroupMemberStatus{ group: net.ParseIP("224.3.3.8"), - localMembers: sets.NewString("aa"), + localMembers: map[string]time.Time{"aa": time.Now()}, } mRoute.groupCache.Add(status1) status2 := &GroupMemberStatus{ group: net.ParseIP("224.3.3.9"), - localMembers: sets.NewString(), + localMembers: map[string]time.Time{}, } mRoute.groupCache.Add(status2) for _, m := range []struct { diff --git a/pkg/agent/nodeportlocal/k8s/annotations.go b/pkg/agent/nodeportlocal/k8s/annotations.go index 9f7a1ad3120..c5a69a73df8 100644 --- a/pkg/agent/nodeportlocal/k8s/annotations.go +++ b/pkg/agent/nodeportlocal/k8s/annotations.go @@ -1,6 +1,3 @@ -//go:build !windows -// +build !windows - // Copyright 2020 Antrea Authors // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -42,7 +39,8 @@ type NPLAnnotation struct { PodPort int `json:"podPort"` NodeIP string `json:"nodeIP"` NodePort int `json:"nodePort"` - Protocols []string `json:"protocols"` + Protocol string `json:"protocol"` + Protocols []string `json:"protocols"` // deprecated, array with a single member which is equal to the Protocol field } func toJSON(serialize interface{}) string { diff --git a/pkg/agent/nodeportlocal/k8s/npl_controller.go b/pkg/agent/nodeportlocal/k8s/npl_controller.go index ba152354aad..362dfa2bf63 100644 --- a/pkg/agent/nodeportlocal/k8s/npl_controller.go +++ b/pkg/agent/nodeportlocal/k8s/npl_controller.go @@ -1,6 +1,3 @@ -//go:build !windows -// +build !windows - // Copyright 2020 Antrea Authors // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -450,7 +447,7 @@ func (c *NPLController) handleAddUpdatePod(key string, obj interface{}) error { } } - nplAnnotationsRequiredMap := map[int]NPLAnnotation{} + nplAnnotationsRequiredMap := map[string]NPLAnnotation{} nplAnnotationsRequired := []NPLAnnotation{} hostPorts := make(map[string]int) @@ -494,7 +491,7 @@ func (c *NPLController) handleAddUpdatePod(key string, obj interface{}) error { return fmt.Errorf("failed to parse port number and protocol from %s for Pod %s: %v", targetPortProto, key, err) } podPorts[targetPortProto] = struct{}{} - portData := c.portTable.GetEntry(podIP, port) + portData := c.portTable.GetEntry(podIP, port, protocol) if portData != nil && !portData.ProtocolInUse(protocol) { // If the PortTable has an entry for the Pod but does not have an // entry with protocol, we enforce AddRule for the missing Protocol. @@ -513,14 +510,12 @@ func (c *NPLController) handleAddUpdatePod(key string, obj interface{}) error { nodePort = portData.NodePort } - if val, ok := nplAnnotationsRequiredMap[nodePort]; ok { - val.Protocols = append(val.Protocols, protocol) - nplAnnotationsRequiredMap[nodePort] = val - } else { - nplAnnotationsRequiredMap[nodePort] = NPLAnnotation{ + if _, ok := nplAnnotationsRequiredMap[portcache.NodePortProtoFormat(nodePort, protocol)]; !ok { + nplAnnotationsRequiredMap[portcache.NodePortProtoFormat(nodePort, protocol)] = NPLAnnotation{ PodPort: port, NodeIP: pod.Status.HostIP, NodePort: nodePort, + Protocol: protocol, Protocols: []string{protocol}, } } @@ -607,6 +602,7 @@ func (c *NPLController) waitForRulesInitialization() { NodePort: npl.NodePort, PodPort: npl.PodPort, PodIP: pod.Status.PodIP, + Protocol: npl.Protocol, Protocols: npl.Protocols, }) } diff --git a/pkg/agent/nodeportlocal/npl_agent_init.go b/pkg/agent/nodeportlocal/npl_agent_init.go index b2b09ef427f..16d1f1f87ff 100644 --- a/pkg/agent/nodeportlocal/npl_agent_init.go +++ b/pkg/agent/nodeportlocal/npl_agent_init.go @@ -1,6 +1,3 @@ -//go:build !windows -// +build !windows - // Copyright 2020 Antrea Authors // // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/pkg/agent/nodeportlocal/npl_agent_init_windows.go b/pkg/agent/nodeportlocal/npl_agent_init_windows.go deleted file mode 100644 index 607c450116d..00000000000 --- a/pkg/agent/nodeportlocal/npl_agent_init_windows.go +++ /dev/null @@ -1,45 +0,0 @@ -//go:build windows -// +build windows - -// Copyright 2020 Antrea Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package nodeportlocal - -import ( - "errors" - - "k8s.io/client-go/informers" - clientset "k8s.io/client-go/kubernetes" - "k8s.io/client-go/tools/cache" -) - -// InitializeNPLAgent starts NodePortLocal (NPL) agent. -// Currently NPL is disabled for windows. -func InitializeNPLAgent( - kubeClient clientset.Interface, - informerFactory informers.SharedInformerFactory, - startPort int, - endPort int, - nodeName string, - podInformer cache.SharedIndexInformer, -) (*windowsCtrl, error) { - return nil, errors.New("Windows Platform not supported for NPL") -} - -type windowsCtrl struct { -} - -func (*windowsCtrl) Run(stopCh <-chan struct{}) { -} diff --git a/pkg/agent/nodeportlocal/npl_agent_test.go b/pkg/agent/nodeportlocal/npl_agent_test.go index c577e7e99b0..2c1efbf0579 100644 --- a/pkg/agent/nodeportlocal/npl_agent_test.go +++ b/pkg/agent/nodeportlocal/npl_agent_test.go @@ -66,7 +66,7 @@ const ( func newPortTable(mockIPTables rules.PodPortRules, mockPortOpener portcache.LocalPortOpener) *portcache.PortTable { return &portcache.PortTable{ - NodePortTable: make(map[int]*portcache.NodePortData), + NodePortTable: make(map[string]*portcache.NodePortData), PodEndpointTable: make(map[string]*portcache.NodePortData), StartPort: defaultStartPort, EndPort: defaultEndPort, diff --git a/pkg/agent/nodeportlocal/portcache/port_table.go b/pkg/agent/nodeportlocal/portcache/port_table.go index e2e8506896d..a2923f74689 100644 --- a/pkg/agent/nodeportlocal/portcache/port_table.go +++ b/pkg/agent/nodeportlocal/portcache/port_table.go @@ -1,6 +1,3 @@ -//go:build !windows -// +build !windows - // Copyright 2020 Antrea Authors // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -22,33 +19,16 @@ import ( "io" "net" "sync" - "time" "k8s.io/klog/v2" "antrea.io/antrea/pkg/agent/nodeportlocal/rules" ) -var ( - supportedProtocols = []string{"tcp", "udp"} -) - // protocolSocketState represents the state of the socket corresponding to a // given (Node port, protocol) tuple. type protocolSocketState int -const ( - // stateOpen means that a listening socket has been opened for the - // protocol (as a means to reserve the port for this protocol), but no - // NPL rule has been installed for it. - stateOpen protocolSocketState = iota - // stateInUse means that a listening socket has been opened AND a NPL - // rule has been installed. - stateInUse - // stateClosed means that the socket has been closed. - stateClosed -) - type ProtocolSocketData struct { Protocol string State protocolSocketState @@ -80,28 +60,6 @@ func (d *NodePortData) ProtocolInUse(protocol string) bool { return false } -func (d *NodePortData) CloseSockets() error { - for idx := range d.Protocols { - protocolSocketData := &d.Protocols[idx] - switch protocolSocketData.State { - case stateClosed: - // already closed - continue - case stateInUse: - // should not happen - return fmt.Errorf("protocol %s is still in use, cannot release socket", protocolSocketData.Protocol) - case stateOpen: - if err := protocolSocketData.socket.Close(); err != nil { - return fmt.Errorf("error when releasing local port %d with protocol %s: %v", d.NodePort, protocolSocketData.Protocol, err) - } - protocolSocketData.State = stateClosed - default: - return fmt.Errorf("invalid protocol socket state") - } - } - return nil -} - type LocalPortOpener interface { OpenLocalPort(port int, protocol string) (io.Closer, error) } @@ -109,7 +67,7 @@ type LocalPortOpener interface { type localPortOpener struct{} type PortTable struct { - NodePortTable map[int]*NodePortData + NodePortTable map[string]*NodePortData PodEndpointTable map[string]*NodePortData StartPort int EndPort int @@ -121,7 +79,7 @@ type PortTable struct { func NewPortTable(start, end int) (*PortTable, error) { ptable := PortTable{ - NodePortTable: make(map[int]*NodePortData), + NodePortTable: make(map[string]*NodePortData), PodEndpointTable: make(map[string]*NodePortData), StartPort: start, EndPort: end, @@ -138,21 +96,10 @@ func NewPortTable(start, end int) (*PortTable, error) { func (pt *PortTable) CleanupAllEntries() { pt.tableLock.Lock() defer pt.tableLock.Unlock() - pt.NodePortTable = make(map[int]*NodePortData) + pt.NodePortTable = make(map[string]*NodePortData) pt.PodEndpointTable = make(map[string]*NodePortData) } -func (pt *PortTable) GetEntry(ip string, port int) *NodePortData { - pt.tableLock.RLock() - defer pt.tableLock.RUnlock() - // Return pointer to copy of data from the PodEndpointTable. - if data := pt.getEntryByPodIPPort(ip, port); data != nil { - dataCopy := *data - return &dataCopy - } - return nil -} - func (pt *PortTable) GetDataForPodIP(ip string) []NodePortData { pt.tableLock.RLock() defer pt.tableLock.RUnlock() @@ -173,195 +120,6 @@ func (pt *PortTable) getEntryByPodIPPort(ip string, port int) *NodePortData { return pt.PodEndpointTable[podIPPortFormat(ip, port)] } -func openSocketsForPort(localPortOpener LocalPortOpener, port int) ([]ProtocolSocketData, error) { - // port needs to be available for all supported protocols: we want to use the same port - // number for all protocols and we don't know at this point which protocols are needed. - protocols := make([]ProtocolSocketData, 0, len(supportedProtocols)) - for _, protocol := range supportedProtocols { - socket, err := localPortOpener.OpenLocalPort(port, protocol) - if err != nil { - klog.V(4).InfoS("Local port cannot be opened", "port", port, "protocol", protocol) - return protocols, err - } - protocols = append(protocols, ProtocolSocketData{ - Protocol: protocol, - State: stateOpen, - socket: socket, - }) - } - return protocols, nil -} - -func closeSockets(protocols []ProtocolSocketData) error { - for idx := range protocols { - protocolSocketData := &protocols[idx] - if protocolSocketData.State != stateOpen { - continue - } - if err := protocolSocketData.socket.Close(); err != nil { - return err - } - protocolSocketData.State = stateClosed - - } - return nil -} - -// closeSocketsOrRetry closes all provided sockets. In case of an error, it -// creates a goroutine to retry asynchronously. -func closeSocketsOrRetry(protocols []ProtocolSocketData) { - var err error - if err = closeSockets(protocols); err == nil { - return - } - // Unlikely that there could be transient errors when closing a socket, - // but just in case, we create a goroutine to retry. We make a copy of - // the protocols slice, since the calling goroutine may modify the - // original one. - protocolsCopy := make([]ProtocolSocketData, len(protocols)) - copy(protocolsCopy, protocols) - go func() { - const delay = 5 * time.Second - for { - klog.ErrorS(err, "Unexpected error when closing socket(s), will retry", "retryDelay", delay) - time.Sleep(delay) - if err = closeSockets(protocolsCopy); err == nil { - return - } - } - }() -} - -func (pt *PortTable) getFreePort(podIP string, podPort int) (int, []ProtocolSocketData, error) { - klog.V(2).InfoS("Looking for free Node port", "podIP", podIP, "podPort", podPort) - numPorts := pt.EndPort - pt.StartPort + 1 - for i := 0; i < numPorts; i++ { - port := pt.PortSearchStart + i - if port > pt.EndPort { - // handle wrap around - port = port - numPorts - } - if _, ok := pt.NodePortTable[port]; ok { - // port is already taken - continue - } - - protocols, err := openSocketsForPort(pt.LocalPortOpener, port) - if err != nil { - klog.V(4).InfoS("Port cannot be reserved, moving on to the next one", "port", port) - closeSocketsOrRetry(protocols) - continue - } - - pt.PortSearchStart = port + 1 - if pt.PortSearchStart > pt.EndPort { - pt.PortSearchStart = pt.StartPort - } - return port, protocols, nil - } - return 0, nil, fmt.Errorf("no free port found") -} - -func (pt *PortTable) AddRule(podIP string, podPort int, protocol string) (int, error) { - pt.tableLock.Lock() - defer pt.tableLock.Unlock() - npData := pt.getEntryByPodIPPort(podIP, podPort) - exists := (npData != nil) - if !exists { - nodePort, protocols, err := pt.getFreePort(podIP, podPort) - if err != nil { - return 0, err - } - npData = &NodePortData{ - NodePort: nodePort, - PodIP: podIP, - PodPort: podPort, - Protocols: protocols, - } - } - protocolSocketData := npData.FindProtocol(protocol) - if protocolSocketData == nil { - return 0, fmt.Errorf("unknown protocol %s", protocol) - } - if protocolSocketData.State == stateInUse { - return 0, fmt.Errorf("rule for %s:%d:%s already exists", podIP, podPort, protocol) - } - if protocolSocketData.State == stateClosed { - return 0, fmt.Errorf("invalid socket state for %s:%d:%s", podIP, podPort, protocol) - } - - nodePort := npData.NodePort - if err := pt.PodPortRules.AddRule(nodePort, podIP, podPort, protocol); err != nil { - return 0, err - } - - protocolSocketData.State = stateInUse - if !exists { - pt.NodePortTable[nodePort] = npData - pt.PodEndpointTable[podIPPortFormat(podIP, podPort)] = npData - } - return npData.NodePort, nil -} - -func (pt *PortTable) DeleteRule(podIP string, podPort int, protocol string) error { - pt.tableLock.Lock() - defer pt.tableLock.Unlock() - data := pt.getEntryByPodIPPort(podIP, podPort) - if data == nil { - // Delete not required when the PortTable entry does not exist - return nil - } - numProtocolsInUse := 0 - var protocolSocketData *ProtocolSocketData - for idx, pData := range data.Protocols { - if pData.State != stateInUse { - continue - } - numProtocolsInUse++ - if pData.Protocol == protocol { - protocolSocketData = &data.Protocols[idx] - } - } - if protocolSocketData != nil { - if err := pt.PodPortRules.DeleteRule(data.NodePort, podIP, podPort, protocol); err != nil { - return err - } - protocolSocketData.State = stateOpen - numProtocolsInUse-- - } - if numProtocolsInUse == 0 { - // Node port is not needed anymore: close all sockets and delete - // table entries. - if err := data.CloseSockets(); err != nil { - return err - } - delete(pt.NodePortTable, data.NodePort) - delete(pt.PodEndpointTable, podIPPortFormat(podIP, podPort)) - } - return nil -} - -func (pt *PortTable) DeleteRulesForPod(podIP string) error { - pt.tableLock.Lock() - defer pt.tableLock.Unlock() - podEntries := pt.getDataForPodIP(podIP) - for _, podEntry := range podEntries { - for len(podEntry.Protocols) > 0 { - protocolSocketData := podEntry.Protocols[0] - if err := pt.PodPortRules.DeleteRule(podEntry.NodePort, podIP, podEntry.PodPort, protocolSocketData.Protocol); err != nil { - return err - } - if err := protocolSocketData.socket.Close(); err != nil { - return fmt.Errorf("error when releasing local port %d with protocol %s: %v", podEntry.NodePort, protocolSocketData.Protocol, err) - } - podEntry.Protocols = podEntry.Protocols[1:] - } - delete(pt.NodePortTable, podEntry.NodePort) - delete(pt.PodEndpointTable, podIPPortFormat(podIP, podEntry.PodPort)) - } - return nil -} - func (pt *PortTable) RuleExists(podIP string, podPort int, protocol string) bool { pt.tableLock.RLock() defer pt.tableLock.RUnlock() @@ -371,77 +129,9 @@ func (pt *PortTable) RuleExists(podIP string, podPort int, protocol string) bool return false } -// syncRules ensures that contents of the port table matches the iptables rules present on the Node. -func (pt *PortTable) syncRules() error { - pt.tableLock.Lock() - defer pt.tableLock.Unlock() - nplPorts := make([]rules.PodNodePort, 0, len(pt.NodePortTable)) - for _, npData := range pt.NodePortTable { - protocols := make([]string, 0, len(supportedProtocols)) - for _, protocol := range npData.Protocols { - if protocol.State == stateInUse { - protocols = append(protocols, protocol.Protocol) - } - } - nplPorts = append(nplPorts, rules.PodNodePort{ - NodePort: npData.NodePort, - PodPort: npData.PodPort, - PodIP: npData.PodIP, - Protocols: protocols, - }) - } - return pt.PodPortRules.AddAllRules(nplPorts) -} - -// RestoreRules should be called on startup to restore a set of NPL rules. It is non-blocking but -// takes as a parameter a channel, synced, which will be closed when the necessary rules have been -// restored successfully. No other operations should be performed on the PortTable until the channel -// is closed. -func (pt *PortTable) RestoreRules(allNPLPorts []rules.PodNodePort, synced chan<- struct{}) error { - pt.tableLock.Lock() - defer pt.tableLock.Unlock() - for _, nplPort := range allNPLPorts { - protocols, err := openSocketsForPort(pt.LocalPortOpener, nplPort.NodePort) - if err != nil { - // This will be handled gracefully by the NPL controller: if there is an - // annotation using this port, it will be removed and replaced with a new - // one with a valid port mapping. - klog.ErrorS(err, "Cannot bind to local port, skipping it", "port", nplPort.NodePort) - closeSocketsOrRetry(protocols) - continue - } - - npData := &NodePortData{ - NodePort: nplPort.NodePort, - PodPort: nplPort.PodPort, - PodIP: nplPort.PodIP, - Protocols: protocols, - } - for _, protocol := range nplPort.Protocols { - protocolSocketData := npData.FindProtocol(protocol) - if protocolSocketData == nil { - return fmt.Errorf("unknown protocol %s", protocol) - } - protocolSocketData.State = stateInUse - } - pt.NodePortTable[nplPort.NodePort] = npData - pt.PodEndpointTable[podIPPortFormat(nplPort.PodIP, nplPort.PodPort)] = pt.NodePortTable[nplPort.NodePort] - } - // retry mechanism as iptables-restore can fail if other components (in Antrea or other - // software) are accessing iptables. - go func() { - defer close(synced) - var backoffTime = 2 * time.Second - for { - if err := pt.syncRules(); err != nil { - klog.ErrorS(err, "Failed to restore iptables rules", "backoff", backoffTime) - time.Sleep(backoffTime) - continue - } - break - } - }() - return nil +// nodePortProtoFormat formats the nodeport, protocol to string port:protocol. +func NodePortProtoFormat(nodeport int, protocol string) string { + return fmt.Sprintf("%d:%s", nodeport, protocol) } // podIPPortFormat formats the ip, port to string ip:port. diff --git a/pkg/agent/nodeportlocal/portcache/port_table_linux.go b/pkg/agent/nodeportlocal/portcache/port_table_linux.go new file mode 100644 index 00000000000..dbaa5a32b86 --- /dev/null +++ b/pkg/agent/nodeportlocal/portcache/port_table_linux.go @@ -0,0 +1,344 @@ +//go:build linux +// +build linux + +// Copyright 2022 Antrea Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package portcache + +import ( + "fmt" + "strconv" + "time" + + "k8s.io/klog/v2" + + "antrea.io/antrea/pkg/agent/nodeportlocal/rules" +) + +const ( + // stateOpen means that a listening socket has been opened for the + // protocol (as a means to reserve the port for this protocol), but no + // NPL rule has been installed for it. + stateOpen protocolSocketState = iota + // stateInUse means that a listening socket has been opened AND a NPL + // rule has been installed. + stateInUse + // stateClosed means that the socket has been closed. + stateClosed +) + +var ( + supportedProtocols = []string{"tcp", "udp"} +) + +func (pt *PortTable) GetEntry(ip string, port int, protocol string) *NodePortData { + var _ = protocol + pt.tableLock.RLock() + defer pt.tableLock.RUnlock() + // Return pointer to copy of data from the PodEndpointTable. + if data := pt.getEntryByPodIPPort(ip, port); data != nil { + dataCopy := *data + return &dataCopy + } + return nil +} + +func openSocketsForPort(localPortOpener LocalPortOpener, port int) ([]ProtocolSocketData, error) { + // Port needs to be available for all supported protocols: we want to use the same port + // number for all protocols and we don't know at this point which protocols are needed. + // This is to preserve the legacy behavior of allocating the same nodePort for all protocols. + protocols := make([]ProtocolSocketData, 0, len(supportedProtocols)) + for _, protocol := range supportedProtocols { + socket, err := localPortOpener.OpenLocalPort(port, protocol) + if err != nil { + klog.V(4).InfoS("Local port cannot be opened", "port", port, "protocol", protocol) + return protocols, err + } + protocols = append(protocols, ProtocolSocketData{ + Protocol: protocol, + State: stateOpen, + socket: socket, + }) + } + return protocols, nil +} + +func (pt *PortTable) getFreePort(podIP string, podPort int) (int, []ProtocolSocketData, error) { + klog.V(2).InfoS("Looking for free Node port", "podIP", podIP, "podPort", podPort) + numPorts := pt.EndPort - pt.StartPort + 1 + for i := 0; i < numPorts; i++ { + port := pt.PortSearchStart + i + if port > pt.EndPort { + // handle wrap around + port = port - numPorts + } + if _, ok := pt.NodePortTable[strconv.Itoa(port)]; ok { + // port is already taken + continue + } + + protocols, err := openSocketsForPort(pt.LocalPortOpener, port) + if err != nil { + klog.V(4).InfoS("Port cannot be reserved, moving on to the next one", "port", port) + closeSocketsOrRetry(protocols) + continue + } + + pt.PortSearchStart = port + 1 + if pt.PortSearchStart > pt.EndPort { + pt.PortSearchStart = pt.StartPort + } + return port, protocols, nil + } + return 0, nil, fmt.Errorf("no free port found") +} + +func closeSockets(protocols []ProtocolSocketData) error { + for idx := range protocols { + protocolSocketData := &protocols[idx] + if protocolSocketData.State != stateOpen { + continue + } + if err := protocolSocketData.socket.Close(); err != nil { + return err + } + protocolSocketData.State = stateClosed + + } + return nil +} + +// closeSocketsOrRetry closes all provided sockets. In case of an error, it +// creates a goroutine to retry asynchronously. +func closeSocketsOrRetry(protocols []ProtocolSocketData) { + var err error + if err = closeSockets(protocols); err == nil { + return + } + // Unlikely that there could be transient errors when closing a socket, + // but just in case, we create a goroutine to retry. We make a copy of + // the protocols slice, since the calling goroutine may modify the + // original one. + protocolsCopy := make([]ProtocolSocketData, len(protocols)) + copy(protocolsCopy, protocols) + go func() { + const delay = 5 * time.Second + for { + klog.ErrorS(err, "Unexpected error when closing socket(s), will retry", "retryDelay", delay) + time.Sleep(delay) + if err = closeSockets(protocolsCopy); err == nil { + return + } + } + }() +} + +func (d *NodePortData) CloseSockets() error { + for idx := range d.Protocols { + protocolSocketData := &d.Protocols[idx] + switch protocolSocketData.State { + case stateClosed: + // already closed + continue + case stateInUse: + // should not happen + return fmt.Errorf("protocol %s is still in use, cannot release socket", protocolSocketData.Protocol) + case stateOpen: + if err := protocolSocketData.socket.Close(); err != nil { + return fmt.Errorf("error when releasing local port %d with protocol %s: %v", d.NodePort, protocolSocketData.Protocol, err) + } + protocolSocketData.State = stateClosed + default: + return fmt.Errorf("invalid protocol socket state") + } + } + return nil +} + +func (pt *PortTable) AddRule(podIP string, podPort int, protocol string) (int, error) { + pt.tableLock.Lock() + defer pt.tableLock.Unlock() + npData := pt.getEntryByPodIPPort(podIP, podPort) + exists := (npData != nil) + if !exists { + nodePort, protocols, err := pt.getFreePort(podIP, podPort) + if err != nil { + return 0, err + } + npData = &NodePortData{ + NodePort: nodePort, + PodIP: podIP, + PodPort: podPort, + Protocols: protocols, + } + } + protocolSocketData := npData.FindProtocol(protocol) + if protocolSocketData == nil { + return 0, fmt.Errorf("unknown protocol %s", protocol) + } + if protocolSocketData.State == stateInUse { + return 0, fmt.Errorf("rule for %s:%d:%s already exists", podIP, podPort, protocol) + } + if protocolSocketData.State == stateClosed { + return 0, fmt.Errorf("invalid socket state for %s:%d:%s", podIP, podPort, protocol) + } + + nodePort := npData.NodePort + if err := pt.PodPortRules.AddRule(nodePort, podIP, podPort, protocol); err != nil { + return 0, err + } + + protocolSocketData.State = stateInUse + if !exists { + pt.NodePortTable[strconv.Itoa(nodePort)] = npData + pt.PodEndpointTable[podIPPortFormat(podIP, podPort)] = npData + } + return npData.NodePort, nil +} + +func (pt *PortTable) DeleteRule(podIP string, podPort int, protocol string) error { + pt.tableLock.Lock() + defer pt.tableLock.Unlock() + data := pt.getEntryByPodIPPort(podIP, podPort) + if data == nil { + // Delete not required when the PortTable entry does not exist + return nil + } + numProtocolsInUse := 0 + var protocolSocketData *ProtocolSocketData + for idx, pData := range data.Protocols { + if pData.State != stateInUse { + continue + } + numProtocolsInUse++ + if pData.Protocol == protocol { + protocolSocketData = &data.Protocols[idx] + } + } + if protocolSocketData != nil { + if err := pt.PodPortRules.DeleteRule(data.NodePort, podIP, podPort, protocol); err != nil { + return err + } + protocolSocketData.State = stateOpen + numProtocolsInUse-- + } + if numProtocolsInUse == 0 { + // Node port is not needed anymore: close all sockets and delete + // table entries. + if err := data.CloseSockets(); err != nil { + return err + } + delete(pt.NodePortTable, strconv.Itoa(data.NodePort)) + delete(pt.PodEndpointTable, podIPPortFormat(podIP, podPort)) + } + return nil +} + +func (pt *PortTable) DeleteRulesForPod(podIP string) error { + pt.tableLock.Lock() + defer pt.tableLock.Unlock() + podEntries := pt.getDataForPodIP(podIP) + for _, podEntry := range podEntries { + for len(podEntry.Protocols) > 0 { + protocolSocketData := podEntry.Protocols[0] + if err := pt.PodPortRules.DeleteRule(podEntry.NodePort, podIP, podEntry.PodPort, protocolSocketData.Protocol); err != nil { + return err + } + if err := protocolSocketData.socket.Close(); err != nil { + return fmt.Errorf("error when releasing local port %d with protocol %s: %v", podEntry.NodePort, protocolSocketData.Protocol, err) + } + podEntry.Protocols = podEntry.Protocols[1:] + } + delete(pt.NodePortTable, strconv.Itoa(podEntry.NodePort)) + delete(pt.PodEndpointTable, podIPPortFormat(podIP, podEntry.PodPort)) + } + return nil +} + +// syncRules ensures that contents of the port table matches the iptables rules present on the Node. +func (pt *PortTable) syncRules() error { + pt.tableLock.Lock() + defer pt.tableLock.Unlock() + nplPorts := make([]rules.PodNodePort, 0, len(pt.NodePortTable)) + for _, npData := range pt.NodePortTable { + protocols := make([]string, 0, len(supportedProtocols)) + for _, protocol := range npData.Protocols { + if protocol.State == stateInUse { + protocols = append(protocols, protocol.Protocol) + } + } + nplPorts = append(nplPorts, rules.PodNodePort{ + NodePort: npData.NodePort, + PodPort: npData.PodPort, + PodIP: npData.PodIP, + Protocols: protocols, + }) + } + if err := pt.PodPortRules.AddAllRules(nplPorts); err != nil { + return err + } + return nil +} + +// RestoreRules should be called at Antrea Agent startup to restore a set of NPL rules. It is non-blocking but +// takes a channel parameter - synced, which will be closed when the necessary rules have been +// restored successfully. No other operations should be performed on the PortTable until the channel +// is closed. +func (pt *PortTable) RestoreRules(allNPLPorts []rules.PodNodePort, synced chan<- struct{}) error { + pt.tableLock.Lock() + defer pt.tableLock.Unlock() + for _, nplPort := range allNPLPorts { + protocols, err := openSocketsForPort(pt.LocalPortOpener, nplPort.NodePort) + if err != nil { + // This will be handled gracefully by the NPL controller: if there is an + // annotation using this port, it will be removed and replaced with a new + // one with a valid port mapping. + klog.ErrorS(err, "Cannot bind to local port, skipping it", "port", nplPort.NodePort) + closeSocketsOrRetry(protocols) + continue + } + + npData := &NodePortData{ + NodePort: nplPort.NodePort, + PodPort: nplPort.PodPort, + PodIP: nplPort.PodIP, + Protocols: protocols, + } + for _, protocol := range nplPort.Protocols { + protocolSocketData := npData.FindProtocol(protocol) + if protocolSocketData == nil { + return fmt.Errorf("unknown protocol %s", protocol) + } + protocolSocketData.State = stateInUse + } + pt.NodePortTable[strconv.Itoa(nplPort.NodePort)] = npData + pt.PodEndpointTable[podIPPortFormat(nplPort.PodIP, nplPort.PodPort)] = pt.NodePortTable[strconv.Itoa(nplPort.NodePort)] + } + // retry mechanism as iptables-restore can fail if other components (in Antrea or other + // software) are accessing iptables. + go func() { + defer close(synced) + var backoffTime = 2 * time.Second + for { + if err := pt.syncRules(); err != nil { + klog.ErrorS(err, "Failed to restore iptables rules", "backoff", backoffTime) + time.Sleep(backoffTime) + continue + } + break + } + }() + return nil +} diff --git a/pkg/agent/nodeportlocal/portcache/port_table_test.go b/pkg/agent/nodeportlocal/portcache/port_table_test.go index 6b681455a75..271ffcc2853 100644 --- a/pkg/agent/nodeportlocal/portcache/port_table_test.go +++ b/pkg/agent/nodeportlocal/portcache/port_table_test.go @@ -35,7 +35,7 @@ const ( func newPortTable(mockIPTables rules.PodPortRules, mockPortOpener LocalPortOpener) *PortTable { return &PortTable{ - NodePortTable: make(map[int]*NodePortData), + NodePortTable: make(map[string]*NodePortData), PodEndpointTable: make(map[string]*NodePortData), StartPort: startPort, EndPort: endPort, diff --git a/pkg/agent/nodeportlocal/portcache/port_table_windows.go b/pkg/agent/nodeportlocal/portcache/port_table_windows.go new file mode 100644 index 00000000000..ef5d6ee539a --- /dev/null +++ b/pkg/agent/nodeportlocal/portcache/port_table_windows.go @@ -0,0 +1,189 @@ +//go:build windows +// +build windows + +// Copyright 2022 Antrea Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package portcache + +import ( + "fmt" + + "k8s.io/klog/v2" + + "antrea.io/antrea/pkg/agent/nodeportlocal/rules" +) + +const ( + // stateInUse means that the NPL rule has been installed. + stateInUse protocolSocketState = 1 +) + +// podIPPortFormat formats the ip, port to string ip:port. +func podIPPortProtoFormat(ip string, port int, protocol string) string { + return fmt.Sprintf("%s:%d:%s", ip, port, protocol) +} + +func (pt *PortTable) getEntryByPodIPPortProto(ip string, port int, protocol string) *NodePortData { + return pt.PodEndpointTable[podIPPortProtoFormat(ip, port, protocol)] +} + +func (pt *PortTable) GetEntry(ip string, port int, protocol string) *NodePortData { + pt.tableLock.RLock() + defer pt.tableLock.RUnlock() + // Return pointer to copy of data from the PodEndpointTable. + if data := pt.getEntryByPodIPPortProto(ip, port, protocol); data != nil { + dataCopy := *data + return &dataCopy + } + return nil +} + +func addRuleForPort(podPortRules rules.PodPortRules, port int, podIP string, podPort int, protocol string) ([]ProtocolSocketData, error) { + // Only the protocol used here should be returned if NetNatStaticMapping rule + // can be inserted to an unused protocol port. + protocols := make([]ProtocolSocketData, 0, 1) + err := podPortRules.AddRule(port, podIP, podPort, protocol) + if err != nil { + klog.ErrorS(err, "Local port cannot be opened", "port", port, "protocol", protocol) + return nil, err + } + protocols = append(protocols, ProtocolSocketData{ + Protocol: protocol, + State: stateInUse, + socket: nil, + }) + return protocols, nil +} + +func (pt *PortTable) addRuleforFreePort(podIP string, podPort int, protocol string) (int, []ProtocolSocketData, error) { + klog.V(2).InfoS("Looking for free Node port on Windows", "podIP", podIP, "podPort", podPort, "protocol", protocol) + numPorts := pt.EndPort - pt.StartPort + 1 + for i := 0; i < numPorts; i++ { + port := pt.PortSearchStart + i + if port > pt.EndPort { + // handle wrap around + port = port - numPorts + } + if _, ok := pt.NodePortTable[NodePortProtoFormat(port, protocol)]; ok { + // protocol port is already taken + continue + } + + protocols, err := addRuleForPort(pt.PodPortRules, port, podIP, podPort, protocol) + if err != nil { + klog.ErrorS(err, "Port cannot be reserved, moving on to the next one", "port", port) + continue + } + + pt.PortSearchStart = port + 1 + if pt.PortSearchStart > pt.EndPort { + pt.PortSearchStart = pt.StartPort + } + return port, protocols, nil + } + return 0, nil, fmt.Errorf("no free port found") +} + +func (pt *PortTable) AddRule(podIP string, podPort int, protocol string) (int, error) { + pt.tableLock.Lock() + defer pt.tableLock.Unlock() + npData := pt.getEntryByPodIPPortProto(podIP, podPort, protocol) + exists := (npData != nil) + if !exists { + nodePort, protocols, err := pt.addRuleforFreePort(podIP, podPort, protocol) + //success means port, protocol available. + if err != nil { + return 0, err + } + npData = &NodePortData{ + NodePort: nodePort, + PodIP: podIP, + PodPort: podPort, + Protocols: protocols, + } + + pt.NodePortTable[NodePortProtoFormat(nodePort, protocol)] = npData + pt.PodEndpointTable[podIPPortProtoFormat(podIP, podPort, protocol)] = npData + } else { + // Only add rules for if the entry does not exist. + return 0, fmt.Errorf("existed windows nodeport entry for %s:%d:%s", podIP, podPort, protocol) + } + return npData.NodePort, nil +} + +// RestoreRules should be called at Antrea Agent startup to restore a set of NPL rules. +func (pt *PortTable) RestoreRules(allNPLPorts []rules.PodNodePort, synced chan<- struct{}) error { + pt.tableLock.Lock() + defer pt.tableLock.Unlock() + for _, nplPort := range allNPLPorts { + protocols, err := addRuleForPort(pt.PodPortRules, nplPort.NodePort, nplPort.PodIP, nplPort.PodPort, nplPort.Protocol) + if err != nil { + // This will be handled gracefully by the NPL controller: if there is an + // annotation using this port, it will be removed and replaced with a new + // one with a valid port mapping. + klog.ErrorS(err, "Cannot bind to local port, skipping it", "port", nplPort.NodePort) + continue + } + + npData := &NodePortData{ + NodePort: nplPort.NodePort, + PodPort: nplPort.PodPort, + PodIP: nplPort.PodIP, + Protocols: protocols, + } + pt.PodEndpointTable[podIPPortProtoFormat(nplPort.PodIP, nplPort.PodPort, nplPort.Protocol)] = pt.NodePortTable[NodePortProtoFormat(nplPort.NodePort, nplPort.Protocol)] + pt.NodePortTable[NodePortProtoFormat(nplPort.NodePort, nplPort.Protocol)] = npData + } + // No need to sync up again because addRuleForPort has updated all rules on Windows + close(synced) + return nil +} + +func (pt *PortTable) DeleteRule(podIP string, podPort int, protocol string) error { + pt.tableLock.Lock() + defer pt.tableLock.Unlock() + data := pt.getEntryByPodIPPortProto(podIP, podPort, protocol) + if data == nil { + // Delete not required when the PortTable entry does not exist + return nil + } + var protocolSocketData *ProtocolSocketData + protocolSocketData = &data.Protocols[0] + if protocolSocketData != nil { + if err := pt.PodPortRules.DeleteRule(data.NodePort, podIP, podPort, protocol); err != nil { + return err + } + } + delete(pt.NodePortTable, NodePortProtoFormat(data.NodePort, protocol)) + delete(pt.PodEndpointTable, podIPPortProtoFormat(podIP, podPort, protocol)) + return nil +} + +func (pt *PortTable) DeleteRulesForPod(podIP string) error { + pt.tableLock.Lock() + defer pt.tableLock.Unlock() + podEntries := pt.getDataForPodIP(podIP) + for _, podEntry := range podEntries { + if len(podEntry.Protocols) > 0 { + protocolSocketData := podEntry.Protocols[0] + if err := pt.PodPortRules.DeleteRule(podEntry.NodePort, podIP, podEntry.PodPort, protocolSocketData.Protocol); err != nil { + return err + } + delete(pt.PodEndpointTable, podIPPortProtoFormat(podIP, podEntry.PodPort, protocolSocketData.Protocol)) + delete(pt.NodePortTable, NodePortProtoFormat(podEntry.NodePort, protocolSocketData.Protocol)) + } + } + return nil +} diff --git a/pkg/agent/nodeportlocal/rules/iptable_rule.go b/pkg/agent/nodeportlocal/rules/iptable_rule.go index 6afe9cb9b33..def5bca618d 100644 --- a/pkg/agent/nodeportlocal/rules/iptable_rule.go +++ b/pkg/agent/nodeportlocal/rules/iptable_rule.go @@ -26,6 +26,12 @@ import ( "antrea.io/antrea/pkg/agent/util/iptables" ) +// InitRules initializes rules based on the underlying implementation +func InitRules() PodPortRules { + // This can be extended based on the system capability. + return NewIPTableRules() +} + // NodePortLocalChain is the name of the chain in IPTABLES for Node Port Local const NodePortLocalChain = "ANTREA-NODE-PORT-LOCAL" diff --git a/pkg/agent/nodeportlocal/rules/netnat_rule.go b/pkg/agent/nodeportlocal/rules/netnat_rule.go new file mode 100644 index 00000000000..e5c36effffc --- /dev/null +++ b/pkg/agent/nodeportlocal/rules/netnat_rule.go @@ -0,0 +1,110 @@ +//go:build windows +// +build windows + +// Copyright 2022 Antrea Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package rules + +import ( + "fmt" + + "k8s.io/klog/v2" + + "antrea.io/antrea/pkg/agent/route" + "antrea.io/antrea/pkg/agent/util" +) + +// Use antrea-nat netnatstaticmapping rules as NPL implementation +var ( + antreaNatNPL = util.AntreaNatName +) + +// InitRules initializes rules based on the netnatstaticmapping implementation on windows +func InitRules() PodPortRules { + return NewNetNatRules() +} + +type netnatRules struct { + name string +} + +// NewNetNatRules retruns a new instance of netnatRules. +func NewNetNatRules() *netnatRules { + nnRule := netnatRules{ + name: antreaNatNPL, + } + return &nnRule +} + +// Init initializes NetNat rules for NPL. +func (nn *netnatRules) Init() error { + if err := nn.initRules(); err != nil { + return fmt.Errorf("initialization of NPL netnat rules failed: %v", err) + } + return nil +} + +// initRules creates or reuses NetNat table as NPL rule instance on Windows. +func (nn *netnatRules) initRules() error { + nn.DeleteAllRules() + if err := util.NewNetNat(antreaNatNPL, route.PodCIDRIPv4); err != nil { + return err + } + klog.InfoS("Successfully created NetNat rule", "name", antreaNatNPL, "CIDR", route.PodCIDRIPv4) + return nil +} + +// AddRule appends a NetNatStaticMapping rule. +func (nn *netnatRules) AddRule(nodePort int, podIP string, podPort int, protocol string) error { + nodePort16 := util.PortToUint16(nodePort) + podPort16 := util.PortToUint16(podPort) + podAddr := fmt.Sprintf("%s:%d", podIP, podPort16) + if err := util.ReplaceNetNatStaticMapping(antreaNatNPL, "0.0.0.0", nodePort16, podIP, podPort16, protocol); err != nil { + return err + } + klog.InfoS("Successfully added NetNat rule", "podAddr", podAddr, "nodePort", nodePort16, "protocol", protocol) + return nil +} + +// AddAllRules constructs a list of NPL rules and performs NetNatStaticMapping replacement. +func (nn *netnatRules) AddAllRules(nplList []PodNodePort) error { + for _, nplData := range nplList { + if err := nn.AddRule(nplData.NodePort, nplData.PodIP, nplData.PodPort, nplData.Protocol); err != nil { + return err + } + } + return nil +} + +// DeleteRule deletes a specific NPL rule from NetNatStaticMapping table +func (nn *netnatRules) DeleteRule(nodePort int, podIP string, podPort int, protocol string) error { + nodePort16 := util.PortToUint16(nodePort) + podPort16 := util.PortToUint16(podPort) + podAddr := fmt.Sprintf("%s:%d", podIP, podPort16) + if err := util.RemoveNetNatStaticMappingByNPLTuples(antreaNatNPL, "0.0.0.0", nodePort16, podIP, podPort16, protocol); err != nil { + return err + } + klog.InfoS("Successfully deleted NetNatStaticMapping rule", "podAddr", podAddr, "nodePort", nodePort16, "protocol", protocol) + return nil +} + +// DeleteAllRules deletes the NetNatStaticMapping table in the node +func (nn *netnatRules) DeleteAllRules() error { + if err := util.RemoveNetNatStaticMappingByNAME(antreaNatNPL); err != nil { + return err + } + klog.InfoS("Successfully deleted all NPL NetNatStaticMapping rules", "NatName", antreaNatNPL) + return nil +} diff --git a/pkg/agent/nodeportlocal/rules/rules.go b/pkg/agent/nodeportlocal/rules/rules.go index 63e0f962927..bcf72e202e4 100644 --- a/pkg/agent/nodeportlocal/rules/rules.go +++ b/pkg/agent/nodeportlocal/rules/rules.go @@ -1,6 +1,3 @@ -//go:build !windows -// +build !windows - // Copyright 2020 Antrea Authors // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -25,9 +22,3 @@ type PodPortRules interface { DeleteAllRules() error AddAllRules(nplList []PodNodePort) error } - -// InitRules initializes rules based on the underlying implementation -func InitRules() PodPortRules { - // Currently we only support IPTABLES. Later this can be extended based on the system capability. - return NewIPTableRules() -} diff --git a/pkg/agent/nodeportlocal/rules/types.go b/pkg/agent/nodeportlocal/rules/types.go index 0ebd4626391..21b89e5eb82 100644 --- a/pkg/agent/nodeportlocal/rules/types.go +++ b/pkg/agent/nodeportlocal/rules/types.go @@ -19,5 +19,6 @@ type PodNodePort struct { NodePort int PodPort int PodIP string + Protocol string Protocols []string } diff --git a/pkg/agent/nodeportlocal/testing/annotations.go b/pkg/agent/nodeportlocal/testing/annotations.go index d7ff30e2b25..415a231af0f 100644 --- a/pkg/agent/nodeportlocal/testing/annotations.go +++ b/pkg/agent/nodeportlocal/testing/annotations.go @@ -40,24 +40,18 @@ func NewExpectedNPLAnnotations(nodeIP *string, nplStartPort, nplEndPort int) *Ex } } -func (a *ExpectedNPLAnnotations) find(podPort int) *nplk8s.NPLAnnotation { +func (a *ExpectedNPLAnnotations) find(podPort int, protocol string) *nplk8s.NPLAnnotation { for _, annotation := range a.annotations { - if annotation.PodPort == podPort { + if annotation.PodPort == podPort && annotation.Protocol == protocol { return &annotation } } return nil } -func (a *ExpectedNPLAnnotations) Add(nodePort *int, podPort int, protocols ...string) *ExpectedNPLAnnotations { - for i, annotation := range a.annotations { - if annotation.PodPort == podPort { - annotation.Protocols = append(annotation.Protocols, protocols...) - a.annotations[i] = annotation - return a - } - } - annotation := nplk8s.NPLAnnotation{PodPort: podPort, Protocols: protocols} +func (a *ExpectedNPLAnnotations) Add(nodePort *int, podPort int, protocol string) *ExpectedNPLAnnotations { + protocols := []string{protocol} + annotation := nplk8s.NPLAnnotation{PodPort: podPort, Protocol: protocol, Protocols: protocols} if nodePort != nil { annotation.NodePort = *nodePort } @@ -70,11 +64,8 @@ func (a *ExpectedNPLAnnotations) Add(nodePort *int, podPort int, protocols ...st func (a *ExpectedNPLAnnotations) Check(t *testing.T, nplValue []nplk8s.NPLAnnotation) { assert.Equal(t, len(a.annotations), len(nplValue), "Invalid number of NPL annotations") - nodePorts := make(map[int]bool) for _, nplAnnotation := range nplValue { - assert.NotContains(t, nodePorts, nplAnnotation.NodePort, "Duplicate Node ports in NPL annotations") - nodePorts[nplAnnotation.NodePort] = true - expectedAnnotation := a.find(nplAnnotation.PodPort) + expectedAnnotation := a.find(nplAnnotation.PodPort, nplAnnotation.Protocol) if !assert.NotNilf(t, expectedAnnotation, "Unexpected annotation with PodPort %d", nplAnnotation.PodPort) { continue } diff --git a/pkg/agent/openflow/client.go b/pkg/agent/openflow/client.go index ef097e9d778..869d4d28c57 100644 --- a/pkg/agent/openflow/client.go +++ b/pkg/agent/openflow/client.go @@ -28,9 +28,9 @@ import ( "antrea.io/antrea/pkg/agent/openflow/cookie" "antrea.io/antrea/pkg/agent/types" "antrea.io/antrea/pkg/agent/util" + "antrea.io/antrea/pkg/apis/crd/v1alpha2" binding "antrea.io/antrea/pkg/ovs/openflow" utilip "antrea.io/antrea/pkg/util/ip" - "antrea.io/antrea/pkg/util/runtime" "antrea.io/antrea/third_party/proxy" ) @@ -43,22 +43,11 @@ type Client interface { // be called to ensure that the set of OVS flows is correct. All flows programmed in the // switch which match the current round number will be deleted before any new flow is // installed. - Initialize(roundInfo types.RoundInfo, config *config.NodeConfig, networkconfig *config.NetworkConfig) (<-chan struct{}, error) - - // InstallGatewayFlows sets up flows related to an OVS gateway port, the gateway must exist. - InstallGatewayFlows() error - - // InstallClusterServiceCIDRFlows sets up the appropriate flows so that traffic can reach - // the different Services running in the Cluster. This method needs to be invoked once with - // the Cluster Service CIDR as a parameter. - InstallClusterServiceCIDRFlows(serviceNets []*net.IPNet) error - - // InstallDefaultServiceFlows sets up the appropriate flows so that traffic can reach - // the different Services running in the Cluster. This method needs to be invoked once. - InstallDefaultServiceFlows(nodePortAddressesIPv4, nodePortAddressesIPv6 []net.IP) error - - // InstallDefaultTunnelFlows sets up the classification flow for the default (flow based) tunnel. - InstallDefaultTunnelFlows() error + Initialize(roundInfo types.RoundInfo, + config *config.NodeConfig, + networkConfig *config.NetworkConfig, + egressConfig *config.EgressConfig, + serviceConfig *config.ServiceConfig) (<-chan struct{}, error) // InstallNodeFlows should be invoked when a connection to a remote Node is going to be set // up. The hostname is used to identify the added flows. When IPsec tunnel is enabled, @@ -94,9 +83,9 @@ type Client interface { // InstallServiceGroup installs a group for Service LB. Each endpoint // is a bucket of the group. For now, each bucket has the same weight. InstallServiceGroup(groupID binding.GroupIDType, withSessionAffinity bool, endpoints []proxy.Endpoint) error - // UninstallServiceGroup removes the group and its buckets that are - // installed by InstallServiceGroup. - UninstallServiceGroup(groupID binding.GroupIDType) error + // UninstallGroup removes the group and its buckets that are + // installed by InstallServiceGroup or InstallMulticastGroup. + UninstallGroup(groupID binding.GroupIDType) error // InstallEndpointFlows installs flows for accessing Endpoints. // If an Endpoint is on the current Node, then flows for hairpin and endpoint @@ -140,16 +129,6 @@ type Client interface { // are removed from PolicyRule.From, else from PolicyRule.To. DeletePolicyRuleAddress(ruleID uint32, addrType types.AddressType, addresses []types.Address, priority *uint16) error - // InstallBridgeUplinkFlows installs Openflow flows between bridge local port and uplink port to support host networking. - InstallBridgeUplinkFlows() error - - // InstallExternalFlows sets up flows to enable Pods to communicate to - // the external IP addresses. The flows identify the packets from local - // Pods to the external IP address, and mark the packets to be SNAT'd - // with the configured SNAT IPs. On Windows Node, the flows also perform - // SNAT with the Openflow NAT action. - InstallExternalFlows(exceptCIDRs []net.IPNet) error - // InstallSNATMarkFlows installs flows for a local SNAT IP. On Linux, a // single flow is added to mark the packets tunnelled from remote Nodes // that should be SNAT'd with the SNAT IP. @@ -236,7 +215,7 @@ type Client interface { // packets through registered handlers. RegisterPacketInHandler(packetHandlerReason uint8, packetHandlerName string, packetInHandler interface{}) - StartPacketInHandler(packetInStartedReason []uint8, stopCh <-chan struct{}) + StartPacketInHandler(stopCh <-chan struct{}) // Get traffic metrics of each NetworkPolicy rule. NetworkPolicyMetrics() map[uint32]*types.RuleMetric // SendTCPPacketOut sends TCP packet as a packet-out to OVS. @@ -290,17 +269,31 @@ type Client interface { // InstallMulticastInitialFlows installs OpenFlow to packetIn the IGMP messages and output the Multicast traffic to // antrea-gw0 so that local Pods could access external Multicast servers. InstallMulticastInitialFlows(pktInReason uint8) error - // InstallMulticastFlow installs the flow to forward Multicast traffic normally, and output it to antrea-gw0 + // InstallMulticastFlows installs the flow to forward Multicast traffic normally, and output it to antrea-gw0 // to ensure it can be forwarded to the external addresses. - InstallMulticastFlow(multicastIP net.IP) error - // UninstallMulticastFlow removes the flow matching the given multicastIP. - UninstallMulticastFlow(multicastIP net.IP) error + InstallMulticastFlows(multicastIP net.IP, groupID binding.GroupIDType) error + // UninstallMulticastFlows removes the flow matching the given multicastIP. + UninstallMulticastFlows(multicastIP net.IP) error // SendIGMPQueryPacketOut sends the IGMPQuery packet as a packet-out to OVS from the gateway port. SendIGMPQueryPacketOut( dstMAC net.HardwareAddr, dstIP net.IP, outPort uint32, igmp ofutil.Message) error + + // InstallTrafficControlMarkFlows installs the flows to mark the packets for a traffic control rule. + InstallTrafficControlMarkFlows(name string, sourceOFPorts []uint32, targetOFPort uint32, direction v1alpha2.Direction, action v1alpha2.TrafficControlAction) error + + // UninstallTrafficControlMarkFlows removes the flows for a traffic control rule. + UninstallTrafficControlMarkFlows(name string) error + + // InstallTrafficControlReturnPortFlow installs the flow to classify the packets from a return port. + InstallTrafficControlReturnPortFlow(returnOFPort uint32) error + + // UninstallTrafficControlReturnPortFlow removes the flow to classify the packets from a return port. + UninstallTrafficControlReturnPortFlow(returnOFPort uint32) error + + InstallMulticastGroup(ofGroupID binding.GroupIDType, localReceivers []uint32) error } // GetFlowTableStatus returns an array of flow table status. @@ -554,7 +547,7 @@ func (c *client) InstallServiceGroup(groupID binding.GroupIDType, withSessionAff return nil } -func (c *client) UninstallServiceGroup(groupID binding.GroupIDType) error { +func (c *client) UninstallGroup(groupID binding.GroupIDType) error { c.replayMutex.RLock() defer c.replayMutex.RUnlock() if !c.bridge.DeleteGroup(groupID) { @@ -582,7 +575,7 @@ func (c *client) InstallEndpointFlows(protocol binding.Protocol, endpoints []pro var flows []binding.Flow endpointPort, _ := endpoint.Port() endpointIP := net.ParseIP(endpoint.IP()) - portVal := portToUint16(endpointPort) + portVal := util.PortToUint16(endpointPort) cacheKey := generateEndpointFlowCacheKey(endpoint.IP(), endpointPort, protocol) flows = append(flows, c.featureService.endpointDNATFlow(endpointIP, portVal, protocol)) if endpoint.GetIsLocal() { @@ -636,80 +629,6 @@ func (c *client) GetServiceFlowKeys(svcIP net.IP, svcPort uint16, protocol bindi return flowKeys } -func (c *client) InstallDefaultServiceFlows(nodePortAddressesIPv4, nodePortAddressesIPv6 []net.IP) error { - flows := []binding.Flow{ - c.featureService.serviceNeedLBFlow(), - c.featureService.sessionAffinityReselectFlow(), - c.featureService.l2ForwardOutputHairpinServiceFlow(), - } - - if c.proxyAll { - for _, ipProtocol := range c.ipProtocols { - // These flows are used to match the first packet of NodePort. The flows will set a bit of a register to mark - // the Service type of the packet as NodePort. The mark will be consumed in table serviceLBTable to match NodePort - nodePortAddresses := nodePortAddressesIPv4 - if ipProtocol == binding.ProtocolIPv6 { - nodePortAddresses = nodePortAddressesIPv6 - } - flows = append(flows, c.featureService.nodePortMarkFlows(nodePortAddresses, ipProtocol)...) - } - } - if err := c.ofEntryOperations.AddAll(flows); err != nil { - return err - } - c.featureService.fixedFlows = flows - return nil -} - -func (c *client) InstallClusterServiceCIDRFlows(serviceNets []*net.IPNet) error { - flows := c.featureService.serviceCIDRDNATFlows(serviceNets) - if err := c.ofEntryOperations.AddAll(flows); err != nil { - return err - } - c.featureService.fixedFlows = flows - return nil -} - -func (c *client) InstallGatewayFlows() error { - gatewayConfig := c.nodeConfig.GatewayConfig - - flows := []binding.Flow{ - c.featurePodConnectivity.gatewayClassifierFlow(), - c.featurePodConnectivity.l2ForwardCalcFlow(gatewayConfig.MAC, config.HostGatewayOFPort), - } - flows = append(flows, c.featurePodConnectivity.gatewayIPSpoofGuardFlows()...) - - // Add ARP SpoofGuard flow for local gateway interface. - if gatewayConfig.IPv4 != nil { - flows = append(flows, c.featurePodConnectivity.arpSpoofGuardFlow(gatewayConfig.IPv4, gatewayConfig.MAC, config.HostGatewayOFPort)) - if c.connectUplinkToBridge { - flows = append(flows, c.featurePodConnectivity.arpSpoofGuardFlow(c.nodeConfig.NodeIPv4Addr.IP, gatewayConfig.MAC, config.HostGatewayOFPort)) - } - } - - // Add flow to ensure the liveness check packet could be forwarded correctly. - flows = append(flows, c.featurePodConnectivity.localProbeFlow(c.ovsDatapathType)...) - flows = append(flows, c.featurePodConnectivity.l3FwdFlowToGateway()...) - - if err := c.ofEntryOperations.AddAll(flows); err != nil { - return err - } - c.featurePodConnectivity.fixedFlows = append(c.featurePodConnectivity.fixedFlows, flows...) - return nil -} - -func (c *client) InstallDefaultTunnelFlows() error { - flows := []binding.Flow{ - c.featurePodConnectivity.tunnelClassifierFlow(config.DefaultTunOFPort), - c.featurePodConnectivity.l2ForwardCalcFlow(GlobalVirtualMAC, config.DefaultTunOFPort), - } - if err := c.ofEntryOperations.AddAll(flows); err != nil { - return err - } - c.featurePodConnectivity.fixedFlows = append(c.featurePodConnectivity.fixedFlows, flows...) - return nil -} - func (c *client) initialize() error { if err := c.ofEntryOperations.AddAll(c.defaultFlows()); err != nil { return fmt.Errorf("failed to install default flows: %v", err) @@ -732,9 +651,15 @@ func (c *client) initialize() error { return nil } -func (c *client) Initialize(roundInfo types.RoundInfo, nodeConfig *config.NodeConfig, networkConfig *config.NetworkConfig) (<-chan struct{}, error) { +func (c *client) Initialize(roundInfo types.RoundInfo, + nodeConfig *config.NodeConfig, + networkConfig *config.NetworkConfig, + egressConfig *config.EgressConfig, + serviceConfig *config.ServiceConfig) (<-chan struct{}, error) { c.nodeConfig = nodeConfig c.networkConfig = networkConfig + c.egressConfig = egressConfig + c.serviceConfig = serviceConfig if networkConfig.IPv4Enabled { c.ipProtocols = append(c.ipProtocols, binding.ProtocolIP) @@ -786,7 +711,9 @@ func (c *client) generatePipelines() { c.nodeConfig, c.networkConfig, c.connectUplinkToBridge, - c.enableMulticast) + c.enableMulticast, + c.proxyAll, + c.enableTrafficControl) c.activatedFeatures = append(c.activatedFeatures, c.featurePodConnectivity) c.traceableFeatures = append(c.traceableFeatures, c.featurePodConnectivity) @@ -803,6 +730,8 @@ func (c *client) generatePipelines() { c.featureService = newFeatureService(c.cookieAllocator, c.ipProtocols, c.nodeConfig, + c.networkConfig, + c.serviceConfig, c.bridge, c.enableProxy, c.proxyAll, @@ -811,13 +740,13 @@ func (c *client) generatePipelines() { c.traceableFeatures = append(c.traceableFeatures, c.featureService) if c.enableEgress { - c.featureEgress = newFeatureEgress(c.cookieAllocator, c.ipProtocols, c.nodeConfig) + c.featureEgress = newFeatureEgress(c.cookieAllocator, c.ipProtocols, c.nodeConfig, c.egressConfig) c.activatedFeatures = append(c.activatedFeatures, c.featureEgress) } if c.enableMulticast { // TODO: add support for IPv6 protocol - c.featureMulticast = newFeatureMulticast(c.cookieAllocator, []binding.Protocol{binding.ProtocolIP}) + c.featureMulticast = newFeatureMulticast(c.cookieAllocator, []binding.Protocol{binding.ProtocolIP}, c.bridge) c.activatedFeatures = append(c.activatedFeatures, c.featureMulticast) } c.featureTraceflow = newFeatureTraceflow() @@ -868,17 +797,6 @@ func (c *client) generatePipelines() { } } -func (c *client) InstallExternalFlows(exceptCIDRs []net.IPNet) error { - if c.enableEgress { - flows := c.featureEgress.externalFlows(exceptCIDRs) - if err := c.ofEntryOperations.AddAll(flows); err != nil { - return fmt.Errorf("failed to install flows for external communication: %v", err) - } - c.featureEgress.fixedFlows = append(c.featureEgress.fixedFlows, flows...) - } - return nil -} - func (c *client) InstallSNATMarkFlows(snatIP net.IP, mark uint32) error { flow := c.featureEgress.snatIPFromTunnelFlow(snatIP, mark) cacheKey := fmt.Sprintf("s%x", mark) @@ -918,6 +836,9 @@ func (c *client) ReplayFlows() { } c.featureService.replayGroups() + if c.enableMulticast { + c.featureMulticast.replayGroups() + } for _, activeFeature := range c.activatedFeatures { if err := c.ofEntryOperations.AddAll(activeFeature.replayFlows()); err != nil { @@ -1190,22 +1111,22 @@ func (c *client) InstallMulticastInitialFlows(pktInReason uint8) error { cacheKey := fmt.Sprintf("multicast") c.replayMutex.RLock() defer c.replayMutex.RUnlock() - return c.addFlows(c.featureMulticast.mcastFlowCache, cacheKey, flows) + return c.addFlows(c.featureMulticast.cachedFlows, cacheKey, flows) } -func (c *client) InstallMulticastFlow(multicastIP net.IP) error { - flows := c.featureMulticast.localMulticastForwardFlow(multicastIP) +func (c *client) InstallMulticastFlows(multicastIP net.IP, groupID binding.GroupIDType) error { + flows := c.featureMulticast.localMulticastForwardFlows(multicastIP, groupID) cacheKey := fmt.Sprintf("multicast_%s", multicastIP.String()) c.replayMutex.RLock() defer c.replayMutex.RUnlock() - return c.addFlows(c.featureMulticast.mcastFlowCache, cacheKey, flows) + return c.addFlows(c.featureMulticast.cachedFlows, cacheKey, flows) } -func (c *client) UninstallMulticastFlow(multicastIP net.IP) error { +func (c *client) UninstallMulticastFlows(multicastIP net.IP) error { c.replayMutex.RLock() defer c.replayMutex.RUnlock() cacheKey := fmt.Sprintf("multicast_%s", multicastIP.String()) - return c.deleteFlows(c.featureMulticast.mcastFlowCache, cacheKey) + return c.deleteFlows(c.featureMulticast.cachedFlows, cacheKey) } func (c *client) SendIGMPQueryPacketOut( @@ -1228,21 +1149,43 @@ func (c *client) SendIGMPQueryPacketOut( return c.bridge.SendPacketOut(packetOutObj) } -func (c *client) InstallBridgeUplinkFlows() error { - if runtime.IsWindowsPlatform() || c.connectUplinkToBridge { - podCIDRMap := make(map[binding.Protocol]net.IPNet) - if c.nodeConfig.PodIPv4CIDR != nil { - podCIDRMap[binding.ProtocolIP] = *c.nodeConfig.PodIPv4CIDR - } - //TODO: support IPv6 - flows := c.featurePodConnectivity.hostBridgeUplinkFlows(podCIDRMap) - if c.connectUplinkToBridge { - flows = append(flows, c.featurePodConnectivity.hostBridgeUplinkVLANFlows()...) - } - if err := c.ofEntryOperations.AddAll(flows); err != nil { - return err - } - c.featurePodConnectivity.fixedFlows = append(c.featurePodConnectivity.fixedFlows, flows...) +func (c *client) InstallTrafficControlMarkFlows(name string, sourceOFPorts []uint32, targetOFPort uint32, direction v1alpha2.Direction, action v1alpha2.TrafficControlAction) error { + flows := c.featurePodConnectivity.trafficControlMarkFlows(sourceOFPorts, targetOFPort, direction, action) + cacheKey := fmt.Sprintf("tc_%s", name) + c.replayMutex.RLock() + defer c.replayMutex.RUnlock() + return c.modifyFlows(c.featurePodConnectivity.tcCachedFlows, cacheKey, flows) +} + +func (c *client) UninstallTrafficControlMarkFlows(name string) error { + cacheKey := fmt.Sprintf("tc_%s", name) + c.replayMutex.RLock() + defer c.replayMutex.RUnlock() + return c.deleteFlows(c.featurePodConnectivity.tcCachedFlows, cacheKey) +} + +func (c *client) InstallTrafficControlReturnPortFlow(returnOFPort uint32) error { + cacheKey := fmt.Sprintf("tc_%d", returnOFPort) + flows := []binding.Flow{c.featurePodConnectivity.trafficControlReturnClassifierFlow(returnOFPort)} + c.replayMutex.RLock() + defer c.replayMutex.RUnlock() + return c.addFlows(c.featurePodConnectivity.tcCachedFlows, cacheKey, flows) +} + +func (c *client) UninstallTrafficControlReturnPortFlow(returnOFPort uint32) error { + cacheKey := fmt.Sprintf("tc_%d", returnOFPort) + c.replayMutex.RLock() + defer c.replayMutex.RUnlock() + return c.deleteFlows(c.featurePodConnectivity.tcCachedFlows, cacheKey) +} + +func (c *client) InstallMulticastGroup(groupID binding.GroupIDType, localReceivers []uint32) error { + c.replayMutex.RLock() + defer c.replayMutex.RUnlock() + + targetPorts := append([]uint32{config.HostGatewayOFPort}, localReceivers...) + if err := c.featureMulticast.multicastReceiversGroup(groupID, targetPorts...); err != nil { + return err } return nil } diff --git a/pkg/agent/openflow/client_test.go b/pkg/agent/openflow/client_test.go index 0dba46b77d0..57d9eddb061 100644 --- a/pkg/agent/openflow/client_test.go +++ b/pkg/agent/openflow/client_test.go @@ -56,6 +56,8 @@ var ( NodeIPv4Addr: nodeIP, } networkConfig = &config.NetworkConfig{IPv4Enabled: true} + egressConfig = &config.EgressConfig{} + serviceConfig = &config.ServiceConfig{} ) func installNodeFlows(ofClient Client, cacheKey string) (int, error) { @@ -105,12 +107,14 @@ func TestIdempotentFlowInstallation(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() m := oftest.NewMockOFEntryOperations(ctrl) - ofClient := NewClient(bridgeName, bridgeMgmtAddr, ovsconfig.OVSDatapathSystem, true, false, false, false, false, false, false) + ofClient := NewClient(bridgeName, bridgeMgmtAddr, true, false, false, false, false, false, false, false) client := ofClient.(*client) client.cookieAllocator = cookie.NewAllocator(0) client.ofEntryOperations = m client.nodeConfig = nodeConfig client.networkConfig = networkConfig + client.egressConfig = egressConfig + client.serviceConfig = serviceConfig client.ipProtocols = []binding.Protocol{binding.ProtocolIP} client.generatePipelines() @@ -136,12 +140,14 @@ func TestIdempotentFlowInstallation(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() m := oftest.NewMockOFEntryOperations(ctrl) - ofClient := NewClient(bridgeName, bridgeMgmtAddr, ovsconfig.OVSDatapathSystem, true, false, false, false, false, false, false) + ofClient := NewClient(bridgeName, bridgeMgmtAddr, true, false, false, false, false, false, false, false) client := ofClient.(*client) client.cookieAllocator = cookie.NewAllocator(0) client.ofEntryOperations = m client.nodeConfig = nodeConfig client.networkConfig = networkConfig + client.egressConfig = egressConfig + client.serviceConfig = serviceConfig client.ipProtocols = []binding.Protocol{binding.ProtocolIP} client.generatePipelines() @@ -180,12 +186,14 @@ func TestFlowInstallationFailed(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() m := oftest.NewMockOFEntryOperations(ctrl) - ofClient := NewClient(bridgeName, bridgeMgmtAddr, ovsconfig.OVSDatapathSystem, true, false, false, false, false, false, false) + ofClient := NewClient(bridgeName, bridgeMgmtAddr, true, false, false, false, false, false, false, false) client := ofClient.(*client) client.cookieAllocator = cookie.NewAllocator(0) client.ofEntryOperations = m client.nodeConfig = nodeConfig client.networkConfig = networkConfig + client.egressConfig = egressConfig + client.serviceConfig = serviceConfig client.ipProtocols = []binding.Protocol{binding.ProtocolIP} client.generatePipelines() @@ -217,12 +225,14 @@ func TestConcurrentFlowInstallation(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() m := oftest.NewMockOFEntryOperations(ctrl) - ofClient := NewClient(bridgeName, bridgeMgmtAddr, ovsconfig.OVSDatapathSystem, true, false, false, false, false, false, false) + ofClient := NewClient(bridgeName, bridgeMgmtAddr, true, false, false, false, false, false, false, false) client := ofClient.(*client) client.cookieAllocator = cookie.NewAllocator(0) client.ofEntryOperations = m client.nodeConfig = nodeConfig client.networkConfig = networkConfig + client.egressConfig = egressConfig + client.serviceConfig = serviceConfig client.ipProtocols = []binding.Protocol{binding.ProtocolIP} client.generatePipelines() @@ -357,6 +367,7 @@ func Test_client_SendTraceflowPacket(t *testing.T) { name: "IPv6 ICMPv6", args: args{ Packet: binding.Packet{ + IsIPv6: true, SourceMAC: srcMAC, DestinationMAC: dstMAC, SourceIP: net.ParseIP("1111::4444"), @@ -371,6 +382,7 @@ func Test_client_SendTraceflowPacket(t *testing.T) { name: "IPv6 TCP", args: args{ Packet: binding.Packet{ + IsIPv6: true, SourceMAC: srcMAC, DestinationMAC: dstMAC, SourceIP: net.ParseIP("1111::4444"), @@ -384,6 +396,7 @@ func Test_client_SendTraceflowPacket(t *testing.T) { name: "IPv6 UDP", args: args{ Packet: binding.Packet{ + IsIPv6: true, SourceMAC: srcMAC, DestinationMAC: dstMAC, SourceIP: net.ParseIP("1111::4444"), @@ -407,7 +420,7 @@ func Test_client_SendTraceflowPacket(t *testing.T) { } func prepareTraceflowFlow(ctrl *gomock.Controller) *client { - ofClient := NewClient(bridgeName, bridgeMgmtAddr, ovsconfig.OVSDatapathSystem, true, true, false, false, false, false, false) + ofClient := NewClient(bridgeName, bridgeMgmtAddr, true, true, false, false, false, false, false, false) c := ofClient.(*client) c.cookieAllocator = cookie.NewAllocator(0) c.nodeConfig = nodeConfig @@ -415,6 +428,8 @@ func prepareTraceflowFlow(ctrl *gomock.Controller) *client { c.ofEntryOperations = m c.nodeConfig = nodeConfig c.networkConfig = networkConfig + c.egressConfig = egressConfig + c.serviceConfig = serviceConfig c.ipProtocols = []binding.Protocol{binding.ProtocolIP} c.generatePipelines() @@ -431,7 +446,7 @@ func prepareTraceflowFlow(ctrl *gomock.Controller) *client { } func prepareSendTraceflowPacket(ctrl *gomock.Controller, success bool) *client { - ofClient := NewClient(bridgeName, bridgeMgmtAddr, ovsconfig.OVSDatapathSystem, true, true, false, false, false, false, false) + ofClient := NewClient(bridgeName, bridgeMgmtAddr, true, true, false, false, false, false, false, false) c := ofClient.(*client) c.nodeConfig = nodeConfig m := ovsoftest.NewMockBridge(ctrl) @@ -519,7 +534,7 @@ func Test_client_setBasePacketOutBuilder(t *testing.T) { } func prepareSetBasePacketOutBuilder(ctrl *gomock.Controller, success bool) *client { - ofClient := NewClient(bridgeName, bridgeMgmtAddr, ovsconfig.OVSDatapathSystem, true, true, false, false, false, false, false) + ofClient := NewClient(bridgeName, bridgeMgmtAddr, true, true, false, false, false, false, false, false) c := ofClient.(*client) m := ovsoftest.NewMockBridge(ctrl) c.bridge = m diff --git a/pkg/agent/openflow/egress.go b/pkg/agent/openflow/egress.go index 5dacb866bae..0d5d980f12b 100644 --- a/pkg/agent/openflow/egress.go +++ b/pkg/agent/openflow/egress.go @@ -27,10 +27,10 @@ type featureEgress struct { ipProtocols []binding.Protocol cachedFlows *flowCategoryCache - fixedFlows []binding.Flow - nodeIPs map[binding.Protocol]net.IP - gatewayMAC net.HardwareAddr + exceptCIDRs map[binding.Protocol][]net.IPNet + nodeIPs map[binding.Protocol]net.IP + gatewayMAC net.HardwareAddr category cookie.Category } @@ -41,7 +41,17 @@ func (f *featureEgress) getFeatureName() string { func newFeatureEgress(cookieAllocator cookie.Allocator, ipProtocols []binding.Protocol, - nodeConfig *config.NodeConfig) *featureEgress { + nodeConfig *config.NodeConfig, + egressConfig *config.EgressConfig) *featureEgress { + exceptCIDRs := make(map[binding.Protocol][]net.IPNet) + for _, cidr := range egressConfig.ExceptCIDRs { + if cidr.IP.To4() == nil { + exceptCIDRs[binding.ProtocolIPv6] = append(exceptCIDRs[binding.ProtocolIPv6], cidr) + } else { + exceptCIDRs[binding.ProtocolIP] = append(exceptCIDRs[binding.ProtocolIP], cidr) + } + } + nodeIPs := make(map[binding.Protocol]net.IP) for _, ipProtocol := range ipProtocols { if ipProtocol == binding.ProtocolIP { @@ -53,6 +63,7 @@ func newFeatureEgress(cookieAllocator cookie.Allocator, return &featureEgress{ cachedFlows: newFlowCategoryCache(), cookieAllocator: cookieAllocator, + exceptCIDRs: exceptCIDRs, ipProtocols: ipProtocols, nodeIPs: nodeIPs, gatewayMAC: nodeConfig.GatewayConfig.MAC, @@ -61,17 +72,13 @@ func newFeatureEgress(cookieAllocator cookie.Allocator, } func (f *featureEgress) initFlows() []binding.Flow { - return []binding.Flow{} + // This installs the flows to enable Pods to communicate to the external IP addresses. The flows identify the packets + // from local Pods to the external IP address, and mark the packets to be SNAT'd with the configured SNAT IPs. + return f.externalFlows() } func (f *featureEgress) replayFlows() []binding.Flow { var flows []binding.Flow - - // Get fixed flows. - for _, flow := range f.fixedFlows { - flow.Reset() - flows = append(flows, flow) - } // Get cached flows. flows = append(flows, getCachedFlows(f.cachedFlows)...) diff --git a/pkg/agent/openflow/fields.go b/pkg/agent/openflow/fields.go index f6e756d5f5d..4198e47bdc6 100644 --- a/pkg/agent/openflow/fields.go +++ b/pkg/agent/openflow/fields.go @@ -21,11 +21,12 @@ import ( // Fields using reg. var ( - tunnelVal = uint32(1) - gatewayVal = uint32(2) - localVal = uint32(3) - uplinkVal = uint32(4) - bridgeVal = uint32(5) + tunnelVal = uint32(1) + gatewayVal = uint32(2) + localVal = uint32(3) + uplinkVal = uint32(4) + bridgeVal = uint32(5) + tcReturnVal = uint32(6) // reg0 (NXM_NX_REG0) // reg0[0..3]: Field to store the packet source. Marks in this field include: @@ -34,12 +35,14 @@ var ( // - 3: from local Pods. // - 4: from uplink port. // - 5: from bridge local port. - PktSourceField = binding.NewRegField(0, 0, 3, "PacketSource") - FromTunnelRegMark = binding.NewRegMark(PktSourceField, tunnelVal) - FromGatewayRegMark = binding.NewRegMark(PktSourceField, gatewayVal) - FromLocalRegMark = binding.NewRegMark(PktSourceField, localVal) - FromUplinkRegMark = binding.NewRegMark(PktSourceField, uplinkVal) - FromBridgeRegMark = binding.NewRegMark(PktSourceField, bridgeVal) + // - 6: from traffic control return port. + PktSourceField = binding.NewRegField(0, 0, 3, "PacketSource") + FromTunnelRegMark = binding.NewRegMark(PktSourceField, tunnelVal) + FromGatewayRegMark = binding.NewRegMark(PktSourceField, gatewayVal) + FromLocalRegMark = binding.NewRegMark(PktSourceField, localVal) + FromUplinkRegMark = binding.NewRegMark(PktSourceField, uplinkVal) + FromBridgeRegMark = binding.NewRegMark(PktSourceField, bridgeVal) + FromTCReturnRegMark = binding.NewRegMark(PktSourceField, tcReturnVal) // reg0[4..7]: Field to store the packet destination. Marks in this field include: // - 1: to tunnel port. // - 2: to Antrea gateway port. @@ -49,11 +52,7 @@ var ( PktDestinationField = binding.NewRegField(0, 4, 7, "PacketDestination") ToTunnelRegMark = binding.NewRegMark(PktDestinationField, tunnelVal) ToGatewayRegMark = binding.NewRegMark(PktDestinationField, gatewayVal) - // reg0[0..7]: Union field of the packet source and destination. It is used to mark hairpin packets. Marks in this - // field include: - // - 0x11: the packet sourced from Antrea gateway interface, and destined for local Node via Antrea gateway interface. - PktUnionField = binding.NewRegField(0, 0, 7, "PacketUnion") - GatewayHairpinRegMark = binding.NewRegMark(PktUnionField, (ToGatewayRegMark.GetValue()< 0 && port <= math.MaxUint16 { - return uint16(port) // lgtm[go/incorrect-integer-conversion] - } - klog.Errorf("Port value %d out-of-bounds", port) - return 0 -} - type client struct { enableProxy bool proxyAll bool @@ -390,6 +384,7 @@ type client struct { enableDenyTracking bool enableEgress bool enableMulticast bool + enableTrafficControl bool connectUplinkToBridge bool roundInfo types.RoundInfo cookieAllocator cookie.Allocator @@ -414,8 +409,8 @@ type client struct { replayMutex sync.RWMutex nodeConfig *config.NodeConfig networkConfig *config.NetworkConfig - // ovsDatapathType is the type of the datapath used by the bridge. - ovsDatapathType ovsconfig.OVSDatapathType + egressConfig *config.EgressConfig + serviceConfig *config.ServiceConfig // ovsMetersAreSupported indicates whether the OVS datapath supports OpenFlow meters. ovsMetersAreSupported bool // packetInHandlers stores handler to process PacketIn event. Each packetin reason can have multiple handlers registered. @@ -574,8 +569,7 @@ func (f *featurePodConnectivity) tunnelClassifierFlow(tunnelOFPort uint32) bindi return ClassifierTable.ofTable.BuildFlow(priorityNormal). Cookie(f.cookieAllocator.Request(f.category).Raw()). MatchInPort(tunnelOFPort). - Action().LoadRegMark(FromTunnelRegMark). - Action().LoadRegMark(RewriteMACRegMark). + Action().LoadRegMark(FromTunnelRegMark, RewriteMACRegMark). Action().GotoStage(stageConntrackState). Done() } @@ -592,17 +586,16 @@ func (f *featurePodConnectivity) gatewayClassifierFlow() binding.Flow { // podClassifierFlow generates the flow to mark the packets from a local Pod port. func (f *featurePodConnectivity) podClassifierFlow(podOFPort uint32, isAntreaFlexibleIPAM bool) binding.Flow { - flowBuilder := ClassifierTable.ofTable.BuildFlow(priorityLow). - Cookie(f.cookieAllocator.Request(f.category).Raw()). - MatchInPort(podOFPort). - Action().LoadRegMark(FromLocalRegMark). - Action().GotoStage(stageValidation) + regMarksToLoad := []*binding.RegMark{FromLocalRegMark} if isAntreaFlexibleIPAM { - // This is used to mark the packets from a local Antrea IPAM Pod port. - flowBuilder = flowBuilder.Action().LoadRegMark(AntreaFlexibleIPAMRegMark). - Action().LoadRegMark(RewriteMACRegMark) + regMarksToLoad = append(regMarksToLoad, AntreaFlexibleIPAMRegMark, RewriteMACRegMark) } - return flowBuilder.Done() + return ClassifierTable.ofTable.BuildFlow(priorityLow). + Cookie(f.cookieAllocator.Request(f.category).Raw()). + MatchInPort(podOFPort). + Action().LoadRegMark(regMarksToLoad...). + Action().GotoStage(stageValidation). + Done() } // podUplinkClassifierFlows generates the flows to mark the packets with target destination MAC address from uplink/bridge @@ -615,10 +608,6 @@ func (f *featurePodConnectivity) podUplinkClassifierFlows(dstMAC net.HardwareAdd nonVLAN = false } for _, ipProtocol := range f.ipProtocols { - ctZoneTypeRegMark := IPCtZoneTypeRegMark - if ipProtocol == binding.ProtocolIPv6 { - ctZoneTypeRegMark = IPv6CtZoneTypeRegMark - } flows = append(flows, // This generates the flow to mark the packets from uplink port. ClassifierTable.ofTable.BuildFlow(priorityHigh). @@ -627,9 +616,8 @@ func (f *featurePodConnectivity) podUplinkClassifierFlows(dstMAC net.HardwareAdd MatchDstMAC(dstMAC). MatchVLAN(nonVLAN, vlanID, nil). MatchProtocol(ipProtocol). - Action().LoadRegMark(ctZoneTypeRegMark). + Action().LoadRegMark(f.ipCtZoneTypeRegMarks[ipProtocol], FromUplinkRegMark). Action().LoadToRegField(VLANIDField, uint32(vlanID)). - Action().LoadRegMark(FromUplinkRegMark). Action().GotoStage(stageConntrackState). Done(), ) @@ -642,8 +630,7 @@ func (f *featurePodConnectivity) podUplinkClassifierFlows(dstMAC net.HardwareAdd MatchDstMAC(dstMAC). MatchVLAN(true, 0, nil). MatchProtocol(ipProtocol). - Action().LoadRegMark(ctZoneTypeRegMark). - Action().LoadRegMark(FromBridgeRegMark). + Action().LoadRegMark(f.ipCtZoneTypeRegMarks[ipProtocol], FromBridgeRegMark). Action().GotoStage(stageConntrackState). Done(), ) @@ -678,7 +665,7 @@ func (f *featurePodConnectivity) conntrackFlows() []binding.Flow { Action().GotoStage(stageEgressSecurity). Done(), // This generates the flow to drop invalid packets. - ConntrackStateTable.ofTable.BuildFlow(priorityLow). + ConntrackStateTable.ofTable.BuildFlow(priorityHigh). Cookie(cookieID). MatchProtocol(ipProtocol). MatchCTStateInv(true). @@ -692,6 +679,7 @@ func (f *featurePodConnectivity) conntrackFlows() []binding.Flow { MatchProtocol(ipProtocol). MatchCTStateNew(true). MatchCTStateTrk(true). + MatchCTMark(NotServiceCTMark). Action().CT(true, ConntrackCommitTable.GetNext(), f.ctZones[ipProtocol], f.ctZoneSrcField). MoveToCtMarkField(PktSourceField, ConnSourceCTMarkField). CTDone(). @@ -724,14 +712,6 @@ func (f *featureService) conntrackFlows() []binding.Flow { Action().LoadRegMark(RewriteMACRegMark). Action().GotoStage(stageEgressSecurity). Done(), - // This generates the flow to avoid committing Service connections (with ServiceCTMark) another time. They - // have been committed in EndpointDNATTable, using the same CT zone. - ConntrackCommitTable.ofTable.BuildFlow(priorityHigh). - Cookie(cookieID). - MatchProtocol(ipProtocol). - MatchCTMark(ServiceCTMark). - Action().GotoStage(stageOutput). - Done(), ) } return flows @@ -775,12 +755,10 @@ func (f *featureService) snatConntrackFlows() []binding.Flow { MatchCTStateNew(true). MatchCTStateTrk(true). MatchRegMark(FromGatewayRegMark). - MatchCTMark(ConnSNATCTMark). MatchCTMark(HairpinCTMark). Action().CT(true, SNATConntrackCommitTable.GetNext(), f.snatCtZones[ipProtocol], nil). SNAT(&binding.IPRange{StartIP: f.virtualIPs[ipProtocol], EndIP: f.virtualIPs[ipProtocol]}, nil). - LoadToCtMark(ServiceCTMark). - LoadToCtMark(HairpinCTMark). + LoadToCtMark(ServiceCTMark, HairpinCTMark). CTDone(). Done(), // This generates the flow to match the first packet of hairpin Service connection initiated through a Pod with @@ -791,12 +769,10 @@ func (f *featureService) snatConntrackFlows() []binding.Flow { MatchCTStateNew(true). MatchCTStateTrk(true). MatchRegMark(FromLocalRegMark). - MatchCTMark(ConnSNATCTMark). MatchCTMark(HairpinCTMark). Action().CT(true, SNATConntrackCommitTable.GetNext(), f.snatCtZones[ipProtocol], nil). SNAT(&binding.IPRange{StartIP: f.gatewayIPs[ipProtocol], EndIP: f.gatewayIPs[ipProtocol]}, nil). - LoadToCtMark(ServiceCTMark). - LoadToCtMark(HairpinCTMark). + LoadToCtMark(ServiceCTMark, HairpinCTMark). CTDone(). Done(), // This generates the flow to match the first packet of NodePort / LoadBalancer connection (non-hairpin) initiated @@ -1253,14 +1229,15 @@ func (f *featurePodConnectivity) l3FwdFlowToPod(localGatewayMAC net.HardwareAddr Done()) } else { // This generates the flow to match the packets with RewriteMACRegMark and destined for a local per-Node IPAM Pod. - fb := L3ForwardingTable.ofTable.BuildFlow(priorityNormal). - Cookie(cookieID) + regMarksToMatch := []*binding.RegMark{RewriteMACRegMark} if f.connectUplinkToBridge { // Only overwrite MAC for untagged traffic which destination is a local per-Node IPAM Pod. - fb = fb.MatchRegFieldWithValue(VLANIDField, 0) + regMarksToMatch = append(regMarksToMatch, binding.NewRegMark(VLANIDField, 0)) } - flows = append(flows, fb.MatchProtocol(ipProtocol). - MatchRegMark(RewriteMACRegMark). + flows = append(flows, L3ForwardingTable.ofTable.BuildFlow(priorityNormal). + Cookie(cookieID). + MatchProtocol(ipProtocol). + MatchRegMark(regMarksToMatch...). MatchDstIP(ip). Action().SetSrcMAC(localGatewayMAC). Action().SetDstMAC(podInterfaceMAC). @@ -1359,16 +1336,18 @@ func (f *featurePodConnectivity) l3FwdFlowToRemoteViaTun(localGatewayMAC net.Har func (f *featurePodConnectivity) l3FwdFlowToRemoteViaGW(localGatewayMAC net.HardwareAddr, peerSubnet net.IPNet) binding.Flow { cookieID := f.cookieAllocator.Request(f.category).Raw() ipProtocol := getIPProtocol(peerSubnet.IP) + var regMarksToMatch []*binding.RegMark + if f.connectUplinkToBridge { + regMarksToMatch = append(regMarksToMatch, NotAntreaFlexibleIPAMRegMark) // Exclude the packets from Antrea IPAM Pods. + } // This generates the flow to match the packets destined for remote Pods. Note that, this flow is installed in Linux Nodes // or Windows Nodes whose remote Node's transport interface MAC is unknown. - fb := L3ForwardingTable.ofTable.BuildFlow(priorityNormal). + return L3ForwardingTable.ofTable.BuildFlow(priorityNormal). Cookie(cookieID). MatchProtocol(ipProtocol). - MatchDstIPNet(peerSubnet) - if f.connectUplinkToBridge { - fb = fb.MatchRegMark(NotAntreaFlexibleIPAMRegMark) // Exclude the packets from Antrea IPAM Pods. - } - return fb.Action().SetDstMAC(localGatewayMAC). + MatchDstIPNet(peerSubnet). + MatchRegMark(regMarksToMatch...). + Action().SetDstMAC(localGatewayMAC). Action().LoadRegMark(ToGatewayRegMark). Action().GotoTable(L3DecTTLTable.GetID()). // Traffic to in-cluster destination should skip EgressMark table. Done() @@ -1392,6 +1371,7 @@ func (f *featurePodConnectivity) l3FwdFlowToRemoteViaUplink(remoteGatewayMAC net MatchDstIPNet(peerSubnet). Action().SetSrcMAC(f.nodeConfig.UplinkNetConfig.MAC). Action().SetDstMAC(remoteGatewayMAC). + Action().LoadRegMark(ToUplinkRegMark). Action().GotoTable(L3DecTTLTable.GetID()). Done() } @@ -1405,6 +1385,7 @@ func (f *featurePodConnectivity) l3FwdFlowToRemoteViaUplink(remoteGatewayMAC net MatchRegMark(AntreaFlexibleIPAMRegMark). MatchDstIPNet(peerSubnet). Action().SetDstMAC(remoteGatewayMAC). + Action().LoadRegMark(ToUplinkRegMark). Action().GotoTable(L3DecTTLTable.GetID()). Done() } @@ -1466,22 +1447,19 @@ func (f *featurePodConnectivity) podIPSpoofGuardFlow(ifIPs []net.IP, ifMAC net.H } for _, ifIP := range ifIPs { + var regMarksToLoad []*binding.RegMark ipProtocol := getIPProtocol(ifIP) - fb := SpoofGuardTable.ofTable.BuildFlow(priorityNormal). + if f.connectUplinkToBridge { + regMarksToLoad = append(regMarksToLoad, f.ipCtZoneTypeRegMarks[ipProtocol], binding.NewRegMark(VLANIDField, uint32(vlanID))) + } + flows = append(flows, SpoofGuardTable.ofTable.BuildFlow(priorityNormal). Cookie(cookieID). MatchProtocol(ipProtocol). MatchInPort(ifOFPort). MatchSrcMAC(ifMAC). - MatchSrcIP(ifIP) - if f.connectUplinkToBridge { - ctZoneTypeRegMark := IPCtZoneTypeRegMark - if ipProtocol == binding.ProtocolIPv6 { - ctZoneTypeRegMark = IPv6CtZoneTypeRegMark - } - fb = fb.Action().LoadRegMark(ctZoneTypeRegMark). - Action().LoadToRegField(VLANIDField, uint32(vlanID)) - } - flows = append(flows, fb.Action().GotoTable(targetTables[ipProtocol]). + MatchSrcIP(ifIP). + Action().LoadRegMark(regMarksToLoad...). + Action().GotoTable(targetTables[ipProtocol]). Done()) } return flows @@ -1540,19 +1518,17 @@ func (f *featurePodConnectivity) gatewayIPSpoofGuardFlows() []binding.Flow { } for _, ipProtocol := range f.ipProtocols { - fb := SpoofGuardTable.ofTable.BuildFlow(priorityNormal). - Cookie(cookieID). - MatchProtocol(ipProtocol). - MatchInPort(config.HostGatewayOFPort) + var regMarksToLoad []*binding.RegMark // Set CtZoneTypeField based on ipProtocol and keep VLANIDField=0 if f.connectUplinkToBridge { - ctZoneTypeRegMark := IPCtZoneTypeRegMark - if ipProtocol == binding.ProtocolIPv6 { - ctZoneTypeRegMark = IPv6CtZoneTypeRegMark - } - fb = fb.Action().LoadRegMark(ctZoneTypeRegMark) + regMarksToLoad = append(regMarksToLoad, f.ipCtZoneTypeRegMarks[ipProtocol]) } - flows = append(flows, fb.Action().GotoTable(targetTables[ipProtocol]). + flows = append(flows, SpoofGuardTable.ofTable.BuildFlow(priorityNormal). + Cookie(cookieID). + MatchProtocol(ipProtocol). + MatchInPort(config.HostGatewayOFPort). + Action().LoadRegMark(regMarksToLoad...). + Action().GotoTable(targetTables[ipProtocol]). Done(), ) } @@ -1560,21 +1536,18 @@ func (f *featurePodConnectivity) gatewayIPSpoofGuardFlows() []binding.Flow { } // serviceCIDRDNATFlows generates the flows to match destination IP in Service CIDR and output to the Antrea gateway directly. -func (f *featureService) serviceCIDRDNATFlows(serviceCIDRs []*net.IPNet) []binding.Flow { +func (f *featureService) serviceCIDRDNATFlows() []binding.Flow { cookieID := f.cookieAllocator.Request(f.category).Raw() var flows []binding.Flow - for _, serviceCIDR := range serviceCIDRs { - if serviceCIDR != nil { - ipProtocol := getIPProtocol(serviceCIDR.IP) - flows = append(flows, DNATTable.ofTable.BuildFlow(priorityNormal). - Cookie(cookieID). - MatchProtocol(ipProtocol). - MatchDstIPNet(*serviceCIDR). - Action().LoadToRegField(TargetOFPortField, config.HostGatewayOFPort). - Action().LoadRegMark(OFPortFoundRegMark). - Action().GotoStage(stageConntrack). - Done()) - } + for ipProtocol, serviceCIDR := range f.serviceCIDRs { + flows = append(flows, DNATTable.ofTable.BuildFlow(priorityNormal). + Cookie(cookieID). + MatchProtocol(ipProtocol). + MatchDstIPNet(serviceCIDR). + Action().LoadToRegField(TargetOFPortField, config.HostGatewayOFPort). + Action().LoadRegMark(OFPortFoundRegMark). + Action().GotoStage(stageConntrack). + Done()) } return flows } @@ -1714,9 +1687,8 @@ func (f *featureNetworkPolicy) conjunctionActionFlow(conjunctionID uint32, table fb = fb.Action().Meter(PacketInMeterIDNP) } return fb. - Action().LoadToRegField(conjReg, conjunctionID). // Traceflow. - Action().LoadRegMark(DispositionAllowRegMark). // AntreaPolicy. - Action().LoadRegMark(CustomReasonLoggingRegMark). // Enable logging. + Action().LoadToRegField(conjReg, conjunctionID). // Traceflow. + Action().LoadRegMark(DispositionAllowRegMark, CustomReasonLoggingRegMark). // AntreaPolicy, Enable logging. Action().SendToController(uint8(PacketInReasonNP)). Action().CT(true, nextTable, ctZone, f.ctZoneSrcField). // CT action requires commit flag if actions other than NAT without arguments are specified. LoadToLabelField(uint64(conjunctionID), labelField). @@ -1798,8 +1770,7 @@ func (f *featureNetworkPolicy) conjunctionActionPassFlow(conjunctionID uint32, t Action().LoadToRegField(conjReg, conjunctionID) if enableLogging { flowBuilder = flowBuilder. - Action().LoadRegMark(DispositionPassRegMark). - Action().LoadRegMark(CustomReasonLoggingRegMark). + Action().LoadRegMark(DispositionPassRegMark, CustomReasonLoggingRegMark). Action().SendToController(uint8(PacketInReasonNP)) } return flowBuilder.Action().GotoTable(nextTable.GetID()). @@ -1935,62 +1906,6 @@ func (f *featureNetworkPolicy) relatedConnectionFlows() []binding.Flow { return flows } -// rejectBypassNetworkpolicyFlows generates flows to ensure reject responses generated by the controller skip the -// NetworkPolicy rules. -func (f *featureNetworkPolicy) rejectBypassNetworkpolicyFlows() []binding.Flow { - // egressDropTable checks the source address of packets, and drops packets sent from the AppliedToGroup but not - // matching the NetworkPolicy rules. Generated reject responses need not to be checked with the - // egressRuleTable or the egressDropTable. - egressDropTable := EgressDefaultTable - // ingressDropTable checks the destination address of packets, and drops packets sent to the AppliedToGroup but not - // matching the NetworkPolicy rules. Generated reject responses need not to be checked with the - // ingressRuleTable or ingressDropTable. - ingressDropTable := IngressDefaultTable - cookieID := f.cookieAllocator.Request(f.category).Raw() - var flows []binding.Flow - for _, ipProtocol := range f.ipProtocols { - egressRejFlow := EgressRuleTable.ofTable.BuildFlow(priorityHigh). - Cookie(cookieID). - MatchProtocol(ipProtocol). - MatchRegFieldWithValue(CustomReasonField, CustomReasonReject). - Action().GotoTable(egressDropTable.GetNext()). - Done() - ingressRejFlow := IngressRuleTable.ofTable.BuildFlow(priorityHigh). - Cookie(cookieID). - MatchProtocol(ipProtocol). - MatchRegFieldWithValue(CustomReasonField, CustomReasonReject). - Action().GotoTable(ingressDropTable.GetID()). - Done() - flows = append(flows, egressRejFlow, ingressRejFlow) - } - if !f.enableAntreaPolicy { - return flows - } - for _, table := range GetAntreaPolicyEgressTables() { - for _, ipProtocol := range f.ipProtocols { - apEgressRejFlow := table.ofTable.BuildFlow(priorityTopAntreaPolicy). - Cookie(cookieID). - MatchProtocol(ipProtocol). - MatchRegFieldWithValue(CustomReasonField, CustomReasonReject). - Action().GotoTable(egressDropTable.GetNext()). - Done() - flows = append(flows, apEgressRejFlow) - } - } - for _, table := range GetAntreaPolicyIngressTables() { - for _, ipProtocol := range f.ipProtocols { - apIngressRejFlow := table.ofTable.BuildFlow(priorityTopAntreaPolicy). - Cookie(cookieID). - MatchProtocol(ipProtocol). - MatchRegFieldWithValue(CustomReasonField, CustomReasonReject). - Action().GotoTable(ingressDropTable.GetNext()). - Done() - flows = append(flows, apIngressRejFlow) - } - } - return flows -} - func (f *featureNetworkPolicy) addFlowMatch(fb binding.FlowBuilder, matchKey *types.MatchKey, matchValue interface{}) binding.FlowBuilder { switch matchKey { case MatchDstOFPort: @@ -2042,6 +1957,26 @@ func (f *featureNetworkPolicy) addFlowMatch(fb binding.FlowBuilder, matchKey *ty if portValue.Value > 0 { fb = fb.MatchSrcPort(portValue.Value, portValue.Mask) } + case MatchICMPType: + fb = fb.MatchProtocol(matchKey.GetOFProtocol()) + if matchValue != nil { + fb = fb.MatchICMPType(uint8(*matchValue.(*int32))) + } + case MatchICMPCode: + fb = fb.MatchProtocol(matchKey.GetOFProtocol()) + if matchValue != nil { + fb = fb.MatchICMPCode(uint8(*matchValue.(*int32))) + } + case MatchICMPv6Type: + fb = fb.MatchProtocol(matchKey.GetOFProtocol()) + if matchValue != nil { + fb = fb.MatchICMPv6Type(uint8(*matchValue.(*int32))) + } + case MatchICMPv6Code: + fb = fb.MatchProtocol(matchKey.GetOFProtocol()) + if matchValue != nil { + fb = fb.MatchICMPv6Code(uint8(*matchValue.(*int32))) + } case MatchServiceGroupID: fb = fb.MatchRegFieldWithValue(ServiceGroupIDField, matchValue.(uint32)) } @@ -2064,7 +1999,7 @@ func (f *featureNetworkPolicy) conjunctionExceptionFlow(conjunctionID uint32, ta } // conjunctiveMatchFlow generates the flow to set conjunctive actions if the match condition is matched. -func (f *featureNetworkPolicy) conjunctiveMatchFlow(tableID uint8, matchKey *types.MatchKey, matchValue interface{}, priority *uint16, actions []*conjunctiveAction) binding.Flow { +func (f *featureNetworkPolicy) conjunctiveMatchFlow(tableID uint8, matchPairs []matchPair, priority *uint16, actions []*conjunctiveAction) binding.Flow { var ofPriority uint16 if priority != nil { ofPriority = *priority @@ -2072,7 +2007,9 @@ func (f *featureNetworkPolicy) conjunctiveMatchFlow(tableID uint8, matchKey *typ ofPriority = priorityNormal } fb := getTableByID(tableID).BuildFlow(ofPriority) - fb = f.addFlowMatch(fb, matchKey, matchValue) + for _, eachMatchPair := range matchPairs { + fb = f.addFlowMatch(fb, eachMatchPair.matchKey, eachMatchPair.matchValue) + } if f.deterministic { sort.Sort(conjunctiveActionsInOrder(actions)) } @@ -2083,20 +2020,20 @@ func (f *featureNetworkPolicy) conjunctiveMatchFlow(tableID uint8, matchKey *typ } // defaultDropFlow generates the flow to drop packets if the match condition is matched. -func (f *featureNetworkPolicy) defaultDropFlow(table binding.Table, matchKey *types.MatchKey, matchValue interface{}) binding.Flow { +func (f *featureNetworkPolicy) defaultDropFlow(table binding.Table, matchPairs []matchPair) binding.Flow { cookieID := f.cookieAllocator.Request(f.category).Raw() fb := table.BuildFlow(priorityNormal) + for _, eachMatchPair := range matchPairs { + fb = f.addFlowMatch(fb, eachMatchPair.matchKey, eachMatchPair.matchValue) + } if f.enableDenyTracking { - return f.addFlowMatch(fb, matchKey, matchValue). - Action().Drop(). - Action().LoadRegMark(DispositionDropRegMark). - Action().LoadRegMark(CustomReasonDenyRegMark). + return fb.Action().Drop(). + Action().LoadRegMark(DispositionDropRegMark, CustomReasonDenyRegMark). Action().SendToController(uint8(PacketInReasonNP)). Cookie(cookieID). Done() } - return f.addFlowMatch(fb, matchKey, matchValue). - Action().Drop(). + return fb.Action().Drop(). Cookie(cookieID). Done() } @@ -2112,34 +2049,48 @@ func (f *featureNetworkPolicy) dnsPacketInFlow(conjunctionID uint32) binding.Flo Done() } -// localProbeFlow generates the flow to forward locally generated packets to ConntrackCommitTable, bypassing ingress -// rules of Network Policies. The packets are sent by kubelet to probe the liveness/readiness of local Pods. -// On Linux and when OVS kernel datapath is used, it identifies locally generated packets by matching the -// HostLocalSourceMark, otherwise it matches the source IP. The difference is because: -// 1. On Windows, kube-proxy userspace mode is used, and currently there is no way to distinguish kubelet generated -// traffic from kube-proxy proxied traffic. +// localProbeFlows generates the flows to forward locally generated request packets to stageConntrack directly, bypassing +// ingress rules of Network Policies. The packets are sent by kubelet to probe the liveness/readiness of local Pods. +// On Linux and when OVS kernel datapath is used, the probe packets are identified by matching the HostLocalSourceMark. +// On Windows or when OVS userspace (netdev) datapath is used, we need a different approach because: +// 1. On Windows, kube-proxy userspace mode is used, and currently there is no way to distinguish kubelet generated traffic +// from kube-proxy proxied traffic. // 2. pkt_mark field is not properly supported for OVS userspace (netdev) datapath. -// Note that there is a defect in the latter way that NodePort Service access by external clients will be masqueraded as -// a local gateway IP to bypass Network Policies. See https://github.com/antrea-io/antrea/issues/280. -// TODO: Fix it after replacing kube-proxy with AntreaProxy. -func (f *featurePodConnectivity) localProbeFlow(ovsDatapathType ovsconfig.OVSDatapathType) []binding.Flow { +// When proxyAll is disabled, the probe packets are identified by matching the source IP is the Antrea gateway IP; +// otherwise, the packets are identified by matching both the Antrea gateway IP and NotServiceCTMark. Note that, when +// proxyAll is disabled, currently there is no way to distinguish kubelet generated traffic from kube-proxy proxied traffic +// only by matching the Antrea gateway IP. There is a defect that NodePort Service access by external clients will be +// masqueraded as the Antrea gateway IP to bypass NetworkPolicies. See https://github.com/antrea-io/antrea/issues/280. +func (f *featurePodConnectivity) localProbeFlows() []binding.Flow { cookieID := f.cookieAllocator.Request(f.category).Raw() var flows []binding.Flow - if runtime.IsWindowsPlatform() || ovsDatapathType == ovsconfig.OVSDatapathNetdev { + if runtime.IsWindowsPlatform() { + var ctMarksToMatch []*binding.CtMark + if f.proxyAll { + ctMarksToMatch = append(ctMarksToMatch, NotServiceCTMark) + } for ipProtocol, gatewayIP := range f.gatewayIPs { flows = append(flows, IngressSecurityClassifierTable.ofTable.BuildFlow(priorityHigh). Cookie(cookieID). MatchProtocol(ipProtocol). + MatchCTStateRpl(false). + MatchCTStateTrk(true). MatchSrcIP(gatewayIP). + MatchCTMark(ctMarksToMatch...). Action().GotoStage(stageConntrack). Done()) } } else { - flows = append(flows, IngressSecurityClassifierTable.ofTable.BuildFlow(priorityHigh). - Cookie(cookieID). - MatchPktMark(types.HostLocalSourceMark, &types.HostLocalSourceMark). - Action().GotoStage(stageConntrack). - Done()) + for _, ipProtocol := range f.ipProtocols { + flows = append(flows, IngressSecurityClassifierTable.ofTable.BuildFlow(priorityHigh). + Cookie(cookieID). + MatchProtocol(ipProtocol). + MatchCTStateRpl(false). + MatchCTStateTrk(true). + MatchPktMark(types.HostLocalSourceMark, &types.HostLocalSourceMark). + Action().GotoStage(stageConntrack). + Done()) + } } return flows } @@ -2161,6 +2112,12 @@ func (f *featureNetworkPolicy) ingressClassifierFlows() []binding.Flow { MatchRegMark(ToTunnelRegMark). Action().GotoTable(IngressMetricTable.GetID()). Done(), + // This generates the flow to match the packets to uplink and forward them to IngressMetricTable. + IngressSecurityClassifierTable.ofTable.BuildFlow(priorityNormal). + Cookie(cookieID). + MatchRegMark(ToUplinkRegMark). + Action().GotoTable(IngressMetricTable.GetID()). + Done(), } } @@ -2226,29 +2183,31 @@ func (f *featureEgress) snatRuleFlow(ofPort uint32, snatIP net.IP, snatMark uint // nodePortMarkFlows generates the flows to mark the first packet of Service NodePort connection with ToNodePortAddressRegMark, // which indicates the Service type is NodePort. -func (f *featureService) nodePortMarkFlows(nodePortAddresses []net.IP, ipProtocol binding.Protocol) []binding.Flow { +func (f *featureService) nodePortMarkFlows() []binding.Flow { cookieID := f.cookieAllocator.Request(f.category).Raw() var flows []binding.Flow - // This generates a flow for every NodePort IP. The flows are used to mark the first packet of NodePort connections - // from a local Pod. - for i := range nodePortAddresses { + for ipProtocol, nodePortAddresses := range f.nodePortAddresses { + // This generates a flow for every NodePort IP. The flows are used to mark the first packet of NodePort connection + // from a local Pod. + for i := range nodePortAddresses { + flows = append(flows, + NodePortMarkTable.ofTable.BuildFlow(priorityNormal). + Cookie(cookieID). + MatchProtocol(ipProtocol). + MatchDstIP(nodePortAddresses[i]). + Action().LoadRegMark(ToNodePortAddressRegMark). + Done()) + } + // This generates the flow for the virtual IP. The flow is used to mark the first packet of NodePort connection from + // the Antrea gateway (the connection is performed DNAT with the virtual IP in host netns). flows = append(flows, NodePortMarkTable.ofTable.BuildFlow(priorityNormal). Cookie(cookieID). MatchProtocol(ipProtocol). - MatchDstIP(nodePortAddresses[i]). + MatchDstIP(f.virtualIPs[ipProtocol]). Action().LoadRegMark(ToNodePortAddressRegMark). Done()) } - // This generates the flow for the virtual IP. The flow is used to mark the first packet of NodePort connection from - // the Antrea gateway (the connection is performed DNAT with the virtual IP in host netns). - flows = append(flows, - NodePortMarkTable.ofTable.BuildFlow(priorityNormal). - Cookie(cookieID). - MatchProtocol(ipProtocol). - MatchDstIP(f.virtualIPs[ipProtocol]). - Action().LoadRegMark(ToNodePortAddressRegMark). - Done()) return flows } @@ -2352,23 +2311,26 @@ func (f *featureService) serviceLBFlow(groupID binding.GroupIDType, } else { lbResultMark = EpSelectedRegMark } + regMarksToMatch := []*binding.RegMark{lbResultMark, RewriteMACRegMark} var flowBuilder binding.FlowBuilder if serviceType == v1.ServiceTypeNodePort { // If externalTrafficPolicy of NodePort is Cluster, the first packet of NodePort requires SNAT, so nodeLocalExternal // will be false, and ServiceNeedSNATRegMark will be set. If externalTrafficPolicy of NodePort is Local, the first // packet of NodePort doesn't require SNAT, ServiceNeedSNATRegMark won't be set. unionVal := (ToNodePortAddressRegMark.GetValue() << ServiceEPStateField.GetRange().Length()) + EpToSelectRegMark.GetValue() + if !nodeLocalExternal { + regMarksToMatch = append(regMarksToMatch, ToClusterServiceRegMark) + } flowBuilder = ServiceLBTable.ofTable.BuildFlow(priorityNormal). Cookie(cookieID). MatchProtocol(protocol). MatchRegFieldWithValue(NodePortUnionField, unionVal). MatchDstPort(svcPort, nil). - Action().LoadRegMark(lbResultMark). - Action().LoadRegMark(RewriteMACRegMark) - if !nodeLocalExternal { - flowBuilder = flowBuilder.Action().LoadRegMark(ToClusterServiceRegMark) - } + Action().LoadRegMark(regMarksToMatch...) } else { + if serviceType == v1.ServiceTypeLoadBalancer && !nodeLocalExternal { + regMarksToMatch = append(regMarksToMatch, ToClusterServiceRegMark) + } // If Service type is LoadBalancer, as above NodePort. flowBuilder = ServiceLBTable.ofTable.BuildFlow(priorityNormal). Cookie(cookieID). @@ -2376,11 +2338,7 @@ func (f *featureService) serviceLBFlow(groupID binding.GroupIDType, MatchDstPort(svcPort, nil). MatchDstIP(svcIP). MatchRegMark(EpToSelectRegMark). - Action().LoadRegMark(lbResultMark). - Action().LoadRegMark(RewriteMACRegMark) - if serviceType == v1.ServiceTypeLoadBalancer && !nodeLocalExternal { - flowBuilder = flowBuilder.Action().LoadRegMark(ToClusterServiceRegMark) - } + Action().LoadRegMark(regMarksToMatch...) } return flowBuilder. Action().LoadToRegField(ServiceGroupIDField, uint32(groupID)). @@ -2431,7 +2389,7 @@ func (f *featureService) serviceEndpointGroup(groupID binding.GroupIDType, withS for _, endpoint := range endpoints { endpointPort, _ := endpoint.Port() endpointIP := net.ParseIP(endpoint.IP()) - portVal := portToUint16(endpointPort) + portVal := util.PortToUint16(endpointPort) ipProtocol := getIPProtocol(endpointIP) if ipProtocol == binding.ProtocolIP { @@ -2481,17 +2439,8 @@ func (f *featurePodConnectivity) decTTLFlows() []binding.Flow { // externalFlows generates the flows to perform SNAT for the packets of connection to the external network. The flows identify // the packets to external network, and send them to EgressMarkTable, where SNAT IPs are looked up for the packets. -func (f *featureEgress) externalFlows(exceptCIDRs []net.IPNet) []binding.Flow { +func (f *featureEgress) externalFlows() []binding.Flow { cookieID := f.cookieAllocator.Request(f.category).Raw() - exceptCIDRsMap := make(map[binding.Protocol][]net.IPNet) - for _, cidr := range exceptCIDRs { - if cidr.IP.To4() == nil { - exceptCIDRsMap[binding.ProtocolIPv6] = append(exceptCIDRsMap[binding.ProtocolIPv6], cidr) - } else { - exceptCIDRsMap[binding.ProtocolIP] = append(exceptCIDRsMap[binding.ProtocolIP], cidr) - } - } - var flows []binding.Flow for _, ipProtocol := range f.ipProtocols { flows = append(flows, @@ -2529,7 +2478,7 @@ func (f *featureEgress) externalFlows(exceptCIDRs []net.IPNet) []binding.Flow { f.snatSkipNodeFlow(f.nodeIPs[ipProtocol]), ) // This generates the flows to bypass the packets sourced from local Pods and destined for the except CIDRs for Egress. - for _, cidr := range exceptCIDRsMap[ipProtocol] { + for _, cidr := range f.exceptCIDRs[ipProtocol] { flows = append(flows, EgressMarkTable.ofTable.BuildFlow(priorityHigh). Cookie(cookieID). MatchProtocol(ipProtocol). @@ -2626,8 +2575,8 @@ func pipelineClassifyFlow(cookieID uint64, protocol binding.Protocol, pipeline b Done() } -// igmpPktInFlows generates the flow to load CustomReasonIGMPRegMark to mark the IGMP packet in MulticastTable and sends -// it to antrea-agent on MulticastTable. +// igmpPktInFlows generates the flow to load CustomReasonIGMPRegMark to mark the IGMP packet in MulticastRoutingTable and sends +// it to antrea-agent. func (f *featureMulticast) igmpPktInFlows(reason uint8) []binding.Flow { flows := []binding.Flow{ // Set a custom reason for the IGMP packets, and then send it to antrea-agent and forward it normally in the @@ -2635,7 +2584,7 @@ func (f *featureMulticast) igmpPktInFlows(reason uint8) []binding.Flow { // group and its members in the meanwhile. // Do not set dst IP address because IGMPv1 report message uses target multicast group as IP destination in // the packet. - MulticastTable.ofTable.BuildFlow(priorityHigh). + MulticastRoutingTable.ofTable.BuildFlow(priorityHigh). Cookie(f.cookieAllocator.Request(f.category).Raw()). MatchProtocol(binding.ProtocolIGMP). MatchRegMark(FromLocalRegMark). @@ -2647,47 +2596,48 @@ func (f *featureMulticast) igmpPktInFlows(reason uint8) []binding.Flow { return flows } -// localMulticastForwardFlow generates the flow to forward multicast packets with OVS action "normal", and outputs +// localMulticastForwardFlows generates the flow to forward multicast packets with OVS action "normal", and outputs // it to Antrea gateway in the meanwhile, so that the packet can be forwarded to local Pods which have joined the Multicast // group and to the external receivers. For external multicast packets accessing to the given multicast IP also hits the // flow, and the packet is not sent back to Antrea gateway because OVS datapath will drop it when it finds the output // port is the same as the input port. -func (f *featureMulticast) localMulticastForwardFlow(multicastIP net.IP) []binding.Flow { +func (f *featureMulticast) localMulticastForwardFlows(multicastIP net.IP, groupID binding.GroupIDType) []binding.Flow { return []binding.Flow{ - MulticastTable.ofTable.BuildFlow(priorityNormal). + MulticastRoutingTable.ofTable.BuildFlow(priorityNormal). Cookie(f.cookieAllocator.Request(f.category).Raw()). MatchProtocol(binding.ProtocolIP). MatchDstIP(multicastIP). - Action().Output(config.HostGatewayOFPort). - Action().Normal(). + Action().Group(groupID). Done(), } } // externalMulticastReceiverFlow generates the flow to output multicast packets to Antrea gateway, so that local Pods can // send multicast packets to access the external receivers. For the case that one or more local Pods have joined the target -// multicast group, it is handled by the flows created by function "localMulticastForwardFlow" after local Pods report the +// multicast group, it is handled by the flows created by function "localMulticastForwardFlows" after local Pods report the // IGMP membership. func (f *featureMulticast) externalMulticastReceiverFlow() binding.Flow { - return MulticastTable.ofTable.BuildFlow(priorityLow). + return MulticastRoutingTable.ofTable.BuildFlow(priorityLow). Cookie(f.cookieAllocator.Request(f.category).Raw()). MatchProtocol(binding.ProtocolIP). MatchDstIPNet(*mcastCIDR). - Action().Output(config.HostGatewayOFPort). + Action().LoadRegMark(OFPortFoundRegMark). + Action().LoadToRegField(TargetOFPortField, config.HostGatewayOFPort). + Action().NextTable(). Done() } // NewClient is the constructor of the Client interface. func NewClient(bridgeName string, mgmtAddr string, - ovsDatapathType ovsconfig.OVSDatapathType, enableProxy bool, enableAntreaPolicy bool, enableEgress bool, enableDenyTracking bool, proxyAll bool, connectUplinkToBridge bool, - enableMulticast bool) Client { + enableMulticast bool, + enableTrafficControl bool) Client { bridge := binding.NewOFBridge(bridgeName, mgmtAddr) c := &client{ bridge: bridge, @@ -2697,12 +2647,12 @@ func NewClient(bridgeName string, enableDenyTracking: enableDenyTracking, enableEgress: enableEgress, enableMulticast: enableMulticast, + enableTrafficControl: enableTrafficControl, connectUplinkToBridge: connectUplinkToBridge, pipelines: make(map[binding.PipelineID]binding.Pipeline), packetInHandlers: map[uint8]map[string]PacketInHandler{}, ovsctlClient: ovsctl.NewClient(bridgeName), - ovsDatapathType: ovsDatapathType, - ovsMetersAreSupported: ovsMetersAreSupported(ovsDatapathType), + ovsMetersAreSupported: ovsMetersAreSupported(), } c.ofEntryOperations = c return c @@ -2726,17 +2676,17 @@ func (sl conjunctiveActionsInOrder) Less(i, j int) bool { func (f *featurePodConnectivity) l3FwdFlowToLocalPodCIDR() []binding.Flow { cookieID := f.cookieAllocator.Request(f.category).Raw() var flows []binding.Flow + regMarksToMatch := []*binding.RegMark{NotRewriteMACRegMark} + if f.connectUplinkToBridge { + regMarksToMatch = append(regMarksToMatch, binding.NewRegMark(VLANIDField, 0)) + } for ipProtocol, cidr := range f.localCIDRs { // This generates the flow to match the packets destined for local Pods without RewriteMACRegMark. - fb := L3ForwardingTable.ofTable.BuildFlow(priorityLow). - Cookie(cookieID) - if f.connectUplinkToBridge { - fb = fb.MatchRegFieldWithValue(VLANIDField, 0) - } - flows = append(flows, fb. + flows = append(flows, L3ForwardingTable.ofTable.BuildFlow(priorityLow). + Cookie(cookieID). MatchProtocol(ipProtocol). MatchDstIPNet(cidr). - MatchRegMark(NotRewriteMACRegMark). + MatchRegMark(regMarksToMatch...). Action().GotoStage(stageSwitching). Done()) } @@ -2746,29 +2696,31 @@ func (f *featurePodConnectivity) l3FwdFlowToLocalPodCIDR() []binding.Flow { // l3FwdFlowToNode generates the flows to match the packets destined for local Node. func (f *featurePodConnectivity) l3FwdFlowToNode() []binding.Flow { cookieID := f.cookieAllocator.Request(f.category).Raw() + var regMarksToMatch []*binding.RegMark + if f.connectUplinkToBridge { + regMarksToMatch = append(regMarksToMatch, binding.NewRegMark(VLANIDField, 0)) + } var flows []binding.Flow for ipProtocol, nodeIP := range f.nodeIPs { - fb1 := L3ForwardingTable.ofTable.BuildFlow(priorityHigh). - Cookie(cookieID) - fb2 := L3ForwardingTable.ofTable.BuildFlow(priorityHigh). - Cookie(cookieID) - if f.connectUplinkToBridge { - fb1 = fb1.MatchRegFieldWithValue(VLANIDField, 0) - fb2 = fb2.MatchRegFieldWithValue(VLANIDField, 0) - } flows = append(flows, // This generates the flow to match the packets sourced from local Antrea Pods and destined for local Node // via bridge local port. - fb1.MatchProtocol(ipProtocol). + L3ForwardingTable.ofTable.BuildFlow(priorityHigh). + Cookie(cookieID). + MatchProtocol(ipProtocol). MatchDstIP(nodeIP). MatchRegMark(AntreaFlexibleIPAMRegMark). + MatchRegMark(regMarksToMatch...). Action().SetDstMAC(f.nodeConfig.UplinkNetConfig.MAC). Action().GotoStage(stageSwitching). Done(), // When Node bridge local port and uplink port connect to OVS, this generates the flow to match the reply // packets of connection initiated through the bridge local port with FromBridgeCTMark. - fb2.MatchProtocol(ipProtocol). + L3ForwardingTable.ofTable.BuildFlow(priorityHigh). + Cookie(cookieID). + MatchProtocol(ipProtocol). MatchCTMark(FromBridgeCTMark). + MatchRegMark(regMarksToMatch...). MatchCTStateRpl(true). MatchCTStateTrk(true). Action().SetDstMAC(f.nodeConfig.UplinkNetConfig.MAC). @@ -2786,7 +2738,6 @@ func (f *featurePodConnectivity) l3FwdFlowToExternal() binding.Flow { Action().LoadRegMark(ToGatewayRegMark). Action().GotoStage(stageSwitching). Done() - } // hostBridgeLocalFlows generates the flows to match the packets forwarded between bridge local port and uplink port. @@ -2867,8 +2818,7 @@ func (f *featureService) l3FwdFlowsToExternalEndpoint() []binding.Flow { // destined for external network. L3ForwardingTable.ofTable.BuildFlow(priorityLow). Cookie(cookieID). - MatchRegMark(RewriteMACRegMark). - MatchRegMark(NotAntreaFlexibleIPAMRegMark). + MatchRegMark(RewriteMACRegMark, NotAntreaFlexibleIPAMRegMark). MatchCTMark(ServiceCTMark). Action().SetDstMAC(f.gatewayMAC). Action().LoadRegMark(ToGatewayRegMark). @@ -2911,8 +2861,7 @@ func (f *featureService) podHairpinSNATFlow(endpoint net.IP) binding.Flow { MatchSrcIP(endpoint). MatchDstIP(endpoint). Action().CT(true, ServiceMarkTable.GetNext(), f.dnatCtZones[ipProtocol], f.ctZoneSrcField). - LoadToCtMark(ConnSNATCTMark). - LoadToCtMark(HairpinCTMark). + LoadToCtMark(ConnSNATCTMark, HairpinCTMark). CTDone(). Done() } @@ -2923,35 +2872,41 @@ func (f *featureService) gatewaySNATFlows() []binding.Flow { cookieID := f.cookieAllocator.Request(f.category).Raw() var flows []binding.Flow for _, ipProtocol := range f.ipProtocols { - flows = append(flows, - // This generates the flow to match the first packet of hairpin connection initiated through the Antrea gateway. - // ConnSNATCTMark and HairpinCTMark will be loaded in DNAT CT zone. - ServiceMarkTable.ofTable.BuildFlow(priorityNormal). - Cookie(cookieID). - MatchProtocol(ipProtocol). - MatchCTStateNew(true). - MatchCTStateTrk(true). - MatchRegMark(GatewayHairpinRegMark). - Action().CT(true, ServiceMarkTable.GetNext(), f.dnatCtZones[ipProtocol], f.ctZoneSrcField). - LoadToCtMark(ConnSNATCTMark). - LoadToCtMark(HairpinCTMark). - CTDone(). - Done(), + // This generates the flow to match the first packet of hairpin connection initiated through the Antrea gateway. + // ConnSNATCTMark and HairpinCTMark will be loaded in DNAT CT zone. + flows = append(flows, ServiceMarkTable.ofTable.BuildFlow(priorityNormal). + Cookie(cookieID). + MatchProtocol(ipProtocol). + MatchCTStateNew(true). + MatchCTStateTrk(true). + MatchRegMark(FromGatewayRegMark, ToGatewayRegMark). + Action().CT(true, ServiceMarkTable.GetNext(), f.dnatCtZones[ipProtocol], f.ctZoneSrcField). + LoadToCtMark(ConnSNATCTMark, HairpinCTMark). + CTDone(). + Done()) + + var pktDstRegMarks []*binding.RegMark + if f.networkConfig.TrafficEncapMode.SupportsEncap() { + pktDstRegMarks = append(pktDstRegMarks, ToTunnelRegMark) + } + if f.networkConfig.TrafficEncapMode.SupportsNoEncap() && runtime.IsWindowsPlatform() { + pktDstRegMarks = append(pktDstRegMarks, ToUplinkRegMark) + } + for _, pktDstRegMark := range pktDstRegMarks { // This generates the flow to match the first packet of NodePort / LoadBalancer connection initiated through the - // Antrea gateway and externalTrafficPolicy of the Service is Cluster. ConnSNATCTMark will be loaded in DNAT - // CT zone. - ServiceMarkTable.ofTable.BuildFlow(priorityLow). + // Antrea gateway and externalTrafficPolicy of the Service is Cluster, and the selected Endpoint is on a remote + // Node, then ConnSNATCTMark will be loaded in DNAT CT zone, indicating that SNAT is required for the connection. + flows = append(flows, ServiceMarkTable.ofTable.BuildFlow(priorityNormal). Cookie(cookieID). MatchProtocol(ipProtocol). MatchCTStateNew(true). MatchCTStateTrk(true). - MatchRegMark(FromGatewayRegMark). - MatchRegMark(ToClusterServiceRegMark). + MatchRegMark(FromGatewayRegMark, pktDstRegMark, ToClusterServiceRegMark). Action().CT(true, ServiceMarkTable.GetNext(), f.dnatCtZones[ipProtocol], f.ctZoneSrcField). LoadToCtMark(ConnSNATCTMark). CTDone(). - Done(), - ) + Done()) + } } return flows diff --git a/pkg/agent/openflow/pipeline_other.go b/pkg/agent/openflow/pipeline_other.go index e431ce28ca0..0a92d0936e1 100644 --- a/pkg/agent/openflow/pipeline_other.go +++ b/pkg/agent/openflow/pipeline_other.go @@ -65,8 +65,7 @@ func (f *featurePodConnectivity) hostBridgeUplinkFlows(localSubnetMap map[bindin L2ForwardingOutTable.ofTable.BuildFlow(priorityHigh). Cookie(cookieID). MatchProtocol(binding.ProtocolIP). - MatchRegMark(OutputToBridgeRegMark). - MatchRegMark(OFPortFoundRegMark). + MatchRegMark(OutputToBridgeRegMark, OFPortFoundRegMark). Action().Output(config.BridgeOFPort). Done(), // Handle outgoing packet from AntreaFlexibleIPAM Pods. Broadcast is not supported. diff --git a/pkg/agent/openflow/pipeline_windows.go b/pkg/agent/openflow/pipeline_windows.go index 59c6dbe54ac..8de809013f6 100644 --- a/pkg/agent/openflow/pipeline_windows.go +++ b/pkg/agent/openflow/pipeline_windows.go @@ -54,8 +54,7 @@ func (f *featurePodConnectivity) hostBridgeUplinkFlows(localSubnetMap map[bindin MatchProtocol(ipProtocol). MatchInPort(config.UplinkOFPort). MatchDstIPNet(localSubnet). - Action().LoadRegMark(FromUplinkRegMark). - Action().LoadRegMark(RewriteMACRegMark). + Action().LoadRegMark(FromUplinkRegMark, RewriteMACRegMark). Action().GotoStage(stageConntrackState). Done()) } diff --git a/pkg/agent/openflow/pod_connectivity.go b/pkg/agent/openflow/pod_connectivity.go index 8e8354d6430..4afaf007d72 100644 --- a/pkg/agent/openflow/pod_connectivity.go +++ b/pkg/agent/openflow/pod_connectivity.go @@ -19,7 +19,9 @@ import ( "antrea.io/antrea/pkg/agent/config" "antrea.io/antrea/pkg/agent/openflow/cookie" + "antrea.io/antrea/pkg/apis/crd/v1alpha2" binding "antrea.io/antrea/pkg/ovs/openflow" + "antrea.io/antrea/pkg/util/runtime" ) type featurePodConnectivity struct { @@ -28,7 +30,7 @@ type featurePodConnectivity struct { nodeCachedFlows *flowCategoryCache podCachedFlows *flowCategoryCache - fixedFlows []binding.Flow + tcCachedFlows *flowCategoryCache gatewayIPs map[binding.Protocol]net.IP ctZones map[binding.Protocol]int @@ -39,7 +41,10 @@ type featurePodConnectivity struct { connectUplinkToBridge bool ctZoneSrcField *binding.RegField + ipCtZoneTypeRegMarks map[binding.Protocol]*binding.RegMark enableMulticast bool + proxyAll bool + enableTrafficControl bool category cookie.Category } @@ -54,11 +59,14 @@ func newFeaturePodConnectivity( nodeConfig *config.NodeConfig, networkConfig *config.NetworkConfig, connectUplinkToBridge bool, - enableMulticast bool) *featurePodConnectivity { + enableMulticast bool, + proxyAll bool, + enableTrafficControl bool) *featurePodConnectivity { ctZones := make(map[binding.Protocol]int) gatewayIPs := make(map[binding.Protocol]net.IP) localCIDRs := make(map[binding.Protocol]net.IPNet) nodeIPs := make(map[binding.Protocol]net.IP) + ipCtZoneTypeRegMarks := make(map[binding.Protocol]*binding.RegMark) for _, ipProtocol := range ipProtocols { if ipProtocol == binding.ProtocolIP { ctZones[ipProtocol] = CtZone @@ -67,6 +75,7 @@ func newFeaturePodConnectivity( if nodeConfig.PodIPv4CIDR != nil { localCIDRs[ipProtocol] = *nodeConfig.PodIPv4CIDR } + ipCtZoneTypeRegMarks[ipProtocol] = IPCtZoneTypeRegMark } else if ipProtocol == binding.ProtocolIPv6 { ctZones[ipProtocol] = CtZoneV6 gatewayIPs[ipProtocol] = nodeConfig.GatewayConfig.IPv6 @@ -74,6 +83,7 @@ func newFeaturePodConnectivity( if nodeConfig.PodIPv6CIDR != nil { localCIDRs[ipProtocol] = *nodeConfig.PodIPv6CIDR } + ipCtZoneTypeRegMarks[ipProtocol] = IPv6CtZoneTypeRegMark } } @@ -82,6 +92,7 @@ func newFeaturePodConnectivity( ipProtocols: ipProtocols, nodeCachedFlows: newFlowCategoryCache(), podCachedFlows: newFlowCategoryCache(), + tcCachedFlows: newFlowCategoryCache(), gatewayIPs: gatewayIPs, ctZones: ctZones, localCIDRs: localCIDRs, @@ -89,22 +100,35 @@ func newFeaturePodConnectivity( nodeConfig: nodeConfig, networkConfig: networkConfig, connectUplinkToBridge: connectUplinkToBridge, + enableTrafficControl: enableTrafficControl, + ipCtZoneTypeRegMarks: ipCtZoneTypeRegMarks, ctZoneSrcField: getZoneSrcField(connectUplinkToBridge), enableMulticast: enableMulticast, + proxyAll: proxyAll, category: cookie.PodConnectivity, } } func (f *featurePodConnectivity) initFlows() []binding.Flow { var flows []binding.Flow + gatewayMAC := f.nodeConfig.GatewayConfig.MAC for _, ipProtocol := range f.ipProtocols { if ipProtocol == binding.ProtocolIPv6 { flows = append(flows, f.ipv6Flows()...) } else if ipProtocol == binding.ProtocolIP { flows = append(flows, f.arpNormalFlow()) + flows = append(flows, f.arpSpoofGuardFlow(f.gatewayIPs[ipProtocol], gatewayMAC, config.HostGatewayOFPort)) if f.connectUplinkToBridge { - flows = append(flows, f.arpResponderFlow(f.nodeConfig.GatewayConfig.IPv4, f.nodeConfig.GatewayConfig.MAC)) + flows = append(flows, f.arpResponderFlow(f.gatewayIPs[ipProtocol], gatewayMAC)) + flows = append(flows, f.arpSpoofGuardFlow(f.nodeConfig.NodeIPv4Addr.IP, gatewayMAC, config.HostGatewayOFPort)) + flows = append(flows, f.hostBridgeUplinkVLANFlows()...) + } + if runtime.IsWindowsPlatform() || f.connectUplinkToBridge { + // This installs the flows between bridge local port and uplink port to support host networking. + // TODO: support IPv6 + podCIDRMap := map[binding.Protocol]net.IPNet{binding.ProtocolIP: *f.nodeConfig.PodIPv4CIDR} + flows = append(flows, f.hostBridgeUplinkFlows(podCIDRMap)...) } } } @@ -115,10 +139,21 @@ func (f *featurePodConnectivity) initFlows() []binding.Flow { flows = append(flows, f.decTTLFlows()...) flows = append(flows, f.conntrackFlows()...) flows = append(flows, f.l2ForwardOutputFlow()) + flows = append(flows, f.gatewayClassifierFlow()) + flows = append(flows, f.l2ForwardCalcFlow(gatewayMAC, config.HostGatewayOFPort)) + flows = append(flows, f.gatewayIPSpoofGuardFlows()...) + flows = append(flows, f.l3FwdFlowToGateway()...) + // Add flow to ensure the liveliness check packet could be forwarded correctly. + flows = append(flows, f.localProbeFlows()...) + + if f.networkConfig.TrafficEncapMode.SupportsEncap() { + flows = append(flows, f.tunnelClassifierFlow(config.DefaultTunOFPort)) + flows = append(flows, f.l2ForwardCalcFlow(GlobalVirtualMAC, config.DefaultTunOFPort)) + } + if f.networkConfig.TrafficEncapMode.IsNetworkPolicyOnly() { flows = append(flows, f.l3FwdFlowRouteToGW()...) - // If IPv6 is enabled, this flow will never get hit. - // Replies any ARP request with the same global virtual MAC. + // If IPv6 is enabled, this flow will never get hit. Replies any ARP request with the same global virtual MAC. flows = append(flows, f.arpResponderStaticFlow()) } else { // If NetworkPolicyOnly mode is enabled, IPAM is implemented by the primary CNI, which may not use the Pod CIDR @@ -126,21 +161,94 @@ func (f *featurePodConnectivity) initFlows() []binding.Flow { // Pod IP will take care of routing the traffic to destination Pod. flows = append(flows, f.l3FwdFlowToLocalPodCIDR()...) } + if f.enableTrafficControl { + flows = append(flows, f.trafficControlCommonFlows()...) + } return flows } func (f *featurePodConnectivity) replayFlows() []binding.Flow { var flows []binding.Flow - // Get fixed flows. - for _, flow := range f.fixedFlows { - flow.Reset() - flows = append(flows, flow) - } // Get cached flows. - for _, cachedFlows := range []*flowCategoryCache{f.nodeCachedFlows, f.podCachedFlows} { + for _, cachedFlows := range []*flowCategoryCache{f.nodeCachedFlows, f.podCachedFlows, f.tcCachedFlows} { flows = append(flows, getCachedFlows(cachedFlows)...) } return flows } + +// trafficControlMarkFlows generates the flows to mark the packets that need to be redirected or mirrored. +func (f *featurePodConnectivity) trafficControlMarkFlows(sourceOFPorts []uint32, targetOFPort uint32, direction v1alpha2.Direction, action v1alpha2.TrafficControlAction) []binding.Flow { + cookieID := f.cookieAllocator.Request(f.category).Raw() + var actionRegMark *binding.RegMark + if action == v1alpha2.ActionRedirect { + actionRegMark = TrafficControlRedirectRegMark + } else if action == v1alpha2.ActionMirror { + actionRegMark = TrafficControlMirrorRegMark + } + var flows []binding.Flow + for _, port := range sourceOFPorts { + if direction == v1alpha2.DirectionIngress || direction == v1alpha2.DirectionBoth { + // This generates the flow to mark the packets destined for a provided port. + flows = append(flows, TrafficControlTable.ofTable.BuildFlow(priorityNormal). + Cookie(cookieID). + MatchRegFieldWithValue(TargetOFPortField, port). + Action().LoadToRegField(TrafficControlTargetOFPortField, targetOFPort). + Action().LoadRegMark(actionRegMark). + Action().NextTable(). + Done()) + } + // This generates the flow to mark the packets sourced from a provided port. + if direction == v1alpha2.DirectionEgress || direction == v1alpha2.DirectionBoth { + flows = append(flows, TrafficControlTable.ofTable.BuildFlow(priorityNormal). + Cookie(cookieID). + MatchInPort(port). + Action().LoadToRegField(TrafficControlTargetOFPortField, targetOFPort). + Action().LoadRegMark(actionRegMark). + Action().NextTable(). + Done()) + } + } + return flows +} + +// trafficControlReturnClassifierFlow generates the flow to mark the packets from traffic control return port and forward +// the packets to stageRouting directly. Note that, for the packets which are originally to be output to a tunnel port, +// value of NXM_NX_TUN_IPV4_DST for the returned packets needs to be loaded in stageRouting. +func (f *featurePodConnectivity) trafficControlReturnClassifierFlow(returnOFPort uint32) binding.Flow { + return ClassifierTable.ofTable.BuildFlow(priorityNormal). + Cookie(f.cookieAllocator.Request(f.category).Raw()). + MatchInPort(returnOFPort). + Action().LoadRegMark(FromTCReturnRegMark). + Action().GotoStage(stageRouting). + Done() +} + +// trafficControlCommonFlows generates the common flows for traffic control. +func (f *featurePodConnectivity) trafficControlCommonFlows() []binding.Flow { + cookieID := f.cookieAllocator.Request(f.category).Raw() + return []binding.Flow{ + // This generates the flow to output packets to the original target port as well as mirror the packets to the target + // traffic control port. + L2ForwardingOutTable.ofTable.BuildFlow(priorityHigh+1). + Cookie(cookieID). + MatchRegMark(OFPortFoundRegMark, TrafficControlMirrorRegMark). + Action().OutputToRegField(TargetOFPortField). + Action().OutputToRegField(TrafficControlTargetOFPortField). + Done(), + // This generates the flow to output the packets to be redirected to the target traffic control port. + L2ForwardingOutTable.ofTable.BuildFlow(priorityHigh+1). + Cookie(cookieID). + MatchRegMark(OFPortFoundRegMark, TrafficControlRedirectRegMark). + Action().OutputToRegField(TrafficControlTargetOFPortField). + Done(), + // This generates the flow to forward the returned packets (with FromTCReturnRegMark) to stageOutput directly + // after loading output port number to reg1 in L2ForwardingCalcTable. + TrafficControlTable.ofTable.BuildFlow(priorityHigh). + Cookie(cookieID). + MatchRegMark(OFPortFoundRegMark, FromTCReturnRegMark). + Action().GotoStage(stageOutput). + Done(), + } +} diff --git a/pkg/agent/openflow/service.go b/pkg/agent/openflow/service.go index 7a102203b70..b24ee2e4a35 100644 --- a/pkg/agent/openflow/service.go +++ b/pkg/agent/openflow/service.go @@ -31,14 +31,16 @@ type featureService struct { bridge binding.Bridge cachedFlows *flowCategoryCache - fixedFlows []binding.Flow groupCache sync.Map - gatewayIPs map[binding.Protocol]net.IP - virtualIPs map[binding.Protocol]net.IP - dnatCtZones map[binding.Protocol]int - snatCtZones map[binding.Protocol]int - gatewayMAC net.HardwareAddr + gatewayIPs map[binding.Protocol]net.IP + virtualIPs map[binding.Protocol]net.IP + dnatCtZones map[binding.Protocol]int + snatCtZones map[binding.Protocol]int + gatewayMAC net.HardwareAddr + nodePortAddresses map[binding.Protocol][]net.IP + serviceCIDRs map[binding.Protocol]net.IPNet + networkConfig *config.NetworkConfig enableProxy bool proxyAll bool @@ -56,6 +58,8 @@ func newFeatureService( cookieAllocator cookie.Allocator, ipProtocols []binding.Protocol, nodeConfig *config.NodeConfig, + networkConfig *config.NetworkConfig, + serviceConfig *config.ServiceConfig, bridge binding.Bridge, enableProxy, proxyAll, @@ -64,17 +68,27 @@ func newFeatureService( virtualIPs := make(map[binding.Protocol]net.IP) dnatCtZones := make(map[binding.Protocol]int) snatCtZones := make(map[binding.Protocol]int) + nodePortAddresses := make(map[binding.Protocol][]net.IP) + serviceCIDRs := make(map[binding.Protocol]net.IPNet) for _, ipProtocol := range ipProtocols { if ipProtocol == binding.ProtocolIP { gatewayIPs[ipProtocol] = nodeConfig.GatewayConfig.IPv4 virtualIPs[ipProtocol] = config.VirtualServiceIPv4 dnatCtZones[ipProtocol] = CtZone snatCtZones[ipProtocol] = SNATCtZone + nodePortAddresses[ipProtocol] = serviceConfig.NodePortAddressesIPv4 + if serviceConfig.ServiceCIDR != nil { + serviceCIDRs[ipProtocol] = *serviceConfig.ServiceCIDR + } } else if ipProtocol == binding.ProtocolIPv6 { gatewayIPs[ipProtocol] = nodeConfig.GatewayConfig.IPv6 virtualIPs[ipProtocol] = config.VirtualServiceIPv6 dnatCtZones[ipProtocol] = CtZoneV6 snatCtZones[ipProtocol] = SNATCtZoneV6 + nodePortAddresses[ipProtocol] = serviceConfig.NodePortAddressesIPv6 + if serviceConfig.ServiceCIDRv6 != nil { + serviceCIDRs[ipProtocol] = *serviceConfig.ServiceCIDRv6 + } } } @@ -88,7 +102,10 @@ func newFeatureService( virtualIPs: virtualIPs, dnatCtZones: dnatCtZones, snatCtZones: snatCtZones, + nodePortAddresses: nodePortAddresses, + serviceCIDRs: serviceCIDRs, gatewayMAC: nodeConfig.GatewayConfig.MAC, + networkConfig: networkConfig, enableProxy: enableProxy, proxyAll: proxyAll, connectUplinkToBridge: connectUplinkToBridge, @@ -105,6 +122,20 @@ func (f *featureService) initFlows() []binding.Flow { flows = append(flows, f.l3FwdFlowsToExternalEndpoint()...) flows = append(flows, f.gatewaySNATFlows()...) flows = append(flows, f.snatConntrackFlows()...) + flows = append(flows, f.serviceNeedLBFlow()) + flows = append(flows, f.sessionAffinityReselectFlow()) + flows = append(flows, f.l2ForwardOutputHairpinServiceFlow()) + if f.proxyAll { + // This installs the flows to match the first packet of NodePort connection. The flows set a bit of a register + // to mark the Service type of the packet as NodePort, and the mark is consumed in table serviceLBTable. + flows = append(flows, f.nodePortMarkFlows()...) + } + } else { + // This installs the flows to enable Service connectivity. Upstream kube-proxy is leveraged to provide load-balancing, + // and the flows installed by this method ensure that traffic sent from local Pods to any Service address can be + // forwarded to the host gateway interface correctly, otherwise packets might be dropped by egress rules before + // they are DNATed to backend Pods. + flows = append(flows, f.serviceCIDRDNATFlows()...) } return flows } @@ -112,11 +143,6 @@ func (f *featureService) initFlows() []binding.Flow { func (f *featureService) replayFlows() []binding.Flow { var flows []binding.Flow - // Get fixed flows. - for _, flow := range f.fixedFlows { - flow.Reset() - flows = append(flows, flow) - } // Get cached flows. flows = append(flows, getCachedFlows(f.cachedFlows)...) diff --git a/pkg/agent/openflow/testing/mock_openflow.go b/pkg/agent/openflow/testing/mock_openflow.go index a03e5047b4d..38feb97b970 100644 --- a/pkg/agent/openflow/testing/mock_openflow.go +++ b/pkg/agent/openflow/testing/mock_openflow.go @@ -22,6 +22,7 @@ package testing import ( config "antrea.io/antrea/pkg/agent/config" types "antrea.io/antrea/pkg/agent/types" + v1alpha2 "antrea.io/antrea/pkg/apis/crd/v1alpha2" openflow "antrea.io/antrea/pkg/ovs/openflow" ip "antrea.io/antrea/pkg/util/ip" proxy "antrea.io/antrea/third_party/proxy" @@ -253,74 +254,18 @@ func (mr *MockClientMockRecorder) InitialTLVMap() *gomock.Call { } // Initialize mocks base method -func (m *MockClient) Initialize(arg0 types.RoundInfo, arg1 *config.NodeConfig, arg2 *config.NetworkConfig) (<-chan struct{}, error) { +func (m *MockClient) Initialize(arg0 types.RoundInfo, arg1 *config.NodeConfig, arg2 *config.NetworkConfig, arg3 *config.EgressConfig, arg4 *config.ServiceConfig) (<-chan struct{}, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Initialize", arg0, arg1, arg2) + ret := m.ctrl.Call(m, "Initialize", arg0, arg1, arg2, arg3, arg4) ret0, _ := ret[0].(<-chan struct{}) ret1, _ := ret[1].(error) return ret0, ret1 } // Initialize indicates an expected call of Initialize -func (mr *MockClientMockRecorder) Initialize(arg0, arg1, arg2 interface{}) *gomock.Call { +func (mr *MockClientMockRecorder) Initialize(arg0, arg1, arg2, arg3, arg4 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Initialize", reflect.TypeOf((*MockClient)(nil).Initialize), arg0, arg1, arg2) -} - -// InstallBridgeUplinkFlows mocks base method -func (m *MockClient) InstallBridgeUplinkFlows() error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "InstallBridgeUplinkFlows") - ret0, _ := ret[0].(error) - return ret0 -} - -// InstallBridgeUplinkFlows indicates an expected call of InstallBridgeUplinkFlows -func (mr *MockClientMockRecorder) InstallBridgeUplinkFlows() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InstallBridgeUplinkFlows", reflect.TypeOf((*MockClient)(nil).InstallBridgeUplinkFlows)) -} - -// InstallClusterServiceCIDRFlows mocks base method -func (m *MockClient) InstallClusterServiceCIDRFlows(arg0 []*net.IPNet) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "InstallClusterServiceCIDRFlows", arg0) - ret0, _ := ret[0].(error) - return ret0 -} - -// InstallClusterServiceCIDRFlows indicates an expected call of InstallClusterServiceCIDRFlows -func (mr *MockClientMockRecorder) InstallClusterServiceCIDRFlows(arg0 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InstallClusterServiceCIDRFlows", reflect.TypeOf((*MockClient)(nil).InstallClusterServiceCIDRFlows), arg0) -} - -// InstallDefaultServiceFlows mocks base method -func (m *MockClient) InstallDefaultServiceFlows(arg0, arg1 []net.IP) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "InstallDefaultServiceFlows", arg0, arg1) - ret0, _ := ret[0].(error) - return ret0 -} - -// InstallDefaultServiceFlows indicates an expected call of InstallDefaultServiceFlows -func (mr *MockClientMockRecorder) InstallDefaultServiceFlows(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InstallDefaultServiceFlows", reflect.TypeOf((*MockClient)(nil).InstallDefaultServiceFlows), arg0, arg1) -} - -// InstallDefaultTunnelFlows mocks base method -func (m *MockClient) InstallDefaultTunnelFlows() error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "InstallDefaultTunnelFlows") - ret0, _ := ret[0].(error) - return ret0 -} - -// InstallDefaultTunnelFlows indicates an expected call of InstallDefaultTunnelFlows -func (mr *MockClientMockRecorder) InstallDefaultTunnelFlows() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InstallDefaultTunnelFlows", reflect.TypeOf((*MockClient)(nil).InstallDefaultTunnelFlows)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Initialize", reflect.TypeOf((*MockClient)(nil).Initialize), arg0, arg1, arg2, arg3, arg4) } // InstallEndpointFlows mocks base method @@ -337,46 +282,32 @@ func (mr *MockClientMockRecorder) InstallEndpointFlows(arg0, arg1 interface{}) * return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InstallEndpointFlows", reflect.TypeOf((*MockClient)(nil).InstallEndpointFlows), arg0, arg1) } -// InstallExternalFlows mocks base method -func (m *MockClient) InstallExternalFlows(arg0 []net.IPNet) error { +// InstallMulticastFlows mocks base method +func (m *MockClient) InstallMulticastFlows(arg0 net.IP, arg1 openflow.GroupIDType) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "InstallExternalFlows", arg0) + ret := m.ctrl.Call(m, "InstallMulticastFlows", arg0, arg1) ret0, _ := ret[0].(error) return ret0 } -// InstallExternalFlows indicates an expected call of InstallExternalFlows -func (mr *MockClientMockRecorder) InstallExternalFlows(arg0 interface{}) *gomock.Call { +// InstallMulticastFlows indicates an expected call of InstallMulticastFlows +func (mr *MockClientMockRecorder) InstallMulticastFlows(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InstallExternalFlows", reflect.TypeOf((*MockClient)(nil).InstallExternalFlows), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InstallMulticastFlows", reflect.TypeOf((*MockClient)(nil).InstallMulticastFlows), arg0, arg1) } -// InstallGatewayFlows mocks base method -func (m *MockClient) InstallGatewayFlows() error { +// InstallMulticastGroup mocks base method +func (m *MockClient) InstallMulticastGroup(arg0 openflow.GroupIDType, arg1 []uint32) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "InstallGatewayFlows") + ret := m.ctrl.Call(m, "InstallMulticastGroup", arg0, arg1) ret0, _ := ret[0].(error) return ret0 } -// InstallGatewayFlows indicates an expected call of InstallGatewayFlows -func (mr *MockClientMockRecorder) InstallGatewayFlows() *gomock.Call { +// InstallMulticastGroup indicates an expected call of InstallMulticastGroup +func (mr *MockClientMockRecorder) InstallMulticastGroup(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InstallGatewayFlows", reflect.TypeOf((*MockClient)(nil).InstallGatewayFlows)) -} - -// InstallMulticastFlow mocks base method -func (m *MockClient) InstallMulticastFlow(arg0 net.IP) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "InstallMulticastFlow", arg0) - ret0, _ := ret[0].(error) - return ret0 -} - -// InstallMulticastFlow indicates an expected call of InstallMulticastFlow -func (mr *MockClientMockRecorder) InstallMulticastFlow(arg0 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InstallMulticastFlow", reflect.TypeOf((*MockClient)(nil).InstallMulticastFlow), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InstallMulticastGroup", reflect.TypeOf((*MockClient)(nil).InstallMulticastGroup), arg0, arg1) } // InstallMulticastInitialFlows mocks base method @@ -505,6 +436,34 @@ func (mr *MockClientMockRecorder) InstallTraceflowFlows(arg0, arg1, arg2, arg3, return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InstallTraceflowFlows", reflect.TypeOf((*MockClient)(nil).InstallTraceflowFlows), arg0, arg1, arg2, arg3, arg4, arg5, arg6) } +// InstallTrafficControlMarkFlows mocks base method +func (m *MockClient) InstallTrafficControlMarkFlows(arg0 string, arg1 []uint32, arg2 uint32, arg3 v1alpha2.Direction, arg4 v1alpha2.TrafficControlAction) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "InstallTrafficControlMarkFlows", arg0, arg1, arg2, arg3, arg4) + ret0, _ := ret[0].(error) + return ret0 +} + +// InstallTrafficControlMarkFlows indicates an expected call of InstallTrafficControlMarkFlows +func (mr *MockClientMockRecorder) InstallTrafficControlMarkFlows(arg0, arg1, arg2, arg3, arg4 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InstallTrafficControlMarkFlows", reflect.TypeOf((*MockClient)(nil).InstallTrafficControlMarkFlows), arg0, arg1, arg2, arg3, arg4) +} + +// InstallTrafficControlReturnPortFlow mocks base method +func (m *MockClient) InstallTrafficControlReturnPortFlow(arg0 uint32) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "InstallTrafficControlReturnPortFlow", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// InstallTrafficControlReturnPortFlow indicates an expected call of InstallTrafficControlReturnPortFlow +func (mr *MockClientMockRecorder) InstallTrafficControlReturnPortFlow(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InstallTrafficControlReturnPortFlow", reflect.TypeOf((*MockClient)(nil).InstallTrafficControlReturnPortFlow), arg0) +} + // IsConnected mocks base method func (m *MockClient) IsConnected() bool { m.ctrl.T.Helper() @@ -656,15 +615,15 @@ func (mr *MockClientMockRecorder) SendUDPPacketOut(arg0, arg1, arg2, arg3, arg4, } // StartPacketInHandler mocks base method -func (m *MockClient) StartPacketInHandler(arg0 []byte, arg1 <-chan struct{}) { +func (m *MockClient) StartPacketInHandler(arg0 <-chan struct{}) { m.ctrl.T.Helper() - m.ctrl.Call(m, "StartPacketInHandler", arg0, arg1) + m.ctrl.Call(m, "StartPacketInHandler", arg0) } // StartPacketInHandler indicates an expected call of StartPacketInHandler -func (mr *MockClientMockRecorder) StartPacketInHandler(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockClientMockRecorder) StartPacketInHandler(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StartPacketInHandler", reflect.TypeOf((*MockClient)(nil).StartPacketInHandler), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StartPacketInHandler", reflect.TypeOf((*MockClient)(nil).StartPacketInHandler), arg0) } // SubscribePacketIn mocks base method @@ -695,18 +654,32 @@ func (mr *MockClientMockRecorder) UninstallEndpointFlows(arg0, arg1 interface{}) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UninstallEndpointFlows", reflect.TypeOf((*MockClient)(nil).UninstallEndpointFlows), arg0, arg1) } -// UninstallMulticastFlow mocks base method -func (m *MockClient) UninstallMulticastFlow(arg0 net.IP) error { +// UninstallGroup mocks base method +func (m *MockClient) UninstallGroup(arg0 openflow.GroupIDType) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UninstallGroup", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// UninstallGroup indicates an expected call of UninstallGroup +func (mr *MockClientMockRecorder) UninstallGroup(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UninstallGroup", reflect.TypeOf((*MockClient)(nil).UninstallGroup), arg0) +} + +// UninstallMulticastFlows mocks base method +func (m *MockClient) UninstallMulticastFlows(arg0 net.IP) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "UninstallMulticastFlow", arg0) + ret := m.ctrl.Call(m, "UninstallMulticastFlows", arg0) ret0, _ := ret[0].(error) return ret0 } -// UninstallMulticastFlow indicates an expected call of UninstallMulticastFlow -func (mr *MockClientMockRecorder) UninstallMulticastFlow(arg0 interface{}) *gomock.Call { +// UninstallMulticastFlows indicates an expected call of UninstallMulticastFlows +func (mr *MockClientMockRecorder) UninstallMulticastFlows(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UninstallMulticastFlow", reflect.TypeOf((*MockClient)(nil).UninstallMulticastFlow), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UninstallMulticastFlows", reflect.TypeOf((*MockClient)(nil).UninstallMulticastFlows), arg0) } // UninstallNodeFlows mocks base method @@ -794,32 +767,46 @@ func (mr *MockClientMockRecorder) UninstallServiceFlows(arg0, arg1, arg2 interfa return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UninstallServiceFlows", reflect.TypeOf((*MockClient)(nil).UninstallServiceFlows), arg0, arg1, arg2) } -// UninstallServiceGroup mocks base method -func (m *MockClient) UninstallServiceGroup(arg0 openflow.GroupIDType) error { +// UninstallTraceflowFlows mocks base method +func (m *MockClient) UninstallTraceflowFlows(arg0 byte) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "UninstallServiceGroup", arg0) + ret := m.ctrl.Call(m, "UninstallTraceflowFlows", arg0) ret0, _ := ret[0].(error) return ret0 } -// UninstallServiceGroup indicates an expected call of UninstallServiceGroup -func (mr *MockClientMockRecorder) UninstallServiceGroup(arg0 interface{}) *gomock.Call { +// UninstallTraceflowFlows indicates an expected call of UninstallTraceflowFlows +func (mr *MockClientMockRecorder) UninstallTraceflowFlows(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UninstallServiceGroup", reflect.TypeOf((*MockClient)(nil).UninstallServiceGroup), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UninstallTraceflowFlows", reflect.TypeOf((*MockClient)(nil).UninstallTraceflowFlows), arg0) } -// UninstallTraceflowFlows mocks base method -func (m *MockClient) UninstallTraceflowFlows(arg0 byte) error { +// UninstallTrafficControlMarkFlows mocks base method +func (m *MockClient) UninstallTrafficControlMarkFlows(arg0 string) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "UninstallTraceflowFlows", arg0) + ret := m.ctrl.Call(m, "UninstallTrafficControlMarkFlows", arg0) ret0, _ := ret[0].(error) return ret0 } -// UninstallTraceflowFlows indicates an expected call of UninstallTraceflowFlows -func (mr *MockClientMockRecorder) UninstallTraceflowFlows(arg0 interface{}) *gomock.Call { +// UninstallTrafficControlMarkFlows indicates an expected call of UninstallTrafficControlMarkFlows +func (mr *MockClientMockRecorder) UninstallTrafficControlMarkFlows(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UninstallTraceflowFlows", reflect.TypeOf((*MockClient)(nil).UninstallTraceflowFlows), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UninstallTrafficControlMarkFlows", reflect.TypeOf((*MockClient)(nil).UninstallTrafficControlMarkFlows), arg0) +} + +// UninstallTrafficControlReturnPortFlow mocks base method +func (m *MockClient) UninstallTrafficControlReturnPortFlow(arg0 uint32) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UninstallTrafficControlReturnPortFlow", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// UninstallTrafficControlReturnPortFlow indicates an expected call of UninstallTrafficControlReturnPortFlow +func (mr *MockClientMockRecorder) UninstallTrafficControlReturnPortFlow(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UninstallTrafficControlReturnPortFlow", reflect.TypeOf((*MockClient)(nil).UninstallTrafficControlReturnPortFlow), arg0) } // MockOFEntryOperations is a mock of OFEntryOperations interface diff --git a/pkg/agent/proxy/proxier.go b/pkg/agent/proxy/proxier.go index 2ab8f7eeb7b..96f10c3c4d8 100644 --- a/pkg/agent/proxy/proxier.go +++ b/pkg/agent/proxy/proxier.go @@ -16,6 +16,7 @@ package proxy import ( "fmt" + "math" "net" "sort" "strings" @@ -50,6 +51,9 @@ const ( // of Endpoints that Antrea can support at the moment is 800. If the number of Endpoints for a given Service exceeds // 800, extra Endpoints will be dropped. maxEndpoints = 800 + // SessionAffinity timeout is implemented using a hard_timeout in OVS. hard_timeout is + // represented by a uint16 in the OpenFlow protocol, + maxSupportedAffinityTimeout = math.MaxUint16 ) // Proxier wraps proxy.Provider and adds extra methods. It is introduced for @@ -169,7 +173,7 @@ func (p *proxier) removeStaleServices() { // Remove Service group whose Endpoints are local. if svcInfo.NodeLocalExternal() { if groupIDLocal, exist := p.groupCounter.Get(svcPortName, true); exist { - if err := p.ofClient.UninstallServiceGroup(groupIDLocal); err != nil { + if err := p.ofClient.UninstallGroup(groupIDLocal); err != nil { klog.ErrorS(err, "Failed to remove Group of local Endpoints for Service", "Service", svcPortName) continue } @@ -178,7 +182,7 @@ func (p *proxier) removeStaleServices() { } // Remove Service group which has all Endpoints. if groupID, exist := p.groupCounter.Get(svcPortName, false); exist { - if err := p.ofClient.UninstallServiceGroup(groupID); err != nil { + if err := p.ofClient.UninstallGroup(groupID); err != nil { klog.ErrorS(err, "Failed to remove Group of all Endpoints for Service", "Service", svcPortName) continue } @@ -347,7 +351,6 @@ func (p *proxier) uninstallLoadBalancerService(loadBalancerIPStrings []string, s func (p *proxier) installServices() { for svcPortName, svcPort := range p.serviceMap { svcInfo := svcPort.(*types.ServiceInfo) - groupID := p.groupCounter.AllocateIfNotExist(svcPortName, false) endpointsInstalled, ok := p.endpointsInstalledMap[svcPortName] if !ok { endpointsInstalled = map[string]k8sproxy.Endpoint{} @@ -366,47 +369,110 @@ func (p *proxier) installServices() { pSvcInfo = installedSvcPort.(*types.ServiceInfo) needRemoval = serviceIdentityChanged(svcInfo, pSvcInfo) || (svcInfo.SessionAffinityType() != pSvcInfo.SessionAffinityType()) needUpdateService = needRemoval || (svcInfo.StickyMaxAgeSeconds() != pSvcInfo.StickyMaxAgeSeconds()) - needUpdateEndpoints = pSvcInfo.SessionAffinityType() != svcInfo.SessionAffinityType() || pSvcInfo.NodeLocalExternal() != svcInfo.NodeLocalExternal() + needUpdateEndpoints = pSvcInfo.SessionAffinityType() != svcInfo.SessionAffinityType() || + pSvcInfo.NodeLocalExternal() != svcInfo.NodeLocalExternal() || + pSvcInfo.NodeLocalInternal() != svcInfo.NodeLocalInternal() } else { // Need to install. needUpdateService = true } - var endpointUpdateList []k8sproxy.Endpoint + affinityTimeout := svcInfo.StickyMaxAgeSeconds() + if svcInfo.StickyMaxAgeSeconds() > maxSupportedAffinityTimeout { + // SessionAffinity timeout is implemented using a hard_timeout in + // OVS. hard_timeout is represented by a uint16 in the OpenFlow protocol, + // hence we cannot support timeouts greater than 65535 seconds. However, the + // K8s Service spec allows timeout values up to 86400 seconds + // (https://godoc.org/k8s.io/api/core/v1#ClientIPConfig). For values greater + // than 65535 seconds, we need to set the hard_timeout to 65535 rather than + // let the timeout value wrap around. + affinityTimeout = maxSupportedAffinityTimeout + if !ok || (svcInfo.StickyMaxAgeSeconds() != pSvcInfo.StickyMaxAgeSeconds()) { + // We only log a warning when the Service hasn't been installed + // yet, or when the timeout has changed. + klog.InfoS( + "The timeout configured for ClientIP-based session affinity exceeds the max supported value", + "service", svcPortName.String(), + "timeout", svcInfo.StickyMaxAgeSeconds(), + "maxTimeout", maxSupportedAffinityTimeout, + ) + } + } + + var internalNodeLocal, externalNodeLocal bool + if svcInfo.NodeLocalInternal() { + internalNodeLocal = true + } + if p.proxyAll && svcInfo.NodeLocalExternal() { + externalNodeLocal = true + } + + var allEndpointUpdateList, localEndpointUpdateList []k8sproxy.Endpoint if len(endpoints) > maxEndpoints { if !p.oversizeServiceSet.Has(svcPortName.String()) { klog.Warningf("Since Endpoints of Service %s exceeds %d, extra Endpoints will be dropped", svcPortName.String(), maxEndpoints) p.oversizeServiceSet.Insert(svcPortName.String()) } - // If the length of endpoints > maxEndpoints, endpoints should be cut. However, endpoints is a map. Therefore, - // iterate the map and append every Endpoint to a slice endpointList. Since the iteration order of map in - // Golang is random, if cut directly without any sorting, some Endpoints may not be installed. So cutting - // slice endpointList after sorting can avoid this situation in some degree. - var endpointList []k8sproxy.Endpoint + // If the length of endpoints > maxEndpoints, endpoints should be cut. However, since endpoints is a map, iterate + // the map and append every Endpoint to a target slice. When the Endpoint is local, append Endpoint to slice + // localEndpointList, otherwise append the Endpoint to slice remoteEndpointList. Since the iteration order + // of map in Golang is not guaranteed, if split the Endpoints directly without any sorting, some Endpoints + // may not be installed, so split the endpointList after sorting. + var remoteEndpointList, localEndpointList []k8sproxy.Endpoint for _, endpoint := range endpoints { - endpointList = append(endpointList, endpoint) + if endpoint.GetIsLocal() { + localEndpointList = append(localEndpointList, endpoint) + } else { + remoteEndpointList = append(remoteEndpointList, endpoint) + } } - sort.Sort(byEndpoint(endpointList)) - endpointList = endpointList[:maxEndpoints] - for _, endpoint := range endpointList { // Check if there is any installed Endpoint which is not expected anymore. - if _, ok := endpointsInstalled[endpoint.String()]; !ok { // There is an expected Endpoint which is not installed. - needUpdateEndpoints = true + sort.Sort(byEndpoint(remoteEndpointList)) + sort.Sort(byEndpoint(localEndpointList)) + + if len(localEndpointList) > maxEndpoints { + // When the number of local Endpoints is greater than maxEndpoints, choose maxEndpoints Endpoints from + // localEndpointList to install. + allEndpointUpdateList = localEndpointList[:maxEndpoints] + } else { + // When the number of local Endpoints is smaller than maxEndpoints, choose all Endpoints of localEndpointList + // and part of remoteEndpointList to install. + localEndpointUpdateList = localEndpointList + allEndpointUpdateList = append(localEndpointList, remoteEndpointList[:maxEndpoints-len(localEndpointList)]...) + } + // Check if there is any installed Endpoint which is not expected anymore. If internalTrafficPolicy and externalTrafficPolicy + // are both Local, only local Endpoints should be installed and checked; if internalTrafficPolicy or externalTrafficPolicy + // is Cluster, all Endpoints should be installed and checked. + for _, endpoint := range allEndpointUpdateList { + if internalNodeLocal && externalNodeLocal && endpoint.GetIsLocal() || !internalNodeLocal || !externalNodeLocal { + if _, ok := endpointsInstalled[endpoint.String()]; !ok { // There is an expected Endpoint which is not installed. + needUpdateEndpoints = true + break + } } - endpointUpdateList = append(endpointUpdateList, endpoint) } } else { if p.oversizeServiceSet.Has(svcPortName.String()) { p.oversizeServiceSet.Delete(svcPortName.String()) } - for _, endpoint := range endpoints { // Check if there is any installed Endpoint which is not expected anymore. - if _, ok := endpointsInstalled[endpoint.String()]; !ok { // There is an expected Endpoint which is not installed. - needUpdateEndpoints = true + // Check if there is any installed Endpoint which is not expected anymore. If internalTrafficPolicy and externalTrafficPolicy + // are both Local, only local Endpoints should be installed and checked; if internalTrafficPolicy or externalTrafficPolicy + // is Cluster, all Endpoints should be installed and checked. + for _, endpoint := range endpoints { + if internalNodeLocal && externalNodeLocal && endpoint.GetIsLocal() || !internalNodeLocal || !externalNodeLocal { + if _, ok := endpointsInstalled[endpoint.String()]; !ok { // There is an expected Endpoint which is not installed. + needUpdateEndpoints = true + } + } + allEndpointUpdateList = append(allEndpointUpdateList, endpoint) + if endpoint.GetIsLocal() { + localEndpointUpdateList = append(localEndpointUpdateList, endpoint) } - endpointUpdateList = append(endpointUpdateList, endpoint) } } - if len(endpoints) < len(endpointsInstalled) { // There are Endpoints which expired. + // If there are expired Endpoints, Endpoints installed should be updated. + if internalNodeLocal && externalNodeLocal && len(localEndpointUpdateList) < len(endpointsInstalled) || + !(internalNodeLocal && externalNodeLocal) && len(allEndpointUpdateList) < len(endpointsInstalled) { klog.V(2).Infof("Some Endpoints of Service %s removed, updating Endpoints", svcInfo.String()) needUpdateEndpoints = true } @@ -437,45 +503,64 @@ func (p *proxier) installServices() { } if needUpdateEndpoints { + var endpointUpdateList []k8sproxy.Endpoint + // If the type of the Service is NodePort or LoadBalancer and both internalTrafficPolicy and externalTrafficPolicy + // are Local, or the type of the Service is ClusterIP and internalTrafficPolicy is Local, then only local + // Endpoints should be installed, otherwise all Endpoints should be installed. + if internalNodeLocal && (externalNodeLocal || svcInfo.NodePort() == 0) { + endpointUpdateList = localEndpointUpdateList + } else { + endpointUpdateList = allEndpointUpdateList + } + // Install Endpoints. err := p.ofClient.InstallEndpointFlows(svcInfo.OFProtocol, endpointUpdateList) if err != nil { klog.ErrorS(err, "Error when installing Endpoints flows") continue } - err = p.ofClient.InstallServiceGroup(groupID, svcInfo.StickyMaxAgeSeconds() != 0, endpointUpdateList) - if err != nil { - klog.ErrorS(err, "Error when installing Endpoints groups") - continue - } - - if p.proxyAll { - if svcInfo.NodeLocalExternal() { - // Install another group when Service externalTrafficPolicy is Local. - groupIDLocal := p.groupCounter.AllocateIfNotExist(svcPortName, true) - var localEndpointList []k8sproxy.Endpoint - for _, ed := range endpointUpdateList { - if !ed.GetIsLocal() { - continue - } - localEndpointList = append(localEndpointList, ed) + if internalNodeLocal != externalNodeLocal { + if svcInfo.NodePort() > 0 { + // If the type of the Service is NodePort or LoadBalancer, when internalTrafficPolicy and externalTrafficPolicy + // of the Service are different, install two groups. One group has all Endpoints, the other has only + // local Endpoints. + groupID := p.groupCounter.AllocateIfNotExist(svcPortName, true) + if err = p.ofClient.InstallServiceGroup(groupID, affinityTimeout != 0, localEndpointUpdateList); err != nil { + klog.ErrorS(err, "Error when installing Group of local Endpoints for Service", "Service", svcPortName) + continue } - if err = p.ofClient.InstallServiceGroup(groupIDLocal, svcInfo.StickyMaxAgeSeconds() != 0, localEndpointList); err != nil { - klog.ErrorS(err, "Error when installing Group for Service whose externalTrafficPolicy is Local") + groupID = p.groupCounter.AllocateIfNotExist(svcPortName, false) + if err = p.ofClient.InstallServiceGroup(groupID, affinityTimeout != 0, allEndpointUpdateList); err != nil { + klog.ErrorS(err, "Error when installing Group of all Endpoints for Service", "Service", svcPortName) continue } } else { - // Uninstall the group with only local Endpoints when Service externalTrafficPolicy is Cluster - // unconditionally. If the group doesn't exist on OVS, then the return value will be nil; if the - // group exists on OVS, and after it is uninstalled successfully, then the return value will be also - // nil. - if groupIDLocal, exist := p.groupCounter.Get(svcPortName, true); exist { - if err := p.ofClient.UninstallServiceGroup(groupIDLocal); err != nil { - klog.ErrorS(err, "Failed to remove Group of local Endpoints for Service", "Service", svcPortName) - continue - } - p.groupCounter.Recycle(svcPortName, true) + // If the type of the Service is ClusterIP, install a group according to internalTrafficPolicy. + groupID := p.groupCounter.AllocateIfNotExist(svcPortName, internalNodeLocal) + if err = p.ofClient.InstallServiceGroup(groupID, affinityTimeout != 0, endpointUpdateList); err != nil { + klog.ErrorS(err, "Error when installing Group of Endpoints for Service", "Service", svcPortName) + continue } } + } else { + // Regardless of the type of the Service, when internalTrafficPolicy and externalTrafficPolicy of the Service + // are the same, only install one group and unconditionally uninstall another group. If both internalTrafficPolicy + // and externalTrafficPolicy are Local, install the group that has only local Endpoints and unconditionally + // uninstall the group which has all Endpoints; if both internalTrafficPolicy and externalTrafficPolicy are + // Cluster, install the group which has all Endpoints and unconditionally uninstall the group which has + // only local Endpoints. Note that, if a group doesn't exist on OVS, then the return value will be nil. + nodeLocalVal := internalNodeLocal && externalNodeLocal + groupID := p.groupCounter.AllocateIfNotExist(svcPortName, nodeLocalVal) + if err = p.ofClient.InstallServiceGroup(groupID, affinityTimeout != 0, endpointUpdateList); err != nil { + klog.ErrorS(err, "Error when installing Group of local Endpoints for Service", "Service", svcPortName) + continue + } + if groupID, exist := p.groupCounter.Get(svcPortName, !nodeLocalVal); exist { + if err := p.ofClient.UninstallGroup(groupID); err != nil { + klog.ErrorS(err, "Failed to uninstall Group of all Endpoints for Service", "Service", svcPortName) + continue + } + p.groupCounter.Recycle(svcPortName, !nodeLocalVal) + } } for _, e := range endpointUpdateList { @@ -515,20 +600,15 @@ func (p *proxier) installServices() { } } - // Install ClusterIP flows of current Service. - if err := p.ofClient.InstallServiceFlows(groupID, svcInfo.ClusterIP(), uint16(svcInfo.Port()), svcInfo.OFProtocol, uint16(svcInfo.StickyMaxAgeSeconds()), false, corev1.ServiceTypeClusterIP); err != nil { + // Install ClusterIP flows for the Service. + groupID := p.groupCounter.AllocateIfNotExist(svcPortName, internalNodeLocal) + if err := p.ofClient.InstallServiceFlows(groupID, svcInfo.ClusterIP(), uint16(svcInfo.Port()), svcInfo.OFProtocol, uint16(affinityTimeout), svcInfo.NodeLocalInternal(), corev1.ServiceTypeClusterIP); err != nil { klog.Errorf("Error when installing Service flows: %v", err) continue } - // If externalTrafficPolicy of the Service is Local, Service NodePort or LoadBalancer should use the Service - // group whose Endpoints are local. - nGroupID := groupID - if svcInfo.NodeLocalExternal() { - nGroupID = p.groupCounter.AllocateIfNotExist(svcPortName, true) - } - if p.proxyAll { + nGroupID := p.groupCounter.AllocateIfNotExist(svcPortName, externalNodeLocal) // Install ClusterIP route on Node so that ClusterIP can be accessed on Node. Every time a new ClusterIP // is created, the routing target IP block will be recalculated for expansion to be able to route the new // created ClusterIP. Deleting a ClusterIP will not shrink the target routing IP block. The Service CIDR @@ -541,7 +621,7 @@ func (p *proxier) installServices() { // If previous Service is nil or NodePort flows and configurations of previous Service have been removed, // install NodePort flows and configurations for current Service. if svcInfo.NodePort() > 0 && (pSvcInfo == nil || needRemoval) { - if err := p.installNodePortService(nGroupID, uint16(svcInfo.NodePort()), svcInfo.OFProtocol, uint16(svcInfo.StickyMaxAgeSeconds()), svcInfo.NodeLocalExternal()); err != nil { + if err := p.installNodePortService(nGroupID, uint16(svcInfo.NodePort()), svcInfo.OFProtocol, uint16(affinityTimeout), svcInfo.NodeLocalExternal()); err != nil { klog.ErrorS(err, "Failed to install NodePort flows and configurations of Service", "Service", svcPortName) continue } @@ -549,6 +629,7 @@ func (p *proxier) installServices() { } if p.proxyLoadBalancerIPs { + nGroupID := p.groupCounter.AllocateIfNotExist(svcPortName, externalNodeLocal) // Service LoadBalancer flows can be partially updated. var toDelete, toAdd []string if needRemoval { @@ -567,7 +648,7 @@ func (p *proxier) installServices() { } // Install LoadBalancer flows and configurations. if len(toAdd) > 0 { - if err := p.installLoadBalancerService(nGroupID, toAdd, uint16(svcInfo.Port()), svcInfo.OFProtocol, uint16(svcInfo.StickyMaxAgeSeconds()), svcInfo.NodeLocalExternal()); err != nil { + if err := p.installLoadBalancerService(nGroupID, toAdd, uint16(svcInfo.Port()), svcInfo.OFProtocol, uint16(affinityTimeout), svcInfo.NodeLocalExternal()); err != nil { klog.ErrorS(err, "Failed to install LoadBalancer flows and configurations of Service", "Service", svcPortName) continue } diff --git a/pkg/agent/proxy/proxier_test.go b/pkg/agent/proxy/proxier_test.go index f5685e3cb49..6c6ec07c2ae 100644 --- a/pkg/agent/proxy/proxier_test.go +++ b/pkg/agent/proxy/proxier_test.go @@ -16,6 +16,7 @@ package proxy import ( "fmt" + "math" "net" "testing" "time" @@ -51,6 +52,7 @@ var ( loadBalancerIPv6 = net.ParseIP("fec0::169:254:169:1") svcNodePortIPv4 = net.ParseIP("192.168.77.100") svcNodePortIPv6 = net.ParseIP("2001::192:168:77:100") + hostname = "localhost" nodePortAddressesIPv4 = []net.IP{svcNodePortIPv4} nodePortAddressesIPv6 = []net.IP{svcNodePortIPv6} @@ -157,7 +159,7 @@ func NewFakeProxier(routeClient route.Interface, ofClient openflow.Client, nodeP return p } -func testClusterIP(t *testing.T, svcIP net.IP, epIP net.IP, isIPv6 bool, extraSvcs []*corev1.Service, extraEps []*corev1.Endpoints) { +func testClusterIP(t *testing.T, svcIP net.IP, ep1IP, ep2IP net.IP, isIPv6, nodeLocalInternal bool, extraSvcs []*corev1.Service, extraEps []*corev1.Endpoints) { ctrl := gomock.NewController(t) defer ctrl.Finish() mockOFClient := ofmock.NewMockClient(ctrl) @@ -171,45 +173,69 @@ func testClusterIP(t *testing.T, svcIP net.IP, epIP net.IP, isIPv6 bool, extraSv Port: "80", Protocol: corev1.ProtocolTCP, } + internalTrafficPolicy := corev1.ServiceInternalTrafficPolicyCluster + if nodeLocalInternal { + internalTrafficPolicy = corev1.ServiceInternalTrafficPolicyLocal + } - allServices := append(extraSvcs, makeTestService(svcPortName.Namespace, svcPortName.Name, func(svc *corev1.Service) { - svc.Spec.ClusterIP = svcIP.String() - svc.Spec.Ports = []corev1.ServicePort{{ - Name: svcPortName.Port, - Port: int32(svcPort), - Protocol: corev1.ProtocolTCP, - }} - })) - makeServiceMap(fp, allServices...) - - allEps := append(extraEps, makeTestEndpoints(svcPortName.Namespace, svcPortName.Name, func(ept *corev1.Endpoints) { - ept.Subsets = []corev1.EndpointSubset{{ - Addresses: []corev1.EndpointAddress{{ - IP: epIP.String(), - }}, - Ports: []corev1.EndpointPort{{ + allServices := append(extraSvcs, + makeTestService(svcPortName.Namespace, svcPortName.Name, func(svc *corev1.Service) { + svc.Spec.ClusterIP = svcIP.String() + svc.Spec.Ports = []corev1.ServicePort{{ Name: svcPortName.Port, Port: int32(svcPort), Protocol: corev1.ProtocolTCP, - }}, - }} - })) + }} + svc.Spec.InternalTrafficPolicy = &internalTrafficPolicy + })) + makeServiceMap(fp, allServices...) + + remoteEndpoint := corev1.EndpointSubset{ + Addresses: []corev1.EndpointAddress{{ + IP: ep1IP.String(), + }}, + Ports: []corev1.EndpointPort{{ + Name: svcPortName.Port, + Port: int32(svcPort), + Protocol: corev1.ProtocolTCP, + }}, + } + localEndpoint := corev1.EndpointSubset{ + Addresses: []corev1.EndpointAddress{{ + IP: ep2IP.String(), + NodeName: &hostname, + }}, + Ports: []corev1.EndpointPort{{ + Name: svcPortName.Port, + Port: int32(svcPort), + Protocol: corev1.ProtocolTCP, + }}, + } + epFunc := func(ept *corev1.Endpoints) { ept.Subsets = []corev1.EndpointSubset{localEndpoint, remoteEndpoint} } + allEps := append(extraEps, makeTestEndpoints(svcPortName.Namespace, svcPortName.Name, epFunc)) makeEndpointsMap(fp, allEps...) - groupID := fp.groupCounter.AllocateIfNotExist(svcPortName, false) - mockOFClient.EXPECT().InstallServiceGroup(groupID, false, gomock.Any()).Times(1) + expectedLocalEps := []k8sproxy.Endpoint{k8sproxy.NewBaseEndpointInfo(ep2IP.String(), svcPort, true, nil)} + expectedAllEps := expectedLocalEps + if !nodeLocalInternal { + expectedAllEps = append(expectedAllEps, k8sproxy.NewBaseEndpointInfo(ep1IP.String(), svcPort, false, nil)) + } + bindingProtocol := binding.ProtocolTCP if isIPv6 { bindingProtocol = binding.ProtocolTCPv6 } - mockOFClient.EXPECT().InstallEndpointFlows(bindingProtocol, gomock.Any()).Times(1) - mockOFClient.EXPECT().InstallServiceFlows(groupID, svcIP, uint16(svcPort), bindingProtocol, uint16(0), false, corev1.ServiceTypeClusterIP).Times(1) + + groupID := fp.groupCounter.AllocateIfNotExist(svcPortName, nodeLocalInternal) + mockOFClient.EXPECT().InstallEndpointFlows(bindingProtocol, gomock.InAnyOrder(expectedAllEps)).Times(1) + mockOFClient.EXPECT().InstallServiceGroup(groupID, false, gomock.InAnyOrder(expectedAllEps)).Times(1) + mockOFClient.EXPECT().InstallServiceFlows(groupID, svcIP, uint16(svcPort), bindingProtocol, uint16(0), nodeLocalInternal, corev1.ServiceTypeClusterIP).Times(1) mockRouteClient.EXPECT().AddClusterIPRoute(svcIP).Times(1) fp.syncProxyRules() } -func testLoadBalancer(t *testing.T, nodePortAddresses []net.IP, svcIP, ep1IP, ep2IP, loadBalancerIP net.IP, isIPv6, nodeLocalExternal, proxyLoadBalancerIPs bool) { +func testLoadBalancer(t *testing.T, nodePortAddresses []net.IP, svcIP, ep1IP, ep2IP, loadBalancerIP net.IP, isIPv6, nodeLocalInternal, nodeLocalExternal, proxyLoadBalancerIPs bool) { ctrl := gomock.NewController(t) defer ctrl.Finish() mockOFClient := ofmock.NewMockClient(ctrl) @@ -232,6 +258,10 @@ func testLoadBalancer(t *testing.T, nodePortAddresses []net.IP, svcIP, ep1IP, ep if nodeLocalExternal { externalTrafficPolicy = corev1.ServiceExternalTrafficPolicyTypeLocal } + internalTrafficPolicy := corev1.ServiceInternalTrafficPolicyCluster + if nodeLocalInternal { + internalTrafficPolicy = corev1.ServiceInternalTrafficPolicyLocal + } makeServiceMap(fp, makeTestService(svcPortName.Namespace, svcPortName.Name, func(svc *corev1.Service) { @@ -247,57 +277,78 @@ func testLoadBalancer(t *testing.T, nodePortAddresses []net.IP, svcIP, ep1IP, ep Protocol: corev1.ProtocolTCP, }} svc.Spec.ExternalTrafficPolicy = externalTrafficPolicy + svc.Spec.InternalTrafficPolicy = &internalTrafficPolicy }), ) - var eps []*corev1.Endpoints - epFunc := func(ept *corev1.Endpoints) { - ept.Subsets = []corev1.EndpointSubset{{ - Addresses: []corev1.EndpointAddress{{ - IP: ep1IP.String(), - Hostname: "localhost", - }}, - Ports: []corev1.EndpointPort{{ - Name: svcPortName.Port, - Port: int32(svcPort), - Protocol: corev1.ProtocolTCP, - }}, - }} + remoteEndpoint := corev1.EndpointSubset{ + Addresses: []corev1.EndpointAddress{{ + IP: ep1IP.String(), + }}, + Ports: []corev1.EndpointPort{{ + Name: svcPortName.Port, + Port: int32(svcPort), + Protocol: corev1.ProtocolTCP, + }}, } - eps = append(eps, makeTestEndpoints(svcPortName.Namespace, svcPortName.Name, epFunc)) - if nodeLocalExternal { - epFunc = func(ept *corev1.Endpoints) { - ept.Subsets = []corev1.EndpointSubset{{ - Addresses: []corev1.EndpointAddress{{ - IP: ep2IP.String(), - Hostname: "remote", - }}, - Ports: []corev1.EndpointPort{{ - Name: svcPortName.Port, - Port: int32(svcPort), - Protocol: corev1.ProtocolTCP, - }}, - }} - } - eps = append(eps, makeTestEndpoints(svcPortName.Namespace, svcPortName.Name, epFunc)) + localEndpoint := corev1.EndpointSubset{ + Addresses: []corev1.EndpointAddress{{ + IP: ep2IP.String(), + NodeName: &hostname, + }}, + Ports: []corev1.EndpointPort{{ + Name: svcPortName.Port, + Port: int32(svcPort), + Protocol: corev1.ProtocolTCP, + }}, } + + epFunc := func(ept *corev1.Endpoints) { ept.Subsets = []corev1.EndpointSubset{localEndpoint, remoteEndpoint} } + eps := []*corev1.Endpoints{makeTestEndpoints(svcPortName.Namespace, svcPortName.Name, epFunc)} makeEndpointsMap(fp, eps...) - groupID := fp.groupCounter.AllocateIfNotExist(svcPortName, false) + + expectedLocalEps := []k8sproxy.Endpoint{k8sproxy.NewBaseEndpointInfo(ep2IP.String(), svcPort, true, nil)} + expectedAllEps := expectedLocalEps + if !(nodeLocalInternal && nodeLocalExternal) { + expectedAllEps = append(expectedAllEps, k8sproxy.NewBaseEndpointInfo(ep1IP.String(), svcPort, false, nil)) + } + bindingProtocol := binding.ProtocolTCP if isIPv6 { bindingProtocol = binding.ProtocolTCPv6 } - mockOFClient.EXPECT().InstallServiceGroup(groupID, false, gomock.Any()).Times(1) - mockOFClient.EXPECT().InstallEndpointFlows(bindingProtocol, gomock.Any()).Times(1) - mockOFClient.EXPECT().InstallServiceFlows(groupID, svcIP, uint16(svcPort), bindingProtocol, uint16(0), false, corev1.ServiceTypeClusterIP).Times(1) - if nodeLocalExternal { - groupID = fp.groupCounter.AllocateIfNotExist(svcPortName, true) - mockOFClient.EXPECT().InstallServiceGroup(groupID, false, gomock.Any()).Times(1) - } - if proxyLoadBalancerIPs { - mockOFClient.EXPECT().InstallServiceFlows(groupID, loadBalancerIP, uint16(svcPort), bindingProtocol, uint16(0), nodeLocalExternal, corev1.ServiceTypeLoadBalancer).Times(1) + + mockOFClient.EXPECT().InstallEndpointFlows(bindingProtocol, gomock.InAnyOrder(expectedAllEps)).Times(1) + if nodeLocalInternal != nodeLocalExternal { + var clusterIPEps, nodePortEps []k8sproxy.Endpoint + if nodeLocalInternal { + clusterIPEps = expectedLocalEps + nodePortEps = expectedAllEps + } else { + clusterIPEps = expectedAllEps + nodePortEps = expectedLocalEps + } + groupID := fp.groupCounter.AllocateIfNotExist(svcPortName, nodeLocalInternal) + mockOFClient.EXPECT().InstallServiceGroup(groupID, false, gomock.InAnyOrder(clusterIPEps)).Times(1) + mockOFClient.EXPECT().InstallServiceFlows(groupID, svcIP, uint16(svcPort), bindingProtocol, uint16(0), nodeLocalInternal, corev1.ServiceTypeClusterIP).Times(1) + groupID = fp.groupCounter.AllocateIfNotExist(svcPortName, nodeLocalExternal) + mockOFClient.EXPECT().InstallServiceGroup(groupID, false, gomock.InAnyOrder(nodePortEps)).Times(1) + mockOFClient.EXPECT().InstallServiceFlows(groupID, gomock.Any(), uint16(svcNodePort), bindingProtocol, uint16(0), nodeLocalExternal, corev1.ServiceTypeNodePort).Times(1) + if proxyLoadBalancerIPs { + mockOFClient.EXPECT().InstallServiceFlows(groupID, loadBalancerIP, uint16(svcPort), bindingProtocol, uint16(0), nodeLocalExternal, corev1.ServiceTypeLoadBalancer).Times(1) + } + } else { + nodeLocalVal := nodeLocalInternal && nodeLocalExternal + groupID := fp.groupCounter.AllocateIfNotExist(svcPortName, nodeLocalVal) + mockOFClient.EXPECT().InstallServiceGroup(groupID, false, gomock.InAnyOrder(expectedAllEps)).Times(1) + mockOFClient.EXPECT().InstallServiceFlows(groupID, svcIP, uint16(svcPort), bindingProtocol, uint16(0), nodeLocalVal, corev1.ServiceTypeClusterIP).Times(1) + mockOFClient.EXPECT().InstallServiceFlows(groupID, gomock.Any(), uint16(svcNodePort), bindingProtocol, uint16(0), nodeLocalVal, corev1.ServiceTypeNodePort).Times(1) + if proxyLoadBalancerIPs { + mockOFClient.EXPECT().InstallServiceFlows(groupID, loadBalancerIP, uint16(svcPort), bindingProtocol, uint16(0), nodeLocalVal, corev1.ServiceTypeLoadBalancer).Times(1) + } + groupID = fp.groupCounter.AllocateIfNotExist(svcPortName, !nodeLocalVal) + mockOFClient.EXPECT().UninstallGroup(groupID).Times(1) } - mockOFClient.EXPECT().InstallServiceFlows(groupID, gomock.Any(), uint16(svcNodePort), bindingProtocol, uint16(0), nodeLocalExternal, corev1.ServiceTypeNodePort).Times(1) mockRouteClient.EXPECT().AddClusterIPRoute(svcIP).Times(1) if proxyLoadBalancerIPs { mockRouteClient.EXPECT().AddLoadBalancer([]string{loadBalancerIP.String()}).Times(1) @@ -307,7 +358,7 @@ func testLoadBalancer(t *testing.T, nodePortAddresses []net.IP, svcIP, ep1IP, ep fp.syncProxyRules() } -func testNodePort(t *testing.T, nodePortAddresses []net.IP, svcIP, ep1IP, ep2IP net.IP, isIPv6, nodeLocalExternal bool) { +func testNodePort(t *testing.T, nodePortAddresses []net.IP, svcIP, ep1IP, ep2IP net.IP, isIPv6, nodeLocalInternal, nodeLocalExternal bool) { ctrl := gomock.NewController(t) defer ctrl.Finish() mockOFClient := ofmock.NewMockClient(ctrl) @@ -326,6 +377,10 @@ func testNodePort(t *testing.T, nodePortAddresses []net.IP, svcIP, ep1IP, ep2IP if nodeLocalExternal { externalTrafficPolicy = corev1.ServiceExternalTrafficPolicyTypeLocal } + internalTrafficPolicy := corev1.ServiceInternalTrafficPolicyCluster + if nodeLocalInternal { + internalTrafficPolicy = corev1.ServiceInternalTrafficPolicyLocal + } makeServiceMap(fp, makeTestService(svcPortName.Namespace, svcPortName.Name, func(svc *corev1.Service) { @@ -338,104 +393,172 @@ func testNodePort(t *testing.T, nodePortAddresses []net.IP, svcIP, ep1IP, ep2IP Protocol: corev1.ProtocolTCP, }} svc.Spec.ExternalTrafficPolicy = externalTrafficPolicy + svc.Spec.InternalTrafficPolicy = &internalTrafficPolicy }), ) + remoteEndpoint := corev1.EndpointSubset{ + Addresses: []corev1.EndpointAddress{{ + IP: ep1IP.String(), + }}, + Ports: []corev1.EndpointPort{{ + Name: svcPortName.Port, + Port: int32(svcPort), + Protocol: corev1.ProtocolTCP, + }}, + } + localEndpoint := corev1.EndpointSubset{ + Addresses: []corev1.EndpointAddress{{ + IP: ep2IP.String(), + NodeName: &hostname, + }}, + Ports: []corev1.EndpointPort{{ + Name: svcPortName.Port, + Port: int32(svcPort), + Protocol: corev1.ProtocolTCP, + }}, + } + var eps []*corev1.Endpoints epFunc := func(ept *corev1.Endpoints) { - ept.Subsets = []corev1.EndpointSubset{{ - Addresses: []corev1.EndpointAddress{{ - IP: ep1IP.String(), - Hostname: "localhost", - }}, - Ports: []corev1.EndpointPort{{ - Name: svcPortName.Port, - Port: int32(svcPort), - Protocol: corev1.ProtocolTCP, - }}, - }} - } - eps = append(eps, makeTestEndpoints(svcPortName.Namespace, svcPortName.Name, epFunc)) - if nodeLocalExternal { - epFunc = func(ept *corev1.Endpoints) { - ept.Subsets = []corev1.EndpointSubset{{ - Addresses: []corev1.EndpointAddress{{ - IP: ep2IP.String(), - Hostname: "remote", - }}, - Ports: []corev1.EndpointPort{{ - Name: svcPortName.Port, - Port: int32(svcPort), - Protocol: corev1.ProtocolTCP, - }}, - }} + if nodeLocalInternal && nodeLocalExternal { + ept.Subsets = []corev1.EndpointSubset{localEndpoint} + } else { + ept.Subsets = []corev1.EndpointSubset{localEndpoint, remoteEndpoint} } - eps = append(eps, makeTestEndpoints(svcPortName.Namespace, svcPortName.Name, epFunc)) } + eps = append(eps, makeTestEndpoints(svcPortName.Namespace, svcPortName.Name, epFunc)) makeEndpointsMap(fp, eps...) - groupID := fp.groupCounter.AllocateIfNotExist(svcPortName, false) + expectedLocalEps := []k8sproxy.Endpoint{k8sproxy.NewBaseEndpointInfo(ep2IP.String(), svcPort, true, nil)} + expectedAllEps := expectedLocalEps + if !(nodeLocalInternal && nodeLocalExternal) { + expectedAllEps = append(expectedAllEps, k8sproxy.NewBaseEndpointInfo(ep1IP.String(), svcPort, false, nil)) + } + bindingProtocol := binding.ProtocolTCP if isIPv6 { bindingProtocol = binding.ProtocolTCPv6 } - mockOFClient.EXPECT().InstallServiceGroup(groupID, false, gomock.Any()).Times(1) - mockOFClient.EXPECT().InstallEndpointFlows(bindingProtocol, gomock.Any()).Times(1) - mockOFClient.EXPECT().InstallServiceFlows(groupID, svcIP, uint16(svcPort), bindingProtocol, uint16(0), false, corev1.ServiceTypeClusterIP).Times(1) - if nodeLocalExternal { - groupID = fp.groupCounter.AllocateIfNotExist(svcPortName, true) - mockOFClient.EXPECT().InstallServiceGroup(groupID, false, gomock.Any()).Times(1) - } - mockOFClient.EXPECT().InstallServiceFlows(groupID, gomock.Any(), uint16(svcNodePort), bindingProtocol, uint16(0), nodeLocalExternal, corev1.ServiceTypeNodePort).Times(1) + mockOFClient.EXPECT().InstallEndpointFlows(bindingProtocol, gomock.InAnyOrder(expectedAllEps)).Times(1) + if nodeLocalInternal != nodeLocalExternal { + var clusterIPEps, nodePortEps []k8sproxy.Endpoint + if nodeLocalInternal { + clusterIPEps = expectedLocalEps + nodePortEps = expectedAllEps + } else { + clusterIPEps = expectedAllEps + nodePortEps = expectedLocalEps + } + groupID := fp.groupCounter.AllocateIfNotExist(svcPortName, nodeLocalInternal) + mockOFClient.EXPECT().InstallServiceGroup(groupID, false, gomock.InAnyOrder(clusterIPEps)).Times(1) + mockOFClient.EXPECT().InstallServiceFlows(groupID, svcIP, uint16(svcPort), bindingProtocol, uint16(0), nodeLocalInternal, corev1.ServiceTypeClusterIP).Times(1) + + groupID = fp.groupCounter.AllocateIfNotExist(svcPortName, nodeLocalExternal) + mockOFClient.EXPECT().InstallServiceGroup(groupID, false, gomock.InAnyOrder(nodePortEps)).Times(1) + mockOFClient.EXPECT().InstallServiceFlows(groupID, gomock.Any(), uint16(svcNodePort), bindingProtocol, uint16(0), nodeLocalExternal, corev1.ServiceTypeNodePort).Times(1) + } else { + nodeLocalVal := nodeLocalInternal && nodeLocalExternal + groupID := fp.groupCounter.AllocateIfNotExist(svcPortName, nodeLocalVal) + mockOFClient.EXPECT().InstallServiceGroup(groupID, false, gomock.InAnyOrder(expectedAllEps)).Times(1) + mockOFClient.EXPECT().InstallServiceFlows(groupID, svcIP, uint16(svcPort), bindingProtocol, uint16(0), nodeLocalVal, corev1.ServiceTypeClusterIP).Times(1) + mockOFClient.EXPECT().InstallServiceFlows(groupID, gomock.Any(), uint16(svcNodePort), bindingProtocol, uint16(0), nodeLocalVal, corev1.ServiceTypeNodePort).Times(1) + + groupID = fp.groupCounter.AllocateIfNotExist(svcPortName, !nodeLocalVal) + mockOFClient.EXPECT().UninstallGroup(groupID).Times(1) + } mockRouteClient.EXPECT().AddClusterIPRoute(svcIP).Times(1) mockRouteClient.EXPECT().AddNodePort(gomock.Any(), uint16(svcNodePort), bindingProtocol).Times(1) fp.syncProxyRules() } -func TestLoadBalancerIPv4(t *testing.T) { - testLoadBalancer(t, nodePortAddressesIPv4, svcIPv4, ep1IPv4, nil, loadBalancerIPv4, false, false, true) -} - -func TestLoadBalancerIPv4ExternalLocal(t *testing.T) { - testLoadBalancer(t, nodePortAddressesIPv4, svcIPv4, ep1IPv4, ep2IPv4, loadBalancerIPv4, false, true, true) -} - -func TestLoadBalancerIPv6(t *testing.T) { - testLoadBalancer(t, nodePortAddressesIPv6, svcIPv6, ep1IPv6, nil, loadBalancerIPv6, true, false, true) -} - -func TestLoadBalancerIPv6ExternalLocal(t *testing.T) { - testLoadBalancer(t, nodePortAddressesIPv6, svcIPv6, ep1IPv6, ep2IPv6, loadBalancerIPv6, true, true, true) -} - -func TestLoadBalancerIPv4NoExternalIPs(t *testing.T) { - testLoadBalancer(t, nodePortAddressesIPv4, svcIPv4, ep1IPv4, nil, loadBalancerIPv4, false, false, false) -} - -func TestNodePortIPv4(t *testing.T) { - testNodePort(t, nodePortAddressesIPv4, svcIPv4, ep1IPv4, nil, false, false) -} - -func TestNodePortIPv4ExternalLocal(t *testing.T) { - testNodePort(t, nodePortAddressesIPv4, svcIPv4, ep1IPv4, ep2IPv4, false, true) -} - -func TestNodePortIPv6(t *testing.T) { - testNodePort(t, nodePortAddressesIPv6, svcIPv6, ep1IPv6, nil, true, false) -} - -func TestNodePortIPv6ExternalLocal(t *testing.T) { - testNodePort(t, nodePortAddressesIPv6, svcIPv6, ep1IPv6, ep2IPv6, true, true) +func TestCluster(t *testing.T) { + t.Run("IPv4", func(t *testing.T) { + t.Run("InternalTrafficPolicy Cluster", func(t *testing.T) { + testClusterIP(t, svcIPv4, ep1IPv4, ep2IPv4, false, false, []*corev1.Service{}, []*corev1.Endpoints{}) + }) + t.Run("InternalTrafficPolicy Local", func(t *testing.T) { + testClusterIP(t, svcIPv4, ep1IPv4, ep2IPv4, false, true, []*corev1.Service{}, []*corev1.Endpoints{}) + }) + }) + t.Run("IPv6", func(t *testing.T) { + t.Run("InternalTrafficPolicy Cluster", func(t *testing.T) { + testClusterIP(t, svcIPv6, ep1IPv6, ep2IPv6, true, false, []*corev1.Service{}, []*corev1.Endpoints{}) + }) + t.Run("InternalTrafficPolicy Local", func(t *testing.T) { + testClusterIP(t, svcIPv6, ep1IPv6, ep2IPv6, true, true, []*corev1.Service{}, []*corev1.Endpoints{}) + }) + }) } -func TestClusterIPv4(t *testing.T) { - testClusterIP(t, svcIPv4, ep1IPv4, false, []*corev1.Service{}, []*corev1.Endpoints{}) +func TestLoadBalancer(t *testing.T) { + t.Run("IPv4", func(t *testing.T) { + t.Run("InternalTrafficPolicy:Cluster ExternalTrafficPolicy:Cluster", func(t *testing.T) { + testLoadBalancer(t, nodePortAddressesIPv4, svcIPv4, ep1IPv4, ep2IPv4, loadBalancerIPv4, false, false, false, true) + }) + t.Run("InternalTrafficPolicy:Cluster ExternalTrafficPolicy:Local", func(t *testing.T) { + testLoadBalancer(t, nodePortAddressesIPv4, svcIPv4, ep1IPv4, ep2IPv4, loadBalancerIPv4, false, false, true, true) + }) + t.Run("InternalTrafficPolicy:Local ExternalTrafficPolicy:Cluster", func(t *testing.T) { + testLoadBalancer(t, nodePortAddressesIPv4, svcIPv4, ep1IPv4, ep2IPv4, loadBalancerIPv4, false, true, false, true) + }) + t.Run("InternalTrafficPolicy:Local ExternalTrafficPolicy:Local", func(t *testing.T) { + testLoadBalancer(t, nodePortAddressesIPv4, svcIPv4, ep1IPv4, ep2IPv4, loadBalancerIPv4, false, true, true, true) + }) + t.Run("No External IPs", func(t *testing.T) { + testLoadBalancer(t, nodePortAddressesIPv4, svcIPv4, ep1IPv4, nil, loadBalancerIPv4, false, false, false, false) + }) + }) + t.Run("IPv6", func(t *testing.T) { + t.Run("InternalTrafficPolicy:Cluster ExternalTrafficPolicy:Cluster", func(t *testing.T) { + testLoadBalancer(t, nodePortAddressesIPv6, svcIPv6, ep1IPv6, ep2IPv6, loadBalancerIPv6, true, false, false, true) + }) + t.Run("InternalTrafficPolicy:Cluster ExternalTrafficPolicy:Local", func(t *testing.T) { + testLoadBalancer(t, nodePortAddressesIPv6, svcIPv6, ep1IPv6, ep2IPv6, loadBalancerIPv6, true, false, true, true) + }) + t.Run("InternalTrafficPolicy:Local ExternalTrafficPolicy:Cluster", func(t *testing.T) { + testLoadBalancer(t, nodePortAddressesIPv6, svcIPv6, ep1IPv6, ep2IPv6, loadBalancerIPv6, true, true, false, true) + }) + t.Run("InternalTrafficPolicy:Local ExternalTrafficPolicy:Local", func(t *testing.T) { + testLoadBalancer(t, nodePortAddressesIPv6, svcIPv6, ep1IPv6, ep2IPv6, loadBalancerIPv6, true, true, true, true) + }) + t.Run("No External IPs", func(t *testing.T) { + testLoadBalancer(t, nodePortAddressesIPv6, svcIPv6, ep1IPv6, nil, loadBalancerIPv6, true, false, false, false) + }) + }) } -func TestClusterIPv6(t *testing.T) { - testClusterIP(t, svcIPv6, ep1IPv6, true, []*corev1.Service{}, []*corev1.Endpoints{}) +func TestNodePort(t *testing.T) { + t.Run("IPv4", func(t *testing.T) { + t.Run("InternalTrafficPolicy:Cluster ExternalTrafficPolicy:Cluster", func(t *testing.T) { + testNodePort(t, nodePortAddressesIPv4, svcIPv4, ep1IPv4, ep2IPv4, false, false, false) + }) + t.Run("InternalTrafficPolicy:Cluster ExternalTrafficPolicy:Local", func(t *testing.T) { + testNodePort(t, nodePortAddressesIPv4, svcIPv4, ep1IPv4, ep2IPv4, false, false, true) + }) + t.Run("InternalTrafficPolicy:Local ExternalTrafficPolicy:Cluster", func(t *testing.T) { + testNodePort(t, nodePortAddressesIPv4, svcIPv4, ep1IPv4, ep2IPv4, false, true, false) + }) + t.Run("InternalTrafficPolicy:Local ExternalTrafficPolicy:Local", func(t *testing.T) { + testNodePort(t, nodePortAddressesIPv4, svcIPv4, ep1IPv4, ep2IPv4, false, true, true) + }) + }) + t.Run("IPv6", func(t *testing.T) { + t.Run("InternalTrafficPolicy:Cluster ExternalTrafficPolicy:Cluster", func(t *testing.T) { + testNodePort(t, nodePortAddressesIPv6, svcIPv6, ep1IPv6, ep2IPv6, true, false, false) + }) + t.Run("InternalTrafficPolicy:Cluster ExternalTrafficPolicy:Local", func(t *testing.T) { + testNodePort(t, nodePortAddressesIPv6, svcIPv6, ep1IPv6, ep2IPv6, true, false, true) + }) + t.Run("InternalTrafficPolicy:Local ExternalTrafficPolicy:Cluster", func(t *testing.T) { + testNodePort(t, nodePortAddressesIPv6, svcIPv6, ep1IPv6, ep2IPv6, true, true, false) + }) + t.Run("InternalTrafficPolicy:Local ExternalTrafficPolicy:Local", func(t *testing.T) { + testNodePort(t, nodePortAddressesIPv6, svcIPv6, ep1IPv6, ep2IPv6, true, true, true) + }) + }) } func TestClusterSkipServices(t *testing.T) { @@ -494,7 +617,7 @@ func TestClusterSkipServices(t *testing.T) { }} }) eps := []*corev1.Endpoints{ep1, ep2} - testClusterIP(t, svcIPv4, ep1IPv4, false, svcs, eps) + testClusterIP(t, svcIPv4, ep1IPv4, ep2IPv4, false, false, svcs, eps) } func TestDualStackService(t *testing.T) { @@ -625,7 +748,7 @@ func testClusterIPRemoval(t *testing.T, svcIP net.IP, epIP net.IP, isIPv6 bool) mockRouteClient.EXPECT().AddClusterIPRoute(svcIP).Times(1) mockOFClient.EXPECT().UninstallServiceFlows(svcIP, uint16(svcPort), bindingProtocol).Times(1) mockOFClient.EXPECT().UninstallEndpointFlows(bindingProtocol, gomock.Any()).Times(1) - mockOFClient.EXPECT().UninstallServiceGroup(gomock.Any()).Times(1) + mockOFClient.EXPECT().UninstallGroup(gomock.Any()).Times(1) fp.syncProxyRules() fp.serviceChanges.OnServiceUpdate(service, nil) @@ -834,7 +957,7 @@ func TestClusterIPRemoveEndpointsIPv6(t *testing.T) { testClusterIPRemoveEndpoints(t, net.ParseIP("10:20::41"), net.ParseIP("10:180::1"), true) } -func testSessionAffinityNoEndpoint(t *testing.T, svcExternalIPs net.IP, svcIP net.IP, epIP net.IP, isIPv6 bool) { +func testSessionAffinity(t *testing.T, svcExternalIPs net.IP, svcIP net.IP, epIP net.IP, affinitySeconds int32, isIPv6 bool) { ctrl := gomock.NewController(t) defer ctrl.Finish() mockOFClient := ofmock.NewMockClient(ctrl) @@ -849,7 +972,6 @@ func testSessionAffinityNoEndpoint(t *testing.T, svcExternalIPs net.IP, svcIP ne Port: "80", Protocol: corev1.ProtocolTCP, } - timeoutSeconds := corev1.DefaultClientIPServiceAffinitySeconds makeServiceMap(fp, makeTestService(svcPortName.Namespace, svcPortName.Name, func(svc *corev1.Service) { @@ -859,7 +981,7 @@ func testSessionAffinityNoEndpoint(t *testing.T, svcExternalIPs net.IP, svcIP ne svc.Spec.SessionAffinity = corev1.ServiceAffinityClientIP svc.Spec.SessionAffinityConfig = &corev1.SessionAffinityConfig{ ClientIP: &corev1.ClientIPConfig{ - TimeoutSeconds: &timeoutSeconds, + TimeoutSeconds: &affinitySeconds, }, } svc.Spec.Ports = []corev1.ServicePort{{ @@ -891,20 +1013,35 @@ func testSessionAffinityNoEndpoint(t *testing.T, svcExternalIPs net.IP, svcIP ne groupID := fp.groupCounter.AllocateIfNotExist(svcPortName, false) mockOFClient.EXPECT().InstallServiceGroup(groupID, true, gomock.Any()).Times(1) mockOFClient.EXPECT().InstallEndpointFlows(bindingProtocol, gomock.Any()).Times(1) - mockOFClient.EXPECT().InstallServiceFlows(groupID, svcIP, uint16(svcPort), bindingProtocol, uint16(corev1.DefaultClientIPServiceAffinitySeconds), false, corev1.ServiceTypeClusterIP).Times(1) + var expectedAffinity uint16 + if affinitySeconds > math.MaxUint16 { + expectedAffinity = math.MaxUint16 + } else { + expectedAffinity = uint16(affinitySeconds) + } + mockOFClient.EXPECT().InstallServiceFlows(groupID, svcIP, uint16(svcPort), bindingProtocol, expectedAffinity, false, corev1.ServiceTypeClusterIP).Times(1) fp.syncProxyRules() } -func TestSessionAffinityNoEndpointIPv4(t *testing.T) { - testSessionAffinityNoEndpoint(t, net.ParseIP("50.60.70.81"), net.ParseIP("10.20.30.41"), net.ParseIP("10.180.0.1"), false) +func TestSessionAffinityIPv4(t *testing.T) { + affinitySeconds := corev1.DefaultClientIPServiceAffinitySeconds + testSessionAffinity(t, net.ParseIP("50.60.70.81"), net.ParseIP("10.20.30.41"), net.ParseIP("10.180.0.1"), affinitySeconds, false) } -func TestSessionAffinityNoEndpointIPv6(t *testing.T) { - testSessionAffinityNoEndpoint(t, net.ParseIP("5060:70::81"), net.ParseIP("10:20::41"), net.ParseIP("10:180::1"), true) +func TestSessionAffinityIPv6(t *testing.T) { + affinitySeconds := corev1.DefaultClientIPServiceAffinitySeconds + testSessionAffinity(t, net.ParseIP("5060:70::81"), net.ParseIP("10:20::41"), net.ParseIP("10:180::1"), affinitySeconds, true) } -func testSessionAffinity(t *testing.T, svcExternalIPs net.IP, svcIP net.IP, isIPv6 bool) { +func TestSessionAffinityOverflow(t *testing.T) { + // Ensure that the SessionAffinity timeout is truncated to the max supported value, instead + // of wrapping around. + affinitySeconds := int32(math.MaxUint16 + 10) + testSessionAffinity(t, net.ParseIP("50.60.70.81"), net.ParseIP("10.20.30.41"), net.ParseIP("10.180.0.1"), affinitySeconds, false) +} + +func testSessionAffinityNoEndpoint(t *testing.T, svcExternalIPs net.IP, svcIP net.IP, isIPv6 bool) { ctrl := gomock.NewController(t) defer ctrl.Finish() mockOFClient := ofmock.NewMockClient(ctrl) @@ -944,12 +1081,12 @@ func testSessionAffinity(t *testing.T, svcExternalIPs net.IP, svcIP net.IP, isIP fp.syncProxyRules() } -func TestSessionAffinityIPv4(t *testing.T) { - testSessionAffinity(t, net.ParseIP("50.60.70.81"), net.ParseIP("10.20.30.41"), false) +func TestSessionAffinityNoEndpointIPv4(t *testing.T) { + testSessionAffinityNoEndpoint(t, net.ParseIP("50.60.70.81"), net.ParseIP("10.20.30.41"), false) } -func TestSessionAffinityIPv6(t *testing.T) { - testSessionAffinity(t, net.ParseIP("5060:70::81"), net.ParseIP("10:20::41"), true) +func TestSessionAffinityIPv6NoEndpoint(t *testing.T) { + testSessionAffinityNoEndpoint(t, net.ParseIP("5060:70::81"), net.ParseIP("10:20::41"), true) } func testPortChange(t *testing.T, svcIP net.IP, epIP net.IP, isIPv6 bool) { @@ -1094,8 +1231,8 @@ func TestServicesWithSameEndpoints(t *testing.T) { mockOFClient.EXPECT().InstallServiceFlows(groupID2, svcIP2, uint16(svcPort), bindingProtocol, uint16(0), false, corev1.ServiceTypeClusterIP).Times(1) mockOFClient.EXPECT().UninstallServiceFlows(svcIP1, uint16(svcPort), bindingProtocol).Times(1) mockOFClient.EXPECT().UninstallServiceFlows(svcIP2, uint16(svcPort), bindingProtocol).Times(1) - mockOFClient.EXPECT().UninstallServiceGroup(groupID1).Times(1) - mockOFClient.EXPECT().UninstallServiceGroup(groupID2).Times(1) + mockOFClient.EXPECT().UninstallGroup(groupID1).Times(1) + mockOFClient.EXPECT().UninstallGroup(groupID2).Times(1) // Since these two Services reference to the same Endpoint, there should only be one operation. mockOFClient.EXPECT().UninstallEndpointFlows(bindingProtocol, gomock.Any()).Times(1) @@ -1114,12 +1251,12 @@ func TestMetrics(t *testing.T) { metrics.Register() for _, tc := range []struct { - name string - svcIP, epIP string - isIPv6 bool + name string + svcIP, ep1IP, ep2IP net.IP + isIPv6 bool }{ - {"IPv4", "10.20.30.41", "10.180.0.1", false}, - {"IPv6", "fc01::1", "fe01::1", true}, + {"IPv4", svcIPv4, ep1IPv4, ep2IPv4, false}, + {"IPv6", svcIPv6, ep1IPv6, ep2IPv6, true}, } { t.Run(tc.name, func(t *testing.T) { endpointsUpdateTotalMetric := metrics.EndpointsUpdatesTotal.CounterMetric @@ -1132,7 +1269,7 @@ func TestMetrics(t *testing.T) { endpointsInstallMetric = metrics.EndpointsInstalledTotalV6.GaugeMetric servicesInstallMetric = metrics.ServicesInstalledTotalV6.GaugeMetric } - testClusterIP(t, net.ParseIP(tc.svcIP), net.ParseIP(tc.epIP), tc.isIPv6, []*corev1.Service{}, []*corev1.Endpoints{}) + testClusterIP(t, tc.svcIP, tc.ep1IP, tc.ep2IP, tc.isIPv6, false, []*corev1.Service{}, []*corev1.Endpoints{}) v, err := testutil.GetCounterMetricValue(endpointsUpdateTotalMetric) assert.NoError(t, err) assert.Equal(t, 0, int(v)) @@ -1143,10 +1280,10 @@ func TestMetrics(t *testing.T) { assert.Equal(t, 1, int(v)) assert.NoError(t, err) v, err = testutil.GetGaugeMetricValue(endpointsInstallMetric) - assert.Equal(t, 1, int(v)) + assert.Equal(t, 2, int(v)) assert.NoError(t, err) - testClusterIPRemoval(t, net.ParseIP(tc.svcIP), net.ParseIP(tc.epIP), tc.isIPv6) + testClusterIPRemoval(t, tc.svcIP, tc.ep1IP, tc.isIPv6) v, err = testutil.GetCounterMetricValue(endpointsUpdateTotalMetric) assert.NoError(t, err) diff --git a/pkg/agent/route/route_linux.go b/pkg/agent/route/route_linux.go index 36c1041e467..f77edb1ec75 100644 --- a/pkg/agent/route/route_linux.go +++ b/pkg/agent/route/route_linux.go @@ -755,8 +755,8 @@ func (c *Client) Reconcile(podCIDRs []string, svcIPs map[string]bool) error { if desiredIPv6GWs.Has(route.Dst.IP.String()) { continue } - // Don't delete the routes which are added by AntreaProxy. - if c.isServiceRoute(&route) { + // Don't delete the routes which are added by AntreaProxy when proxyAll is enabled. + if c.proxyAll && c.isServiceRoute(&route) { continue } @@ -1116,7 +1116,7 @@ func (c *Client) addVirtualServiceIPRoute(isIPv6 bool) error { neigh := generateNeigh(svcIP, linkIndex) if err := netlink.NeighSet(neigh); err != nil { - return fmt.Errorf("failed to add new IP neighbour for %s: %v", svcIP, err) + return fmt.Errorf("failed to add new IP neighbour for %s: %w", svcIP, err) } c.serviceNeighbors.Store(svcIP.String(), neigh) @@ -1187,48 +1187,68 @@ func (c *Client) AddClusterIPRoute(svcIP net.IP) error { gw = config.VirtualServiceIPv6 } + // If the route exists and its destination CIDR contains the ClusterIP, there is no need to update the route. + if curClusterIPCIDR != nil && curClusterIPCIDR.Contains(svcIP) { + klog.V(4).InfoS("Route with current ClusterIP CIDR can route the ClusterIP to Antrea gateway", "ClusterIP CIDR", curClusterIPCIDR, "ClusterIP", svcIP) + return nil + } + + var newClusterIPCIDR *net.IPNet + var err error if curClusterIPCIDR != nil { - // If the route exists, check that whether the route can cover the ClusterIP. - if !curClusterIPCIDR.Contains(svcIP) { - // If not, generate a new destination ipNet. - newClusterIPCIDR, err := util.ExtendCIDRWithIP(curClusterIPCIDR, svcIP) - if err != nil { - return fmt.Errorf("extend route CIDR with error: %v", err) - } - // Generate a new route with new ClusterIP CIDR and install the route. - mask, _ = newClusterIPCIDR.Mask.Size() - route := generateRoute(newClusterIPCIDR.IP, mask, gw, linkIndex, scope) - if err = netlink.RouteReplace(route); err != nil { - return fmt.Errorf("failed to install new route: %w", err) - } + // If the route exists and its destination CIDR doesn't contain the ClusterIP, generate a new destination CIDR by + // enlarging the current destination CIDR with the ClusterIP. + if newClusterIPCIDR, err = util.ExtendCIDRWithIP(curClusterIPCIDR, svcIP); err != nil { + return fmt.Errorf("enlarge the destination CIDR with an error: %w", err) + } + } else { + // If the route doesn't exist, generate a new destination CIDR with the ClusterIP. Note that, this is the first + // ClusterIP since the route doesn't exist. + newClusterIPCIDR = &net.IPNet{IP: svcIP, Mask: net.CIDRMask(mask, mask)} + } - // Generate the current route by replacing the destination CIDR with current ClusterIP CIDR and delete the - // route. - route.Dst = curClusterIPCIDR - if err = netlink.RouteDel(route); err != nil { - return fmt.Errorf("failed to uninstall old route: %w", err) - } + // Generate a route with the new destination CIDR and install it. + newClusterIPCIDRMask, _ := newClusterIPCIDR.Mask.Size() + route := generateRoute(newClusterIPCIDR.IP, newClusterIPCIDRMask, gw, linkIndex, scope) + if err = netlink.RouteReplace(route); err != nil { + return fmt.Errorf("failed to install new ClusterIP route: %w", err) + } + // Store the new destination CIDR. + if isIPv6 { + c.clusterIPv6CIDR = route.Dst + } else { + c.clusterIPv4CIDR = route.Dst + } + klog.V(4).InfoS("Created a route to route the ClusterIP to Antrea gateway", "route", route, "ClusterIP", svcIP) - if isIPv6 { - c.clusterIPv6CIDR = newClusterIPCIDR - } else { - c.clusterIPv4CIDR = newClusterIPCIDR - } - klog.V(4).InfoS("Created a route with new ClusterIP CIDR to route the ClusterIP to Antrea gateway", "ClusterIP CIDR", newClusterIPCIDR, "clusterIP", svcIP) - } else { - klog.V(4).InfoS("Route with current ClusterIP CIDR can route the ClusterIP to Antrea gateway", "ClusterIP CIDR", curClusterIPCIDR, "clusterIP", svcIP) - } + // Collect stale routes. + var staleRoutes []*netlink.Route + if curClusterIPCIDR != nil { + // If current destination CIDR is not nil, the route with current destination CIDR should be uninstalled. + route.Dst = curClusterIPCIDR + staleRoutes = []*netlink.Route{route} } else { - route := generateRoute(svcIP, mask, gw, linkIndex, scope) - if err := netlink.RouteReplace(route); err != nil { - return fmt.Errorf("failed to install new ClusterIP route: %w", err) + // If current destination CIDR is nil, which means that Antrea Agent has just started, then all existing routes + // whose destination CIDR contains the first ClusterIP should be uninstalled, except the newly installed route. + // Note that, there may be multiple stale routes prior to this commit. When upgrading, all stale routes will be + // collected. After this commit, there will be only one stale route after Antrea Agent started. + routes, err := c.listIPRoutesOnGW() + if err != nil { + return fmt.Errorf("error listing ip routes: %w", err) } + for i := 0; i < len(routes); i++ { + if routes[i].Gw.Equal(gw) && !routes[i].Dst.IP.Equal(svcIP) && routes[i].Dst.Contains(svcIP) { + staleRoutes = append(staleRoutes, &routes[i]) + } + } + } - if isIPv6 { - c.clusterIPv6CIDR = route.Dst - } else { - c.clusterIPv4CIDR = route.Dst + // Remove stale routes. + for _, rt := range staleRoutes { + if err = netlink.RouteDel(rt); err != nil { + return fmt.Errorf("failed to uninstall stale ClusterIP route %s: %w", rt.String(), err) } + klog.V(4).InfoS("Uninstalled stale ClusterIP route successfully", "stale route", rt) } return nil @@ -1278,7 +1298,11 @@ func (c *Client) deleteLoadBalancerIngressIPRoute(svcIPStr string) error { route := generateRoute(svcIP, mask, gw, linkIndex, netlink.SCOPE_UNIVERSE) if err := netlink.RouteDel(route); err != nil { - return fmt.Errorf("failed to delete routing entry for LoadBalancer ingress IP %s: %w", svcIP.String(), err) + if err.Error() == "no such process" { + klog.InfoS("Failed to delete LoadBalancer ingress IP route since the route has been deleted", "route", route) + } else { + return fmt.Errorf("failed to delete routing entry for LoadBalancer ingress IP %s: %w", svcIP.String(), err) + } } klog.V(4).InfoS("Deleted LoadBalancer ingress IP route", "route", route) c.serviceRoutes.Delete(svcIP.String()) diff --git a/pkg/agent/route/route_windows.go b/pkg/agent/route/route_windows.go index 81b6fb7d8e2..25e2a3ba870 100644 --- a/pkg/agent/route/route_windows.go +++ b/pkg/agent/route/route_windows.go @@ -38,12 +38,13 @@ const ( inboundFirewallRuleName = "Antrea: accept packets from local Pods" outboundFirewallRuleName = "Antrea: accept packets to local Pods" - antreaNat = "antrea-nat" antreaNatNodePort = "antrea-nat-nodeport" ) var ( + antreaNat = util.AntreaNatName virtualServiceIPv4Net = util.NewIPNet(config.VirtualServiceIPv4) + PodCIDRIPv4 *net.IPNet ) type Client struct { @@ -71,6 +72,7 @@ func NewClient(networkConfig *config.NetworkConfig, noSNAT, proxyAll, connectUpl // Service LoadBalancing is provided by OpenFlow. func (c *Client) Initialize(nodeConfig *config.NodeConfig, done func()) error { c.nodeConfig = nodeConfig + PodCIDRIPv4 = nodeConfig.PodIPv4CIDR bridgeInf, err := net.InterfaceByName(nodeConfig.OVSBridge) if err != nil { return fmt.Errorf("failed to find the interface %s: %v", nodeConfig.OVSBridge, err) diff --git a/pkg/agent/cniserver/types/arg_types.go b/pkg/agent/types/event.go similarity index 64% rename from pkg/agent/cniserver/types/arg_types.go rename to pkg/agent/types/event.go index a64faca186f..eea70f66e42 100644 --- a/pkg/agent/cniserver/types/arg_types.go +++ b/pkg/agent/types/event.go @@ -1,4 +1,4 @@ -// Copyright 2019 Antrea Authors +// Copyright 2022 Antrea Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -14,13 +14,9 @@ package types -import ( - cnitypes "github.com/containernetworking/cni/pkg/types" -) - -type K8sArgs struct { - cnitypes.CommonArgs - K8S_POD_NAME cnitypes.UnmarshallableString - K8S_POD_NAMESPACE cnitypes.UnmarshallableString - K8S_POD_INFRA_CONTAINER_ID cnitypes.UnmarshallableString +type PodUpdate struct { + PodNamespace string + PodName string + IsAdd bool + ContainerID string } diff --git a/pkg/agent/types/networkpolicy.go b/pkg/agent/types/networkpolicy.go index 4bac731c221..a0a90d1bb13 100644 --- a/pkg/agent/types/networkpolicy.go +++ b/pkg/agent/types/networkpolicy.go @@ -53,6 +53,7 @@ const ( IPNetAddr OFPortAddr L4PortAddr + ICMPAddr ServiceGroupIDAddr UnSupported ) diff --git a/pkg/agent/util/net.go b/pkg/agent/util/net.go index 81719628e9f..3b3304c9ded 100644 --- a/pkg/agent/util/net.go +++ b/pkg/agent/util/net.go @@ -20,10 +20,12 @@ import ( "errors" "fmt" "io" + "math" "net" "strings" "k8s.io/apimachinery/pkg/util/sets" + "k8s.io/klog/v2" utilnet "k8s.io/utils/net" "antrea.io/antrea/pkg/util/ip" @@ -368,3 +370,11 @@ func NewIPNet(ip net.IP) *net.IPNet { } return &net.IPNet{IP: ip, Mask: net.CIDRMask(128, 128)} } + +func PortToUint16(port int) uint16 { + if port > 0 && port <= math.MaxUint16 { + return uint16(port) // lgtm[go/incorrect-integer-conversion] + } + klog.Errorf("Port value %d out-of-bounds", port) + return 0 +} diff --git a/pkg/agent/util/net_windows.go b/pkg/agent/util/net_windows.go index bfcf8ad9935..ac5abc8c7a5 100644 --- a/pkg/agent/util/net_windows.go +++ b/pkg/agent/util/net_windows.go @@ -19,6 +19,7 @@ package util import ( "bufio" + "bytes" "encoding/json" "fmt" "net" @@ -46,6 +47,8 @@ const ( MetricDefault = 256 MetricHigh = 50 + + AntreaNatName = "antrea-nat" ) type Route struct { @@ -172,7 +175,17 @@ func EnableIPForwarding(ifaceName string) error { } func RenameVMNetworkAdapter(networkName string, macStr, newName string, renameNetAdapter bool) error { - cmd := fmt.Sprintf(`$name=$(Get-VMNetworkAdapter -ManagementOS -ComputerName "$(hostname)" -SwitchName "%s" | ? MacAddress -EQ "%s").Name; Rename-VMNetworkAdapter -ManagementOS -ComputerName "$(hostname)" -Name "$name" -NewName "%s"`, networkName, macStr, newName) + cmd := fmt.Sprintf(`Get-VMNetworkAdapter -ManagementOS -ComputerName "$(hostname)" -SwitchName "%s" | ? MacAddress -EQ "%s" | Select-Object -Property Name | Format-Table -HideTableHeaders`, networkName, macStr) + stdout, err := ps.RunCommand(cmd) + if err != nil { + return err + } + stdout = strings.TrimSpace(stdout) + if len(stdout) == 0 { + return fmt.Errorf("unable to find vmnetwork adapter configured with uplink MAC address %s", macStr) + } + vmNetworkAdapterName := stdout + cmd = fmt.Sprintf(`Get-VMNetworkAdapter -ManagementOS -ComputerName "$(hostname)" -Name "%s" | Rename-VMNetworkAdapter -NewName "%s"`, vmNetworkAdapterName, newName) if _, err := ps.RunCommand(cmd); err != nil { return err } @@ -385,15 +398,15 @@ func PrepareHNSNetwork(subnetCIDR *net.IPNet, nodeIPNet *net.IPNet, uplinkAdapte } }() - vNicName := VirtualAdapterName(uplinkAdapter.Name) - index, found, err := adapterIPExists(nodeIPNet.IP, vNicName) + adapter, ipFound, err := adapterIPExists(nodeIPNet.IP, uplinkAdapter.HardwareAddr, ContainerVNICPrefix) if err != nil { return err } - // By default, "found" should be true after Windows creates the HNSNetwork. The following check is for some corner + vNicName, index := adapter.Name, adapter.Index + // By default, "ipFound" should be true after Windows creates the HNSNetwork. The following check is for some corner // cases that Windows fails to move the physical adapter's IP address to the virtual network adapter, e.g., DHCP // Server fails to allocate IP to new virtual network. - if !found { + if !ipFound { klog.InfoS("Moving uplink configuration to the management virtual network adapter", "adapter", vNicName) if err := ConfigureInterfaceAddressWithDefaultGateway(vNicName, nodeIPNet, nodeGateway); err != nil { klog.ErrorS(err, "Failed to configure IP and gateway on the management virtual network adapter", "adapter", vNicName, "ip", nodeIPNet.String()) @@ -443,19 +456,35 @@ func PrepareHNSNetwork(subnetCIDR *net.IPNet, nodeIPNet *net.IPNet, uplinkAdapte return nil } -func adapterIPExists(ip net.IP, adapter string) (int, bool, error) { - iface, err := net.InterfaceByName(adapter) +// adapterIPExists finds the network adapter configured with the provided IP, MAC and its name has the given prefix. +// If "namePrefix" is empty, it returns the first network adapter with the provided IP and MAC. +// It returns true if the IP is found on the adapter, otherwise it returns false. +func adapterIPExists(ip net.IP, mac net.HardwareAddr, namePrefix string) (*net.Interface, bool, error) { + adapters, err := net.Interfaces() if err != nil { - return 0, false, err - } - cmd := fmt.Sprintf(`Get-NetIPAddress -IPAddress %s -InterfaceIndex %d`, ip.String(), iface.Index) - if _, err = ps.RunCommand(cmd); err != nil { - if strings.Contains(err.Error(), "No matching MSFT_NetIPAddress objects found") { - return iface.Index, false, nil + return nil, false, err + } + ipExists := false + for _, adapter := range adapters { + if bytes.Equal(adapter.HardwareAddr, mac) { + if namePrefix == "" || strings.Contains(adapter.Name, namePrefix) { + addrList, err := adapter.Addrs() + if err != nil { + return nil, false, err + } + for _, addr := range addrList { + if ipNet, ok := addr.(*net.IPNet); ok { + if ipNet.IP.Equal(ip) { + ipExists = true + break + } + } + } + return &adapter, ipExists, nil + } } - return 0, false, err } - return iface.Index, true, nil + return nil, false, fmt.Errorf("unable to find a network adapter with MAC %s, IP %s, and name prefix %s", mac.String(), ip.String(), namePrefix) } // EnableRSCOnVSwitch enables RSC in the vSwitch to reduce host CPU utilization and increase throughput for virtual @@ -673,6 +702,7 @@ func NewNetNat(netNatName string, subnetCIDR *net.IPNet) error { } } else { if strings.Contains(internalNet, subnetCIDR.String()) { + klog.InfoS("existing netnat in CIDR", "name", internalNet, "subnetCIDR", subnetCIDR.String()) return nil } klog.InfoS("Removing the existing netnat", "name", netNatName, "internalIPInterfaceAddressPrefix", internalNet) @@ -754,12 +784,41 @@ func RemoveNetNatStaticMapping(netNatName string, externalIPAddr string, externa return RemoveNetNatStaticMappingByID(netNatName, id) } +func RemoveNetNatStaticMappingByNPLTuples(netNatName string, externalIPAddr string, externalPort uint16, internalIPAddr string, internalPort uint16, proto string) error { + staticMappingStr, err := GetNetNatStaticMapping(netNatName, externalIPAddr, externalPort, proto) + if err != nil { + return err + } + parsed := parseGetNetCmdResult(staticMappingStr, 6) + if len(parsed) > 0 { + items := parsed[0] + if items[4] == internalIPAddr && items[5] == strconv.Itoa(int(internalPort)) { + firstCol := strings.Split(items[0], ";") + id, err := strconv.Atoi(firstCol[1]) + if err != nil { + return err + } + if err := RemoveNetNatStaticMappingByID(netNatName, id); err != nil { + return err + } + return nil + } + } + return nil +} + func RemoveNetNatStaticMappingByID(netNatName string, id int) error { cmd := fmt.Sprintf("Remove-NetNatStaticMapping -NatName %s -StaticMappingID %d -Confirm:$false", netNatName, id) _, err := ps.RunCommand(cmd) return err } +func RemoveNetNatStaticMappingByNAME(netNatName string) error { + cmd := fmt.Sprintf("Remove-NetNatStaticMapping -NatName %s -Confirm:$false", netNatName) + _, err := ps.RunCommand(cmd) + return err +} + // GetNetNeighbor gets neighbor cache entries with Get-NetNeighbor. func GetNetNeighbor(neighbor *Neighbor) ([]Neighbor, error) { cmd := fmt.Sprintf("Get-NetNeighbor -InterfaceIndex %d -IPAddress %s | Format-Table -HideTableHeaders", neighbor.LinkIndex, neighbor.IPAddress.String()) diff --git a/pkg/antctl/antctl.go b/pkg/antctl/antctl.go index 7a58b19a907..cfe9605e132 100644 --- a/pkg/antctl/antctl.go +++ b/pkg/antctl/antctl.go @@ -21,6 +21,7 @@ import ( "antrea.io/antrea/pkg/agent/apiserver/handlers/agentinfo" "antrea.io/antrea/pkg/agent/apiserver/handlers/ovsflows" "antrea.io/antrea/pkg/agent/apiserver/handlers/podinterface" + "antrea.io/antrea/pkg/agent/apiserver/handlers/serviceexternalip" "antrea.io/antrea/pkg/agent/openflow" fallbackversion "antrea.io/antrea/pkg/antctl/fallback/version" "antrea.io/antrea/pkg/antctl/raw/featuregates" @@ -509,6 +510,32 @@ var CommandList = &commandList{ }, transformedResponse: reflect.TypeOf(recordmetrics.Response{}), }, + { + use: "serviceexternalip", + short: "Print Service external IP status", + long: "Print Service external IP status. It includes the external IP, external IP pool and the assigned Node for Services with type LoadBalancer managed by Antrea", + commandGroup: get, + aliases: []string{"seip", "serviceexternalips"}, + agentEndpoint: &endpoint{ + nonResourceEndpoint: &nonResourceEndpoint{ + path: "/serviceexternalip", + params: []flagInfo{ + { + name: "name", + usage: "Name of the Service; if present, Namespace must be provided as well.", + arg: true, + }, + { + name: "namespace", + usage: "Only get the external IP status for Services in the provided Namespace.", + shorthand: "n", + }, + }, + outputType: multiple, + }, + }, + transformedResponse: reflect.TypeOf(serviceexternalip.Response{}), + }, }, rawCommands: []rawCommand{ { diff --git a/pkg/antctl/client.go b/pkg/antctl/client.go index 2e820802cb8..15a6a59a65f 100644 --- a/pkg/antctl/client.go +++ b/pkg/antctl/client.go @@ -71,12 +71,9 @@ func newClient(codec serializer.CodecFactory) AntctlClient { // It will return error if the stating of the file failed or the kubeconfig is malformed. // If the default kubeconfig not exists, it will try to use an in-cluster config. func (c *client) resolveKubeconfig(opt *requestOption) (*rest.Config, error) { - kubeconfig, err := runtime.ResolveKubeconfig(opt.kubeconfig) - if err != nil { - return nil, err - } - kubeconfig.NegotiatedSerializer = c.codec + var kubeconfig *rest.Config if runtime.InPod { + kubeconfig = &rest.Config{} kubeconfig.Insecure = true kubeconfig.CAFile = "" kubeconfig.CAData = nil @@ -90,7 +87,13 @@ func (c *client) resolveKubeconfig(opt *requestOption) (*rest.Config, error) { kubeconfig.Host = net.JoinHostPort("127.0.0.1", fmt.Sprint(apis.FlowAggregatorAPIPort)) kubeconfig.BearerTokenFile = flowaggregatorapiserver.TokenPath } + } else { + var err error + if kubeconfig, err = runtime.ResolveKubeconfig(opt.kubeconfig); err != nil { + return nil, err + } } + kubeconfig.NegotiatedSerializer = c.codec return kubeconfig, nil } diff --git a/pkg/antctl/command_definition.go b/pkg/antctl/command_definition.go index 8aaae9728c3..3e93aa846aa 100644 --- a/pkg/antctl/command_definition.go +++ b/pkg/antctl/command_definition.go @@ -295,7 +295,11 @@ func (cd *commandDefinition) applySubCommandToRoot(root *cobra.Command, client A if groupCommand, ok := groupCommands[cd.commandGroup]; ok { groupCommand.AddCommand(cmd) } else { - root.AddCommand(cmd) + // when antctl runs outside the Controller/Agent/FlowAggregator Pod. This check ensures that + // the log-level command is not added to the list of available commands. + if cmd.Use != "log-level [level]" || (cmd.Use == "log-level [level]" && runtime.InPod) { + root.AddCommand(cmd) + } } cd.applyExampleToCommand(cmd) diff --git a/pkg/antctl/command_list.go b/pkg/antctl/command_list.go index ce0cb977e5c..e4f911916f8 100644 --- a/pkg/antctl/command_list.go +++ b/pkg/antctl/command_list.go @@ -15,7 +15,6 @@ package antctl import ( - "flag" "fmt" "io" "math" @@ -57,7 +56,6 @@ func (cl *commandList) applyToRootCommand(root *cobra.Command, client AntctlClie continue } def.applySubCommandToRoot(root, client, out) - klog.Infof("Added command %s", def.use) } cl.applyPersistentFlagsToRoot(root) @@ -79,13 +77,10 @@ func (cl *commandList) applyToRootCommand(root *cobra.Command, client AntctlClie if err != nil { return err } - err = flag.Set("logtostderr", fmt.Sprint(enableVerbose)) - if err != nil { - return err - } + klog.LogToStderr(enableVerbose) if enableVerbose { - err := flag.Set("v", fmt.Sprint(math.MaxInt32)) - if err != nil { + var logLevel klog.Level + if err := logLevel.Set(fmt.Sprint(math.MaxInt32)); err != nil { return err } } diff --git a/pkg/antctl/raw/proxy/command.go b/pkg/antctl/raw/proxy/command.go index 9ffe8569cb8..b4d42409471 100644 --- a/pkg/antctl/raw/proxy/command.go +++ b/pkg/antctl/raw/proxy/command.go @@ -187,7 +187,15 @@ func runE(cmd *cobra.Command, _ []string) error { } } - server, err := proxy.NewServer(options.staticDir, options.apiPrefix, options.staticPrefix, options.filter, clientCfg, options.keepalive) + // The last argument is for "appendLocationPath", which for "kubectl proxy" is used as + // follows: if the Kubeconfig context provides a server URL which includes a Path comppnent + // (e.g., https://example.com/PATH), then this path is automatically added to all incoming + // requests to the proxy. + // See https://github.com/kubernetes/kubernetes/pull/97350 + // In our case, we craft the config manually and clientCfg.Host never includes a Path + // component, so we always set "appendLocationPath" to "false", and there is no need to + // expose a flag like --append-server-path for "antctl proxy". + server, err := proxy.NewServer(options.staticDir, options.apiPrefix, options.staticPrefix, options.filter, clientCfg, options.keepalive, false) if err != nil { return err diff --git a/pkg/antctl/raw/traceflow/command_test.go b/pkg/antctl/raw/traceflow/command_test.go index 49efe213b37..02a39c09cf9 100644 --- a/pkg/antctl/raw/traceflow/command_test.go +++ b/pkg/antctl/raw/traceflow/command_test.go @@ -146,7 +146,7 @@ func TestParseFlow(t *testing.T) { pkt, err := parseFlow() if err != nil { if tc.success { - t.Errorf("error when running parseFlow(): %w", err) + t.Errorf("error when running parseFlow(): %v", err) } } else { assert.Equal(t, tc.expected.Spec.Packet, *pkt) diff --git a/pkg/antctl/runtime/runtime.go b/pkg/antctl/runtime/runtime.go index e23a36674d2..5c2b881f60e 100644 --- a/pkg/antctl/runtime/runtime.go +++ b/pkg/antctl/runtime/runtime.go @@ -20,6 +20,9 @@ import ( "k8s.io/client-go/rest" "k8s.io/client-go/tools/clientcmd" + + agentapiserver "antrea.io/antrea/pkg/agent/apiserver" + "antrea.io/antrea/pkg/util/runtime" ) const ( @@ -53,6 +56,15 @@ func init() { podName, found := os.LookupEnv("POD_NAME") InPod = found && (strings.HasPrefix(podName, "antrea-agent") || strings.HasPrefix(podName, "antrea-controller") || strings.HasPrefix(podName, "flow-aggregator")) + + if runtime.IsWindowsPlatform() && !InPod { + if _, err := os.Stat(agentapiserver.TokenPath); err == nil { + InPod = true + Mode = ModeAgent + return + } + } + if strings.HasPrefix(podName, "antrea-agent") { Mode = ModeAgent } else if strings.HasPrefix(podName, "flow-aggregator") { diff --git a/pkg/apis/controlplane/types.go b/pkg/apis/controlplane/types.go index e0f1de33a4d..68920081df2 100644 --- a/pkg/apis/controlplane/types.go +++ b/pkg/apis/controlplane/types.go @@ -267,21 +267,29 @@ const ( ProtocolUDP Protocol = "UDP" // ProtocolSCTP is the SCTP protocol. ProtocolSCTP Protocol = "SCTP" + // ProtocolICMP is the ICMP protocol. + ProtocolICMP Protocol = "ICMP" ) // Service describes a port to allow traffic on. type Service struct { - // The protocol (TCP, UDP, or SCTP) which traffic must match. If not specified, this + // The protocol (TCP, UDP, SCTP, or ICMP) which traffic must match. If not specified, this // field defaults to TCP. // +optional Protocol *Protocol - // The port name or number on the given protocol. If not specified, this matches all port numbers. + // Port and EndPort can only be specified, when the Protocol is TCP, UDP, or SCTP. + // Port defines the port name or number on the given protocol. If not specified + // and the Protocol is TCP, UDP, or SCTP, this matches all port numbers. // +optional Port *intstr.IntOrString // EndPort defines the end of the port range, being the end included within the range. // It can only be specified when a numerical `port` is specified. // +optional EndPort *int32 + // ICMPType and ICMPCode can only be specified, when the Protocol is ICMP. If they + // both are not specified and the Protocol is ICMP, this matches all ICMP traffic. + ICMPType *int32 + ICMPCode *int32 } // NetworkPolicyPeer describes a peer of NetworkPolicyRules. @@ -332,6 +340,16 @@ type NodeStatsSummary struct { AntreaClusterNetworkPolicies []NetworkPolicyStats // The TrafficStats of Antrea NetworkPolicies collected from the Node. AntreaNetworkPolicies []NetworkPolicyStats + // Multicast group information from the Node. + Multicast []MulticastGroupInfo +} + +// MulticastGroupInfo contains the list of Pods that have joined a multicast group, for a given Node. +type MulticastGroupInfo struct { + // Group is the IP of the multicast group. + Group string + // Pods is the list of Pods that have joined the multicast group. + Pods []PodReference } // NetworkPolicyStats contains the information and traffic stats of a NetworkPolicy. diff --git a/pkg/apis/controlplane/v1beta2/generated.pb.go b/pkg/apis/controlplane/v1beta2/generated.pb.go index 7d6933fddb8..c02582c105d 100644 --- a/pkg/apis/controlplane/v1beta2/generated.pb.go +++ b/pkg/apis/controlplane/v1beta2/generated.pb.go @@ -495,10 +495,38 @@ func (m *IPNet) XXX_DiscardUnknown() { var xxx_messageInfo_IPNet proto.InternalMessageInfo +func (m *MulticastGroupInfo) Reset() { *m = MulticastGroupInfo{} } +func (*MulticastGroupInfo) ProtoMessage() {} +func (*MulticastGroupInfo) Descriptor() ([]byte, []int) { + return fileDescriptor_fbaa7d016762fa1d, []int{16} +} +func (m *MulticastGroupInfo) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MulticastGroupInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil +} +func (m *MulticastGroupInfo) XXX_Merge(src proto.Message) { + xxx_messageInfo_MulticastGroupInfo.Merge(m, src) +} +func (m *MulticastGroupInfo) XXX_Size() int { + return m.Size() +} +func (m *MulticastGroupInfo) XXX_DiscardUnknown() { + xxx_messageInfo_MulticastGroupInfo.DiscardUnknown(m) +} + +var xxx_messageInfo_MulticastGroupInfo proto.InternalMessageInfo + func (m *NamedPort) Reset() { *m = NamedPort{} } func (*NamedPort) ProtoMessage() {} func (*NamedPort) Descriptor() ([]byte, []int) { - return fileDescriptor_fbaa7d016762fa1d, []int{16} + return fileDescriptor_fbaa7d016762fa1d, []int{17} } func (m *NamedPort) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -526,7 +554,7 @@ var xxx_messageInfo_NamedPort proto.InternalMessageInfo func (m *NetworkPolicy) Reset() { *m = NetworkPolicy{} } func (*NetworkPolicy) ProtoMessage() {} func (*NetworkPolicy) Descriptor() ([]byte, []int) { - return fileDescriptor_fbaa7d016762fa1d, []int{17} + return fileDescriptor_fbaa7d016762fa1d, []int{18} } func (m *NetworkPolicy) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -554,7 +582,7 @@ var xxx_messageInfo_NetworkPolicy proto.InternalMessageInfo func (m *NetworkPolicyList) Reset() { *m = NetworkPolicyList{} } func (*NetworkPolicyList) ProtoMessage() {} func (*NetworkPolicyList) Descriptor() ([]byte, []int) { - return fileDescriptor_fbaa7d016762fa1d, []int{18} + return fileDescriptor_fbaa7d016762fa1d, []int{19} } func (m *NetworkPolicyList) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -582,7 +610,7 @@ var xxx_messageInfo_NetworkPolicyList proto.InternalMessageInfo func (m *NetworkPolicyNodeStatus) Reset() { *m = NetworkPolicyNodeStatus{} } func (*NetworkPolicyNodeStatus) ProtoMessage() {} func (*NetworkPolicyNodeStatus) Descriptor() ([]byte, []int) { - return fileDescriptor_fbaa7d016762fa1d, []int{19} + return fileDescriptor_fbaa7d016762fa1d, []int{20} } func (m *NetworkPolicyNodeStatus) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -610,7 +638,7 @@ var xxx_messageInfo_NetworkPolicyNodeStatus proto.InternalMessageInfo func (m *NetworkPolicyPeer) Reset() { *m = NetworkPolicyPeer{} } func (*NetworkPolicyPeer) ProtoMessage() {} func (*NetworkPolicyPeer) Descriptor() ([]byte, []int) { - return fileDescriptor_fbaa7d016762fa1d, []int{20} + return fileDescriptor_fbaa7d016762fa1d, []int{21} } func (m *NetworkPolicyPeer) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -638,7 +666,7 @@ var xxx_messageInfo_NetworkPolicyPeer proto.InternalMessageInfo func (m *NetworkPolicyReference) Reset() { *m = NetworkPolicyReference{} } func (*NetworkPolicyReference) ProtoMessage() {} func (*NetworkPolicyReference) Descriptor() ([]byte, []int) { - return fileDescriptor_fbaa7d016762fa1d, []int{21} + return fileDescriptor_fbaa7d016762fa1d, []int{22} } func (m *NetworkPolicyReference) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -666,7 +694,7 @@ var xxx_messageInfo_NetworkPolicyReference proto.InternalMessageInfo func (m *NetworkPolicyRule) Reset() { *m = NetworkPolicyRule{} } func (*NetworkPolicyRule) ProtoMessage() {} func (*NetworkPolicyRule) Descriptor() ([]byte, []int) { - return fileDescriptor_fbaa7d016762fa1d, []int{22} + return fileDescriptor_fbaa7d016762fa1d, []int{23} } func (m *NetworkPolicyRule) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -694,7 +722,7 @@ var xxx_messageInfo_NetworkPolicyRule proto.InternalMessageInfo func (m *NetworkPolicyStats) Reset() { *m = NetworkPolicyStats{} } func (*NetworkPolicyStats) ProtoMessage() {} func (*NetworkPolicyStats) Descriptor() ([]byte, []int) { - return fileDescriptor_fbaa7d016762fa1d, []int{23} + return fileDescriptor_fbaa7d016762fa1d, []int{24} } func (m *NetworkPolicyStats) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -722,7 +750,7 @@ var xxx_messageInfo_NetworkPolicyStats proto.InternalMessageInfo func (m *NetworkPolicyStatus) Reset() { *m = NetworkPolicyStatus{} } func (*NetworkPolicyStatus) ProtoMessage() {} func (*NetworkPolicyStatus) Descriptor() ([]byte, []int) { - return fileDescriptor_fbaa7d016762fa1d, []int{24} + return fileDescriptor_fbaa7d016762fa1d, []int{25} } func (m *NetworkPolicyStatus) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -750,7 +778,7 @@ var xxx_messageInfo_NetworkPolicyStatus proto.InternalMessageInfo func (m *NodeReference) Reset() { *m = NodeReference{} } func (*NodeReference) ProtoMessage() {} func (*NodeReference) Descriptor() ([]byte, []int) { - return fileDescriptor_fbaa7d016762fa1d, []int{25} + return fileDescriptor_fbaa7d016762fa1d, []int{26} } func (m *NodeReference) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -778,7 +806,7 @@ var xxx_messageInfo_NodeReference proto.InternalMessageInfo func (m *NodeStatsSummary) Reset() { *m = NodeStatsSummary{} } func (*NodeStatsSummary) ProtoMessage() {} func (*NodeStatsSummary) Descriptor() ([]byte, []int) { - return fileDescriptor_fbaa7d016762fa1d, []int{26} + return fileDescriptor_fbaa7d016762fa1d, []int{27} } func (m *NodeStatsSummary) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -806,7 +834,7 @@ var xxx_messageInfo_NodeStatsSummary proto.InternalMessageInfo func (m *PaginationGetOptions) Reset() { *m = PaginationGetOptions{} } func (*PaginationGetOptions) ProtoMessage() {} func (*PaginationGetOptions) Descriptor() ([]byte, []int) { - return fileDescriptor_fbaa7d016762fa1d, []int{27} + return fileDescriptor_fbaa7d016762fa1d, []int{28} } func (m *PaginationGetOptions) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -834,7 +862,7 @@ var xxx_messageInfo_PaginationGetOptions proto.InternalMessageInfo func (m *PodReference) Reset() { *m = PodReference{} } func (*PodReference) ProtoMessage() {} func (*PodReference) Descriptor() ([]byte, []int) { - return fileDescriptor_fbaa7d016762fa1d, []int{28} + return fileDescriptor_fbaa7d016762fa1d, []int{29} } func (m *PodReference) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -862,7 +890,7 @@ var xxx_messageInfo_PodReference proto.InternalMessageInfo func (m *Service) Reset() { *m = Service{} } func (*Service) ProtoMessage() {} func (*Service) Descriptor() ([]byte, []int) { - return fileDescriptor_fbaa7d016762fa1d, []int{29} + return fileDescriptor_fbaa7d016762fa1d, []int{30} } func (m *Service) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -890,7 +918,7 @@ var xxx_messageInfo_Service proto.InternalMessageInfo func (m *ServiceReference) Reset() { *m = ServiceReference{} } func (*ServiceReference) ProtoMessage() {} func (*ServiceReference) Descriptor() ([]byte, []int) { - return fileDescriptor_fbaa7d016762fa1d, []int{30} + return fileDescriptor_fbaa7d016762fa1d, []int{31} } func (m *ServiceReference) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -932,6 +960,7 @@ func init() { proto.RegisterType((*GroupReference)(nil), "antrea_io.antrea.pkg.apis.controlplane.v1beta2.GroupReference") proto.RegisterType((*IPBlock)(nil), "antrea_io.antrea.pkg.apis.controlplane.v1beta2.IPBlock") proto.RegisterType((*IPNet)(nil), "antrea_io.antrea.pkg.apis.controlplane.v1beta2.IPNet") + proto.RegisterType((*MulticastGroupInfo)(nil), "antrea_io.antrea.pkg.apis.controlplane.v1beta2.MulticastGroupInfo") proto.RegisterType((*NamedPort)(nil), "antrea_io.antrea.pkg.apis.controlplane.v1beta2.NamedPort") proto.RegisterType((*NetworkPolicy)(nil), "antrea_io.antrea.pkg.apis.controlplane.v1beta2.NetworkPolicy") proto.RegisterType((*NetworkPolicyList)(nil), "antrea_io.antrea.pkg.apis.controlplane.v1beta2.NetworkPolicyList") @@ -954,134 +983,141 @@ func init() { } var fileDescriptor_fbaa7d016762fa1d = []byte{ - // 2032 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x3a, 0xcf, 0x6f, 0x1b, 0x59, - 0xfd, 0x1d, 0xff, 0x48, 0xe2, 0x8f, 0x9d, 0xc4, 0x79, 0x69, 0xbf, 0xf5, 0x77, 0x29, 0x76, 0x76, - 0x16, 0x50, 0x0e, 0xec, 0x78, 0x13, 0xda, 0x6d, 0x61, 0xb7, 0x0b, 0x71, 0x93, 0x46, 0x96, 0xba, - 0xa9, 0x79, 0xc9, 0xaa, 0x12, 0x50, 0xd8, 0xc9, 0xcc, 0xb3, 0xf3, 0x88, 0x3d, 0x33, 0xcc, 0x3c, - 0x87, 0x46, 0x48, 0x68, 0x11, 0x70, 0x58, 0x40, 0x82, 0x1b, 0x57, 0x38, 0x71, 0xe1, 0xcc, 0x9d, - 0x03, 0x52, 0xc5, 0x69, 0x57, 0x08, 0xb1, 0x27, 0x8b, 0x1a, 0x01, 0xe2, 0xc0, 0x3f, 0x10, 0x2e, - 0xe8, 0xbd, 0x79, 0x33, 0xf3, 0xc6, 0x4e, 0x9a, 0xba, 0x49, 0x83, 0x04, 0x7b, 0xaa, 0xe7, 0x7d, - 0x7e, 0xbf, 0xcf, 0xef, 0x97, 0xc2, 0x5b, 0xa6, 0xc3, 0x7c, 0x62, 0x1a, 0xd4, 0xad, 0x87, 0xbf, - 0xea, 0xde, 0x7e, 0xa7, 0x6e, 0x7a, 0x34, 0xa8, 0x5b, 0xae, 0xc3, 0x7c, 0xb7, 0xeb, 0x75, 0x4d, - 0x87, 0xd4, 0x0f, 0x56, 0x76, 0x09, 0x33, 0x57, 0xeb, 0x1d, 0xe2, 0x10, 0xdf, 0x64, 0xc4, 0x36, - 0x3c, 0xdf, 0x65, 0x2e, 0x32, 0x42, 0xaa, 0x6f, 0x50, 0x57, 0xfe, 0x32, 0xbc, 0xfd, 0x8e, 0xc1, - 0xe9, 0x0d, 0x95, 0xde, 0x90, 0xf4, 0x2f, 0xdd, 0x3a, 0x59, 0x5e, 0xc0, 0x4c, 0x16, 0xd4, 0x0f, - 0x56, 0xcc, 0xae, 0xb7, 0x67, 0xae, 0x8c, 0x4a, 0x7a, 0xe9, 0xd5, 0x0e, 0x65, 0x7b, 0xfd, 0x5d, - 0xc3, 0x72, 0x7b, 0xf5, 0x8e, 0xdb, 0x71, 0xeb, 0xe2, 0x78, 0xb7, 0xdf, 0x16, 0x5f, 0xe2, 0x43, - 0xfc, 0x92, 0xe8, 0xd7, 0xf7, 0x6f, 0x05, 0x42, 0x8a, 0x47, 0x7b, 0xa6, 0xb5, 0x47, 0x1d, 0xe2, - 0x1f, 0x26, 0xb2, 0x7a, 0x84, 0x99, 0xf5, 0x83, 0x71, 0x21, 0xf5, 0x93, 0xa8, 0xfc, 0xbe, 0xc3, - 0x68, 0x8f, 0x8c, 0x11, 0xbc, 0x7e, 0x1a, 0x41, 0x60, 0xed, 0x91, 0x9e, 0x39, 0x46, 0xf7, 0xb9, - 0x93, 0xe8, 0xfa, 0x8c, 0x76, 0xeb, 0xd4, 0x61, 0x01, 0xf3, 0x47, 0x89, 0xf4, 0xbf, 0x6b, 0x50, - 0x5a, 0xb3, 0x6d, 0x9f, 0x04, 0xc1, 0xa6, 0xef, 0xf6, 0x3d, 0xf4, 0x2e, 0xcc, 0x70, 0x4b, 0x6c, - 0x93, 0x99, 0x15, 0x6d, 0x49, 0x5b, 0x2e, 0xae, 0xbe, 0x66, 0x84, 0x8c, 0x0d, 0x95, 0x71, 0xe2, - 0x13, 0x8e, 0x6d, 0x1c, 0xac, 0x18, 0xf7, 0x77, 0xbf, 0x49, 0x2c, 0xf6, 0x36, 0x61, 0x66, 0x03, - 0x3d, 0x1e, 0xd4, 0x2e, 0x0d, 0x07, 0x35, 0x48, 0xce, 0x70, 0xcc, 0x15, 0xf5, 0xa1, 0xd4, 0xe1, - 0xa2, 0xde, 0x26, 0xbd, 0x5d, 0xe2, 0x07, 0x95, 0xcc, 0x52, 0x76, 0xb9, 0xb8, 0xfa, 0xc6, 0x84, - 0x6e, 0x37, 0x36, 0x13, 0x1e, 0x8d, 0xcb, 0x52, 0x60, 0x49, 0x39, 0x0c, 0x70, 0x4a, 0x8c, 0xfe, - 0x07, 0x0d, 0xca, 0xaa, 0xa5, 0xf7, 0x68, 0xc0, 0xd0, 0xd7, 0xc6, 0xac, 0x35, 0x9e, 0xcd, 0x5a, - 0x4e, 0x2d, 0x6c, 0x2d, 0x4b, 0xd1, 0x33, 0xd1, 0x89, 0x62, 0xa9, 0x09, 0x79, 0xca, 0x48, 0x2f, - 0x32, 0xf1, 0xcd, 0x49, 0x4d, 0x54, 0xd5, 0x6d, 0xcc, 0x4a, 0x41, 0xf9, 0x26, 0x67, 0x89, 0x43, - 0xce, 0xfa, 0xfb, 0x59, 0x58, 0x50, 0xd1, 0x5a, 0x26, 0xb3, 0xf6, 0x2e, 0xc0, 0x89, 0x3f, 0xd0, - 0x60, 0xc1, 0xb4, 0x6d, 0x62, 0x6f, 0x9e, 0xb3, 0x2b, 0xff, 0x5f, 0x8a, 0xe5, 0x56, 0xa5, 0xb9, - 0xe3, 0x71, 0x81, 0xe8, 0x47, 0x1a, 0x2c, 0xfa, 0xa4, 0xe7, 0x1e, 0x8c, 0x28, 0x92, 0x3d, 0xbb, - 0x22, 0x9f, 0x90, 0x8a, 0x2c, 0xe2, 0x71, 0xfe, 0xf8, 0x38, 0xa1, 0xfa, 0x3f, 0x34, 0x98, 0x5b, - 0xf3, 0xbc, 0x2e, 0x25, 0xf6, 0x8e, 0xfb, 0x5f, 0x9e, 0x4d, 0x7f, 0xd2, 0x00, 0xa5, 0x6d, 0xbd, - 0x80, 0x7c, 0xb2, 0xd2, 0xf9, 0xf4, 0xd6, 0xc4, 0xf9, 0x94, 0x52, 0xf8, 0x84, 0x8c, 0xfa, 0x71, - 0x16, 0x16, 0xd3, 0x88, 0x1f, 0xe7, 0xd4, 0x7f, 0x2e, 0xa7, 0x7e, 0x91, 0x83, 0xc5, 0x3b, 0xdd, - 0x7e, 0xc0, 0x88, 0x9f, 0x52, 0xf2, 0xc5, 0x7b, 0xe3, 0x7b, 0x1a, 0x94, 0x49, 0xbb, 0x4d, 0x2c, - 0x46, 0x0f, 0xc8, 0x39, 0x3a, 0xa3, 0x22, 0xa5, 0x96, 0x37, 0x46, 0x98, 0xe3, 0x31, 0x71, 0xe8, - 0xbb, 0xb0, 0x10, 0x9f, 0x35, 0x5b, 0x8d, 0xae, 0x6b, 0xed, 0x47, 0x7e, 0xb8, 0x31, 0xa9, 0x0e, - 0xcd, 0xd6, 0x16, 0x61, 0x49, 0x28, 0x6c, 0x8c, 0xf2, 0xc5, 0xe3, 0xa2, 0xd0, 0x2d, 0x28, 0x31, - 0x97, 0x99, 0xdd, 0xc8, 0xfc, 0xdc, 0x92, 0xb6, 0x9c, 0x4d, 0xea, 0xc3, 0x8e, 0x02, 0xc3, 0x29, - 0x4c, 0xb4, 0x0a, 0x20, 0xbe, 0x5b, 0x66, 0x87, 0x04, 0x95, 0xbc, 0xa0, 0x8b, 0xef, 0x7b, 0x27, - 0x86, 0x60, 0x05, 0x0b, 0xdd, 0x80, 0xa2, 0xd5, 0xf7, 0x7d, 0xe2, 0x30, 0xfe, 0x5d, 0x99, 0x12, - 0x44, 0x8b, 0x92, 0xa8, 0x78, 0x27, 0x01, 0x61, 0x15, 0x4f, 0xff, 0x9b, 0x06, 0xc5, 0x8d, 0xce, - 0xff, 0xc0, 0x04, 0xf3, 0xa1, 0x06, 0xf3, 0x8a, 0xa1, 0x17, 0x50, 0x70, 0xdf, 0x4d, 0x17, 0xdc, - 0x89, 0x2d, 0x54, 0xb4, 0x3d, 0xa1, 0xda, 0xfe, 0x24, 0x0b, 0x65, 0x05, 0x2b, 0x2c, 0xb5, 0x36, - 0x80, 0x1b, 0xdf, 0xfb, 0xb9, 0xfa, 0x50, 0xe1, 0xfb, 0x71, 0xb9, 0x3d, 0xa6, 0xdc, 0x76, 0xe1, - 0xea, 0xc6, 0x23, 0x46, 0x7c, 0xc7, 0xec, 0x6e, 0x38, 0x8c, 0xb2, 0x43, 0x4c, 0xda, 0xc4, 0x27, - 0x8e, 0x45, 0xd0, 0x12, 0xe4, 0x1c, 0xb3, 0x47, 0x84, 0x3b, 0x0a, 0x8d, 0x92, 0x64, 0x9d, 0xdb, - 0x32, 0x7b, 0x04, 0x0b, 0x08, 0xaa, 0x43, 0x81, 0xff, 0x1b, 0x78, 0xa6, 0x45, 0x2a, 0x19, 0x81, - 0xb6, 0x20, 0xd1, 0x0a, 0x5b, 0x11, 0x00, 0x27, 0x38, 0xfa, 0xbf, 0x34, 0x28, 0x0b, 0xf1, 0x6b, - 0x41, 0xe0, 0x5a, 0xd4, 0x64, 0xd4, 0x75, 0x2e, 0xa6, 0xcf, 0x96, 0x4d, 0x29, 0x51, 0xda, 0xff, - 0xdc, 0x23, 0x85, 0xa0, 0x8e, 0x2f, 0x29, 0x29, 0xee, 0x6b, 0x23, 0xfc, 0xf1, 0x98, 0x44, 0xfd, - 0xc3, 0x2c, 0x14, 0x95, 0xcb, 0x47, 0x0f, 0x20, 0xeb, 0xb9, 0xb6, 0xb4, 0x79, 0xe2, 0x5d, 0xa1, - 0xe5, 0xda, 0x89, 0x1a, 0xd3, 0xc3, 0x41, 0x2d, 0xcb, 0x4f, 0x38, 0x47, 0xf4, 0x7d, 0x0d, 0xe6, - 0x48, 0xca, 0xab, 0xc2, 0x3b, 0xc5, 0xd5, 0xcd, 0x89, 0xf3, 0xf9, 0xf8, 0xd8, 0x68, 0xa0, 0xe1, - 0xa0, 0x36, 0x37, 0x02, 0x1c, 0x11, 0x89, 0x3e, 0x03, 0x59, 0xea, 0x85, 0x61, 0x5d, 0x6a, 0x5c, - 0xe6, 0x0a, 0x36, 0x5b, 0xc1, 0xd1, 0xa0, 0x56, 0x68, 0xb6, 0xe4, 0x02, 0x83, 0x39, 0x02, 0xfa, - 0x3a, 0xe4, 0x3d, 0xd7, 0x67, 0xbc, 0xd9, 0x70, 0x8f, 0x7c, 0x7e, 0x52, 0x1d, 0x79, 0xa4, 0xd9, - 0x2d, 0xd7, 0x67, 0x49, 0xc5, 0xe1, 0x5f, 0x01, 0x0e, 0xd9, 0xa2, 0xaf, 0x42, 0xce, 0x71, 0x6d, - 0x22, 0x7a, 0x52, 0x71, 0xf5, 0xf6, 0xc4, 0xec, 0x5d, 0x9b, 0x24, 0x86, 0xcf, 0x88, 0x14, 0xe0, - 0x47, 0x82, 0xa9, 0xfe, 0x2b, 0x0d, 0xe6, 0xd2, 0x21, 0x91, 0xce, 0x0a, 0xed, 0xf4, 0xac, 0x88, - 0x13, 0x2d, 0x73, 0x62, 0xa2, 0x35, 0x20, 0xdb, 0xa7, 0x76, 0x25, 0x2b, 0x10, 0x5e, 0x93, 0x08, - 0xd9, 0x77, 0x9a, 0xeb, 0x47, 0x83, 0xda, 0xcb, 0x27, 0xbd, 0x02, 0xb0, 0x43, 0x8f, 0x04, 0xc6, - 0x3b, 0xcd, 0x75, 0xcc, 0x89, 0xf5, 0xdf, 0x6a, 0x30, 0x2d, 0xfb, 0x3c, 0x7a, 0x00, 0x39, 0x8b, - 0xda, 0xbe, 0x0c, 0xbd, 0xe7, 0x9c, 0x2c, 0x62, 0x45, 0xef, 0x34, 0xd7, 0x31, 0x16, 0x0c, 0xd1, - 0x43, 0x98, 0x22, 0x8f, 0x2c, 0xe2, 0x31, 0x99, 0x5e, 0xcf, 0xc9, 0x7a, 0x4e, 0xb2, 0x9e, 0xda, - 0x10, 0xcc, 0xb0, 0x64, 0xaa, 0xb7, 0x21, 0x2f, 0x10, 0xd0, 0x2b, 0x90, 0xa1, 0x9e, 0x50, 0xbf, - 0xd4, 0x58, 0x1c, 0x0e, 0x6a, 0x99, 0x66, 0x2b, 0x1d, 0x59, 0x19, 0xea, 0xf1, 0x61, 0xc6, 0xf3, - 0x49, 0x9b, 0x3e, 0xba, 0x47, 0x9c, 0x0e, 0xdb, 0x13, 0xf7, 0x9b, 0x4f, 0x1a, 0x6f, 0x4b, 0x81, - 0xe1, 0x14, 0xa6, 0xfe, 0xbe, 0x06, 0x85, 0x38, 0xac, 0xb8, 0x7f, 0x78, 0x24, 0x09, 0x71, 0xf9, - 0xc4, 0x6c, 0x0e, 0xc3, 0x02, 0xf2, 0x0c, 0x1e, 0xbc, 0x05, 0x33, 0xe2, 0xfd, 0xc5, 0x72, 0xbb, - 0xd2, 0x8d, 0xd7, 0xa2, 0x36, 0xdc, 0x92, 0xe7, 0x47, 0xca, 0x6f, 0x1c, 0x63, 0xeb, 0xff, 0xcc, - 0xc2, 0xec, 0x16, 0x61, 0xdf, 0x76, 0xfd, 0xfd, 0x96, 0xdb, 0xa5, 0xd6, 0xe1, 0x05, 0x14, 0xcc, - 0x36, 0xe4, 0xfd, 0x7e, 0x97, 0x44, 0x45, 0x72, 0x6d, 0xe2, 0x9c, 0x51, 0xf5, 0xc5, 0xfd, 0x2e, - 0x49, 0x52, 0x93, 0x7f, 0x05, 0x38, 0x64, 0x8f, 0x6e, 0xc3, 0xbc, 0x99, 0xda, 0xbc, 0xc2, 0x72, - 0x51, 0x10, 0x3e, 0x9d, 0x4f, 0x2f, 0x65, 0x01, 0x1e, 0xc5, 0x45, 0xcb, 0xfc, 0x52, 0xa9, 0xeb, - 0xf3, 0x02, 0xc7, 0x27, 0x55, 0xad, 0x51, 0x0a, 0x2f, 0x34, 0x3c, 0xc3, 0x31, 0x14, 0x5d, 0x87, - 0x12, 0xa3, 0xc4, 0x8f, 0x20, 0xa2, 0x16, 0xe4, 0x1b, 0x65, 0x31, 0xd3, 0x2a, 0xe7, 0x38, 0x85, - 0x85, 0x02, 0x28, 0x04, 0x6e, 0xdf, 0xb7, 0x78, 0xfe, 0x8b, 0xe9, 0xb4, 0xb8, 0x7a, 0xf7, 0x6c, - 0x57, 0x11, 0xd7, 0x91, 0x59, 0x5e, 0x0d, 0xb6, 0x23, 0xe6, 0x38, 0x91, 0xa3, 0xff, 0x51, 0x83, - 0x85, 0x14, 0xd1, 0x05, 0x8c, 0x7d, 0xbb, 0xe9, 0xb1, 0xef, 0xf6, 0x99, 0x8c, 0x3c, 0x61, 0xf0, - 0xfb, 0x0e, 0x5c, 0x4d, 0xa1, 0xf1, 0x22, 0xba, 0xcd, 0x4c, 0xd6, 0x0f, 0xd0, 0x67, 0x61, 0x86, - 0x17, 0xd3, 0xad, 0x64, 0xda, 0x88, 0x95, 0xdd, 0x92, 0xe7, 0x38, 0xc6, 0xe0, 0x9b, 0x86, 0x7c, - 0xd4, 0xa4, 0xae, 0x23, 0x52, 0x4e, 0xd9, 0x34, 0x36, 0x63, 0x08, 0x56, 0xb0, 0xf4, 0xdf, 0x67, - 0x46, 0x2e, 0xb5, 0x45, 0x88, 0x8f, 0x6e, 0xc2, 0xac, 0xa9, 0x3c, 0xa5, 0x05, 0x15, 0x4d, 0x04, - 0xdf, 0xc2, 0x70, 0x50, 0x9b, 0x55, 0xdf, 0xd8, 0x02, 0x9c, 0xc6, 0x43, 0x04, 0x66, 0xa8, 0x27, - 0xb7, 0xb3, 0xf0, 0xca, 0x6e, 0x4e, 0x5e, 0xe8, 0x04, 0x7d, 0x62, 0x69, 0xbc, 0x96, 0xc5, 0xac, - 0x51, 0x0d, 0xf2, 0xed, 0x6f, 0xd9, 0x4e, 0x94, 0x14, 0x05, 0x7e, 0xa7, 0x77, 0xbf, 0xbc, 0xbe, - 0x15, 0xe0, 0xf0, 0x1c, 0x31, 0xbe, 0x74, 0x6d, 0x13, 0xff, 0x80, 0x5a, 0x24, 0xea, 0x9f, 0x5f, - 0x9a, 0x54, 0x13, 0x49, 0xaf, 0x34, 0xf7, 0x64, 0x6d, 0x8b, 0x78, 0x63, 0x45, 0x0e, 0xdf, 0xbf, - 0xfe, 0xef, 0xf8, 0xb0, 0x46, 0x37, 0x20, 0xc7, 0xdb, 0x8e, 0xf4, 0xe2, 0xcb, 0x51, 0x21, 0xdc, - 0x39, 0xf4, 0xc8, 0xd1, 0xa0, 0x96, 0x76, 0x01, 0x3f, 0xc4, 0x02, 0x7d, 0xe2, 0x41, 0x32, 0x2e, - 0xb8, 0xd9, 0xd3, 0x5a, 0x66, 0xee, 0x2c, 0x2d, 0xf3, 0x97, 0xf9, 0x91, 0xa8, 0xe1, 0xc5, 0x0b, - 0xbd, 0x09, 0x05, 0x9b, 0xfa, 0x7c, 0x71, 0x76, 0x1d, 0x69, 0x68, 0x35, 0x52, 0x76, 0x3d, 0x02, - 0x1c, 0xa9, 0x1f, 0x38, 0x21, 0x40, 0x16, 0xe4, 0xda, 0xbe, 0xdb, 0x93, 0x03, 0xd9, 0xd9, 0x2a, - 0x2b, 0x0f, 0xe2, 0xc4, 0xf8, 0xbb, 0xbe, 0xdb, 0xc3, 0x82, 0x39, 0x7a, 0x08, 0x19, 0xe6, 0x8a, - 0xcb, 0x39, 0x17, 0x11, 0x20, 0x45, 0x64, 0x76, 0x5c, 0x9c, 0x61, 0x2e, 0x0f, 0xff, 0x20, 0x1d, - 0x74, 0x37, 0x9f, 0x33, 0xe8, 0x92, 0xf0, 0x8f, 0x23, 0x2d, 0x66, 0xcd, 0xcb, 0x82, 0x37, 0x52, - 0xb0, 0x93, 0x9e, 0x39, 0x56, 0xe2, 0x1f, 0xc0, 0x94, 0x19, 0xfa, 0x64, 0x4a, 0xf8, 0xe4, 0x8b, - 0x7c, 0x7e, 0x58, 0x8b, 0x9c, 0xb1, 0xf2, 0x94, 0xbf, 0x51, 0xf9, 0x76, 0xfc, 0x17, 0x23, 0x83, - 0x7b, 0x38, 0x24, 0xc2, 0x92, 0x1d, 0x7a, 0x03, 0x66, 0x89, 0x63, 0xee, 0x76, 0xc9, 0x3d, 0xb7, - 0xd3, 0xa1, 0x4e, 0xa7, 0x32, 0xbd, 0xa4, 0x2d, 0xcf, 0x34, 0xae, 0x48, 0x5d, 0x66, 0x37, 0x54, - 0x20, 0x4e, 0xe3, 0x1e, 0xd7, 0xe1, 0x66, 0x26, 0xe8, 0x70, 0x51, 0x9c, 0x17, 0x4e, 0x8a, 0x73, - 0xfd, 0xa7, 0x59, 0x40, 0x29, 0x8f, 0xf1, 0x9a, 0x1a, 0xf0, 0x15, 0x60, 0xd6, 0x51, 0x8f, 0x65, - 0xd7, 0x38, 0xaf, 0xfe, 0x15, 0x5b, 0x9f, 0x86, 0xa7, 0x65, 0x22, 0x0f, 0x4a, 0xcc, 0x37, 0xdb, - 0x6d, 0x6a, 0x09, 0xad, 0x64, 0xd0, 0xbf, 0xfe, 0x14, 0x1d, 0xc4, 0x1f, 0xf0, 0x8c, 0xd8, 0x1d, - 0x3b, 0x0a, 0xb5, 0xf2, 0x0c, 0xa5, 0x9c, 0xe2, 0x94, 0x04, 0xf4, 0x9e, 0x06, 0x65, 0x3e, 0x5b, - 0xa8, 0x28, 0x72, 0xb3, 0xfe, 0xc2, 0xb3, 0x8b, 0xc5, 0x23, 0x1c, 0x92, 0x35, 0x6f, 0x14, 0x82, - 0xc7, 0xa4, 0xe9, 0x7f, 0xd5, 0x60, 0x71, 0xcc, 0x23, 0xfd, 0x8b, 0x78, 0xc1, 0xec, 0x42, 0x9e, - 0x77, 0xc9, 0xa8, 0x27, 0x6d, 0x9e, 0xc9, 0xd7, 0x49, 0x7f, 0x4e, 0x1a, 0x3a, 0x3f, 0x0b, 0x70, - 0x28, 0x44, 0x5f, 0x81, 0xd9, 0xd4, 0x6e, 0x74, 0xfa, 0x83, 0x81, 0xfe, 0xbb, 0x1c, 0x94, 0x23, - 0xbe, 0xc1, 0x76, 0xbf, 0xd7, 0x33, 0xfd, 0x8b, 0x18, 0x67, 0x7f, 0xa8, 0xc1, 0xbc, 0x1a, 0x98, - 0x34, 0xbe, 0xa2, 0xc6, 0x99, 0xae, 0x28, 0x8c, 0x8d, 0xab, 0x52, 0xf6, 0xfc, 0x56, 0x5a, 0x04, - 0x1e, 0x95, 0x89, 0x7e, 0xad, 0xc1, 0xb5, 0x50, 0x8a, 0x7c, 0xe1, 0x1e, 0xa1, 0x90, 0x81, 0x7a, - 0x1e, 0x4a, 0x7d, 0x4a, 0x2a, 0x75, 0x6d, 0xed, 0x29, 0xf2, 0xf0, 0x53, 0xb5, 0x41, 0x3f, 0xd7, - 0xe0, 0x4a, 0x88, 0x30, 0xaa, 0x67, 0xee, 0xdc, 0xf4, 0xfc, 0xa4, 0xd4, 0xf3, 0xca, 0xda, 0x71, - 0x82, 0xf0, 0xf1, 0xf2, 0xf5, 0x87, 0x70, 0xb9, 0x65, 0x76, 0xa8, 0x23, 0x86, 0xbb, 0x4d, 0xc2, - 0xee, 0x7b, 0xfc, 0x87, 0x28, 0x97, 0x9e, 0xd9, 0x09, 0x23, 0x30, 0xab, 0x6c, 0x6a, 0x66, 0x87, - 0x60, 0x01, 0x41, 0xaf, 0x40, 0xbe, 0x4b, 0x7b, 0x94, 0xc9, 0xb9, 0x31, 0x8e, 0xec, 0x7b, 0xfc, - 0x10, 0x87, 0x30, 0xdd, 0x84, 0x92, 0xfa, 0xba, 0xf2, 0x22, 0x5e, 0xc2, 0x7e, 0xa3, 0xc1, 0xb4, - 0x6c, 0x79, 0xe8, 0xba, 0xb2, 0x1b, 0x86, 0x22, 0x2a, 0xa7, 0xef, 0x85, 0x68, 0x4b, 0x6e, 0xa5, - 0x99, 0x53, 0x52, 0xa6, 0xcf, 0x68, 0xd7, 0x08, 0xff, 0x33, 0x80, 0xd1, 0x74, 0xd8, 0x7d, 0x7f, - 0x9b, 0xf9, 0xd4, 0xe9, 0x84, 0x2f, 0x19, 0xca, 0x0e, 0xfb, 0x69, 0x98, 0x26, 0x8e, 0x58, 0x78, - 0xc5, 0xe0, 0x90, 0x6f, 0x14, 0x87, 0x83, 0xda, 0xf4, 0x46, 0x78, 0x84, 0x23, 0x98, 0x4e, 0xa0, - 0x3c, 0x3a, 0x30, 0xbe, 0x80, 0xfb, 0x69, 0xbc, 0xfa, 0xf8, 0x49, 0xf5, 0xd2, 0x07, 0x4f, 0xaa, - 0x97, 0x3e, 0x7a, 0x52, 0xbd, 0xf4, 0xde, 0xb0, 0xaa, 0x3d, 0x1e, 0x56, 0xb5, 0x0f, 0x86, 0x55, - 0xed, 0xa3, 0x61, 0x55, 0xfb, 0xf3, 0xb0, 0xaa, 0xfd, 0xec, 0x2f, 0xd5, 0x4b, 0x5f, 0x99, 0x96, - 0x91, 0xf5, 0xef, 0x00, 0x00, 0x00, 0xff, 0xff, 0xcd, 0xae, 0x62, 0x49, 0x83, 0x22, 0x00, 0x00, + // 2132 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x1a, 0xcd, 0x6f, 0x1b, 0x59, + 0xbd, 0xe3, 0x8f, 0x26, 0xfe, 0xd9, 0x69, 0x9d, 0x97, 0x96, 0x9a, 0xa5, 0xd8, 0xd9, 0x59, 0x40, + 0x39, 0xc0, 0x78, 0x13, 0xda, 0x6d, 0x61, 0xb7, 0x0b, 0x71, 0x92, 0x46, 0x96, 0xda, 0xd4, 0xbc, + 0x64, 0x55, 0x09, 0xe8, 0xb2, 0x93, 0x99, 0x67, 0x67, 0x88, 0x3d, 0x6f, 0x98, 0x79, 0x0e, 0x8d, + 0x90, 0xd0, 0x22, 0xe0, 0xb0, 0x0b, 0x12, 0xdc, 0x10, 0x37, 0x38, 0x71, 0xe1, 0x2f, 0xe0, 0xc6, + 0xad, 0xe2, 0xb4, 0x2b, 0x84, 0xd8, 0x93, 0x45, 0x8d, 0x00, 0x71, 0xe0, 0x1f, 0x08, 0x17, 0xf4, + 0xde, 0xbc, 0x99, 0x79, 0x63, 0x27, 0x4d, 0x9d, 0xa4, 0x41, 0x82, 0x3d, 0xd5, 0xf3, 0x7e, 0xdf, + 0xef, 0xf7, 0xfd, 0x52, 0x78, 0xd3, 0x74, 0x99, 0x4f, 0x4c, 0xc3, 0xa1, 0xf5, 0xf0, 0x57, 0xdd, + 0xdb, 0xed, 0xd4, 0x4d, 0xcf, 0x09, 0xea, 0x16, 0x75, 0x99, 0x4f, 0xbb, 0x5e, 0xd7, 0x74, 0x49, + 0x7d, 0x6f, 0x71, 0x9b, 0x30, 0x73, 0xa9, 0xde, 0x21, 0x2e, 0xf1, 0x4d, 0x46, 0x6c, 0xc3, 0xf3, + 0x29, 0xa3, 0xc8, 0x08, 0xa9, 0xbe, 0xe5, 0x50, 0xf9, 0xcb, 0xf0, 0x76, 0x3b, 0x06, 0xa7, 0x37, + 0x54, 0x7a, 0x43, 0xd2, 0xbf, 0x74, 0xfb, 0x68, 0x79, 0x01, 0x33, 0x59, 0x50, 0xdf, 0x5b, 0x34, + 0xbb, 0xde, 0x8e, 0xb9, 0x38, 0x2a, 0xe9, 0xa5, 0x2f, 0x74, 0x1c, 0xb6, 0xd3, 0xdf, 0x36, 0x2c, + 0xda, 0xab, 0x77, 0x68, 0x87, 0xd6, 0xc5, 0xf1, 0x76, 0xbf, 0x2d, 0xbe, 0xc4, 0x87, 0xf8, 0x25, + 0xd1, 0x6f, 0xec, 0xde, 0x0e, 0x84, 0x14, 0xcf, 0xe9, 0x99, 0xd6, 0x8e, 0xe3, 0x12, 0x7f, 0x3f, + 0x91, 0xd5, 0x23, 0xcc, 0xac, 0xef, 0x8d, 0x0b, 0xa9, 0x1f, 0x45, 0xe5, 0xf7, 0x5d, 0xe6, 0xf4, + 0xc8, 0x18, 0xc1, 0x6b, 0xc7, 0x11, 0x04, 0xd6, 0x0e, 0xe9, 0x99, 0x63, 0x74, 0x5f, 0x3c, 0x8a, + 0xae, 0xcf, 0x9c, 0x6e, 0xdd, 0x71, 0x59, 0xc0, 0xfc, 0x51, 0x22, 0xfd, 0x1f, 0x1a, 0x94, 0x96, + 0x6d, 0xdb, 0x27, 0x41, 0xb0, 0xee, 0xd3, 0xbe, 0x87, 0xde, 0x81, 0x69, 0x6e, 0x89, 0x6d, 0x32, + 0xb3, 0xa2, 0xcd, 0x6b, 0x0b, 0xc5, 0xa5, 0x57, 0x8d, 0x90, 0xb1, 0xa1, 0x32, 0x4e, 0x7c, 0xc2, + 0xb1, 0x8d, 0xbd, 0x45, 0xe3, 0xc1, 0xf6, 0xb7, 0x89, 0xc5, 0xee, 0x13, 0x66, 0x36, 0xd0, 0x93, + 0x41, 0xed, 0xc2, 0x70, 0x50, 0x83, 0xe4, 0x0c, 0xc7, 0x5c, 0x51, 0x1f, 0x4a, 0x1d, 0x2e, 0xea, + 0x3e, 0xe9, 0x6d, 0x13, 0x3f, 0xa8, 0x64, 0xe6, 0xb3, 0x0b, 0xc5, 0xa5, 0xd7, 0x27, 0x74, 0xbb, + 0xb1, 0x9e, 0xf0, 0x68, 0x5c, 0x91, 0x02, 0x4b, 0xca, 0x61, 0x80, 0x53, 0x62, 0xf4, 0x3f, 0x6a, + 0x50, 0x56, 0x2d, 0xbd, 0xe7, 0x04, 0x0c, 0x7d, 0x73, 0xcc, 0x5a, 0xe3, 0xf9, 0xac, 0xe5, 0xd4, + 0xc2, 0xd6, 0xb2, 0x14, 0x3d, 0x1d, 0x9d, 0x28, 0x96, 0x9a, 0x90, 0x77, 0x18, 0xe9, 0x45, 0x26, + 0xbe, 0x31, 0xa9, 0x89, 0xaa, 0xba, 0x8d, 0x19, 0x29, 0x28, 0xdf, 0xe4, 0x2c, 0x71, 0xc8, 0x59, + 0x7f, 0x2f, 0x0b, 0xb3, 0x2a, 0x5a, 0xcb, 0x64, 0xd6, 0xce, 0x39, 0x38, 0xf1, 0x47, 0x1a, 0xcc, + 0x9a, 0xb6, 0x4d, 0xec, 0xf5, 0x33, 0x76, 0xe5, 0x27, 0xa5, 0x58, 0x6e, 0x55, 0x9a, 0x3b, 0x1e, + 0x17, 0x88, 0xde, 0xd7, 0x60, 0xce, 0x27, 0x3d, 0xba, 0x37, 0xa2, 0x48, 0xf6, 0xf4, 0x8a, 0x7c, + 0x4a, 0x2a, 0x32, 0x87, 0xc7, 0xf9, 0xe3, 0xc3, 0x84, 0xea, 0xff, 0xd4, 0xe0, 0xd2, 0xb2, 0xe7, + 0x75, 0x1d, 0x62, 0x6f, 0xd1, 0xff, 0xf1, 0x6c, 0xfa, 0xb3, 0x06, 0x28, 0x6d, 0xeb, 0x39, 0xe4, + 0x93, 0x95, 0xce, 0xa7, 0x37, 0x27, 0xce, 0xa7, 0x94, 0xc2, 0x47, 0x64, 0xd4, 0x4f, 0xb2, 0x30, + 0x97, 0x46, 0xfc, 0x38, 0xa7, 0xfe, 0x7b, 0x39, 0xf5, 0xab, 0x1c, 0xcc, 0xad, 0x74, 0xfb, 0x01, + 0x23, 0x7e, 0x4a, 0xc9, 0x17, 0xef, 0x8d, 0x1f, 0x68, 0x50, 0x26, 0xed, 0x36, 0xb1, 0x98, 0xb3, + 0x47, 0xce, 0xd0, 0x19, 0x15, 0x29, 0xb5, 0xbc, 0x36, 0xc2, 0x1c, 0x8f, 0x89, 0x43, 0xdf, 0x87, + 0xd9, 0xf8, 0xac, 0xd9, 0x6a, 0x74, 0xa9, 0xb5, 0x1b, 0xf9, 0xe1, 0xe6, 0xa4, 0x3a, 0x34, 0x5b, + 0x1b, 0x84, 0x25, 0xa1, 0xb0, 0x36, 0xca, 0x17, 0x8f, 0x8b, 0x42, 0xb7, 0xa1, 0xc4, 0x28, 0x33, + 0xbb, 0x91, 0xf9, 0xb9, 0x79, 0x6d, 0x21, 0x9b, 0xd4, 0x87, 0x2d, 0x05, 0x86, 0x53, 0x98, 0x68, + 0x09, 0x40, 0x7c, 0xb7, 0xcc, 0x0e, 0x09, 0x2a, 0x79, 0x41, 0x17, 0xdf, 0xf7, 0x56, 0x0c, 0xc1, + 0x0a, 0x16, 0xba, 0x09, 0x45, 0xab, 0xef, 0xfb, 0xc4, 0x65, 0xfc, 0xbb, 0x72, 0x51, 0x10, 0xcd, + 0x49, 0xa2, 0xe2, 0x4a, 0x02, 0xc2, 0x2a, 0x9e, 0xfe, 0x77, 0x0d, 0x8a, 0x6b, 0x9d, 0xff, 0x83, + 0x09, 0xe6, 0x43, 0x0d, 0x2e, 0x2b, 0x86, 0x9e, 0x43, 0xc1, 0x7d, 0x27, 0x5d, 0x70, 0x27, 0xb6, + 0x50, 0xd1, 0xf6, 0x88, 0x6a, 0xfb, 0xd3, 0x2c, 0x94, 0x15, 0xac, 0xb0, 0xd4, 0xda, 0x00, 0x34, + 0xbe, 0xf7, 0x33, 0xf5, 0xa1, 0xc2, 0xf7, 0xe3, 0x72, 0x7b, 0x48, 0xb9, 0xed, 0xc2, 0xb5, 0xb5, + 0xc7, 0x8c, 0xf8, 0xae, 0xd9, 0x5d, 0x73, 0x99, 0xc3, 0xf6, 0x31, 0x69, 0x13, 0x9f, 0xb8, 0x16, + 0x41, 0xf3, 0x90, 0x73, 0xcd, 0x1e, 0x11, 0xee, 0x28, 0x34, 0x4a, 0x92, 0x75, 0x6e, 0xc3, 0xec, + 0x11, 0x2c, 0x20, 0xa8, 0x0e, 0x05, 0xfe, 0x6f, 0xe0, 0x99, 0x16, 0xa9, 0x64, 0x04, 0xda, 0xac, + 0x44, 0x2b, 0x6c, 0x44, 0x00, 0x9c, 0xe0, 0xe8, 0xff, 0xd6, 0xa0, 0x2c, 0xc4, 0x2f, 0x07, 0x01, + 0xb5, 0x1c, 0x93, 0x39, 0xd4, 0x3d, 0x9f, 0x3e, 0x5b, 0x36, 0xa5, 0x44, 0x69, 0xff, 0x89, 0x47, + 0x0a, 0x41, 0x1d, 0x5f, 0x52, 0x52, 0xdc, 0x97, 0x47, 0xf8, 0xe3, 0x31, 0x89, 0xfa, 0x87, 0x59, + 0x28, 0x2a, 0x97, 0x8f, 0x1e, 0x42, 0xd6, 0xa3, 0xb6, 0xb4, 0x79, 0xe2, 0x5d, 0xa1, 0x45, 0xed, + 0x44, 0x8d, 0xa9, 0xe1, 0xa0, 0x96, 0xe5, 0x27, 0x9c, 0x23, 0xfa, 0xa1, 0x06, 0x97, 0x48, 0xca, + 0xab, 0xc2, 0x3b, 0xc5, 0xa5, 0xf5, 0x89, 0xf3, 0xf9, 0xf0, 0xd8, 0x68, 0xa0, 0xe1, 0xa0, 0x76, + 0x69, 0x04, 0x38, 0x22, 0x12, 0x7d, 0x0e, 0xb2, 0x8e, 0x17, 0x86, 0x75, 0xa9, 0x71, 0x85, 0x2b, + 0xd8, 0x6c, 0x05, 0x07, 0x83, 0x5a, 0xa1, 0xd9, 0x92, 0x0b, 0x0c, 0xe6, 0x08, 0xe8, 0x6d, 0xc8, + 0x7b, 0xd4, 0x67, 0xbc, 0xd9, 0x70, 0x8f, 0x7c, 0x69, 0x52, 0x1d, 0x79, 0xa4, 0xd9, 0x2d, 0xea, + 0xb3, 0xa4, 0xe2, 0xf0, 0xaf, 0x00, 0x87, 0x6c, 0xd1, 0x37, 0x20, 0xe7, 0x52, 0x9b, 0x88, 0x9e, + 0x54, 0x5c, 0xba, 0x33, 0x31, 0x7b, 0x6a, 0x93, 0xc4, 0xf0, 0x69, 0x91, 0x02, 0xfc, 0x48, 0x30, + 0xd5, 0x7f, 0xa3, 0xc1, 0xa5, 0x74, 0x48, 0xa4, 0xb3, 0x42, 0x3b, 0x3e, 0x2b, 0xe2, 0x44, 0xcb, + 0x1c, 0x99, 0x68, 0x0d, 0xc8, 0xf6, 0x1d, 0xbb, 0x92, 0x15, 0x08, 0xaf, 0x4a, 0x84, 0xec, 0x5b, + 0xcd, 0xd5, 0x83, 0x41, 0xed, 0xe5, 0xa3, 0x5e, 0x01, 0xd8, 0xbe, 0x47, 0x02, 0xe3, 0xad, 0xe6, + 0x2a, 0xe6, 0xc4, 0xfa, 0xef, 0x35, 0x98, 0x92, 0x7d, 0x1e, 0x3d, 0x84, 0x9c, 0xe5, 0xd8, 0xbe, + 0x0c, 0xbd, 0x13, 0x4e, 0x16, 0xb1, 0xa2, 0x2b, 0xcd, 0x55, 0x8c, 0x05, 0x43, 0xf4, 0x08, 0x2e, + 0x92, 0xc7, 0x16, 0xf1, 0x98, 0x4c, 0xaf, 0x13, 0xb2, 0xbe, 0x24, 0x59, 0x5f, 0x5c, 0x13, 0xcc, + 0xb0, 0x64, 0xaa, 0xb7, 0x21, 0x2f, 0x10, 0xd0, 0x2b, 0x90, 0x71, 0x3c, 0xa1, 0x7e, 0xa9, 0x31, + 0x37, 0x1c, 0xd4, 0x32, 0xcd, 0x56, 0x3a, 0xb2, 0x32, 0x8e, 0xc7, 0x87, 0x19, 0xcf, 0x27, 0x6d, + 0xe7, 0xf1, 0x3d, 0xe2, 0x76, 0xd8, 0x8e, 0xb8, 0xdf, 0x7c, 0xd2, 0x78, 0x5b, 0x0a, 0x0c, 0xa7, + 0x30, 0xf5, 0x5f, 0x6a, 0x80, 0xee, 0xf7, 0xbb, 0xcc, 0xb1, 0xcc, 0x80, 0x09, 0xf7, 0x36, 0xdd, + 0x36, 0x45, 0xaf, 0x40, 0x5e, 0xf4, 0x67, 0xe9, 0xd5, 0x38, 0xdc, 0xc2, 0x00, 0x08, 0x61, 0xe8, + 0x6d, 0xc8, 0x79, 0xd4, 0x3e, 0xf1, 0x13, 0x40, 0x2a, 0xad, 0xe3, 0x2b, 0x6e, 0x51, 0x3b, 0xc0, + 0x82, 0xaf, 0xfe, 0x9e, 0x06, 0x85, 0x38, 0xe4, 0x79, 0xec, 0xf0, 0x28, 0x17, 0x1a, 0xe5, 0x55, + 0x7c, 0x9f, 0x61, 0x01, 0x79, 0x8e, 0xe8, 0xba, 0x0d, 0xd3, 0xe2, 0x6d, 0xc8, 0xa2, 0x5d, 0x19, + 0x62, 0xd7, 0xa3, 0x11, 0xa1, 0x25, 0xcf, 0x0f, 0x94, 0xdf, 0x38, 0xc6, 0xd6, 0xff, 0x95, 0x85, + 0x99, 0x0d, 0xc2, 0xbe, 0x4b, 0xfd, 0xdd, 0x16, 0xed, 0x3a, 0xd6, 0xfe, 0x39, 0x14, 0xf3, 0x36, + 0xe4, 0xfd, 0x7e, 0x97, 0x44, 0x17, 0xbc, 0x3c, 0x71, 0x3e, 0xab, 0xfa, 0xe2, 0x7e, 0x97, 0x24, + 0x7e, 0xe4, 0x5f, 0x01, 0x0e, 0xd9, 0xa3, 0x3b, 0x70, 0xd9, 0x4c, 0x6d, 0x85, 0x61, 0x29, 0x2b, + 0x88, 0x78, 0xbb, 0x9c, 0x5e, 0x18, 0x03, 0x3c, 0x8a, 0x8b, 0x16, 0xf8, 0xa5, 0x3a, 0xd4, 0xe7, + 0xc5, 0x97, 0x4f, 0xd1, 0x5a, 0xa3, 0x14, 0x5e, 0x68, 0x78, 0x86, 0x63, 0x28, 0xba, 0x01, 0x25, + 0xe6, 0x10, 0x3f, 0x82, 0x88, 0x3a, 0x95, 0x6f, 0x94, 0xc5, 0xbc, 0xad, 0x9c, 0xe3, 0x14, 0x16, + 0x0a, 0xa0, 0x10, 0xd0, 0xbe, 0x6f, 0xf1, 0xda, 0x24, 0x26, 0xe7, 0xe2, 0xd2, 0xdd, 0xd3, 0x5d, + 0x45, 0x1c, 0x75, 0x33, 0xbc, 0x52, 0x6d, 0x46, 0xcc, 0x71, 0x22, 0x47, 0xff, 0x93, 0x06, 0xb3, + 0x29, 0xa2, 0x73, 0x18, 0x49, 0xb7, 0xd3, 0x23, 0xe9, 0x9d, 0x53, 0x19, 0x79, 0xc4, 0x50, 0xfa, + 0x3d, 0xb8, 0x96, 0x42, 0xe3, 0x05, 0x7e, 0x93, 0x99, 0xac, 0x1f, 0xa0, 0xcf, 0xc3, 0x34, 0x2f, + 0xf4, 0x1b, 0xc9, 0x24, 0x14, 0x2b, 0xbb, 0x21, 0xcf, 0x71, 0x8c, 0xc1, 0xb7, 0x20, 0xf9, 0xe0, + 0xea, 0x50, 0x57, 0xa4, 0x9c, 0xb2, 0x05, 0xad, 0xc7, 0x10, 0xac, 0x60, 0xe9, 0x7f, 0xc8, 0x8c, + 0x5c, 0x6a, 0x8b, 0x10, 0x1f, 0xdd, 0x82, 0x19, 0x53, 0x79, 0xe6, 0x0b, 0x2a, 0x9a, 0x08, 0xbe, + 0xd9, 0xe1, 0xa0, 0x36, 0xa3, 0xbe, 0xff, 0x05, 0x38, 0x8d, 0x87, 0x08, 0x4c, 0x3b, 0x9e, 0xdc, + 0x1c, 0xc3, 0x2b, 0xbb, 0x35, 0x79, 0x11, 0x16, 0xf4, 0x89, 0xa5, 0xf1, 0xca, 0x18, 0xb3, 0x46, + 0x35, 0xc8, 0xb7, 0xbf, 0x63, 0xbb, 0x51, 0x52, 0x14, 0xf8, 0x9d, 0xde, 0xfd, 0xda, 0xea, 0x46, + 0x80, 0xc3, 0x73, 0xc4, 0xf8, 0x42, 0xb8, 0x49, 0xfc, 0x3d, 0xc7, 0x22, 0x51, 0x6f, 0xff, 0xea, + 0xa4, 0x9a, 0x48, 0x7a, 0x65, 0xf0, 0x48, 0x56, 0xca, 0x88, 0x37, 0x56, 0xe4, 0xf0, 0xdd, 0xf0, + 0x13, 0x87, 0x87, 0x35, 0xba, 0x09, 0x39, 0xde, 0x12, 0xa5, 0x17, 0x5f, 0x8e, 0x0a, 0xe1, 0xd6, + 0xbe, 0x47, 0x0e, 0x06, 0xb5, 0xb4, 0x0b, 0xf8, 0x21, 0x16, 0xe8, 0x13, 0x0f, 0xb9, 0x71, 0xc1, + 0xcd, 0x1e, 0xd7, 0xce, 0x73, 0xa7, 0x69, 0xe7, 0xbf, 0xce, 0x8f, 0x44, 0x0d, 0x2f, 0x5e, 0xe8, + 0x0d, 0x28, 0xd8, 0x8e, 0xcf, 0x97, 0x7a, 0xea, 0x4a, 0x43, 0xab, 0x91, 0xb2, 0xab, 0x11, 0xe0, + 0x40, 0xfd, 0xc0, 0x09, 0x01, 0xb2, 0x20, 0xd7, 0xf6, 0x69, 0x4f, 0x0e, 0x8b, 0xa7, 0xab, 0xac, + 0x3c, 0x88, 0x13, 0xe3, 0xef, 0xfa, 0xb4, 0x87, 0x05, 0x73, 0xf4, 0x08, 0x32, 0x8c, 0x8a, 0xcb, + 0x39, 0x13, 0x11, 0x20, 0x45, 0x64, 0xb6, 0x28, 0xce, 0x30, 0xca, 0xc3, 0x3f, 0x48, 0x07, 0xdd, + 0xad, 0x13, 0x06, 0x5d, 0x12, 0xfe, 0x71, 0xa4, 0xc5, 0xac, 0x79, 0x59, 0xf0, 0x46, 0x0a, 0x76, + 0xd2, 0x33, 0xc7, 0x4a, 0xfc, 0x43, 0xb8, 0x68, 0x86, 0x3e, 0xb9, 0x28, 0x7c, 0xf2, 0x15, 0x3e, + 0xdb, 0x2c, 0x47, 0xce, 0x58, 0x7c, 0xc6, 0xdf, 0xcf, 0x7c, 0x3b, 0xfe, 0x6b, 0x96, 0xc1, 0x3d, + 0x1c, 0x12, 0x61, 0xc9, 0x0e, 0xbd, 0x0e, 0x33, 0xc4, 0x35, 0xb7, 0xbb, 0xe4, 0x1e, 0xed, 0x74, + 0x1c, 0xb7, 0x53, 0x99, 0x9a, 0xd7, 0x16, 0xa6, 0x1b, 0x57, 0xa5, 0x2e, 0x33, 0x6b, 0x2a, 0x10, + 0xa7, 0x71, 0x0f, 0xeb, 0x70, 0xd3, 0x13, 0x74, 0xb8, 0x28, 0xce, 0x0b, 0x47, 0xc5, 0xb9, 0xfe, + 0xb3, 0x2c, 0xa0, 0x94, 0xc7, 0x78, 0x4d, 0x0d, 0xf8, 0x7a, 0x32, 0xe3, 0xaa, 0xc7, 0xb2, 0x6b, + 0x9c, 0x55, 0xff, 0x8a, 0xad, 0x4f, 0xc3, 0xd3, 0x32, 0x91, 0x07, 0x25, 0xe6, 0x9b, 0xed, 0xb6, + 0x63, 0x09, 0xad, 0x64, 0xd0, 0xbf, 0xf6, 0x0c, 0x1d, 0xc4, 0x1f, 0x17, 0x8d, 0xd8, 0x1d, 0x5b, + 0x0a, 0xb5, 0xf2, 0x44, 0xa6, 0x9c, 0xe2, 0x94, 0x04, 0xf4, 0xae, 0x06, 0x65, 0x3e, 0x5b, 0xa8, + 0x28, 0x72, 0xeb, 0xff, 0xf2, 0xf3, 0x8b, 0xc5, 0x23, 0x1c, 0x92, 0x15, 0x74, 0x14, 0x82, 0xc7, + 0xa4, 0xe9, 0x7f, 0xd3, 0x60, 0x6e, 0xcc, 0x23, 0xfd, 0xf3, 0x78, 0x5d, 0xed, 0x42, 0x9e, 0x77, + 0xc9, 0xa8, 0x27, 0xad, 0x9f, 0xca, 0xd7, 0x49, 0x7f, 0x4e, 0x1a, 0x3a, 0x3f, 0x0b, 0x70, 0x28, + 0x44, 0x5f, 0x84, 0x99, 0xd4, 0xde, 0x76, 0xfc, 0x63, 0x86, 0xfe, 0xbb, 0x3c, 0x94, 0x23, 0xbe, + 0xc1, 0x66, 0xbf, 0xd7, 0x33, 0xfd, 0xf3, 0x18, 0x67, 0x7f, 0xac, 0xc1, 0x65, 0x35, 0x30, 0x9d, + 0xf8, 0x8a, 0x1a, 0xa7, 0xba, 0xa2, 0x30, 0x36, 0xae, 0x49, 0xd9, 0x97, 0x37, 0xd2, 0x22, 0xf0, + 0xa8, 0x4c, 0xf4, 0x5b, 0x0d, 0xae, 0x87, 0x52, 0xe4, 0xeb, 0xfb, 0x08, 0x85, 0x0c, 0xd4, 0xb3, + 0x50, 0xea, 0x33, 0x52, 0xa9, 0xeb, 0xcb, 0xcf, 0x90, 0x87, 0x9f, 0xa9, 0x0d, 0xfa, 0x85, 0x06, + 0x57, 0x43, 0x84, 0x51, 0x3d, 0x73, 0x67, 0xa6, 0xe7, 0xa7, 0xa5, 0x9e, 0x57, 0x97, 0x0f, 0x13, + 0x84, 0x0f, 0x97, 0xcf, 0x07, 0xf3, 0x5e, 0xb4, 0x3a, 0x56, 0xf2, 0x27, 0x53, 0x66, 0x7c, 0xf7, + 0x4c, 0x66, 0x8e, 0x18, 0x86, 0x13, 0x39, 0xfa, 0x23, 0xb8, 0xd2, 0x32, 0x3b, 0x8e, 0x2b, 0x26, + 0xca, 0x75, 0xc2, 0x1e, 0x78, 0xfc, 0x87, 0xa8, 0xd1, 0x9e, 0xd9, 0x09, 0xc3, 0x3e, 0xab, 0xac, + 0x87, 0x66, 0x87, 0x60, 0x01, 0xe1, 0x3b, 0x6d, 0xd7, 0xe9, 0x39, 0x4c, 0x0e, 0xab, 0x71, 0x3a, + 0xdd, 0xe3, 0x87, 0x38, 0x84, 0xe9, 0x26, 0x94, 0xd4, 0xbd, 0xf4, 0x45, 0x3c, 0x0d, 0xbe, 0x9f, + 0x81, 0x29, 0xd9, 0x67, 0xd1, 0x0d, 0x65, 0x21, 0x0d, 0x45, 0x54, 0x8e, 0x5f, 0x46, 0xd1, 0x86, + 0x5c, 0x85, 0x33, 0xc7, 0xe4, 0x69, 0x9f, 0x39, 0x5d, 0x23, 0xfc, 0xdf, 0x11, 0x46, 0xd3, 0x65, + 0x0f, 0xfc, 0x4d, 0xe6, 0x3b, 0x6e, 0x27, 0x7c, 0xda, 0x51, 0x16, 0xe7, 0xcf, 0xc2, 0x14, 0x71, + 0xc5, 0x96, 0x2d, 0xa6, 0x95, 0x7c, 0xa3, 0x38, 0x1c, 0xd4, 0xa6, 0xd6, 0xc2, 0x23, 0x1c, 0xc1, + 0xf8, 0xa2, 0xe7, 0x58, 0x3d, 0x8f, 0x4f, 0x8c, 0x62, 0xa2, 0xcb, 0x87, 0x8b, 0x5e, 0x73, 0xe5, + 0x7e, 0x4b, 0x4c, 0x91, 0x31, 0x34, 0xc2, 0x5c, 0x89, 0x1e, 0xa3, 0x14, 0x4c, 0x7e, 0x86, 0x63, + 0xa8, 0x4e, 0xa0, 0x3c, 0x3a, 0xf9, 0xbe, 0x80, 0x3b, 0x6f, 0x6c, 0x3d, 0x79, 0x5a, 0xbd, 0xf0, + 0xc1, 0xd3, 0xea, 0x85, 0x8f, 0x9e, 0x56, 0x2f, 0xbc, 0x3b, 0xac, 0x6a, 0x4f, 0x86, 0x55, 0xed, + 0x83, 0x61, 0x55, 0xfb, 0x68, 0x58, 0xd5, 0xfe, 0x32, 0xac, 0x6a, 0x3f, 0xff, 0x6b, 0xf5, 0xc2, + 0xd7, 0x8d, 0xc9, 0xfe, 0x7b, 0xcf, 0x7f, 0x02, 0x00, 0x00, 0xff, 0xff, 0xa6, 0x1d, 0x87, 0x1b, + 0x0f, 0x24, 0x00, 0x00, } func (m *AddressGroup) Marshal() (dAtA []byte, err error) { @@ -1899,6 +1935,48 @@ func (m *IPNet) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *MulticastGroupInfo) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MulticastGroupInfo) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MulticastGroupInfo) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Pods) > 0 { + for iNdEx := len(m.Pods) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Pods[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + } + i -= len(m.Group) + copy(dAtA[i:], m.Group) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Group))) + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + func (m *NamedPort) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -2450,6 +2528,20 @@ func (m *NodeStatsSummary) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if len(m.Multicast) > 0 { + for iNdEx := len(m.Multicast) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Multicast[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x2a + } + } if len(m.AntreaNetworkPolicies) > 0 { for iNdEx := len(m.AntreaNetworkPolicies) - 1; iNdEx >= 0; iNdEx-- { { @@ -2587,6 +2679,16 @@ func (m *Service) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.ICMPCode != nil { + i = encodeVarintGenerated(dAtA, i, uint64(*m.ICMPCode)) + i-- + dAtA[i] = 0x28 + } + if m.ICMPType != nil { + i = encodeVarintGenerated(dAtA, i, uint64(*m.ICMPType)) + i-- + dAtA[i] = 0x20 + } if m.EndPort != nil { i = encodeVarintGenerated(dAtA, i, uint64(*m.EndPort)) i-- @@ -2964,6 +3066,23 @@ func (m *IPNet) Size() (n int) { return n } +func (m *MulticastGroupInfo) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Group) + n += 1 + l + sovGenerated(uint64(l)) + if len(m.Pods) > 0 { + for _, e := range m.Pods { + l = e.Size() + n += 1 + l + sovGenerated(uint64(l)) + } + } + return n +} + func (m *NamedPort) Size() (n int) { if m == nil { return 0 @@ -3198,6 +3317,12 @@ func (m *NodeStatsSummary) Size() (n int) { n += 1 + l + sovGenerated(uint64(l)) } } + if len(m.Multicast) > 0 { + for _, e := range m.Multicast { + l = e.Size() + n += 1 + l + sovGenerated(uint64(l)) + } + } return n } @@ -3242,6 +3367,12 @@ func (m *Service) Size() (n int) { if m.EndPort != nil { n += 1 + sovGenerated(uint64(*m.EndPort)) } + if m.ICMPType != nil { + n += 1 + sovGenerated(uint64(*m.ICMPType)) + } + if m.ICMPCode != nil { + n += 1 + sovGenerated(uint64(*m.ICMPCode)) + } return n } @@ -3536,6 +3667,22 @@ func (this *IPNet) String() string { }, "") return s } +func (this *MulticastGroupInfo) String() string { + if this == nil { + return "nil" + } + repeatedStringForPods := "[]PodReference{" + for _, f := range this.Pods { + repeatedStringForPods += strings.Replace(strings.Replace(f.String(), "PodReference", "PodReference", 1), `&`, ``, 1) + "," + } + repeatedStringForPods += "}" + s := strings.Join([]string{`&MulticastGroupInfo{`, + `Group:` + fmt.Sprintf("%v", this.Group) + `,`, + `Pods:` + repeatedStringForPods + `,`, + `}`, + }, "") + return s +} func (this *NamedPort) String() string { if this == nil { return "nil" @@ -3716,11 +3863,17 @@ func (this *NodeStatsSummary) String() string { repeatedStringForAntreaNetworkPolicies += strings.Replace(strings.Replace(f.String(), "NetworkPolicyStats", "NetworkPolicyStats", 1), `&`, ``, 1) + "," } repeatedStringForAntreaNetworkPolicies += "}" + repeatedStringForMulticast := "[]MulticastGroupInfo{" + for _, f := range this.Multicast { + repeatedStringForMulticast += strings.Replace(strings.Replace(f.String(), "MulticastGroupInfo", "MulticastGroupInfo", 1), `&`, ``, 1) + "," + } + repeatedStringForMulticast += "}" s := strings.Join([]string{`&NodeStatsSummary{`, `ObjectMeta:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.ObjectMeta), "ObjectMeta", "v1.ObjectMeta", 1), `&`, ``, 1) + `,`, `NetworkPolicies:` + repeatedStringForNetworkPolicies + `,`, `AntreaClusterNetworkPolicies:` + repeatedStringForAntreaClusterNetworkPolicies + `,`, `AntreaNetworkPolicies:` + repeatedStringForAntreaNetworkPolicies + `,`, + `Multicast:` + repeatedStringForMulticast + `,`, `}`, }, "") return s @@ -3755,6 +3908,8 @@ func (this *Service) String() string { `Protocol:` + valueToStringGenerated(this.Protocol) + `,`, `Port:` + strings.Replace(fmt.Sprintf("%v", this.Port), "IntOrString", "intstr.IntOrString", 1) + `,`, `EndPort:` + valueToStringGenerated(this.EndPort) + `,`, + `ICMPType:` + valueToStringGenerated(this.ICMPType) + `,`, + `ICMPCode:` + valueToStringGenerated(this.ICMPCode) + `,`, `}`, }, "") return s @@ -5962,6 +6117,122 @@ func (m *IPNet) Unmarshal(dAtA []byte) error { } return nil } +func (m *MulticastGroupInfo) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MulticastGroupInfo: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MulticastGroupInfo: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Group", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Group = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Pods", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Pods = append(m.Pods, PodReference{}) + if err := m.Pods[len(m.Pods)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *NamedPort) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 @@ -7721,6 +7992,40 @@ func (m *NodeStatsSummary) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Multicast", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Multicast = append(m.Multicast, MulticastGroupInfo{}) + if err := m.Multicast[len(m.Multicast)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipGenerated(dAtA[iNdEx:]) @@ -8062,6 +8367,46 @@ func (m *Service) Unmarshal(dAtA []byte) error { } } m.EndPort = &v + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ICMPType", wireType) + } + var v int32 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int32(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.ICMPType = &v + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ICMPCode", wireType) + } + var v int32 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int32(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.ICMPCode = &v default: iNdEx = preIndex skippy, err := skipGenerated(dAtA[iNdEx:]) diff --git a/pkg/apis/controlplane/v1beta2/generated.proto b/pkg/apis/controlplane/v1beta2/generated.proto index 57166969a61..e1a23bf4a41 100644 --- a/pkg/apis/controlplane/v1beta2/generated.proto +++ b/pkg/apis/controlplane/v1beta2/generated.proto @@ -25,7 +25,7 @@ import "k8s.io/apimachinery/pkg/runtime/schema/generated.proto"; import "k8s.io/apimachinery/pkg/util/intstr/generated.proto"; // Package-wide variables from generator "generated". -option go_package = "v1beta2"; +option go_package = "antrea.io/antrea/pkg/apis/controlplane/v1beta2"; // AddressGroup is the message format of antrea/pkg/controller/types.AddressGroup in an API response. message AddressGroup { @@ -178,6 +178,15 @@ message IPNet { optional int32 prefixLength = 2; } +// MulticastGroupInfo contains the list of Pods that have joined a multicast group, for a given Node. +message MulticastGroupInfo { + // Group is the IP of the multicast group. + optional string group = 1; + + // Pods is the list of Pods that have joined the multicast group. + repeated PodReference pods = 2; +} + // NamedPort represents a Port with a name on Pod. message NamedPort { // Port represents the Port number. @@ -337,6 +346,9 @@ message NodeStatsSummary { // The TrafficStats of Antrea NetworkPolicies collected from the Node. repeated NetworkPolicyStats antreaNetworkPolicies = 4; + + // Multicast group information collected from the Node. + repeated MulticastGroupInfo multicast = 5; } message PaginationGetOptions { @@ -356,12 +368,14 @@ message PodReference { // Service describes a port to allow traffic on. message Service { - // The protocol (TCP, UDP, or SCTP) which traffic must match. If not specified, this + // The protocol (TCP, UDP, SCTP, or ICMP) which traffic must match. If not specified, this // field defaults to TCP. // +optional optional string protocol = 1; - // The port name or number on the given protocol. If not specified, this matches all port numbers. + // Port and EndPort can only be specified, when the Protocol is TCP, UDP, or SCTP. + // Port defines the port name or number on the given protocol. If not specified + // and the Protocol is TCP, UDP, or SCTP, this matches all port numbers. // +optional optional k8s.io.apimachinery.pkg.util.intstr.IntOrString port = 2; @@ -369,6 +383,13 @@ message Service { // It can only be specified when a numerical `port` is specified. // +optional optional int32 endPort = 3; + + // ICMPType and ICMPCode can only be specified, when the Protocol is ICMP. If they + // both are not specified and the Protocol is ICMP, this matches all ICMP traffic. + // +optional + optional int32 icmpType = 4; + + optional int32 icmpCode = 5; } // ServiceReference represents reference to a v1.Service. diff --git a/pkg/apis/controlplane/v1beta2/types.go b/pkg/apis/controlplane/v1beta2/types.go index 6f7aa1c35c9..5ac4d8b4ac2 100644 --- a/pkg/apis/controlplane/v1beta2/types.go +++ b/pkg/apis/controlplane/v1beta2/types.go @@ -265,21 +265,30 @@ const ( ProtocolUDP Protocol = "UDP" // ProtocolSCTP is the SCTP protocol. ProtocolSCTP Protocol = "SCTP" + // ProtocolICMP is the ICMP protocol. + ProtocolICMP Protocol = "ICMP" ) // Service describes a port to allow traffic on. type Service struct { - // The protocol (TCP, UDP, or SCTP) which traffic must match. If not specified, this + // The protocol (TCP, UDP, SCTP, or ICMP) which traffic must match. If not specified, this // field defaults to TCP. // +optional Protocol *Protocol `json:"protocol,omitempty" protobuf:"bytes,1,opt,name=protocol"` - // The port name or number on the given protocol. If not specified, this matches all port numbers. + // Port and EndPort can only be specified, when the Protocol is TCP, UDP, or SCTP. + // Port defines the port name or number on the given protocol. If not specified + // and the Protocol is TCP, UDP, or SCTP, this matches all port numbers. // +optional Port *intstr.IntOrString `json:"port,omitempty" protobuf:"bytes,2,opt,name=port"` // EndPort defines the end of the port range, being the end included within the range. // It can only be specified when a numerical `port` is specified. // +optional EndPort *int32 `json:"endPort,omitempty" protobuf:"bytes,3,opt,name=endPort"` + // ICMPType and ICMPCode can only be specified, when the Protocol is ICMP. If they + // both are not specified and the Protocol is ICMP, this matches all ICMP traffic. + // +optional + ICMPType *int32 `json:"icmpType,omitempty" protobuf:"bytes,4,opt,name=icmpType"` + ICMPCode *int32 `json:"icmpCode,omitempty" protobuf:"bytes,5,opt,name=icmpCode"` } // NetworkPolicyPeer describes a peer of NetworkPolicyRules. @@ -333,6 +342,16 @@ type NodeStatsSummary struct { AntreaClusterNetworkPolicies []NetworkPolicyStats `json:"antreaClusterNetworkPolicies,omitempty" protobuf:"bytes,3,rep,name=antreaClusterNetworkPolicies"` // The TrafficStats of Antrea NetworkPolicies collected from the Node. AntreaNetworkPolicies []NetworkPolicyStats `json:"antreaNetworkPolicies,omitempty" protobuf:"bytes,4,rep,name=antreaNetworkPolicies"` + // Multicast group information collected from the Node. + Multicast []MulticastGroupInfo `json:"multicast,omitempty" protobuf:"bytes,5,rep,name=multicast"` +} + +// MulticastGroupInfo contains the list of Pods that have joined a multicast group, for a given Node. +type MulticastGroupInfo struct { + // Group is the IP of the multicast group. + Group string `json:"group,omitempty" protobuf:"bytes,1,opt,name=group"` + // Pods is the list of Pods that have joined the multicast group. + Pods []PodReference `json:"pods,omitempty" protobuf:"bytes,2,rep,name=pods"` } // NetworkPolicyStats contains the information and traffic stats of a NetworkPolicy. diff --git a/pkg/apis/controlplane/v1beta2/zz_generated.conversion.go b/pkg/apis/controlplane/v1beta2/zz_generated.conversion.go index b8f2a246ca0..91049c1b299 100644 --- a/pkg/apis/controlplane/v1beta2/zz_generated.conversion.go +++ b/pkg/apis/controlplane/v1beta2/zz_generated.conversion.go @@ -199,6 +199,16 @@ func RegisterConversions(s *runtime.Scheme) error { }); err != nil { return err } + if err := s.AddGeneratedConversionFunc((*MulticastGroupInfo)(nil), (*controlplane.MulticastGroupInfo)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta2_MulticastGroupInfo_To_controlplane_MulticastGroupInfo(a.(*MulticastGroupInfo), b.(*controlplane.MulticastGroupInfo), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*controlplane.MulticastGroupInfo)(nil), (*MulticastGroupInfo)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_controlplane_MulticastGroupInfo_To_v1beta2_MulticastGroupInfo(a.(*controlplane.MulticastGroupInfo), b.(*MulticastGroupInfo), scope) + }); err != nil { + return err + } if err := s.AddGeneratedConversionFunc((*NamedPort)(nil), (*controlplane.NamedPort)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_v1beta2_NamedPort_To_controlplane_NamedPort(a.(*NamedPort), b.(*controlplane.NamedPort), scope) }); err != nil { @@ -995,6 +1005,28 @@ func Convert_controlplane_IPNet_To_v1beta2_IPNet(in *controlplane.IPNet, out *IP return autoConvert_controlplane_IPNet_To_v1beta2_IPNet(in, out, s) } +func autoConvert_v1beta2_MulticastGroupInfo_To_controlplane_MulticastGroupInfo(in *MulticastGroupInfo, out *controlplane.MulticastGroupInfo, s conversion.Scope) error { + out.Group = in.Group + out.Pods = *(*[]controlplane.PodReference)(unsafe.Pointer(&in.Pods)) + return nil +} + +// Convert_v1beta2_MulticastGroupInfo_To_controlplane_MulticastGroupInfo is an autogenerated conversion function. +func Convert_v1beta2_MulticastGroupInfo_To_controlplane_MulticastGroupInfo(in *MulticastGroupInfo, out *controlplane.MulticastGroupInfo, s conversion.Scope) error { + return autoConvert_v1beta2_MulticastGroupInfo_To_controlplane_MulticastGroupInfo(in, out, s) +} + +func autoConvert_controlplane_MulticastGroupInfo_To_v1beta2_MulticastGroupInfo(in *controlplane.MulticastGroupInfo, out *MulticastGroupInfo, s conversion.Scope) error { + out.Group = in.Group + out.Pods = *(*[]PodReference)(unsafe.Pointer(&in.Pods)) + return nil +} + +// Convert_controlplane_MulticastGroupInfo_To_v1beta2_MulticastGroupInfo is an autogenerated conversion function. +func Convert_controlplane_MulticastGroupInfo_To_v1beta2_MulticastGroupInfo(in *controlplane.MulticastGroupInfo, out *MulticastGroupInfo, s conversion.Scope) error { + return autoConvert_controlplane_MulticastGroupInfo_To_v1beta2_MulticastGroupInfo(in, out, s) +} + func autoConvert_v1beta2_NamedPort_To_controlplane_NamedPort(in *NamedPort, out *controlplane.NamedPort, s conversion.Scope) error { out.Port = in.Port out.Name = in.Name @@ -1304,6 +1336,7 @@ func autoConvert_v1beta2_NodeStatsSummary_To_controlplane_NodeStatsSummary(in *N out.NetworkPolicies = *(*[]controlplane.NetworkPolicyStats)(unsafe.Pointer(&in.NetworkPolicies)) out.AntreaClusterNetworkPolicies = *(*[]controlplane.NetworkPolicyStats)(unsafe.Pointer(&in.AntreaClusterNetworkPolicies)) out.AntreaNetworkPolicies = *(*[]controlplane.NetworkPolicyStats)(unsafe.Pointer(&in.AntreaNetworkPolicies)) + out.Multicast = *(*[]controlplane.MulticastGroupInfo)(unsafe.Pointer(&in.Multicast)) return nil } @@ -1317,6 +1350,7 @@ func autoConvert_controlplane_NodeStatsSummary_To_v1beta2_NodeStatsSummary(in *c out.NetworkPolicies = *(*[]NetworkPolicyStats)(unsafe.Pointer(&in.NetworkPolicies)) out.AntreaClusterNetworkPolicies = *(*[]NetworkPolicyStats)(unsafe.Pointer(&in.AntreaClusterNetworkPolicies)) out.AntreaNetworkPolicies = *(*[]NetworkPolicyStats)(unsafe.Pointer(&in.AntreaNetworkPolicies)) + out.Multicast = *(*[]MulticastGroupInfo)(unsafe.Pointer(&in.Multicast)) return nil } @@ -1398,6 +1432,8 @@ func autoConvert_v1beta2_Service_To_controlplane_Service(in *Service, out *contr out.Protocol = (*controlplane.Protocol)(unsafe.Pointer(in.Protocol)) out.Port = (*intstr.IntOrString)(unsafe.Pointer(in.Port)) out.EndPort = (*int32)(unsafe.Pointer(in.EndPort)) + out.ICMPType = (*int32)(unsafe.Pointer(in.ICMPType)) + out.ICMPCode = (*int32)(unsafe.Pointer(in.ICMPCode)) return nil } @@ -1410,6 +1446,8 @@ func autoConvert_controlplane_Service_To_v1beta2_Service(in *controlplane.Servic out.Protocol = (*Protocol)(unsafe.Pointer(in.Protocol)) out.Port = (*intstr.IntOrString)(unsafe.Pointer(in.Port)) out.EndPort = (*int32)(unsafe.Pointer(in.EndPort)) + out.ICMPType = (*int32)(unsafe.Pointer(in.ICMPType)) + out.ICMPCode = (*int32)(unsafe.Pointer(in.ICMPCode)) return nil } diff --git a/pkg/apis/controlplane/v1beta2/zz_generated.deepcopy.go b/pkg/apis/controlplane/v1beta2/zz_generated.deepcopy.go index 39b4a9e417a..957f7416c98 100644 --- a/pkg/apis/controlplane/v1beta2/zz_generated.deepcopy.go +++ b/pkg/apis/controlplane/v1beta2/zz_generated.deepcopy.go @@ -559,6 +559,27 @@ func (in *IPNet) DeepCopy() *IPNet { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *MulticastGroupInfo) DeepCopyInto(out *MulticastGroupInfo) { + *out = *in + if in.Pods != nil { + in, out := &in.Pods, &out.Pods + *out = make([]PodReference, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MulticastGroupInfo. +func (in *MulticastGroupInfo) DeepCopy() *MulticastGroupInfo { + if in == nil { + return nil + } + out := new(MulticastGroupInfo) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *NamedPort) DeepCopyInto(out *NamedPort) { *out = *in @@ -862,6 +883,13 @@ func (in *NodeStatsSummary) DeepCopyInto(out *NodeStatsSummary) { (*in)[i].DeepCopyInto(&(*out)[i]) } } + if in.Multicast != nil { + in, out := &in.Multicast, &out.Multicast + *out = make([]MulticastGroupInfo, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } return } @@ -942,6 +970,16 @@ func (in *Service) DeepCopyInto(out *Service) { *out = new(int32) **out = **in } + if in.ICMPType != nil { + in, out := &in.ICMPType, &out.ICMPType + *out = new(int32) + **out = **in + } + if in.ICMPCode != nil { + in, out := &in.ICMPCode, &out.ICMPCode + *out = new(int32) + **out = **in + } return } diff --git a/pkg/apis/controlplane/zz_generated.deepcopy.go b/pkg/apis/controlplane/zz_generated.deepcopy.go index 592b9740344..e5ca10a3280 100644 --- a/pkg/apis/controlplane/zz_generated.deepcopy.go +++ b/pkg/apis/controlplane/zz_generated.deepcopy.go @@ -559,6 +559,27 @@ func (in *IPNet) DeepCopy() *IPNet { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *MulticastGroupInfo) DeepCopyInto(out *MulticastGroupInfo) { + *out = *in + if in.Pods != nil { + in, out := &in.Pods, &out.Pods + *out = make([]PodReference, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MulticastGroupInfo. +func (in *MulticastGroupInfo) DeepCopy() *MulticastGroupInfo { + if in == nil { + return nil + } + out := new(MulticastGroupInfo) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *NamedPort) DeepCopyInto(out *NamedPort) { *out = *in @@ -862,6 +883,13 @@ func (in *NodeStatsSummary) DeepCopyInto(out *NodeStatsSummary) { (*in)[i].DeepCopyInto(&(*out)[i]) } } + if in.Multicast != nil { + in, out := &in.Multicast, &out.Multicast + *out = make([]MulticastGroupInfo, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } return } @@ -942,6 +970,16 @@ func (in *Service) DeepCopyInto(out *Service) { *out = new(int32) **out = **in } + if in.ICMPType != nil { + in, out := &in.ICMPType, &out.ICMPType + *out = new(int32) + **out = **in + } + if in.ICMPCode != nil { + in, out := &in.ICMPCode, &out.ICMPCode + *out = new(int32) + **out = **in + } return } diff --git a/pkg/apis/crd/v1alpha1/types.go b/pkg/apis/crd/v1alpha1/types.go index 434ccfaea4e..bd334359756 100644 --- a/pkg/apis/crd/v1alpha1/types.go +++ b/pkg/apis/crd/v1alpha1/types.go @@ -56,23 +56,23 @@ const ( // List the supported protocols and their codes in traceflow. // According to code in Antrea agent and controller, default protocol is ICMP if protocol is not inputted by users. const ( - ICMPProtocol int32 = 1 - TCPProtocol int32 = 6 - UDPProtocol int32 = 17 - SCTPProtocol int32 = 132 + ICMPProtocolNumber int32 = 1 + TCPProtocolNumber int32 = 6 + UDPProtocolNumber int32 = 17 + SCTPProtocolNumber int32 = 132 ) var SupportedProtocols = map[string]int32{ - "TCP": TCPProtocol, - "UDP": UDPProtocol, - "ICMP": ICMPProtocol, + "TCP": TCPProtocolNumber, + "UDP": UDPProtocolNumber, + "ICMP": ICMPProtocolNumber, } var ProtocolsToString = map[int32]string{ - TCPProtocol: "TCP", - UDPProtocol: "UDP", - ICMPProtocol: "ICMP", - SCTPProtocol: "SCTP", + TCPProtocolNumber: "TCP", + UDPProtocolNumber: "UDP", + ICMPProtocolNumber: "ICMP", + SCTPProtocolNumber: "SCTP", } // List the supported destination types in traceflow. @@ -353,10 +353,14 @@ type NetworkPolicyStatus struct { type Rule struct { // Action specifies the action to be applied on the rule. Action *RuleAction `json:"action"` - // Set of port and protocol allowed/denied by the rule. If this field is unset - // or empty, this rule matches all ports. + // Set of ports and protocols matched by the rule. If this field and Protocols + // are unset or empty, this rule matches all ports. // +optional Ports []NetworkPolicyPort `json:"ports,omitempty"` + // Set of protocols matched by the rule. If this field and Ports are unset or + // empty, this rule matches all protocols supported. + // +optional + Protocols []NetworkPolicyProtocol `json:"protocols,omitempty"` // Rule is matched if traffic originates from workloads selected by // this field. If this field is empty, this rule matches all sources. // +optional @@ -600,3 +604,17 @@ type NamespacedName struct { Name string `json:"name,omitempty"` Namespace string `json:"namespace,omitempty"` } + +// NetworkPolicyProtocol defines additional protocols that are not supported by +// `ports`. All fields should be used as a standalone field. +type NetworkPolicyProtocol struct { + ICMP *ICMPProtocol `json:"icmp,omitempty"` +} + +// ICMPProtocol matches ICMP traffic with specific ICMPType and/or ICMPCode. All +// fields could be used alone or together. If all fields are not provided, this +// matches all ICMP traffic. +type ICMPProtocol struct { + ICMPType *int32 `json:"icmpType,omitempty"` + ICMPCode *int32 `json:"icmpCode,omitempty"` +} diff --git a/pkg/apis/crd/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/crd/v1alpha1/zz_generated.deepcopy.go index 3b72cc18ac1..5420a8b2123 100644 --- a/pkg/apis/crd/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/crd/v1alpha1/zz_generated.deepcopy.go @@ -156,6 +156,32 @@ func (in *ICMPEchoRequestHeader) DeepCopy() *ICMPEchoRequestHeader { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ICMPProtocol) DeepCopyInto(out *ICMPProtocol) { + *out = *in + if in.ICMPType != nil { + in, out := &in.ICMPType, &out.ICMPType + *out = new(int32) + **out = **in + } + if in.ICMPCode != nil { + in, out := &in.ICMPCode, &out.ICMPCode + *out = new(int32) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ICMPProtocol. +func (in *ICMPProtocol) DeepCopy() *ICMPProtocol { + if in == nil { + return nil + } + out := new(ICMPProtocol) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *IPBlock) DeepCopyInto(out *IPBlock) { *out = *in @@ -368,6 +394,27 @@ func (in *NetworkPolicyPort) DeepCopy() *NetworkPolicyPort { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NetworkPolicyProtocol) DeepCopyInto(out *NetworkPolicyProtocol) { + *out = *in + if in.ICMP != nil { + in, out := &in.ICMP, &out.ICMP + *out = new(ICMPProtocol) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkPolicyProtocol. +func (in *NetworkPolicyProtocol) DeepCopy() *NetworkPolicyProtocol { + if in == nil { + return nil + } + out := new(NetworkPolicyProtocol) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *NetworkPolicySpec) DeepCopyInto(out *NetworkPolicySpec) { *out = *in @@ -512,6 +559,13 @@ func (in *Rule) DeepCopyInto(out *Rule) { (*in)[i].DeepCopyInto(&(*out)[i]) } } + if in.Protocols != nil { + in, out := &in.Protocols, &out.Protocols + *out = make([]NetworkPolicyProtocol, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } if in.From != nil { in, out := &in.From, &out.From *out = make([]NetworkPolicyPeer, len(*in)) diff --git a/pkg/apis/crd/v1alpha2/types.go b/pkg/apis/crd/v1alpha2/types.go index 43e9361a82f..15d18e2b926 100644 --- a/pkg/apis/crd/v1alpha2/types.go +++ b/pkg/apis/crd/v1alpha2/types.go @@ -304,9 +304,16 @@ type IPPool struct { Status IPPoolStatus `json:"status"` } +type IPVersion int + +const ( + IPv4 = IPVersion(4) + IPv6 = IPVersion(6) +) + type IPPoolSpec struct { // IP Version for this IP pool - either 4 or 6 - IPVersion int `json:"ipVersion"` + IPVersion IPVersion `json:"ipVersion"` // List IP ranges, along with subnet definition. IPRanges []SubnetIPRange `json:"ipRanges"` } @@ -361,6 +368,9 @@ type PodOwner struct { Name string `json:"name"` Namespace string `json:"namespace"` ContainerID string `json:"containerID"` + // Network interface name. Used when the IP is allocated for a secondary network interface + // of the Pod. + IFName string `json:"ifName,omitempty"` } // StatefulSet owner @@ -379,3 +389,127 @@ type IPPoolList struct { Items []IPPool `json:"items"` } + +// +genclient +// +genclient:nonNamespaced +// +genclient:noStatus +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// TrafficControl allows mirroring or redirecting the traffic Pods send or receive. It enables users to monitor and +// analyze Pod traffic, and to enforce custom network protections for Pods with fine-grained control over network +// traffic. +type TrafficControl struct { + metav1.TypeMeta `json:",inline"` + // Standard metadata of the object. + metav1.ObjectMeta `json:"metadata,omitempty"` + + // Specification of the desired behavior of TrafficControl. + Spec TrafficControlSpec `json:"spec"` +} + +type TrafficControlSpec struct { + // AppliedTo selects Pods to which the traffic control configuration will be applied. + AppliedTo AppliedTo `json:"appliedTo"` + + // The direction of traffic that should be matched. It can be Ingress, Egress, or Both. + Direction Direction `json:"direction"` + + // The action that should be taken for the traffic. It can be Redirect or Mirror. + Action TrafficControlAction `json:"action"` + + // The port to which the traffic should be redirected or mirrored. + TargetPort TrafficControlPort `json:"targetPort"` + + // The port from which the traffic will be sent back to OVS. It should only be set for Redirect action. + ReturnPort *TrafficControlPort `json:"returnPort,omitempty"` +} + +type Direction string + +const ( + DirectionIngress Direction = "Ingress" + DirectionEgress Direction = "Egress" + DirectionBoth Direction = "Both" +) + +type TrafficControlAction string + +const ( + ActionRedirect TrafficControlAction = "Redirect" + ActionMirror TrafficControlAction = "Mirror" +) + +// TrafficControlPort represents a port that can be used as the target of traffic mirroring or redirecting, and the +// return port of traffic redirecting. +type TrafficControlPort struct { + // OVSInternal represents an OVS internal port. + OVSInternal *OVSInternalPort `json:"ovsInternal,omitempty"` + // Device represents a network device. + Device *NetworkDevice `json:"device,omitempty"` + // GENEVE represents a GENEVE tunnel. + GENEVE *UDPTunnel `json:"geneve,omitempty"` + // VXLAN represents a VXLAN tunnel. + VXLAN *UDPTunnel `json:"vxlan,omitempty"` + // GRE represents a GRE tunnel. + GRE *GRETunnel `json:"gre,omitempty"` + // ERSPAN represents a ERSPAN tunnel. + ERSPAN *ERSPANTunnel `json:"erspan,omitempty"` +} + +// OVSInternalPort represents an OVS internal port. Antrea will create the port if it doesn't exist. +type OVSInternalPort struct { + // The name of the OVS internal port. + Name string `json:"name"` +} + +// NetworkDevice represents a network device. It must exist on all Nodes. Antrea will attach it to the OVS bridge if it +// is not attached. +type NetworkDevice struct { + // The name of the network device. + Name string `json:"name"` +} + +// UDPTunnel represents a UDP based tunnel. Antrea will create a port on the OVS bridge for the tunnel. +type UDPTunnel struct { + // The remote IP of the tunnel. + RemoteIP string `json:"remoteIP"` + // The ID of the tunnel. + VNI *int32 `json:"vni,omitempty"` + // The transport layer destination port of the tunnel. If not specified, the assigned IANA port will be used, i.e., + // 4789 for VXLAN, 6081 for GENEVE. + DestinationPort *int32 `json:"destinationPort,omitempty"` +} + +// GRETunnel represents a GRE tunnel. Antrea will create a port on the OVS bridge for the tunnel. +type GRETunnel struct { + // The remote IP of the tunnel. + RemoteIP string `json:"remoteIP"` + // GRE key. + Key *int32 `json:"key,omitempty"` +} + +// ERSPANTunnel represents an ERSPAN tunnel. Antrea will create a port on the OVS bridge for the tunnel. +type ERSPANTunnel struct { + // The remote IP of the tunnel. + RemoteIP string `json:"remoteIP"` + // ERSPAN session ID. + SessionID *int32 `json:"sessionID,omitempty"` + // ERSPAN version. + Version int32 `json:"version"` + // ERSPAN Index. + Index *int32 `json:"index,omitempty"` + // ERSPAN v2 mirrored traffic’s direction. + Dir *int32 `json:"dir,omitempty"` + // ERSPAN hardware ID. + HardwareID *int32 `json:"hardwareID,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +type TrafficControlList struct { + metav1.TypeMeta `json:",inline"` + // +optional + metav1.ListMeta `json:"metadata,omitempty"` + + Items []TrafficControl `json:"items"` +} diff --git a/pkg/apis/crd/v1alpha2/zz_generated.deepcopy.go b/pkg/apis/crd/v1alpha2/zz_generated.deepcopy.go index 4334cb9f36e..ab1449891e8 100644 --- a/pkg/apis/crd/v1alpha2/zz_generated.deepcopy.go +++ b/pkg/apis/crd/v1alpha2/zz_generated.deepcopy.go @@ -117,6 +117,42 @@ func (in *ClusterGroupList) DeepCopyObject() runtime.Object { return nil } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ERSPANTunnel) DeepCopyInto(out *ERSPANTunnel) { + *out = *in + if in.SessionID != nil { + in, out := &in.SessionID, &out.SessionID + *out = new(int32) + **out = **in + } + if in.Index != nil { + in, out := &in.Index, &out.Index + *out = new(int32) + **out = **in + } + if in.Dir != nil { + in, out := &in.Dir, &out.Dir + *out = new(int32) + **out = **in + } + if in.HardwareID != nil { + in, out := &in.HardwareID, &out.HardwareID + *out = new(int32) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ERSPANTunnel. +func (in *ERSPANTunnel) DeepCopy() *ERSPANTunnel { + if in == nil { + return nil + } + out := new(ERSPANTunnel) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Egress) DeepCopyInto(out *Egress) { *out = *in @@ -429,6 +465,27 @@ func (in *ExternalIPPoolUsage) DeepCopy() *ExternalIPPoolUsage { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *GRETunnel) DeepCopyInto(out *GRETunnel) { + *out = *in + if in.Key != nil { + in, out := &in.Key, &out.Key + *out = new(int32) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GRETunnel. +func (in *GRETunnel) DeepCopy() *GRETunnel { + if in == nil { + return nil + } + out := new(GRETunnel) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *GroupCondition) DeepCopyInto(out *GroupCondition) { *out = *in @@ -700,6 +757,38 @@ func (in *NamedPort) DeepCopy() *NamedPort { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NetworkDevice) DeepCopyInto(out *NetworkDevice) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkDevice. +func (in *NetworkDevice) DeepCopy() *NetworkDevice { + if in == nil { + return nil + } + out := new(NetworkDevice) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *OVSInternalPort) DeepCopyInto(out *OVSInternalPort) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OVSInternalPort. +func (in *OVSInternalPort) DeepCopy() *OVSInternalPort { + if in == nil { + return nil + } + out := new(OVSInternalPort) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *PodOwner) DeepCopyInto(out *PodOwner) { *out = *in @@ -765,3 +854,158 @@ func (in *SubnetInfo) DeepCopy() *SubnetInfo { in.DeepCopyInto(out) return out } + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TrafficControl) DeepCopyInto(out *TrafficControl) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TrafficControl. +func (in *TrafficControl) DeepCopy() *TrafficControl { + if in == nil { + return nil + } + out := new(TrafficControl) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *TrafficControl) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TrafficControlList) DeepCopyInto(out *TrafficControlList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]TrafficControl, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TrafficControlList. +func (in *TrafficControlList) DeepCopy() *TrafficControlList { + if in == nil { + return nil + } + out := new(TrafficControlList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *TrafficControlList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TrafficControlPort) DeepCopyInto(out *TrafficControlPort) { + *out = *in + if in.OVSInternal != nil { + in, out := &in.OVSInternal, &out.OVSInternal + *out = new(OVSInternalPort) + **out = **in + } + if in.Device != nil { + in, out := &in.Device, &out.Device + *out = new(NetworkDevice) + **out = **in + } + if in.GENEVE != nil { + in, out := &in.GENEVE, &out.GENEVE + *out = new(UDPTunnel) + (*in).DeepCopyInto(*out) + } + if in.VXLAN != nil { + in, out := &in.VXLAN, &out.VXLAN + *out = new(UDPTunnel) + (*in).DeepCopyInto(*out) + } + if in.GRE != nil { + in, out := &in.GRE, &out.GRE + *out = new(GRETunnel) + (*in).DeepCopyInto(*out) + } + if in.ERSPAN != nil { + in, out := &in.ERSPAN, &out.ERSPAN + *out = new(ERSPANTunnel) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TrafficControlPort. +func (in *TrafficControlPort) DeepCopy() *TrafficControlPort { + if in == nil { + return nil + } + out := new(TrafficControlPort) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TrafficControlSpec) DeepCopyInto(out *TrafficControlSpec) { + *out = *in + in.AppliedTo.DeepCopyInto(&out.AppliedTo) + in.TargetPort.DeepCopyInto(&out.TargetPort) + if in.ReturnPort != nil { + in, out := &in.ReturnPort, &out.ReturnPort + *out = new(TrafficControlPort) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TrafficControlSpec. +func (in *TrafficControlSpec) DeepCopy() *TrafficControlSpec { + if in == nil { + return nil + } + out := new(TrafficControlSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *UDPTunnel) DeepCopyInto(out *UDPTunnel) { + *out = *in + if in.VNI != nil { + in, out := &in.VNI, &out.VNI + *out = new(int32) + **out = **in + } + if in.DestinationPort != nil { + in, out := &in.DestinationPort, &out.DestinationPort + *out = new(int32) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UDPTunnel. +func (in *UDPTunnel) DeepCopy() *UDPTunnel { + if in == nil { + return nil + } + out := new(UDPTunnel) + in.DeepCopyInto(out) + return out +} diff --git a/pkg/apis/stats/register.go b/pkg/apis/stats/register.go index 5f60829f1c2..6ecb66e61da 100644 --- a/pkg/apis/stats/register.go +++ b/pkg/apis/stats/register.go @@ -50,6 +50,8 @@ func addKnownTypes(scheme *runtime.Scheme) error { &AntreaNetworkPolicyStatsList{}, &NetworkPolicyStats{}, &NetworkPolicyStatsList{}, + &MulticastGroup{}, + &MulticastGroupList{}, ) return nil } diff --git a/pkg/apis/stats/types.go b/pkg/apis/stats/types.go index f99886e1ae5..e293b3352bd 100644 --- a/pkg/apis/stats/types.go +++ b/pkg/apis/stats/types.go @@ -65,6 +65,38 @@ type AntreaNetworkPolicyStatsList struct { Items []AntreaNetworkPolicyStats } +// PodReference represents a Pod Reference. +type PodReference struct { + // The name of this Pod. + Name string + // The namespace of this Pod. + Namespace string +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// MulticastGroup contains the mapping between multicast group and Pods. +type MulticastGroup struct { + metav1.TypeMeta + metav1.ObjectMeta + + // Group is the IP of the multicast group. + Group string + // Pods is the list of Pods that have joined the multicast group. + Pods []PodReference +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// MulticastGroupList is a list of MulticastGroup. +type MulticastGroupList struct { + metav1.TypeMeta + metav1.ListMeta + + // List of MulticastGroup. + Items []MulticastGroup +} + // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object // NetworkPolicyStats is the statistics of a K8s NetworkPolicy. diff --git a/pkg/apis/stats/v1alpha1/generated.pb.go b/pkg/apis/stats/v1alpha1/generated.pb.go index 01089d5c0bb..97c8feb6c68 100644 --- a/pkg/apis/stats/v1alpha1/generated.pb.go +++ b/pkg/apis/stats/v1alpha1/generated.pb.go @@ -1,4 +1,4 @@ -// Copyright 2021 Antrea Authors +// Copyright 2022 Antrea Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -152,10 +152,66 @@ func (m *AntreaNetworkPolicyStatsList) XXX_DiscardUnknown() { var xxx_messageInfo_AntreaNetworkPolicyStatsList proto.InternalMessageInfo +func (m *MulticastGroup) Reset() { *m = MulticastGroup{} } +func (*MulticastGroup) ProtoMessage() {} +func (*MulticastGroup) Descriptor() ([]byte, []int) { + return fileDescriptor_91b517c6fa558473, []int{4} +} +func (m *MulticastGroup) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MulticastGroup) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil +} +func (m *MulticastGroup) XXX_Merge(src proto.Message) { + xxx_messageInfo_MulticastGroup.Merge(m, src) +} +func (m *MulticastGroup) XXX_Size() int { + return m.Size() +} +func (m *MulticastGroup) XXX_DiscardUnknown() { + xxx_messageInfo_MulticastGroup.DiscardUnknown(m) +} + +var xxx_messageInfo_MulticastGroup proto.InternalMessageInfo + +func (m *MulticastGroupList) Reset() { *m = MulticastGroupList{} } +func (*MulticastGroupList) ProtoMessage() {} +func (*MulticastGroupList) Descriptor() ([]byte, []int) { + return fileDescriptor_91b517c6fa558473, []int{5} +} +func (m *MulticastGroupList) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MulticastGroupList) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil +} +func (m *MulticastGroupList) XXX_Merge(src proto.Message) { + xxx_messageInfo_MulticastGroupList.Merge(m, src) +} +func (m *MulticastGroupList) XXX_Size() int { + return m.Size() +} +func (m *MulticastGroupList) XXX_DiscardUnknown() { + xxx_messageInfo_MulticastGroupList.DiscardUnknown(m) +} + +var xxx_messageInfo_MulticastGroupList proto.InternalMessageInfo + func (m *NetworkPolicyStats) Reset() { *m = NetworkPolicyStats{} } func (*NetworkPolicyStats) ProtoMessage() {} func (*NetworkPolicyStats) Descriptor() ([]byte, []int) { - return fileDescriptor_91b517c6fa558473, []int{4} + return fileDescriptor_91b517c6fa558473, []int{6} } func (m *NetworkPolicyStats) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -183,7 +239,7 @@ var xxx_messageInfo_NetworkPolicyStats proto.InternalMessageInfo func (m *NetworkPolicyStatsList) Reset() { *m = NetworkPolicyStatsList{} } func (*NetworkPolicyStatsList) ProtoMessage() {} func (*NetworkPolicyStatsList) Descriptor() ([]byte, []int) { - return fileDescriptor_91b517c6fa558473, []int{5} + return fileDescriptor_91b517c6fa558473, []int{7} } func (m *NetworkPolicyStatsList) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -208,10 +264,38 @@ func (m *NetworkPolicyStatsList) XXX_DiscardUnknown() { var xxx_messageInfo_NetworkPolicyStatsList proto.InternalMessageInfo +func (m *PodReference) Reset() { *m = PodReference{} } +func (*PodReference) ProtoMessage() {} +func (*PodReference) Descriptor() ([]byte, []int) { + return fileDescriptor_91b517c6fa558473, []int{8} +} +func (m *PodReference) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *PodReference) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil +} +func (m *PodReference) XXX_Merge(src proto.Message) { + xxx_messageInfo_PodReference.Merge(m, src) +} +func (m *PodReference) XXX_Size() int { + return m.Size() +} +func (m *PodReference) XXX_DiscardUnknown() { + xxx_messageInfo_PodReference.DiscardUnknown(m) +} + +var xxx_messageInfo_PodReference proto.InternalMessageInfo + func (m *RuleTrafficStats) Reset() { *m = RuleTrafficStats{} } func (*RuleTrafficStats) ProtoMessage() {} func (*RuleTrafficStats) Descriptor() ([]byte, []int) { - return fileDescriptor_91b517c6fa558473, []int{6} + return fileDescriptor_91b517c6fa558473, []int{9} } func (m *RuleTrafficStats) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -239,7 +323,7 @@ var xxx_messageInfo_RuleTrafficStats proto.InternalMessageInfo func (m *TrafficStats) Reset() { *m = TrafficStats{} } func (*TrafficStats) ProtoMessage() {} func (*TrafficStats) Descriptor() ([]byte, []int) { - return fileDescriptor_91b517c6fa558473, []int{7} + return fileDescriptor_91b517c6fa558473, []int{10} } func (m *TrafficStats) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -269,8 +353,11 @@ func init() { proto.RegisterType((*AntreaClusterNetworkPolicyStatsList)(nil), "antrea_io.antrea.pkg.apis.stats.v1alpha1.AntreaClusterNetworkPolicyStatsList") proto.RegisterType((*AntreaNetworkPolicyStats)(nil), "antrea_io.antrea.pkg.apis.stats.v1alpha1.AntreaNetworkPolicyStats") proto.RegisterType((*AntreaNetworkPolicyStatsList)(nil), "antrea_io.antrea.pkg.apis.stats.v1alpha1.AntreaNetworkPolicyStatsList") + proto.RegisterType((*MulticastGroup)(nil), "antrea_io.antrea.pkg.apis.stats.v1alpha1.MulticastGroup") + proto.RegisterType((*MulticastGroupList)(nil), "antrea_io.antrea.pkg.apis.stats.v1alpha1.MulticastGroupList") proto.RegisterType((*NetworkPolicyStats)(nil), "antrea_io.antrea.pkg.apis.stats.v1alpha1.NetworkPolicyStats") proto.RegisterType((*NetworkPolicyStatsList)(nil), "antrea_io.antrea.pkg.apis.stats.v1alpha1.NetworkPolicyStatsList") + proto.RegisterType((*PodReference)(nil), "antrea_io.antrea.pkg.apis.stats.v1alpha1.PodReference") proto.RegisterType((*RuleTrafficStats)(nil), "antrea_io.antrea.pkg.apis.stats.v1alpha1.RuleTrafficStats") proto.RegisterType((*TrafficStats)(nil), "antrea_io.antrea.pkg.apis.stats.v1alpha1.TrafficStats") } @@ -280,44 +367,51 @@ func init() { } var fileDescriptor_91b517c6fa558473 = []byte{ - // 591 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x54, 0xcf, 0x6b, 0x13, 0x41, - 0x14, 0xce, 0x34, 0x0d, 0x8d, 0xd3, 0x88, 0x61, 0x10, 0x09, 0x41, 0x36, 0x21, 0xbd, 0x44, 0xd0, - 0x59, 0x53, 0xa4, 0x14, 0xf1, 0xe2, 0x7a, 0x2a, 0x68, 0x2d, 0x5b, 0x4f, 0x22, 0xe8, 0x64, 0x3b, - 0xd9, 0x8c, 0xc9, 0xee, 0x2c, 0x3b, 0x93, 0x48, 0x6e, 0xfd, 0x03, 0x3c, 0xf8, 0x57, 0xf8, 0xb7, - 0xe4, 0xd8, 0x63, 0xbd, 0x14, 0xb3, 0x22, 0x78, 0x15, 0x2f, 0x1e, 0x65, 0x66, 0x37, 0x3f, 0x97, - 0x92, 0xf5, 0xd2, 0x1e, 0xf4, 0xb6, 0xf3, 0xde, 0xfb, 0xde, 0xf7, 0xde, 0xf7, 0x3e, 0x16, 0xee, - 0x13, 0x5f, 0x86, 0x94, 0x60, 0xc6, 0xcd, 0xf8, 0xcb, 0x0c, 0x7a, 0xae, 0x49, 0x02, 0x26, 0x4c, - 0x21, 0x89, 0x14, 0xe6, 0xb0, 0x45, 0xfa, 0x41, 0x97, 0xb4, 0x4c, 0x97, 0xfa, 0x34, 0x24, 0x92, - 0x9e, 0xe0, 0x20, 0xe4, 0x92, 0xa3, 0x66, 0x5c, 0xff, 0x96, 0x71, 0x9c, 0xf4, 0x08, 0x7a, 0x2e, - 0x56, 0x48, 0xac, 0x91, 0x78, 0x8a, 0xac, 0x3e, 0x70, 0x99, 0xec, 0x0e, 0xda, 0xd8, 0xe1, 0x9e, - 0xe9, 0x72, 0x97, 0x9b, 0xba, 0x41, 0x7b, 0xd0, 0xd1, 0x2f, 0xfd, 0xd0, 0x5f, 0x71, 0xe3, 0xea, - 0xa3, 0xde, 0xbe, 0xd0, 0xf3, 0x04, 0xcc, 0x23, 0x4e, 0x97, 0xf9, 0x34, 0x1c, 0xcd, 0xa7, 0xf2, - 0xa8, 0x24, 0xe6, 0x30, 0x35, 0x4e, 0xd5, 0xbc, 0x0c, 0x15, 0x0e, 0x7c, 0xc9, 0x3c, 0x9a, 0x02, - 0xec, 0xad, 0x03, 0x08, 0xa7, 0x4b, 0x3d, 0xb2, 0x8a, 0x6b, 0xfc, 0xde, 0x80, 0xb5, 0xa7, 0x7a, - 0xe1, 0x67, 0xfd, 0x81, 0x90, 0x34, 0x3c, 0xa4, 0xf2, 0x03, 0x0f, 0x7b, 0x47, 0xbc, 0xcf, 0x9c, - 0xd1, 0xb1, 0x5a, 0x1d, 0xbd, 0x83, 0x45, 0x35, 0xe7, 0x09, 0x91, 0xa4, 0x02, 0xea, 0xa0, 0xb9, - 0xbd, 0xfb, 0x10, 0xc7, 0x74, 0x78, 0x91, 0x6e, 0xae, 0x98, 0xaa, 0xc6, 0xc3, 0x16, 0x7e, 0xd9, - 0x7e, 0x4f, 0x1d, 0xf9, 0x82, 0x4a, 0x62, 0xa1, 0xf1, 0x45, 0x2d, 0x17, 0x5d, 0xd4, 0xe0, 0x3c, - 0x66, 0xcf, 0xba, 0xa2, 0x00, 0x96, 0x64, 0x48, 0x3a, 0x1d, 0xe6, 0x68, 0xc6, 0xca, 0x86, 0x66, - 0xd9, 0xc3, 0x59, 0x8f, 0x82, 0x5f, 0x2d, 0xa0, 0xad, 0xdb, 0x09, 0x57, 0x69, 0x31, 0x6a, 0x2f, - 0x31, 0xa0, 0x53, 0x00, 0xcb, 0xe1, 0xa0, 0x4f, 0x17, 0x4b, 0x2a, 0xf9, 0x7a, 0xbe, 0xb9, 0xbd, - 0xfb, 0x38, 0x3b, 0xad, 0xbd, 0xd2, 0xc1, 0xaa, 0x24, 0xd4, 0xe5, 0xd5, 0x8c, 0x9d, 0x62, 0x6b, - 0xfc, 0x02, 0x70, 0x67, 0x8d, 0xf4, 0xcf, 0x99, 0x90, 0xe8, 0x4d, 0x4a, 0x7e, 0x9c, 0x4d, 0x7e, - 0x85, 0xd6, 0xe2, 0x97, 0x93, 0xa9, 0x8a, 0xd3, 0xc8, 0x82, 0xf4, 0x3e, 0x2c, 0x30, 0x49, 0x3d, - 0xa5, 0xb9, 0x5a, 0xfe, 0x20, 0xfb, 0xf2, 0x6b, 0x66, 0xb7, 0x6e, 0x26, 0xac, 0x85, 0x03, 0xd5, - 0xdf, 0x8e, 0x69, 0x1a, 0x3f, 0x37, 0x60, 0x25, 0x46, 0xfe, 0x77, 0xda, 0x55, 0x39, 0xed, 0x3b, - 0x80, 0x77, 0x2f, 0xd3, 0xfc, 0x0a, 0x2c, 0xe6, 0x2e, 0x5b, 0xcc, 0xfa, 0x5b, 0x8b, 0x65, 0xf6, - 0xd6, 0x0f, 0x00, 0xd1, 0xbf, 0xe1, 0xaa, 0xc6, 0x17, 0x00, 0xef, 0x5c, 0xcb, 0x31, 0xc9, 0xf2, - 0x31, 0x9f, 0x64, 0xdf, 0x31, 0xf3, 0x19, 0x3f, 0x03, 0x98, 0x72, 0x35, 0xaa, 0xc3, 0x4d, 0x9f, - 0x78, 0x54, 0x6f, 0x74, 0xc3, 0x2a, 0x25, 0xc0, 0xcd, 0x43, 0xe2, 0x51, 0x5b, 0x67, 0xae, 0xe1, - 0x08, 0x1f, 0x01, 0x5c, 0x4a, 0xa3, 0x7b, 0x70, 0x2b, 0x20, 0x4e, 0x8f, 0x4a, 0xa1, 0xe7, 0xcc, - 0x5b, 0xb7, 0x92, 0x2e, 0x5b, 0x47, 0x71, 0xd8, 0x9e, 0xe6, 0xd1, 0x0e, 0x2c, 0xb4, 0x47, 0x92, - 0xc6, 0x63, 0xe6, 0xe7, 0x4a, 0x58, 0x2a, 0x68, 0xc7, 0x39, 0x74, 0x1f, 0x16, 0x05, 0x15, 0x82, - 0x71, 0x5f, 0xfd, 0x32, 0x54, 0xdd, 0xec, 0x34, 0xc7, 0x49, 0xdc, 0x9e, 0x55, 0x58, 0x78, 0x3c, - 0x31, 0x72, 0x67, 0x13, 0x23, 0x77, 0x3e, 0x31, 0x72, 0xa7, 0x91, 0x01, 0xc6, 0x91, 0x01, 0xce, - 0x22, 0x03, 0x9c, 0x47, 0x06, 0xf8, 0x1a, 0x19, 0xe0, 0xd3, 0x37, 0x23, 0xf7, 0xba, 0x38, 0xdd, - 0xf7, 0x4f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x68, 0x79, 0xc3, 0x5a, 0x2e, 0x09, 0x00, 0x00, + // 704 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x56, 0x4f, 0x6b, 0x13, 0x4d, + 0x18, 0xcf, 0x34, 0x2d, 0x6d, 0xa6, 0x79, 0xdf, 0xb7, 0xef, 0x20, 0x12, 0x8a, 0x6c, 0x4b, 0x7a, + 0x89, 0xa0, 0xb3, 0xb6, 0x48, 0x29, 0xe2, 0xc5, 0xf5, 0x20, 0x05, 0x1b, 0xc3, 0xd4, 0x83, 0x88, + 0xa2, 0x93, 0xcd, 0x64, 0x33, 0x26, 0xbb, 0xb3, 0xec, 0xcc, 0x56, 0x7a, 0xeb, 0x07, 0xf0, 0xe0, + 0xa7, 0xf0, 0xb3, 0xf4, 0x58, 0x6f, 0xf5, 0x52, 0x6c, 0x44, 0xf0, 0x2a, 0x5e, 0x3c, 0xca, 0xcc, + 0x6e, 0xba, 0xd9, 0x86, 0xd2, 0xed, 0x25, 0x1e, 0xf4, 0x94, 0x9d, 0xe7, 0xdf, 0xef, 0xf7, 0x3c, + 0xcf, 0x6f, 0x86, 0xc0, 0x2d, 0x1a, 0xa8, 0x88, 0x51, 0xcc, 0x85, 0x9d, 0x7c, 0xd9, 0x61, 0xdf, + 0xb3, 0x69, 0xc8, 0xa5, 0x2d, 0x15, 0x55, 0xd2, 0xde, 0x5b, 0xa7, 0x83, 0xb0, 0x47, 0xd7, 0x6d, + 0x8f, 0x05, 0x2c, 0xa2, 0x8a, 0x75, 0x70, 0x18, 0x09, 0x25, 0x50, 0x23, 0x89, 0x7f, 0xc5, 0x05, + 0x4e, 0x6b, 0x84, 0x7d, 0x0f, 0xeb, 0x4c, 0x6c, 0x32, 0xf1, 0x28, 0x73, 0xf9, 0xb6, 0xc7, 0x55, + 0x2f, 0x6e, 0x63, 0x57, 0xf8, 0xb6, 0x27, 0x3c, 0x61, 0x9b, 0x02, 0xed, 0xb8, 0x6b, 0x4e, 0xe6, + 0x60, 0xbe, 0x92, 0xc2, 0xcb, 0x77, 0xfb, 0x5b, 0xd2, 0xf0, 0x09, 0xb9, 0x4f, 0xdd, 0x1e, 0x0f, + 0x58, 0xb4, 0x9f, 0xb1, 0xf2, 0x99, 0xa2, 0xf6, 0xde, 0x04, 0x9d, 0x65, 0xfb, 0xa2, 0xac, 0x28, + 0x0e, 0x14, 0xf7, 0xd9, 0x44, 0xc2, 0xe6, 0x65, 0x09, 0xd2, 0xed, 0x31, 0x9f, 0x9e, 0xcf, 0xab, + 0xff, 0x9c, 0x81, 0x2b, 0x0f, 0x4c, 0xc3, 0x0f, 0x07, 0xb1, 0x54, 0x2c, 0x6a, 0x32, 0xf5, 0x56, + 0x44, 0xfd, 0x96, 0x18, 0x70, 0x77, 0x7f, 0x57, 0xb7, 0x8e, 0x5e, 0xc3, 0x05, 0xcd, 0xb3, 0x43, + 0x15, 0xad, 0x81, 0x55, 0xd0, 0x58, 0xdc, 0xb8, 0x83, 0x13, 0x38, 0x3c, 0x0e, 0x97, 0x4d, 0x4c, + 0x47, 0xe3, 0xbd, 0x75, 0xfc, 0xa4, 0xfd, 0x86, 0xb9, 0x6a, 0x87, 0x29, 0xea, 0xa0, 0xc3, 0x93, + 0x95, 0xd2, 0xf0, 0x64, 0x05, 0x66, 0x36, 0x72, 0x56, 0x15, 0x85, 0xb0, 0xaa, 0x22, 0xda, 0xed, + 0x72, 0xd7, 0x20, 0xd6, 0x66, 0x0c, 0xca, 0x26, 0x2e, 0xba, 0x14, 0xfc, 0x74, 0x2c, 0xdb, 0xb9, + 0x96, 0x62, 0x55, 0xc7, 0xad, 0x24, 0x87, 0x80, 0x0e, 0x00, 0x5c, 0x8a, 0xe2, 0x01, 0x1b, 0x0f, + 0xa9, 0x95, 0x57, 0xcb, 0x8d, 0xc5, 0x8d, 0x7b, 0xc5, 0x61, 0xc9, 0xb9, 0x0a, 0x4e, 0x2d, 0x85, + 0x5e, 0x3a, 0xef, 0x21, 0x13, 0x68, 0xf5, 0x1f, 0x00, 0xae, 0x5d, 0x32, 0xfa, 0xc7, 0x5c, 0x2a, + 0xf4, 0x62, 0x62, 0xfc, 0xb8, 0xd8, 0xf8, 0x75, 0xb6, 0x19, 0xfe, 0x52, 0xca, 0x6a, 0x61, 0x64, + 0x19, 0x1b, 0x7d, 0x00, 0xe7, 0xb8, 0x62, 0xbe, 0x9e, 0xb9, 0x6e, 0x7e, 0xbb, 0x78, 0xf3, 0x97, + 0x70, 0x77, 0xfe, 0x49, 0x51, 0xe7, 0xb6, 0x75, 0x7d, 0x92, 0xc0, 0xd4, 0xbf, 0xcf, 0xc0, 0x5a, + 0x92, 0xf9, 0x57, 0x69, 0xd3, 0x52, 0xda, 0x57, 0x00, 0x6f, 0x5c, 0x34, 0xf3, 0x29, 0x48, 0xcc, + 0xcb, 0x4b, 0xcc, 0xb9, 0xaa, 0xc4, 0x8a, 0x6b, 0x0b, 0xc0, 0x7f, 0x77, 0xe2, 0x81, 0xe2, 0x2e, + 0x95, 0xea, 0x51, 0x24, 0xe2, 0x70, 0x0a, 0x8a, 0x5a, 0x83, 0x73, 0x9e, 0x86, 0x32, 0x52, 0xaa, + 0x64, 0xcc, 0x0c, 0x3e, 0x49, 0x7c, 0xe8, 0x19, 0x9c, 0x0d, 0x45, 0x67, 0xb4, 0xf7, 0x2b, 0xc8, + 0xad, 0x25, 0x3a, 0x84, 0x75, 0x59, 0xc4, 0x02, 0x97, 0x39, 0xd5, 0xb4, 0xf6, 0x6c, 0x4b, 0x74, + 0x24, 0x31, 0x15, 0xeb, 0x1f, 0x01, 0x44, 0xf9, 0x9e, 0xa7, 0xb0, 0xd1, 0x97, 0xf9, 0x8d, 0x6e, + 0x15, 0xef, 0x27, 0x4f, 0xf5, 0x82, 0x3d, 0x7e, 0x03, 0x10, 0xfd, 0x19, 0xaf, 0x43, 0xfd, 0x13, + 0x80, 0xd7, 0x7f, 0xcb, 0xa5, 0xa4, 0xf9, 0x15, 0xde, 0x2f, 0xde, 0x63, 0xe1, 0xeb, 0x48, 0x61, + 0x75, 0x5c, 0xbe, 0x68, 0x15, 0xce, 0x06, 0xd4, 0x67, 0xa6, 0x99, 0x4a, 0x26, 0xe6, 0x26, 0xf5, + 0x19, 0x31, 0x1e, 0x64, 0xc3, 0x8a, 0xfe, 0x95, 0x21, 0x75, 0x59, 0x7a, 0x9f, 0xfe, 0x4f, 0xc3, + 0x2a, 0xcd, 0x91, 0x83, 0x64, 0x31, 0xf5, 0x0f, 0x00, 0x4e, 0x3c, 0x80, 0x05, 0x70, 0xa6, 0xbf, + 0xe7, 0x77, 0x00, 0xe6, 0xdc, 0xe8, 0x26, 0x9c, 0x0f, 0xa9, 0xdb, 0x67, 0x4a, 0x1a, 0x9e, 0x65, + 0xe7, 0xbf, 0xb4, 0xca, 0x7c, 0x2b, 0x31, 0x93, 0x91, 0x5f, 0xbf, 0x30, 0xed, 0x7d, 0xc5, 0x12, + 0x9a, 0xe5, 0x6c, 0xd8, 0x8e, 0x36, 0x92, 0xc4, 0x87, 0x6e, 0xc1, 0x05, 0xc9, 0xa4, 0xe4, 0x22, + 0xd0, 0xaf, 0x8c, 0x8e, 0x3b, 0xdb, 0xfe, 0x6e, 0x6a, 0x27, 0x67, 0x11, 0x4e, 0xf3, 0xf0, 0xd4, + 0x2a, 0x1d, 0x9d, 0x5a, 0xa5, 0xe3, 0x53, 0xab, 0x74, 0x30, 0xb4, 0xc0, 0xe1, 0xd0, 0x02, 0x47, + 0x43, 0x0b, 0x1c, 0x0f, 0x2d, 0xf0, 0x79, 0x68, 0x81, 0xf7, 0x5f, 0xac, 0xd2, 0xf3, 0x46, 0xd1, + 0xbf, 0xd3, 0xbf, 0x02, 0x00, 0x00, 0xff, 0xff, 0x73, 0x1f, 0x1a, 0xcb, 0x79, 0x0b, 0x00, 0x00, } func (m *AntreaClusterNetworkPolicyStats) Marshal() (dAtA []byte, err error) { @@ -528,6 +622,105 @@ func (m *AntreaNetworkPolicyStatsList) MarshalToSizedBuffer(dAtA []byte) (int, e return len(dAtA) - i, nil } +func (m *MulticastGroup) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MulticastGroup) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MulticastGroup) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Pods) > 0 { + for iNdEx := len(m.Pods) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Pods[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + } + i -= len(m.Group) + copy(dAtA[i:], m.Group) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Group))) + i-- + dAtA[i] = 0x12 + { + size, err := m.ObjectMeta.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *MulticastGroupList) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MulticastGroupList) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MulticastGroupList) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Items) > 0 { + for iNdEx := len(m.Items) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Items[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + } + { + size, err := m.ListMeta.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + func (m *NetworkPolicyStats) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -618,6 +811,39 @@ func (m *NetworkPolicyStatsList) MarshalToSizedBuffer(dAtA []byte) (int, error) return len(dAtA) - i, nil } +func (m *PodReference) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *PodReference) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *PodReference) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + i -= len(m.Namespace) + copy(dAtA[i:], m.Namespace) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Namespace))) + i-- + dAtA[i] = 0x12 + i -= len(m.Name) + copy(dAtA[i:], m.Name) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Name))) + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + func (m *RuleTrafficStats) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -771,6 +997,42 @@ func (m *AntreaNetworkPolicyStatsList) Size() (n int) { return n } +func (m *MulticastGroup) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.ObjectMeta.Size() + n += 1 + l + sovGenerated(uint64(l)) + l = len(m.Group) + n += 1 + l + sovGenerated(uint64(l)) + if len(m.Pods) > 0 { + for _, e := range m.Pods { + l = e.Size() + n += 1 + l + sovGenerated(uint64(l)) + } + } + return n +} + +func (m *MulticastGroupList) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.ListMeta.Size() + n += 1 + l + sovGenerated(uint64(l)) + if len(m.Items) > 0 { + for _, e := range m.Items { + l = e.Size() + n += 1 + l + sovGenerated(uint64(l)) + } + } + return n +} + func (m *NetworkPolicyStats) Size() (n int) { if m == nil { return 0 @@ -801,6 +1063,19 @@ func (m *NetworkPolicyStatsList) Size() (n int) { return n } +func (m *PodReference) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Name) + n += 1 + l + sovGenerated(uint64(l)) + l = len(m.Namespace) + n += 1 + l + sovGenerated(uint64(l)) + return n +} + func (m *RuleTrafficStats) Size() (n int) { if m == nil { return 0 @@ -898,6 +1173,39 @@ func (this *AntreaNetworkPolicyStatsList) String() string { }, "") return s } +func (this *MulticastGroup) String() string { + if this == nil { + return "nil" + } + repeatedStringForPods := "[]PodReference{" + for _, f := range this.Pods { + repeatedStringForPods += strings.Replace(strings.Replace(f.String(), "PodReference", "PodReference", 1), `&`, ``, 1) + "," + } + repeatedStringForPods += "}" + s := strings.Join([]string{`&MulticastGroup{`, + `ObjectMeta:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.ObjectMeta), "ObjectMeta", "v1.ObjectMeta", 1), `&`, ``, 1) + `,`, + `Group:` + fmt.Sprintf("%v", this.Group) + `,`, + `Pods:` + repeatedStringForPods + `,`, + `}`, + }, "") + return s +} +func (this *MulticastGroupList) String() string { + if this == nil { + return "nil" + } + repeatedStringForItems := "[]MulticastGroup{" + for _, f := range this.Items { + repeatedStringForItems += strings.Replace(strings.Replace(f.String(), "MulticastGroup", "MulticastGroup", 1), `&`, ``, 1) + "," + } + repeatedStringForItems += "}" + s := strings.Join([]string{`&MulticastGroupList{`, + `ListMeta:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.ListMeta), "ListMeta", "v1.ListMeta", 1), `&`, ``, 1) + `,`, + `Items:` + repeatedStringForItems + `,`, + `}`, + }, "") + return s +} func (this *NetworkPolicyStats) String() string { if this == nil { return "nil" @@ -925,6 +1233,17 @@ func (this *NetworkPolicyStatsList) String() string { }, "") return s } +func (this *PodReference) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&PodReference{`, + `Name:` + fmt.Sprintf("%v", this.Name) + `,`, + `Namespace:` + fmt.Sprintf("%v", this.Namespace) + `,`, + `}`, + }, "") + return s +} func (this *RuleTrafficStats) String() string { if this == nil { return "nil" @@ -1490,7 +1809,7 @@ func (m *AntreaNetworkPolicyStatsList) Unmarshal(dAtA []byte) error { } return nil } -func (m *NetworkPolicyStats) Unmarshal(dAtA []byte) error { +func (m *MulticastGroup) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -1513,10 +1832,10 @@ func (m *NetworkPolicyStats) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: NetworkPolicyStats: wiretype end group for non-group") + return fmt.Errorf("proto: MulticastGroup: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: NetworkPolicyStats: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: MulticastGroup: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: @@ -1554,9 +1873,9 @@ func (m *NetworkPolicyStats) Unmarshal(dAtA []byte) error { iNdEx = postIndex case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field TrafficStats", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Group", wireType) } - var msglen int + var stringLen uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowGenerated @@ -1566,23 +1885,289 @@ func (m *NetworkPolicyStats) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } } - if msglen < 0 { + intStringLen := int(stringLen) + if intStringLen < 0 { return ErrInvalidLengthGenerated } - postIndex := iNdEx + msglen + postIndex := iNdEx + intStringLen if postIndex < 0 { return ErrInvalidLengthGenerated } if postIndex > l { return io.ErrUnexpectedEOF } - if err := m.TrafficStats.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err + m.Group = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Pods", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Pods = append(m.Pods, PodReference{}) + if err := m.Pods[len(m.Pods)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MulticastGroupList) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MulticastGroupList: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MulticastGroupList: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ListMeta", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.ListMeta.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Items", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Items = append(m.Items, MulticastGroup{}) + if err := m.Items[len(m.Items)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *NetworkPolicyStats) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: NetworkPolicyStats: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: NetworkPolicyStats: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ObjectMeta", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.ObjectMeta.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TrafficStats", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.TrafficStats.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err } iNdEx = postIndex default: @@ -1723,6 +2308,120 @@ func (m *NetworkPolicyStatsList) Unmarshal(dAtA []byte) error { } return nil } +func (m *PodReference) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: PodReference: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: PodReference: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Name = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Namespace", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Namespace = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *RuleTrafficStats) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 diff --git a/pkg/apis/stats/v1alpha1/generated.proto b/pkg/apis/stats/v1alpha1/generated.proto index 2fbf6432e2b..dd18b35deae 100644 --- a/pkg/apis/stats/v1alpha1/generated.proto +++ b/pkg/apis/stats/v1alpha1/generated.proto @@ -1,4 +1,4 @@ -// Copyright 2021 Antrea Authors +// Copyright 2022 Antrea Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -23,7 +23,7 @@ import "k8s.io/apimachinery/pkg/runtime/generated.proto"; import "k8s.io/apimachinery/pkg/runtime/schema/generated.proto"; // Package-wide variables from generator "generated". -option go_package = "v1alpha1"; +option go_package = "antrea.io/antrea/pkg/apis/stats/v1alpha1"; // AntreaClusterNetworkPolicyStats is the statistics of a Antrea ClusterNetworkPolicy. message AntreaClusterNetworkPolicyStats { @@ -63,6 +63,25 @@ message AntreaNetworkPolicyStatsList { repeated AntreaNetworkPolicyStats items = 2; } +// MulticastGroup contains the mapping between multicast group and Pods. +message MulticastGroup { + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + // Group is the IP of the multicast group. + optional string group = 2; + + // Pods is the list of Pods that have joined the multicast group. + repeated PodReference pods = 3; +} + +// MulticastGroupList is a list of MulticastGroup. +message MulticastGroupList { + optional k8s.io.apimachinery.pkg.apis.meta.v1.ListMeta metadata = 1; + + // List of MulticastGroup. + repeated MulticastGroup items = 2; +} + // NetworkPolicyStats is the statistics of a K8s NetworkPolicy. message NetworkPolicyStats { optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; @@ -79,6 +98,15 @@ message NetworkPolicyStatsList { repeated NetworkPolicyStats items = 2; } +// PodReference represents a Pod Reference. +message PodReference { + // The name of this Pod. + optional string name = 1; + + // The namespace of this Pod. + optional string namespace = 2; +} + // RuleTrafficStats contains TrafficStats of single rule inside a NetworkPolicy. message RuleTrafficStats { optional string name = 1; diff --git a/pkg/apis/stats/v1alpha1/register.go b/pkg/apis/stats/v1alpha1/register.go index 30c40f47fe5..fcdb9032339 100644 --- a/pkg/apis/stats/v1alpha1/register.go +++ b/pkg/apis/stats/v1alpha1/register.go @@ -47,6 +47,8 @@ func addKnownTypes(scheme *runtime.Scheme) error { &AntreaNetworkPolicyStatsList{}, &NetworkPolicyStats{}, &NetworkPolicyStatsList{}, + &MulticastGroup{}, + &MulticastGroupList{}, ) metav1.AddToGroupVersion(scheme, SchemeGroupVersion) return nil diff --git a/pkg/apis/stats/v1alpha1/types.go b/pkg/apis/stats/v1alpha1/types.go index 4189f56f8b7..c36f63a8a26 100644 --- a/pkg/apis/stats/v1alpha1/types.go +++ b/pkg/apis/stats/v1alpha1/types.go @@ -85,6 +85,33 @@ type NetworkPolicyStats struct { TrafficStats TrafficStats `json:"trafficStats,omitempty" protobuf:"bytes,2,opt,name=trafficStats"` } +// +genclient +// +genclient:readonly +// +genclient:nonNamespaced +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// MulticastGroup contains the mapping between multicast group and Pods. +type MulticastGroup struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"` + + // Group is the IP of the multicast group. + Group string `json:"group,omitempty" protobuf:"bytes,2,opt,name=group"` + // Pods is the list of Pods that have joined the multicast group. + Pods []PodReference `json:"pods" protobuf:"bytes,3,rep,name=pods"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// MulticastGroupList is a list of MulticastGroup. +type MulticastGroupList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"` + + // List of MulticastGroup. + Items []MulticastGroup `json:"items" protobuf:"bytes,2,rep,name=items"` +} + // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object // NetworkPolicyStatsList is a list of NetworkPolicyStats. @@ -96,6 +123,14 @@ type NetworkPolicyStatsList struct { Items []NetworkPolicyStats `json:"items" protobuf:"bytes,2,rep,name=items"` } +// PodReference represents a Pod Reference. +type PodReference struct { + // The name of this Pod. + Name string `json:"name,omitempty" protobuf:"bytes,1,opt,name=name"` + // The namespace of this Pod. + Namespace string `json:"namespace,omitempty" protobuf:"bytes,2,opt,name=namespace"` +} + // TrafficStats contains the traffic stats of a NetworkPolicy. type TrafficStats struct { // Packets is the packets count hit by the NetworkPolicy. diff --git a/pkg/apis/stats/v1alpha1/zz_generated.conversion.go b/pkg/apis/stats/v1alpha1/zz_generated.conversion.go index f2ba8f55d9c..223acb85361 100644 --- a/pkg/apis/stats/v1alpha1/zz_generated.conversion.go +++ b/pkg/apis/stats/v1alpha1/zz_generated.conversion.go @@ -1,7 +1,7 @@ //go:build !ignore_autogenerated // +build !ignore_autogenerated -// Copyright 2021 Antrea Authors +// Copyright 2022 Antrea Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -74,6 +74,26 @@ func RegisterConversions(s *runtime.Scheme) error { }); err != nil { return err } + if err := s.AddGeneratedConversionFunc((*MulticastGroup)(nil), (*stats.MulticastGroup)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha1_MulticastGroup_To_stats_MulticastGroup(a.(*MulticastGroup), b.(*stats.MulticastGroup), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*stats.MulticastGroup)(nil), (*MulticastGroup)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_stats_MulticastGroup_To_v1alpha1_MulticastGroup(a.(*stats.MulticastGroup), b.(*MulticastGroup), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*MulticastGroupList)(nil), (*stats.MulticastGroupList)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha1_MulticastGroupList_To_stats_MulticastGroupList(a.(*MulticastGroupList), b.(*stats.MulticastGroupList), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*stats.MulticastGroupList)(nil), (*MulticastGroupList)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_stats_MulticastGroupList_To_v1alpha1_MulticastGroupList(a.(*stats.MulticastGroupList), b.(*MulticastGroupList), scope) + }); err != nil { + return err + } if err := s.AddGeneratedConversionFunc((*NetworkPolicyStats)(nil), (*stats.NetworkPolicyStats)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_v1alpha1_NetworkPolicyStats_To_stats_NetworkPolicyStats(a.(*NetworkPolicyStats), b.(*stats.NetworkPolicyStats), scope) }); err != nil { @@ -94,6 +114,16 @@ func RegisterConversions(s *runtime.Scheme) error { }); err != nil { return err } + if err := s.AddGeneratedConversionFunc((*PodReference)(nil), (*stats.PodReference)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha1_PodReference_To_stats_PodReference(a.(*PodReference), b.(*stats.PodReference), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*stats.PodReference)(nil), (*PodReference)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_stats_PodReference_To_v1alpha1_PodReference(a.(*stats.PodReference), b.(*PodReference), scope) + }); err != nil { + return err + } if err := s.AddGeneratedConversionFunc((*RuleTrafficStats)(nil), (*stats.RuleTrafficStats)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_v1alpha1_RuleTrafficStats_To_stats_RuleTrafficStats(a.(*RuleTrafficStats), b.(*stats.RuleTrafficStats), scope) }); err != nil { @@ -217,6 +247,52 @@ func Convert_stats_AntreaNetworkPolicyStatsList_To_v1alpha1_AntreaNetworkPolicyS return autoConvert_stats_AntreaNetworkPolicyStatsList_To_v1alpha1_AntreaNetworkPolicyStatsList(in, out, s) } +func autoConvert_v1alpha1_MulticastGroup_To_stats_MulticastGroup(in *MulticastGroup, out *stats.MulticastGroup, s conversion.Scope) error { + out.ObjectMeta = in.ObjectMeta + out.Group = in.Group + out.Pods = *(*[]stats.PodReference)(unsafe.Pointer(&in.Pods)) + return nil +} + +// Convert_v1alpha1_MulticastGroup_To_stats_MulticastGroup is an autogenerated conversion function. +func Convert_v1alpha1_MulticastGroup_To_stats_MulticastGroup(in *MulticastGroup, out *stats.MulticastGroup, s conversion.Scope) error { + return autoConvert_v1alpha1_MulticastGroup_To_stats_MulticastGroup(in, out, s) +} + +func autoConvert_stats_MulticastGroup_To_v1alpha1_MulticastGroup(in *stats.MulticastGroup, out *MulticastGroup, s conversion.Scope) error { + out.ObjectMeta = in.ObjectMeta + out.Group = in.Group + out.Pods = *(*[]PodReference)(unsafe.Pointer(&in.Pods)) + return nil +} + +// Convert_stats_MulticastGroup_To_v1alpha1_MulticastGroup is an autogenerated conversion function. +func Convert_stats_MulticastGroup_To_v1alpha1_MulticastGroup(in *stats.MulticastGroup, out *MulticastGroup, s conversion.Scope) error { + return autoConvert_stats_MulticastGroup_To_v1alpha1_MulticastGroup(in, out, s) +} + +func autoConvert_v1alpha1_MulticastGroupList_To_stats_MulticastGroupList(in *MulticastGroupList, out *stats.MulticastGroupList, s conversion.Scope) error { + out.ListMeta = in.ListMeta + out.Items = *(*[]stats.MulticastGroup)(unsafe.Pointer(&in.Items)) + return nil +} + +// Convert_v1alpha1_MulticastGroupList_To_stats_MulticastGroupList is an autogenerated conversion function. +func Convert_v1alpha1_MulticastGroupList_To_stats_MulticastGroupList(in *MulticastGroupList, out *stats.MulticastGroupList, s conversion.Scope) error { + return autoConvert_v1alpha1_MulticastGroupList_To_stats_MulticastGroupList(in, out, s) +} + +func autoConvert_stats_MulticastGroupList_To_v1alpha1_MulticastGroupList(in *stats.MulticastGroupList, out *MulticastGroupList, s conversion.Scope) error { + out.ListMeta = in.ListMeta + out.Items = *(*[]MulticastGroup)(unsafe.Pointer(&in.Items)) + return nil +} + +// Convert_stats_MulticastGroupList_To_v1alpha1_MulticastGroupList is an autogenerated conversion function. +func Convert_stats_MulticastGroupList_To_v1alpha1_MulticastGroupList(in *stats.MulticastGroupList, out *MulticastGroupList, s conversion.Scope) error { + return autoConvert_stats_MulticastGroupList_To_v1alpha1_MulticastGroupList(in, out, s) +} + func autoConvert_v1alpha1_NetworkPolicyStats_To_stats_NetworkPolicyStats(in *NetworkPolicyStats, out *stats.NetworkPolicyStats, s conversion.Scope) error { out.ObjectMeta = in.ObjectMeta if err := Convert_v1alpha1_TrafficStats_To_stats_TrafficStats(&in.TrafficStats, &out.TrafficStats, s); err != nil { @@ -265,6 +341,28 @@ func Convert_stats_NetworkPolicyStatsList_To_v1alpha1_NetworkPolicyStatsList(in return autoConvert_stats_NetworkPolicyStatsList_To_v1alpha1_NetworkPolicyStatsList(in, out, s) } +func autoConvert_v1alpha1_PodReference_To_stats_PodReference(in *PodReference, out *stats.PodReference, s conversion.Scope) error { + out.Name = in.Name + out.Namespace = in.Namespace + return nil +} + +// Convert_v1alpha1_PodReference_To_stats_PodReference is an autogenerated conversion function. +func Convert_v1alpha1_PodReference_To_stats_PodReference(in *PodReference, out *stats.PodReference, s conversion.Scope) error { + return autoConvert_v1alpha1_PodReference_To_stats_PodReference(in, out, s) +} + +func autoConvert_stats_PodReference_To_v1alpha1_PodReference(in *stats.PodReference, out *PodReference, s conversion.Scope) error { + out.Name = in.Name + out.Namespace = in.Namespace + return nil +} + +// Convert_stats_PodReference_To_v1alpha1_PodReference is an autogenerated conversion function. +func Convert_stats_PodReference_To_v1alpha1_PodReference(in *stats.PodReference, out *PodReference, s conversion.Scope) error { + return autoConvert_stats_PodReference_To_v1alpha1_PodReference(in, out, s) +} + func autoConvert_v1alpha1_RuleTrafficStats_To_stats_RuleTrafficStats(in *RuleTrafficStats, out *stats.RuleTrafficStats, s conversion.Scope) error { out.Name = in.Name if err := Convert_v1alpha1_TrafficStats_To_stats_TrafficStats(&in.TrafficStats, &out.TrafficStats, s); err != nil { diff --git a/pkg/apis/stats/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/stats/v1alpha1/zz_generated.deepcopy.go index c5684b4d825..d1c3417a338 100644 --- a/pkg/apis/stats/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/stats/v1alpha1/zz_generated.deepcopy.go @@ -1,7 +1,7 @@ //go:build !ignore_autogenerated // +build !ignore_autogenerated -// Copyright 2021 Antrea Authors +// Copyright 2022 Antrea Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -153,6 +153,70 @@ func (in *AntreaNetworkPolicyStatsList) DeepCopyObject() runtime.Object { return nil } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *MulticastGroup) DeepCopyInto(out *MulticastGroup) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + if in.Pods != nil { + in, out := &in.Pods, &out.Pods + *out = make([]PodReference, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MulticastGroup. +func (in *MulticastGroup) DeepCopy() *MulticastGroup { + if in == nil { + return nil + } + out := new(MulticastGroup) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *MulticastGroup) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *MulticastGroupList) DeepCopyInto(out *MulticastGroupList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]MulticastGroup, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MulticastGroupList. +func (in *MulticastGroupList) DeepCopy() *MulticastGroupList { + if in == nil { + return nil + } + out := new(MulticastGroupList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *MulticastGroupList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *NetworkPolicyStats) DeepCopyInto(out *NetworkPolicyStats) { *out = *in @@ -213,6 +277,22 @@ func (in *NetworkPolicyStatsList) DeepCopyObject() runtime.Object { return nil } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PodReference) DeepCopyInto(out *PodReference) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodReference. +func (in *PodReference) DeepCopy() *PodReference { + if in == nil { + return nil + } + out := new(PodReference) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *RuleTrafficStats) DeepCopyInto(out *RuleTrafficStats) { *out = *in diff --git a/pkg/apis/stats/zz_generated.deepcopy.go b/pkg/apis/stats/zz_generated.deepcopy.go index 79273b68231..88b296afe19 100644 --- a/pkg/apis/stats/zz_generated.deepcopy.go +++ b/pkg/apis/stats/zz_generated.deepcopy.go @@ -1,7 +1,7 @@ //go:build !ignore_autogenerated // +build !ignore_autogenerated -// Copyright 2021 Antrea Authors +// Copyright 2022 Antrea Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -153,6 +153,70 @@ func (in *AntreaNetworkPolicyStatsList) DeepCopyObject() runtime.Object { return nil } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *MulticastGroup) DeepCopyInto(out *MulticastGroup) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + if in.Pods != nil { + in, out := &in.Pods, &out.Pods + *out = make([]PodReference, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MulticastGroup. +func (in *MulticastGroup) DeepCopy() *MulticastGroup { + if in == nil { + return nil + } + out := new(MulticastGroup) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *MulticastGroup) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *MulticastGroupList) DeepCopyInto(out *MulticastGroupList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]MulticastGroup, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MulticastGroupList. +func (in *MulticastGroupList) DeepCopy() *MulticastGroupList { + if in == nil { + return nil + } + out := new(MulticastGroupList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *MulticastGroupList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *NetworkPolicyStats) DeepCopyInto(out *NetworkPolicyStats) { *out = *in @@ -213,6 +277,22 @@ func (in *NetworkPolicyStatsList) DeepCopyObject() runtime.Object { return nil } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PodReference) DeepCopyInto(out *PodReference) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodReference. +func (in *PodReference) DeepCopy() *PodReference { + if in == nil { + return nil + } + out := new(PodReference) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *RuleTrafficStats) DeepCopyInto(out *RuleTrafficStats) { *out = *in diff --git a/pkg/apiserver/apiserver.go b/pkg/apiserver/apiserver.go index f5108803d95..aca1bb7f616 100644 --- a/pkg/apiserver/apiserver.go +++ b/pkg/apiserver/apiserver.go @@ -114,14 +114,14 @@ type APIServer struct { caCertController *certificate.CACertController } -func (s *APIServer) Run(stopCh <-chan struct{}) error { +func (s *APIServer) Run(ctx context.Context) error { // Make sure CACertController runs once to publish the CA cert before starting APIServer. - if err := s.caCertController.RunOnce(); err != nil { + if err := s.caCertController.RunOnce(ctx); err != nil { klog.Warningf("caCertController RunOnce failed: %v", err) } - go s.caCertController.Run(1, stopCh) + go s.caCertController.Run(ctx, 1) - return s.GenericAPIServer.PrepareRun().Run(stopCh) + return s.GenericAPIServer.PrepareRun().Run(ctx.Done()) } type completedConfig struct { diff --git a/pkg/apiserver/certificate/cacert_controller.go b/pkg/apiserver/certificate/cacert_controller.go index 0de71e59ba4..420a4775c70 100644 --- a/pkg/apiserver/certificate/cacert_controller.go +++ b/pkg/apiserver/certificate/cacert_controller.go @@ -83,9 +83,9 @@ func newCACertController(caContentProvider dynamiccertificates.CAContentProvider return c } -func (c *CACertController) UpdateCertificate() error { +func (c *CACertController) UpdateCertificate(ctx context.Context) error { if controller, ok := c.caContentProvider.(dynamiccertificates.ControllerRunner); ok { - if err := controller.RunOnce(); err != nil { + if err := controller.RunOnce(ctx); err != nil { klog.Warningf("Updating of CA content failed: %v", err) c.Enqueue() return err @@ -288,9 +288,9 @@ func (c *CACertController) syncConfigMap(caCert []byte) error { } // RunOnce runs a single sync step to ensure that we have a valid starting configuration. -func (c *CACertController) RunOnce() error { +func (c *CACertController) RunOnce(ctx context.Context) error { if controller, ok := c.caContentProvider.(dynamiccertificates.ControllerRunner); ok { - if err := controller.RunOnce(); err != nil { + if err := controller.RunOnce(ctx); err != nil { klog.Warningf("Initial population of CA content failed: %v", err) c.Enqueue() return err @@ -304,20 +304,22 @@ func (c *CACertController) RunOnce() error { return nil } -// Run starts the CACertController and blocks until stopCh is closed. -func (c *CACertController) Run(workers int, stopCh <-chan struct{}) { +// Run starts the CACertController and blocks until the context is canceled. +func (c *CACertController) Run(ctx context.Context, workers int) { defer c.queue.ShutDown() klog.Infof("Starting CACertController") defer klog.Infof("Shutting down CACertController") if controller, ok := c.caContentProvider.(dynamiccertificates.ControllerRunner); ok { - go controller.Run(1, stopCh) + // doesn't matter what workers say, only start one. + go controller.Run(ctx, 1) } - go wait.Until(c.runWorker, time.Second, stopCh) + // doesn't matter what workers say, only start one. + go wait.Until(c.runWorker, time.Second, ctx.Done()) - <-stopCh + <-ctx.Done() } func (c *CACertController) runWorker() { diff --git a/pkg/apiserver/certificate/certificate.go b/pkg/apiserver/certificate/certificate.go index 93fc3e7a193..fb24d427225 100644 --- a/pkg/apiserver/certificate/certificate.go +++ b/pkg/apiserver/certificate/certificate.go @@ -15,6 +15,7 @@ package certificate import ( + "context" "fmt" "net" "os" @@ -169,7 +170,7 @@ func rotateSelfSignedCertificates(c *CACertController, secureServing *options.Se klog.Errorf("error generating new cert: %v", err) return } - c.UpdateCertificate() + c.UpdateCertificate(context.TODO()) } } diff --git a/pkg/apiserver/handlers/featuregates/handler_test.go b/pkg/apiserver/handlers/featuregates/handler_test.go index ec2d2921026..05bb8f1d28f 100644 --- a/pkg/apiserver/handlers/featuregates/handler_test.go +++ b/pkg/apiserver/handlers/featuregates/handler_test.go @@ -29,6 +29,12 @@ import ( "k8s.io/client-go/kubernetes/fake" "antrea.io/antrea/pkg/features" + "antrea.io/antrea/pkg/util/runtime" +) + +var ( + egressStatus string + nplStatus string ) func Test_getGatesResponse(t *testing.T) { @@ -47,13 +53,13 @@ func Test_getGatesResponse(t *testing.T) { want: []Response{ {Component: "agent", Name: "AntreaPolicy", Status: "Disabled", Version: "BETA"}, {Component: "agent", Name: "AntreaProxy", Status: "Enabled", Version: "BETA"}, - {Component: "agent", Name: "Egress", Status: "Enabled", Version: "BETA"}, + {Component: "agent", Name: "Egress", Status: egressStatus, Version: "BETA"}, {Component: "agent", Name: "EndpointSlice", Status: "Disabled", Version: "ALPHA"}, {Component: "agent", Name: "AntreaIPAM", Status: "Disabled", Version: "ALPHA"}, {Component: "agent", Name: "Traceflow", Status: "Enabled", Version: "BETA"}, {Component: "agent", Name: "FlowExporter", Status: "Disabled", Version: "ALPHA"}, {Component: "agent", Name: "NetworkPolicyStats", Status: "Enabled", Version: "BETA"}, - {Component: "agent", Name: "NodePortLocal", Status: "Enabled", Version: "BETA"}, + {Component: "agent", Name: "NodePortLocal", Status: nplStatus, Version: "BETA"}, {Component: "agent", Name: "Multicast", Status: "Disabled", Version: "ALPHA"}, {Component: "agent", Name: "ServiceExternalIP", Status: "Disabled", Version: "ALPHA"}, }, @@ -128,30 +134,12 @@ func TestHandleFunc(t *testing.T) { ) tests := []struct { - name string - expectedStatus int - expectedResponse []Response + name string + expectedStatus int }{ { name: "good path", expectedStatus: http.StatusOK, - expectedResponse: []Response{ - {Component: "controller", Name: "AntreaPolicy", Status: "Enabled", Version: "BETA"}, - {Component: "controller", Name: "Egress", Status: "Disabled", Version: "ALPHA"}, - {Component: "controller", Name: "Traceflow", Status: "Enabled", Version: "BETA"}, - {Component: "controller", Name: "NetworkPolicyStats", Status: "Enabled", Version: "BETA"}, - {Component: "controller", Name: "NodeIPAM", Status: "Disabled", Version: "ALPHA"}, - {Component: "controller", Name: "ServiceExternalIP", Status: "Disabled", Version: "ALPHA"}, - {Component: "agent", Name: "AntreaPolicy", Status: "Enabled", Version: "BETA"}, - {Component: "agent", Name: "AntreaProxy", Status: "Enabled", Version: "BETA"}, - {Component: "agent", Name: "Egress", Status: "Disabled", Version: "ALPHA"}, - {Component: "agent", Name: "EndpointSlice", Status: "Disabled", Version: "ALPHA"}, - {Component: "agent", Name: "Traceflow", Status: "Enabled", Version: "BETA"}, - {Component: "agent", Name: "FlowExporter", Status: "Disabled", Version: "ALPHA"}, - {Component: "agent", Name: "NetworkPolicyStats", Status: "Enabled", Version: "BETA"}, - {Component: "agent", Name: "NodePortLocal", Status: "Enabled", Version: "BETA"}, - {Component: "agent", Name: "ServiceExternalIP", Status: "Disabled", Version: "ALPHA"}, - }, }, } os.Setenv("POD_NAME", "antrea-controller-wotqiwth") @@ -191,7 +179,7 @@ func Test_getControllerGatesResponse(t *testing.T) { name: "good path", want: []Response{ {Component: "controller", Name: "AntreaPolicy", Status: "Enabled", Version: "BETA"}, - {Component: "controller", Name: "Egress", Status: "Enabled", Version: "BETA"}, + {Component: "controller", Name: "Egress", Status: egressStatus, Version: "BETA"}, {Component: "controller", Name: "Traceflow", Status: "Enabled", Version: "BETA"}, {Component: "controller", Name: "NetworkPolicyStats", Status: "Enabled", Version: "BETA"}, {Component: "controller", Name: "NodeIPAM", Status: "Disabled", Version: "ALPHA"}, @@ -214,3 +202,11 @@ func Test_getControllerGatesResponse(t *testing.T) { }) } } + +func init() { + egressStatus = "Enabled" + nplStatus = "Enabled" + if runtime.IsWindowsPlatform() { + egressStatus = "Disabled" + } +} diff --git a/pkg/apiserver/handlers/loglevel/handler.go b/pkg/apiserver/handlers/loglevel/handler.go index 9c4ccf9b534..9dc9f470955 100644 --- a/pkg/apiserver/handlers/loglevel/handler.go +++ b/pkg/apiserver/handlers/loglevel/handler.go @@ -29,8 +29,11 @@ func HandleFunc() http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { level := r.URL.Query().Get("level") if level != "" { - err := log.SetLogLevel(level) - if err != nil { + if levelNum, err := strconv.Atoi(level); err != nil || levelNum < 0 { + http.Error(w, "log level must be a positive integer", http.StatusBadRequest) + return + } + if err := log.SetLogLevel(level); err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } @@ -39,7 +42,7 @@ func HandleFunc() http.HandlerFunc { err := json.NewEncoder(w).Encode(levelNum) if err != nil { w.WriteHeader(http.StatusInternalServerError) - klog.Errorf("Error when encoding log level to json: %v", err) + klog.ErrorS(err, "Error when encoding log level to json") } } } diff --git a/pkg/apiserver/openapi/zz_generated.openapi.go b/pkg/apiserver/openapi/zz_generated.openapi.go index 361ab3de44a..ae42535cc6a 100644 --- a/pkg/apiserver/openapi/zz_generated.openapi.go +++ b/pkg/apiserver/openapi/zz_generated.openapi.go @@ -22,10 +22,10 @@ package openapi import ( - spec "github.com/go-openapi/spec" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" intstr "k8s.io/apimachinery/pkg/util/intstr" common "k8s.io/kube-openapi/pkg/common" + spec "k8s.io/kube-openapi/pkg/validation/spec" ) func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenAPIDefinition { @@ -46,6 +46,7 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "antrea.io/antrea/pkg/apis/controlplane/v1beta2.GroupReference": schema_pkg_apis_controlplane_v1beta2_GroupReference(ref), "antrea.io/antrea/pkg/apis/controlplane/v1beta2.IPBlock": schema_pkg_apis_controlplane_v1beta2_IPBlock(ref), "antrea.io/antrea/pkg/apis/controlplane/v1beta2.IPNet": schema_pkg_apis_controlplane_v1beta2_IPNet(ref), + "antrea.io/antrea/pkg/apis/controlplane/v1beta2.MulticastGroupInfo": schema_pkg_apis_controlplane_v1beta2_MulticastGroupInfo(ref), "antrea.io/antrea/pkg/apis/controlplane/v1beta2.NamedPort": schema_pkg_apis_controlplane_v1beta2_NamedPort(ref), "antrea.io/antrea/pkg/apis/controlplane/v1beta2.NetworkPolicy": schema_pkg_apis_controlplane_v1beta2_NetworkPolicy(ref), "antrea.io/antrea/pkg/apis/controlplane/v1beta2.NetworkPolicyList": schema_pkg_apis_controlplane_v1beta2_NetworkPolicyList(ref), @@ -73,8 +74,11 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "antrea.io/antrea/pkg/apis/stats/v1alpha1.AntreaClusterNetworkPolicyStatsList": schema_pkg_apis_stats_v1alpha1_AntreaClusterNetworkPolicyStatsList(ref), "antrea.io/antrea/pkg/apis/stats/v1alpha1.AntreaNetworkPolicyStats": schema_pkg_apis_stats_v1alpha1_AntreaNetworkPolicyStats(ref), "antrea.io/antrea/pkg/apis/stats/v1alpha1.AntreaNetworkPolicyStatsList": schema_pkg_apis_stats_v1alpha1_AntreaNetworkPolicyStatsList(ref), + "antrea.io/antrea/pkg/apis/stats/v1alpha1.MulticastGroup": schema_pkg_apis_stats_v1alpha1_MulticastGroup(ref), + "antrea.io/antrea/pkg/apis/stats/v1alpha1.MulticastGroupList": schema_pkg_apis_stats_v1alpha1_MulticastGroupList(ref), "antrea.io/antrea/pkg/apis/stats/v1alpha1.NetworkPolicyStats": schema_pkg_apis_stats_v1alpha1_NetworkPolicyStats(ref), "antrea.io/antrea/pkg/apis/stats/v1alpha1.NetworkPolicyStatsList": schema_pkg_apis_stats_v1alpha1_NetworkPolicyStatsList(ref), + "antrea.io/antrea/pkg/apis/stats/v1alpha1.PodReference": schema_pkg_apis_stats_v1alpha1_PodReference(ref), "antrea.io/antrea/pkg/apis/stats/v1alpha1.RuleTrafficStats": schema_pkg_apis_stats_v1alpha1_RuleTrafficStats(ref), "antrea.io/antrea/pkg/apis/stats/v1alpha1.TrafficStats": schema_pkg_apis_stats_v1alpha1_TrafficStats(ref), "antrea.io/antrea/pkg/apis/system/v1beta1.SupportBundle": schema_pkg_apis_system_v1beta1_SupportBundle(ref), @@ -127,7 +131,6 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "k8s.io/api/core/v1.EnvVarSource": schema_k8sio_api_core_v1_EnvVarSource(ref), "k8s.io/api/core/v1.EphemeralContainer": schema_k8sio_api_core_v1_EphemeralContainer(ref), "k8s.io/api/core/v1.EphemeralContainerCommon": schema_k8sio_api_core_v1_EphemeralContainerCommon(ref), - "k8s.io/api/core/v1.EphemeralContainers": schema_k8sio_api_core_v1_EphemeralContainers(ref), "k8s.io/api/core/v1.EphemeralVolumeSource": schema_k8sio_api_core_v1_EphemeralVolumeSource(ref), "k8s.io/api/core/v1.Event": schema_k8sio_api_core_v1_Event(ref), "k8s.io/api/core/v1.EventList": schema_k8sio_api_core_v1_EventList(ref), @@ -139,18 +142,19 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "k8s.io/api/core/v1.FlexVolumeSource": schema_k8sio_api_core_v1_FlexVolumeSource(ref), "k8s.io/api/core/v1.FlockerVolumeSource": schema_k8sio_api_core_v1_FlockerVolumeSource(ref), "k8s.io/api/core/v1.GCEPersistentDiskVolumeSource": schema_k8sio_api_core_v1_GCEPersistentDiskVolumeSource(ref), + "k8s.io/api/core/v1.GRPCAction": schema_k8sio_api_core_v1_GRPCAction(ref), "k8s.io/api/core/v1.GitRepoVolumeSource": schema_k8sio_api_core_v1_GitRepoVolumeSource(ref), "k8s.io/api/core/v1.GlusterfsPersistentVolumeSource": schema_k8sio_api_core_v1_GlusterfsPersistentVolumeSource(ref), "k8s.io/api/core/v1.GlusterfsVolumeSource": schema_k8sio_api_core_v1_GlusterfsVolumeSource(ref), "k8s.io/api/core/v1.HTTPGetAction": schema_k8sio_api_core_v1_HTTPGetAction(ref), "k8s.io/api/core/v1.HTTPHeader": schema_k8sio_api_core_v1_HTTPHeader(ref), - "k8s.io/api/core/v1.Handler": schema_k8sio_api_core_v1_Handler(ref), "k8s.io/api/core/v1.HostAlias": schema_k8sio_api_core_v1_HostAlias(ref), "k8s.io/api/core/v1.HostPathVolumeSource": schema_k8sio_api_core_v1_HostPathVolumeSource(ref), "k8s.io/api/core/v1.ISCSIPersistentVolumeSource": schema_k8sio_api_core_v1_ISCSIPersistentVolumeSource(ref), "k8s.io/api/core/v1.ISCSIVolumeSource": schema_k8sio_api_core_v1_ISCSIVolumeSource(ref), "k8s.io/api/core/v1.KeyToPath": schema_k8sio_api_core_v1_KeyToPath(ref), "k8s.io/api/core/v1.Lifecycle": schema_k8sio_api_core_v1_Lifecycle(ref), + "k8s.io/api/core/v1.LifecycleHandler": schema_k8sio_api_core_v1_LifecycleHandler(ref), "k8s.io/api/core/v1.LimitRange": schema_k8sio_api_core_v1_LimitRange(ref), "k8s.io/api/core/v1.LimitRangeItem": schema_k8sio_api_core_v1_LimitRangeItem(ref), "k8s.io/api/core/v1.LimitRangeList": schema_k8sio_api_core_v1_LimitRangeList(ref), @@ -209,6 +213,7 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "k8s.io/api/core/v1.PodIP": schema_k8sio_api_core_v1_PodIP(ref), "k8s.io/api/core/v1.PodList": schema_k8sio_api_core_v1_PodList(ref), "k8s.io/api/core/v1.PodLogOptions": schema_k8sio_api_core_v1_PodLogOptions(ref), + "k8s.io/api/core/v1.PodOS": schema_k8sio_api_core_v1_PodOS(ref), "k8s.io/api/core/v1.PodPortForwardOptions": schema_k8sio_api_core_v1_PodPortForwardOptions(ref), "k8s.io/api/core/v1.PodProxyOptions": schema_k8sio_api_core_v1_PodProxyOptions(ref), "k8s.io/api/core/v1.PodReadinessGate": schema_k8sio_api_core_v1_PodReadinessGate(ref), @@ -225,6 +230,7 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "k8s.io/api/core/v1.PreferAvoidPodsEntry": schema_k8sio_api_core_v1_PreferAvoidPodsEntry(ref), "k8s.io/api/core/v1.PreferredSchedulingTerm": schema_k8sio_api_core_v1_PreferredSchedulingTerm(ref), "k8s.io/api/core/v1.Probe": schema_k8sio_api_core_v1_Probe(ref), + "k8s.io/api/core/v1.ProbeHandler": schema_k8sio_api_core_v1_ProbeHandler(ref), "k8s.io/api/core/v1.ProjectedVolumeSource": schema_k8sio_api_core_v1_ProjectedVolumeSource(ref), "k8s.io/api/core/v1.QuobyteVolumeSource": schema_k8sio_api_core_v1_QuobyteVolumeSource(ref), "k8s.io/api/core/v1.RBDPersistentVolumeSource": schema_k8sio_api_core_v1_RBDPersistentVolumeSource(ref), @@ -1124,6 +1130,42 @@ func schema_pkg_apis_controlplane_v1beta2_IPNet(ref common.ReferenceCallback) co } } +func schema_pkg_apis_controlplane_v1beta2_MulticastGroupInfo(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "MulticastGroupInfo contains the list of Pods that have joined a multicast group, for a given Node.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "group": { + SchemaProps: spec.SchemaProps{ + Description: "Group is the IP of the multicast group.", + Type: []string{"string"}, + Format: "", + }, + }, + "pods": { + SchemaProps: spec.SchemaProps{ + Description: "Pods is the list of Pods that have joined the multicast group.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("antrea.io/antrea/pkg/apis/controlplane/v1beta2.PodReference"), + }, + }, + }, + }, + }, + }, + }, + }, + Dependencies: []string{ + "antrea.io/antrea/pkg/apis/controlplane/v1beta2.PodReference"}, + } +} + func schema_pkg_apis_controlplane_v1beta2_NamedPort(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ @@ -1707,11 +1749,25 @@ func schema_pkg_apis_controlplane_v1beta2_NodeStatsSummary(ref common.ReferenceC }, }, }, + "multicast": { + SchemaProps: spec.SchemaProps{ + Description: "Multicast group information collected from the Node.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("antrea.io/antrea/pkg/apis/controlplane/v1beta2.MulticastGroupInfo"), + }, + }, + }, + }, + }, }, }, }, Dependencies: []string{ - "antrea.io/antrea/pkg/apis/controlplane/v1beta2.NetworkPolicyStats", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"}, + "antrea.io/antrea/pkg/apis/controlplane/v1beta2.MulticastGroupInfo", "antrea.io/antrea/pkg/apis/controlplane/v1beta2.NetworkPolicyStats", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"}, } } @@ -1792,14 +1848,14 @@ func schema_pkg_apis_controlplane_v1beta2_Service(ref common.ReferenceCallback) Properties: map[string]spec.Schema{ "protocol": { SchemaProps: spec.SchemaProps{ - Description: "The protocol (TCP, UDP, or SCTP) which traffic must match. If not specified, this field defaults to TCP.", + Description: "The protocol (TCP, UDP, SCTP, or ICMP) which traffic must match. If not specified, this field defaults to TCP.", Type: []string{"string"}, Format: "", }, }, "port": { SchemaProps: spec.SchemaProps{ - Description: "The port name or number on the given protocol. If not specified, this matches all port numbers.", + Description: "Port and EndPort can only be specified, when the Protocol is TCP, UDP, or SCTP. Port defines the port name or number on the given protocol. If not specified and the Protocol is TCP, UDP, or SCTP, this matches all port numbers.", Ref: ref("k8s.io/apimachinery/pkg/util/intstr.IntOrString"), }, }, @@ -1810,6 +1866,19 @@ func schema_pkg_apis_controlplane_v1beta2_Service(ref common.ReferenceCallback) Format: "int32", }, }, + "icmpType": { + SchemaProps: spec.SchemaProps{ + Description: "ICMPType and ICMPCode can only be specified, when the Protocol is ICMP. If they both are not specified and the Protocol is ICMP, this matches all ICMP traffic.", + Type: []string{"integer"}, + Format: "int32", + }, + }, + "icmpCode": { + SchemaProps: spec.SchemaProps{ + Type: []string{"integer"}, + Format: "int32", + }, + }, }, }, }, @@ -2531,6 +2600,113 @@ func schema_pkg_apis_stats_v1alpha1_AntreaNetworkPolicyStatsList(ref common.Refe } } +func schema_pkg_apis_stats_v1alpha1_MulticastGroup(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "MulticastGroup contains the mapping between multicast group and Pods.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "metadata": { + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"), + }, + }, + "group": { + SchemaProps: spec.SchemaProps{ + Description: "Group is the IP of the multicast group.", + Type: []string{"string"}, + Format: "", + }, + }, + "pods": { + SchemaProps: spec.SchemaProps{ + Description: "Pods is the list of Pods that have joined the multicast group.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("antrea.io/antrea/pkg/apis/stats/v1alpha1.PodReference"), + }, + }, + }, + }, + }, + }, + Required: []string{"pods"}, + }, + }, + Dependencies: []string{ + "antrea.io/antrea/pkg/apis/stats/v1alpha1.PodReference", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"}, + } +} + +func schema_pkg_apis_stats_v1alpha1_MulticastGroupList(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "MulticastGroupList is a list of MulticastGroup.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "metadata": { + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"), + }, + }, + "items": { + SchemaProps: spec.SchemaProps{ + Description: "List of MulticastGroup.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("antrea.io/antrea/pkg/apis/stats/v1alpha1.MulticastGroup"), + }, + }, + }, + }, + }, + }, + Required: []string{"items"}, + }, + }, + Dependencies: []string{ + "antrea.io/antrea/pkg/apis/stats/v1alpha1.MulticastGroup", "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"}, + } +} + func schema_pkg_apis_stats_v1alpha1_NetworkPolicyStats(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ @@ -2623,6 +2799,33 @@ func schema_pkg_apis_stats_v1alpha1_NetworkPolicyStatsList(ref common.ReferenceC } } +func schema_pkg_apis_stats_v1alpha1_PodReference(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "PodReference represents a Pod Reference.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "name": { + SchemaProps: spec.SchemaProps{ + Description: "The name of this Pod.", + Type: []string{"string"}, + Format: "", + }, + }, + "namespace": { + SchemaProps: spec.SchemaProps{ + Description: "The namespace of this Pod.", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + } +} + func schema_pkg_apis_stats_v1alpha1_RuleTrafficStats(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ @@ -2751,7 +2954,7 @@ func schema_k8sio_api_core_v1_AWSElasticBlockStoreVolumeSource(ref common.Refere Properties: map[string]spec.Schema{ "volumeID": { SchemaProps: spec.SchemaProps{ - Description: "Unique ID of the persistent disk resource in AWS (Amazon EBS volume). More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore", + Description: "volumeID is unique ID of the persistent disk resource in AWS (Amazon EBS volume). More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore", Default: "", Type: []string{"string"}, Format: "", @@ -2759,21 +2962,21 @@ func schema_k8sio_api_core_v1_AWSElasticBlockStoreVolumeSource(ref common.Refere }, "fsType": { SchemaProps: spec.SchemaProps{ - Description: "Filesystem type of the volume that you want to mount. Tip: Ensure that the filesystem type is supported by the host operating system. Examples: \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore", + Description: "fsType is the filesystem type of the volume that you want to mount. Tip: Ensure that the filesystem type is supported by the host operating system. Examples: \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore", Type: []string{"string"}, Format: "", }, }, "partition": { SchemaProps: spec.SchemaProps{ - Description: "The partition in the volume that you want to mount. If omitted, the default is to mount by volume name. Examples: For volume /dev/sda1, you specify the partition as \"1\". Similarly, the volume partition for /dev/sda is \"0\" (or you can leave the property empty).", + Description: "partition is the partition in the volume that you want to mount. If omitted, the default is to mount by volume name. Examples: For volume /dev/sda1, you specify the partition as \"1\". Similarly, the volume partition for /dev/sda is \"0\" (or you can leave the property empty).", Type: []string{"integer"}, Format: "int32", }, }, "readOnly": { SchemaProps: spec.SchemaProps{ - Description: "Specify \"true\" to force and set the ReadOnly property in VolumeMounts to \"true\". If omitted, the default is \"false\". More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore", + Description: "readOnly value true will force the readOnly setting in VolumeMounts. More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore", Type: []string{"boolean"}, Format: "", }, @@ -2886,7 +3089,7 @@ func schema_k8sio_api_core_v1_AzureDiskVolumeSource(ref common.ReferenceCallback Properties: map[string]spec.Schema{ "diskName": { SchemaProps: spec.SchemaProps{ - Description: "The Name of the data disk in the blob storage", + Description: "diskName is the Name of the data disk in the blob storage", Default: "", Type: []string{"string"}, Format: "", @@ -2894,7 +3097,7 @@ func schema_k8sio_api_core_v1_AzureDiskVolumeSource(ref common.ReferenceCallback }, "diskURI": { SchemaProps: spec.SchemaProps{ - Description: "The URI the data disk in the blob storage", + Description: "diskURI is the URI of data disk in the blob storage", Default: "", Type: []string{"string"}, Format: "", @@ -2902,28 +3105,28 @@ func schema_k8sio_api_core_v1_AzureDiskVolumeSource(ref common.ReferenceCallback }, "cachingMode": { SchemaProps: spec.SchemaProps{ - Description: "Host Caching mode: None, Read Only, Read Write.", + Description: "cachingMode is the Host Caching mode: None, Read Only, Read Write.", Type: []string{"string"}, Format: "", }, }, "fsType": { SchemaProps: spec.SchemaProps{ - Description: "Filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified.", + Description: "fsType is Filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified.", Type: []string{"string"}, Format: "", }, }, "readOnly": { SchemaProps: spec.SchemaProps{ - Description: "Defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts.", + Description: "readOnly Defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts.", Type: []string{"boolean"}, Format: "", }, }, "kind": { SchemaProps: spec.SchemaProps{ - Description: "Expected values Shared: multiple blob disks per storage account Dedicated: single blob disk per storage account Managed: azure managed data disk (only in managed availability set). defaults to shared", + Description: "kind expected values are Shared: multiple blob disks per storage account Dedicated: single blob disk per storage account Managed: azure managed data disk (only in managed availability set). defaults to shared", Type: []string{"string"}, Format: "", }, @@ -2944,7 +3147,7 @@ func schema_k8sio_api_core_v1_AzureFilePersistentVolumeSource(ref common.Referen Properties: map[string]spec.Schema{ "secretName": { SchemaProps: spec.SchemaProps{ - Description: "the name of secret that contains Azure Storage Account Name and Key", + Description: "secretName is the name of secret that contains Azure Storage Account Name and Key", Default: "", Type: []string{"string"}, Format: "", @@ -2952,7 +3155,7 @@ func schema_k8sio_api_core_v1_AzureFilePersistentVolumeSource(ref common.Referen }, "shareName": { SchemaProps: spec.SchemaProps{ - Description: "Share Name", + Description: "shareName is the azure Share Name", Default: "", Type: []string{"string"}, Format: "", @@ -2960,14 +3163,14 @@ func schema_k8sio_api_core_v1_AzureFilePersistentVolumeSource(ref common.Referen }, "readOnly": { SchemaProps: spec.SchemaProps{ - Description: "Defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts.", + Description: "readOnly defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts.", Type: []string{"boolean"}, Format: "", }, }, "secretNamespace": { SchemaProps: spec.SchemaProps{ - Description: "the namespace of the secret that contains Azure Storage Account Name and Key default is the same as the Pod", + Description: "secretNamespace is the namespace of the secret that contains Azure Storage Account Name and Key default is the same as the Pod", Type: []string{"string"}, Format: "", }, @@ -2988,7 +3191,7 @@ func schema_k8sio_api_core_v1_AzureFileVolumeSource(ref common.ReferenceCallback Properties: map[string]spec.Schema{ "secretName": { SchemaProps: spec.SchemaProps{ - Description: "the name of secret that contains Azure Storage Account Name and Key", + Description: "secretName is the name of secret that contains Azure Storage Account Name and Key", Default: "", Type: []string{"string"}, Format: "", @@ -2996,7 +3199,7 @@ func schema_k8sio_api_core_v1_AzureFileVolumeSource(ref common.ReferenceCallback }, "shareName": { SchemaProps: spec.SchemaProps{ - Description: "Share Name", + Description: "shareName is the azure share Name", Default: "", Type: []string{"string"}, Format: "", @@ -3004,7 +3207,7 @@ func schema_k8sio_api_core_v1_AzureFileVolumeSource(ref common.ReferenceCallback }, "readOnly": { SchemaProps: spec.SchemaProps{ - Description: "Defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts.", + Description: "readOnly defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts.", Type: []string{"boolean"}, Format: "", }, @@ -3069,7 +3272,7 @@ func schema_k8sio_api_core_v1_CSIPersistentVolumeSource(ref common.ReferenceCall Properties: map[string]spec.Schema{ "driver": { SchemaProps: spec.SchemaProps{ - Description: "Driver is the name of the driver to use for this volume. Required.", + Description: "driver is the name of the driver to use for this volume. Required.", Default: "", Type: []string{"string"}, Format: "", @@ -3077,7 +3280,7 @@ func schema_k8sio_api_core_v1_CSIPersistentVolumeSource(ref common.ReferenceCall }, "volumeHandle": { SchemaProps: spec.SchemaProps{ - Description: "VolumeHandle is the unique volume name returned by the CSI volume plugin’s CreateVolume to refer to the volume on all subsequent calls. Required.", + Description: "volumeHandle is the unique volume name returned by the CSI volume plugin’s CreateVolume to refer to the volume on all subsequent calls. Required.", Default: "", Type: []string{"string"}, Format: "", @@ -3085,21 +3288,21 @@ func schema_k8sio_api_core_v1_CSIPersistentVolumeSource(ref common.ReferenceCall }, "readOnly": { SchemaProps: spec.SchemaProps{ - Description: "Optional: The value to pass to ControllerPublishVolumeRequest. Defaults to false (read/write).", + Description: "readOnly value to pass to ControllerPublishVolumeRequest. Defaults to false (read/write).", Type: []string{"boolean"}, Format: "", }, }, "fsType": { SchemaProps: spec.SchemaProps{ - Description: "Filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. \"ext4\", \"xfs\", \"ntfs\".", + Description: "fsType to mount. Must be a filesystem type supported by the host operating system. Ex. \"ext4\", \"xfs\", \"ntfs\".", Type: []string{"string"}, Format: "", }, }, "volumeAttributes": { SchemaProps: spec.SchemaProps{ - Description: "Attributes of the volume to publish.", + Description: "volumeAttributes of the volume to publish.", Type: []string{"object"}, AdditionalProperties: &spec.SchemaOrBool{ Allows: true, @@ -3115,25 +3318,25 @@ func schema_k8sio_api_core_v1_CSIPersistentVolumeSource(ref common.ReferenceCall }, "controllerPublishSecretRef": { SchemaProps: spec.SchemaProps{ - Description: "ControllerPublishSecretRef is a reference to the secret object containing sensitive information to pass to the CSI driver to complete the CSI ControllerPublishVolume and ControllerUnpublishVolume calls. This field is optional, and may be empty if no secret is required. If the secret object contains more than one secret, all secrets are passed.", + Description: "controllerPublishSecretRef is a reference to the secret object containing sensitive information to pass to the CSI driver to complete the CSI ControllerPublishVolume and ControllerUnpublishVolume calls. This field is optional, and may be empty if no secret is required. If the secret object contains more than one secret, all secrets are passed.", Ref: ref("k8s.io/api/core/v1.SecretReference"), }, }, "nodeStageSecretRef": { SchemaProps: spec.SchemaProps{ - Description: "NodeStageSecretRef is a reference to the secret object containing sensitive information to pass to the CSI driver to complete the CSI NodeStageVolume and NodeStageVolume and NodeUnstageVolume calls. This field is optional, and may be empty if no secret is required. If the secret object contains more than one secret, all secrets are passed.", + Description: "nodeStageSecretRef is a reference to the secret object containing sensitive information to pass to the CSI driver to complete the CSI NodeStageVolume and NodeStageVolume and NodeUnstageVolume calls. This field is optional, and may be empty if no secret is required. If the secret object contains more than one secret, all secrets are passed.", Ref: ref("k8s.io/api/core/v1.SecretReference"), }, }, "nodePublishSecretRef": { SchemaProps: spec.SchemaProps{ - Description: "NodePublishSecretRef is a reference to the secret object containing sensitive information to pass to the CSI driver to complete the CSI NodePublishVolume and NodeUnpublishVolume calls. This field is optional, and may be empty if no secret is required. If the secret object contains more than one secret, all secrets are passed.", + Description: "nodePublishSecretRef is a reference to the secret object containing sensitive information to pass to the CSI driver to complete the CSI NodePublishVolume and NodeUnpublishVolume calls. This field is optional, and may be empty if no secret is required. If the secret object contains more than one secret, all secrets are passed.", Ref: ref("k8s.io/api/core/v1.SecretReference"), }, }, "controllerExpandSecretRef": { SchemaProps: spec.SchemaProps{ - Description: "ControllerExpandSecretRef is a reference to the secret object containing sensitive information to pass to the CSI driver to complete the CSI ControllerExpandVolume call. This is an alpha field and requires enabling ExpandCSIVolumes feature gate. This field is optional, and may be empty if no secret is required. If the secret object contains more than one secret, all secrets are passed.", + Description: "controllerExpandSecretRef is a reference to the secret object containing sensitive information to pass to the CSI driver to complete the CSI ControllerExpandVolume call. This is an alpha field and requires enabling ExpandCSIVolumes feature gate. This field is optional, and may be empty if no secret is required. If the secret object contains more than one secret, all secrets are passed.", Ref: ref("k8s.io/api/core/v1.SecretReference"), }, }, @@ -3155,7 +3358,7 @@ func schema_k8sio_api_core_v1_CSIVolumeSource(ref common.ReferenceCallback) comm Properties: map[string]spec.Schema{ "driver": { SchemaProps: spec.SchemaProps{ - Description: "Driver is the name of the CSI driver that handles this volume. Consult with your admin for the correct name as registered in the cluster.", + Description: "driver is the name of the CSI driver that handles this volume. Consult with your admin for the correct name as registered in the cluster.", Default: "", Type: []string{"string"}, Format: "", @@ -3163,21 +3366,21 @@ func schema_k8sio_api_core_v1_CSIVolumeSource(ref common.ReferenceCallback) comm }, "readOnly": { SchemaProps: spec.SchemaProps{ - Description: "Specifies a read-only configuration for the volume. Defaults to false (read/write).", + Description: "readOnly specifies a read-only configuration for the volume. Defaults to false (read/write).", Type: []string{"boolean"}, Format: "", }, }, "fsType": { SchemaProps: spec.SchemaProps{ - Description: "Filesystem type to mount. Ex. \"ext4\", \"xfs\", \"ntfs\". If not provided, the empty value is passed to the associated CSI driver which will determine the default filesystem to apply.", + Description: "fsType to mount. Ex. \"ext4\", \"xfs\", \"ntfs\". If not provided, the empty value is passed to the associated CSI driver which will determine the default filesystem to apply.", Type: []string{"string"}, Format: "", }, }, "volumeAttributes": { SchemaProps: spec.SchemaProps{ - Description: "VolumeAttributes stores driver-specific properties that are passed to the CSI driver. Consult your driver's documentation for supported values.", + Description: "volumeAttributes stores driver-specific properties that are passed to the CSI driver. Consult your driver's documentation for supported values.", Type: []string{"object"}, AdditionalProperties: &spec.SchemaOrBool{ Allows: true, @@ -3193,7 +3396,7 @@ func schema_k8sio_api_core_v1_CSIVolumeSource(ref common.ReferenceCallback) comm }, "nodePublishSecretRef": { SchemaProps: spec.SchemaProps{ - Description: "NodePublishSecretRef is a reference to the secret object containing sensitive information to pass to the CSI driver to complete the CSI NodePublishVolume and NodeUnpublishVolume calls. This field is optional, and may be empty if no secret is required. If the secret object contains more than one secret, all secret references are passed.", + Description: "nodePublishSecretRef is a reference to the secret object containing sensitive information to pass to the CSI driver to complete the CSI NodePublishVolume and NodeUnpublishVolume calls. This field is optional, and may be empty if no secret is required. If the secret object contains more than one secret, all secret references are passed.", Ref: ref("k8s.io/api/core/v1.LocalObjectReference"), }, }, @@ -3258,7 +3461,7 @@ func schema_k8sio_api_core_v1_CephFSPersistentVolumeSource(ref common.ReferenceC Properties: map[string]spec.Schema{ "monitors": { SchemaProps: spec.SchemaProps{ - Description: "Required: Monitors is a collection of Ceph monitors More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it", + Description: "monitors is Required: Monitors is a collection of Ceph monitors More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ @@ -3273,34 +3476,34 @@ func schema_k8sio_api_core_v1_CephFSPersistentVolumeSource(ref common.ReferenceC }, "path": { SchemaProps: spec.SchemaProps{ - Description: "Optional: Used as the mounted root, rather than the full Ceph tree, default is /", + Description: "path is Optional: Used as the mounted root, rather than the full Ceph tree, default is /", Type: []string{"string"}, Format: "", }, }, "user": { SchemaProps: spec.SchemaProps{ - Description: "Optional: User is the rados user name, default is admin More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it", + Description: "user is Optional: User is the rados user name, default is admin More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it", Type: []string{"string"}, Format: "", }, }, "secretFile": { SchemaProps: spec.SchemaProps{ - Description: "Optional: SecretFile is the path to key ring for User, default is /etc/ceph/user.secret More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it", + Description: "secretFile is Optional: SecretFile is the path to key ring for User, default is /etc/ceph/user.secret More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it", Type: []string{"string"}, Format: "", }, }, "secretRef": { SchemaProps: spec.SchemaProps{ - Description: "Optional: SecretRef is reference to the authentication secret for User, default is empty. More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it", + Description: "secretRef is Optional: SecretRef is reference to the authentication secret for User, default is empty. More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it", Ref: ref("k8s.io/api/core/v1.SecretReference"), }, }, "readOnly": { SchemaProps: spec.SchemaProps{ - Description: "Optional: Defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts. More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it", + Description: "readOnly is Optional: Defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts. More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it", Type: []string{"boolean"}, Format: "", }, @@ -3323,7 +3526,7 @@ func schema_k8sio_api_core_v1_CephFSVolumeSource(ref common.ReferenceCallback) c Properties: map[string]spec.Schema{ "monitors": { SchemaProps: spec.SchemaProps{ - Description: "Required: Monitors is a collection of Ceph monitors More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it", + Description: "monitors is Required: Monitors is a collection of Ceph monitors More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ @@ -3338,34 +3541,34 @@ func schema_k8sio_api_core_v1_CephFSVolumeSource(ref common.ReferenceCallback) c }, "path": { SchemaProps: spec.SchemaProps{ - Description: "Optional: Used as the mounted root, rather than the full Ceph tree, default is /", + Description: "path is Optional: Used as the mounted root, rather than the full Ceph tree, default is /", Type: []string{"string"}, Format: "", }, }, "user": { SchemaProps: spec.SchemaProps{ - Description: "Optional: User is the rados user name, default is admin More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it", + Description: "user is optional: User is the rados user name, default is admin More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it", Type: []string{"string"}, Format: "", }, }, "secretFile": { SchemaProps: spec.SchemaProps{ - Description: "Optional: SecretFile is the path to key ring for User, default is /etc/ceph/user.secret More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it", + Description: "secretFile is Optional: SecretFile is the path to key ring for User, default is /etc/ceph/user.secret More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it", Type: []string{"string"}, Format: "", }, }, "secretRef": { SchemaProps: spec.SchemaProps{ - Description: "Optional: SecretRef is reference to the authentication secret for User, default is empty. More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it", + Description: "secretRef is Optional: SecretRef is reference to the authentication secret for User, default is empty. More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it", Ref: ref("k8s.io/api/core/v1.LocalObjectReference"), }, }, "readOnly": { SchemaProps: spec.SchemaProps{ - Description: "Optional: Defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts. More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it", + Description: "readOnly is Optional: Defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts. More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it", Type: []string{"boolean"}, Format: "", }, @@ -3388,7 +3591,7 @@ func schema_k8sio_api_core_v1_CinderPersistentVolumeSource(ref common.ReferenceC Properties: map[string]spec.Schema{ "volumeID": { SchemaProps: spec.SchemaProps{ - Description: "volume id used to identify the volume in cinder. More info: https://examples.k8s.io/mysql-cinder-pd/README.md", + Description: "volumeID used to identify the volume in cinder. More info: https://examples.k8s.io/mysql-cinder-pd/README.md", Default: "", Type: []string{"string"}, Format: "", @@ -3396,21 +3599,21 @@ func schema_k8sio_api_core_v1_CinderPersistentVolumeSource(ref common.ReferenceC }, "fsType": { SchemaProps: spec.SchemaProps{ - Description: "Filesystem type to mount. Must be a filesystem type supported by the host operating system. Examples: \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified. More info: https://examples.k8s.io/mysql-cinder-pd/README.md", + Description: "fsType Filesystem type to mount. Must be a filesystem type supported by the host operating system. Examples: \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified. More info: https://examples.k8s.io/mysql-cinder-pd/README.md", Type: []string{"string"}, Format: "", }, }, "readOnly": { SchemaProps: spec.SchemaProps{ - Description: "Optional: Defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts. More info: https://examples.k8s.io/mysql-cinder-pd/README.md", + Description: "readOnly is Optional: Defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts. More info: https://examples.k8s.io/mysql-cinder-pd/README.md", Type: []string{"boolean"}, Format: "", }, }, "secretRef": { SchemaProps: spec.SchemaProps{ - Description: "Optional: points to a secret object containing parameters used to connect to OpenStack.", + Description: "secretRef is Optional: points to a secret object containing parameters used to connect to OpenStack.", Ref: ref("k8s.io/api/core/v1.SecretReference"), }, }, @@ -3432,7 +3635,7 @@ func schema_k8sio_api_core_v1_CinderVolumeSource(ref common.ReferenceCallback) c Properties: map[string]spec.Schema{ "volumeID": { SchemaProps: spec.SchemaProps{ - Description: "volume id used to identify the volume in cinder. More info: https://examples.k8s.io/mysql-cinder-pd/README.md", + Description: "volumeID used to identify the volume in cinder. More info: https://examples.k8s.io/mysql-cinder-pd/README.md", Default: "", Type: []string{"string"}, Format: "", @@ -3440,21 +3643,21 @@ func schema_k8sio_api_core_v1_CinderVolumeSource(ref common.ReferenceCallback) c }, "fsType": { SchemaProps: spec.SchemaProps{ - Description: "Filesystem type to mount. Must be a filesystem type supported by the host operating system. Examples: \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified. More info: https://examples.k8s.io/mysql-cinder-pd/README.md", + Description: "fsType is the filesystem type to mount. Must be a filesystem type supported by the host operating system. Examples: \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified. More info: https://examples.k8s.io/mysql-cinder-pd/README.md", Type: []string{"string"}, Format: "", }, }, "readOnly": { SchemaProps: spec.SchemaProps{ - Description: "Optional: Defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts. More info: https://examples.k8s.io/mysql-cinder-pd/README.md", + Description: "readOnly defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts. More info: https://examples.k8s.io/mysql-cinder-pd/README.md", Type: []string{"boolean"}, Format: "", }, }, "secretRef": { SchemaProps: spec.SchemaProps{ - Description: "Optional: points to a secret object containing parameters used to connect to OpenStack.", + Description: "secretRef is optional: points to a secret object containing parameters used to connect to OpenStack.", Ref: ref("k8s.io/api/core/v1.LocalObjectReference"), }, }, @@ -3771,6 +3974,11 @@ func schema_k8sio_api_core_v1_ConfigMapKeySelector(ref common.ReferenceCallback) }, Required: []string{"key"}, }, + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-map-type": "atomic", + }, + }, }, } } @@ -3830,7 +4038,7 @@ func schema_k8sio_api_core_v1_ConfigMapNodeConfigSource(ref common.ReferenceCall return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "ConfigMapNodeConfigSource contains the information to reference a ConfigMap as a config source for the Node.", + Description: "ConfigMapNodeConfigSource contains the information to reference a ConfigMap as a config source for the Node. This API is deprecated since 1.22: https://git.k8s.io/enhancements/keps/sig-node/281-dynamic-kubelet-configuration", Type: []string{"object"}, Properties: map[string]spec.Schema{ "namespace": { @@ -3894,7 +4102,7 @@ func schema_k8sio_api_core_v1_ConfigMapProjection(ref common.ReferenceCallback) }, "items": { SchemaProps: spec.SchemaProps{ - Description: "If unspecified, each key-value pair in the Data field of the referenced ConfigMap will be projected into the volume as a file whose name is the key and content is the value. If specified, the listed keys will be projected into the specified paths, and unlisted keys will not be present. If a key is specified which is not present in the ConfigMap, the volume setup will error unless it is marked optional. Paths must be relative and may not contain the '..' path or start with '..'.", + Description: "items if unspecified, each key-value pair in the Data field of the referenced ConfigMap will be projected into the volume as a file whose name is the key and content is the value. If specified, the listed keys will be projected into the specified paths, and unlisted keys will not be present. If a key is specified which is not present in the ConfigMap, the volume setup will error unless it is marked optional. Paths must be relative and may not contain the '..' path or start with '..'.", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ @@ -3908,7 +4116,7 @@ func schema_k8sio_api_core_v1_ConfigMapProjection(ref common.ReferenceCallback) }, "optional": { SchemaProps: spec.SchemaProps{ - Description: "Specify whether the ConfigMap or its keys must be defined", + Description: "optional specify whether the ConfigMap or its keys must be defined", Type: []string{"boolean"}, Format: "", }, @@ -3937,7 +4145,7 @@ func schema_k8sio_api_core_v1_ConfigMapVolumeSource(ref common.ReferenceCallback }, "items": { SchemaProps: spec.SchemaProps{ - Description: "If unspecified, each key-value pair in the Data field of the referenced ConfigMap will be projected into the volume as a file whose name is the key and content is the value. If specified, the listed keys will be projected into the specified paths, and unlisted keys will not be present. If a key is specified which is not present in the ConfigMap, the volume setup will error unless it is marked optional. Paths must be relative and may not contain the '..' path or start with '..'.", + Description: "items if unspecified, each key-value pair in the Data field of the referenced ConfigMap will be projected into the volume as a file whose name is the key and content is the value. If specified, the listed keys will be projected into the specified paths, and unlisted keys will not be present. If a key is specified which is not present in the ConfigMap, the volume setup will error unless it is marked optional. Paths must be relative and may not contain the '..' path or start with '..'.", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ @@ -3951,14 +4159,14 @@ func schema_k8sio_api_core_v1_ConfigMapVolumeSource(ref common.ReferenceCallback }, "defaultMode": { SchemaProps: spec.SchemaProps{ - Description: "Optional: mode bits used to set permissions on created files by default. Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. Defaults to 0644. Directories within the path are not affected by this setting. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.", + Description: "defaultMode is optional: mode bits used to set permissions on created files by default. Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. Defaults to 0644. Directories within the path are not affected by this setting. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.", Type: []string{"integer"}, Format: "int32", }, }, "optional": { SchemaProps: spec.SchemaProps{ - Description: "Specify whether the ConfigMap or its keys must be defined", + Description: "optional specify whether the ConfigMap or its keys must be defined", Type: []string{"boolean"}, Format: "", }, @@ -3988,14 +4196,14 @@ func schema_k8sio_api_core_v1_Container(ref common.ReferenceCallback) common.Ope }, "image": { SchemaProps: spec.SchemaProps{ - Description: "Docker image name. More info: https://kubernetes.io/docs/concepts/containers/images This field is optional to allow higher level config management to default or override container images in workload controllers like Deployments and StatefulSets.", + Description: "Container image name. More info: https://kubernetes.io/docs/concepts/containers/images This field is optional to allow higher level config management to default or override container images in workload controllers like Deployments and StatefulSets.", Type: []string{"string"}, Format: "", }, }, "command": { SchemaProps: spec.SchemaProps{ - Description: "Entrypoint array. Not executed within a shell. The docker image's ENTRYPOINT is used if this is not provided. Variable references $(VAR_NAME) are expanded using the container's environment. If a variable cannot be resolved, the reference in the input string will be unchanged. The $(VAR_NAME) syntax can be escaped with a double $$, ie: $$(VAR_NAME). Escaped references will never be expanded, regardless of whether the variable exists or not. Cannot be updated. More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell", + Description: "Entrypoint array. Not executed within a shell. The container image's ENTRYPOINT is used if this is not provided. Variable references $(VAR_NAME) are expanded using the container's environment. If a variable cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. \"$$(VAR_NAME)\" will produce the string literal \"$(VAR_NAME)\". Escaped references will never be expanded, regardless of whether the variable exists or not. Cannot be updated. More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ @@ -4010,7 +4218,7 @@ func schema_k8sio_api_core_v1_Container(ref common.ReferenceCallback) common.Ope }, "args": { SchemaProps: spec.SchemaProps{ - Description: "Arguments to the entrypoint. The docker image's CMD is used if this is not provided. Variable references $(VAR_NAME) are expanded using the container's environment. If a variable cannot be resolved, the reference in the input string will be unchanged. The $(VAR_NAME) syntax can be escaped with a double $$, ie: $$(VAR_NAME). Escaped references will never be expanded, regardless of whether the variable exists or not. Cannot be updated. More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell", + Description: "Arguments to the entrypoint. The container image's CMD is used if this is not provided. Variable references $(VAR_NAME) are expanded using the container's environment. If a variable cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. \"$$(VAR_NAME)\" will produce the string literal \"$(VAR_NAME)\". Escaped references will never be expanded, regardless of whether the variable exists or not. Cannot be updated. More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ @@ -4169,21 +4377,21 @@ func schema_k8sio_api_core_v1_Container(ref common.ReferenceCallback) common.Ope }, "terminationMessagePolicy": { SchemaProps: spec.SchemaProps{ - Description: "Indicate how the termination message should be populated. File will use the contents of terminationMessagePath to populate the container status message on both success and failure. FallbackToLogsOnError will use the last chunk of container log output if the termination message file is empty and the container exited with an error. The log output is limited to 2048 bytes or 80 lines, whichever is smaller. Defaults to File. Cannot be updated.", + Description: "Indicate how the termination message should be populated. File will use the contents of terminationMessagePath to populate the container status message on both success and failure. FallbackToLogsOnError will use the last chunk of container log output if the termination message file is empty and the container exited with an error. The log output is limited to 2048 bytes or 80 lines, whichever is smaller. Defaults to File. Cannot be updated.\n\nPossible enum values:\n - `\"FallbackToLogsOnError\"` will read the most recent contents of the container logs for the container status message when the container exits with an error and the terminationMessagePath has no contents.\n - `\"File\"` is the default behavior and will set the container status message to the contents of the container's terminationMessagePath when the container exits.", Type: []string{"string"}, Format: "", - }, + Enum: []interface{}{"FallbackToLogsOnError", "File"}}, }, "imagePullPolicy": { SchemaProps: spec.SchemaProps{ - Description: "Image pull policy. One of Always, Never, IfNotPresent. Defaults to Always if :latest tag is specified, or IfNotPresent otherwise. Cannot be updated. More info: https://kubernetes.io/docs/concepts/containers/images#updating-images", + Description: "Image pull policy. One of Always, Never, IfNotPresent. Defaults to Always if :latest tag is specified, or IfNotPresent otherwise. Cannot be updated. More info: https://kubernetes.io/docs/concepts/containers/images#updating-images\n\nPossible enum values:\n - `\"Always\"` means that kubelet always attempts to pull the latest image. Container will fail If the pull fails.\n - `\"IfNotPresent\"` means that kubelet pulls if the image isn't present on disk. Container will fail if the image isn't present and the pull fails.\n - `\"Never\"` means that kubelet never pulls an image, but only uses a local image. Container will fail if the image isn't present", Type: []string{"string"}, Format: "", - }, + Enum: []interface{}{"Always", "IfNotPresent", "Never"}}, }, "securityContext": { SchemaProps: spec.SchemaProps{ - Description: "Security options the pod should run with. More info: https://kubernetes.io/docs/concepts/policy/security-context/ More info: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/", + Description: "SecurityContext defines the security options the container should be run with. If set, the fields of SecurityContext override the equivalent fields of PodSecurityContext. More info: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/", Ref: ref("k8s.io/api/core/v1.SecurityContext"), }, }, @@ -4247,7 +4455,6 @@ func schema_k8sio_api_core_v1_ContainerImage(ref common.ReferenceCallback) commo }, }, }, - Required: []string{"names"}, }, }, } @@ -4284,11 +4491,11 @@ func schema_k8sio_api_core_v1_ContainerPort(ref common.ReferenceCallback) common }, "protocol": { SchemaProps: spec.SchemaProps{ - Description: "Protocol for port. Must be UDP, TCP, or SCTP. Defaults to \"TCP\".", + Description: "Protocol for port. Must be UDP, TCP, or SCTP. Defaults to \"TCP\".\n\nPossible enum values:\n - `\"SCTP\"` is the SCTP protocol.\n - `\"TCP\"` is the TCP protocol.\n - `\"UDP\"` is the UDP protocol.", Default: "TCP", Type: []string{"string"}, Format: "", - }, + Enum: []interface{}{"SCTP", "TCP", "UDP"}}, }, "hostIP": { SchemaProps: spec.SchemaProps{ @@ -4411,7 +4618,7 @@ func schema_k8sio_api_core_v1_ContainerStateTerminated(ref common.ReferenceCallb }, "containerID": { SchemaProps: spec.SchemaProps{ - Description: "Container's ID in the format 'docker://'", + Description: "Container's ID in the format '://'", Type: []string{"string"}, Format: "", }, @@ -4491,7 +4698,7 @@ func schema_k8sio_api_core_v1_ContainerStatus(ref common.ReferenceCallback) comm }, "restartCount": { SchemaProps: spec.SchemaProps{ - Description: "The number of times the container has been restarted, currently based on the number of dead containers that have not yet been removed. Note that this is calculated from dead containers. But those containers are subject to garbage collection. This value will get capped at 5 by GC.", + Description: "The number of times the container has been restarted.", Default: 0, Type: []string{"integer"}, Format: "int32", @@ -4499,7 +4706,7 @@ func schema_k8sio_api_core_v1_ContainerStatus(ref common.ReferenceCallback) comm }, "image": { SchemaProps: spec.SchemaProps{ - Description: "The image the container is running. More info: https://kubernetes.io/docs/concepts/containers/images", + Description: "The image the container is running. More info: https://kubernetes.io/docs/concepts/containers/images.", Default: "", Type: []string{"string"}, Format: "", @@ -4515,7 +4722,7 @@ func schema_k8sio_api_core_v1_ContainerStatus(ref common.ReferenceCallback) comm }, "containerID": { SchemaProps: spec.SchemaProps{ - Description: "Container's ID in the format 'docker://'.", + Description: "Container's ID in the format '://'.", Type: []string{"string"}, Format: "", }, @@ -4675,14 +4882,14 @@ func schema_k8sio_api_core_v1_EmptyDirVolumeSource(ref common.ReferenceCallback) Properties: map[string]spec.Schema{ "medium": { SchemaProps: spec.SchemaProps{ - Description: "What type of storage medium should back this directory. The default is \"\" which means to use the node's default medium. Must be an empty string (default) or Memory. More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir", + Description: "medium represents what type of storage medium should back this directory. The default is \"\" which means to use the node's default medium. Must be an empty string (default) or Memory. More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir", Type: []string{"string"}, Format: "", }, }, "sizeLimit": { SchemaProps: spec.SchemaProps{ - Description: "Total amount of local storage required for this EmptyDir volume. The size limit is also applicable for memory medium. The maximum usage on memory medium EmptyDir would be the minimum value between the SizeLimit specified here and the sum of memory limits of all containers in a pod. The default is nil which means that the limit is undefined. More info: http://kubernetes.io/docs/user-guide/volumes#emptydir", + Description: "sizeLimit is the total amount of local storage required for this EmptyDir volume. The size limit is also applicable for memory medium. The maximum usage on memory medium EmptyDir would be the minimum value between the SizeLimit specified here and the sum of memory limits of all containers in a pod. The default is nil which means that the limit is undefined. More info: http://kubernetes.io/docs/user-guide/volumes#emptydir", Ref: ref("k8s.io/apimachinery/pkg/api/resource.Quantity"), }, }, @@ -4732,6 +4939,11 @@ func schema_k8sio_api_core_v1_EndpointAddress(ref common.ReferenceCallback) comm }, Required: []string{"ip"}, }, + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-map-type": "atomic", + }, + }, }, Dependencies: []string{ "k8s.io/api/core/v1.ObjectReference"}, @@ -4762,14 +4974,14 @@ func schema_k8sio_api_core_v1_EndpointPort(ref common.ReferenceCallback) common. }, "protocol": { SchemaProps: spec.SchemaProps{ - Description: "The IP protocol for this port. Must be UDP, TCP, or SCTP. Default is TCP.", + Description: "The IP protocol for this port. Must be UDP, TCP, or SCTP. Default is TCP.\n\nPossible enum values:\n - `\"SCTP\"` is the SCTP protocol.\n - `\"TCP\"` is the TCP protocol.\n - `\"UDP\"` is the UDP protocol.", Type: []string{"string"}, Format: "", - }, + Enum: []interface{}{"SCTP", "TCP", "UDP"}}, }, "appProtocol": { SchemaProps: spec.SchemaProps{ - Description: "The application protocol for this port. This field follows standard Kubernetes label syntax. Un-prefixed names are reserved for IANA standard service names (as per RFC-6335 and http://www.iana.org/assignments/service-names). Non-standard protocols should use prefixed names such as mycompany.com/my-custom-protocol. This is a beta field that is guarded by the ServiceAppProtocol feature gate and enabled by default.", + Description: "The application protocol for this port. This field follows standard Kubernetes label syntax. Un-prefixed names are reserved for IANA standard service names (as per RFC-6335 and https://www.iana.org/assignments/service-names). Non-standard protocols should use prefixed names such as mycompany.com/my-custom-protocol.", Type: []string{"string"}, Format: "", }, @@ -4777,6 +4989,11 @@ func schema_k8sio_api_core_v1_EndpointPort(ref common.ReferenceCallback) common. }, Required: []string{"port"}, }, + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-map-type": "atomic", + }, + }, }, } } @@ -4990,7 +5207,7 @@ func schema_k8sio_api_core_v1_EnvVar(ref common.ReferenceCallback) common.OpenAP }, "value": { SchemaProps: spec.SchemaProps{ - Description: "Variable references $(VAR_NAME) are expanded using the previous defined environment variables in the container and any service environment variables. If a variable cannot be resolved, the reference in the input string will be unchanged. The $(VAR_NAME) syntax can be escaped with a double $$, ie: $$(VAR_NAME). Escaped references will never be expanded, regardless of whether the variable exists or not. Defaults to \"\".", + Description: "Variable references $(VAR_NAME) are expanded using the previously defined environment variables in the container and any service environment variables. If a variable cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. \"$$(VAR_NAME)\" will produce the string literal \"$(VAR_NAME)\". Escaped references will never be expanded, regardless of whether the variable exists or not. Defaults to \"\".", Type: []string{"string"}, Format: "", }, @@ -5053,7 +5270,7 @@ func schema_k8sio_api_core_v1_EphemeralContainer(ref common.ReferenceCallback) c return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "An EphemeralContainer is a container that may be added temporarily to an existing pod for user-initiated activities such as debugging. Ephemeral containers have no resource or scheduling guarantees, and they will not be restarted when they exit or when a pod is removed or restarted. If an ephemeral container causes a pod to exceed its resource allocation, the pod may be evicted. Ephemeral containers may not be added by directly updating the pod spec. They must be added via the pod's ephemeralcontainers subresource, and they will appear in the pod spec once added. This is an alpha feature enabled by the EphemeralContainers feature flag.", + Description: "An EphemeralContainer is a temporary container that you may add to an existing Pod for user-initiated activities such as debugging. Ephemeral containers have no resource or scheduling guarantees, and they will not be restarted when they exit or when a Pod is removed or restarted. The kubelet may evict a Pod if an ephemeral container causes the Pod to exceed its resource allocation.\n\nTo add an ephemeral container, use the ephemeralcontainers subresource of an existing Pod. Ephemeral containers may not be removed or restarted.\n\nThis is a beta feature available on clusters that haven't disabled the EphemeralContainers feature gate.", Type: []string{"object"}, Properties: map[string]spec.Schema{ "name": { @@ -5066,14 +5283,14 @@ func schema_k8sio_api_core_v1_EphemeralContainer(ref common.ReferenceCallback) c }, "image": { SchemaProps: spec.SchemaProps{ - Description: "Docker image name. More info: https://kubernetes.io/docs/concepts/containers/images", + Description: "Container image name. More info: https://kubernetes.io/docs/concepts/containers/images", Type: []string{"string"}, Format: "", }, }, "command": { SchemaProps: spec.SchemaProps{ - Description: "Entrypoint array. Not executed within a shell. The docker image's ENTRYPOINT is used if this is not provided. Variable references $(VAR_NAME) are expanded using the container's environment. If a variable cannot be resolved, the reference in the input string will be unchanged. The $(VAR_NAME) syntax can be escaped with a double $$, ie: $$(VAR_NAME). Escaped references will never be expanded, regardless of whether the variable exists or not. Cannot be updated. More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell", + Description: "Entrypoint array. Not executed within a shell. The image's ENTRYPOINT is used if this is not provided. Variable references $(VAR_NAME) are expanded using the container's environment. If a variable cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. \"$$(VAR_NAME)\" will produce the string literal \"$(VAR_NAME)\". Escaped references will never be expanded, regardless of whether the variable exists or not. Cannot be updated. More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ @@ -5088,7 +5305,7 @@ func schema_k8sio_api_core_v1_EphemeralContainer(ref common.ReferenceCallback) c }, "args": { SchemaProps: spec.SchemaProps{ - Description: "Arguments to the entrypoint. The docker image's CMD is used if this is not provided. Variable references $(VAR_NAME) are expanded using the container's environment. If a variable cannot be resolved, the reference in the input string will be unchanged. The $(VAR_NAME) syntax can be escaped with a double $$, ie: $$(VAR_NAME). Escaped references will never be expanded, regardless of whether the variable exists or not. Cannot be updated. More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell", + Description: "Arguments to the entrypoint. The image's CMD is used if this is not provided. Variable references $(VAR_NAME) are expanded using the container's environment. If a variable cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. \"$$(VAR_NAME)\" will produce the string literal \"$(VAR_NAME)\". Escaped references will never be expanded, regardless of whether the variable exists or not. Cannot be updated. More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ @@ -5109,6 +5326,17 @@ func schema_k8sio_api_core_v1_EphemeralContainer(ref common.ReferenceCallback) c }, }, "ports": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-map-keys": []interface{}{ + "containerPort", + "protocol", + }, + "x-kubernetes-list-type": "map", + "x-kubernetes-patch-merge-key": "containerPort", + "x-kubernetes-patch-strategy": "merge", + }, + }, SchemaProps: spec.SchemaProps{ Description: "Ports are not allowed for ephemeral containers.", Type: []string{"array"}, @@ -5171,7 +5399,7 @@ func schema_k8sio_api_core_v1_EphemeralContainer(ref common.ReferenceCallback) c }, }, SchemaProps: spec.SchemaProps{ - Description: "Pod volumes to mount into the container's filesystem. Cannot be updated.", + Description: "Pod volumes to mount into the container's filesystem. Subpath mounts are not allowed for ephemeral containers. Cannot be updated.", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ @@ -5236,21 +5464,21 @@ func schema_k8sio_api_core_v1_EphemeralContainer(ref common.ReferenceCallback) c }, "terminationMessagePolicy": { SchemaProps: spec.SchemaProps{ - Description: "Indicate how the termination message should be populated. File will use the contents of terminationMessagePath to populate the container status message on both success and failure. FallbackToLogsOnError will use the last chunk of container log output if the termination message file is empty and the container exited with an error. The log output is limited to 2048 bytes or 80 lines, whichever is smaller. Defaults to File. Cannot be updated.", + Description: "Indicate how the termination message should be populated. File will use the contents of terminationMessagePath to populate the container status message on both success and failure. FallbackToLogsOnError will use the last chunk of container log output if the termination message file is empty and the container exited with an error. The log output is limited to 2048 bytes or 80 lines, whichever is smaller. Defaults to File. Cannot be updated.\n\nPossible enum values:\n - `\"FallbackToLogsOnError\"` will read the most recent contents of the container logs for the container status message when the container exits with an error and the terminationMessagePath has no contents.\n - `\"File\"` is the default behavior and will set the container status message to the contents of the container's terminationMessagePath when the container exits.", Type: []string{"string"}, Format: "", - }, + Enum: []interface{}{"FallbackToLogsOnError", "File"}}, }, "imagePullPolicy": { SchemaProps: spec.SchemaProps{ - Description: "Image pull policy. One of Always, Never, IfNotPresent. Defaults to Always if :latest tag is specified, or IfNotPresent otherwise. Cannot be updated. More info: https://kubernetes.io/docs/concepts/containers/images#updating-images", + Description: "Image pull policy. One of Always, Never, IfNotPresent. Defaults to Always if :latest tag is specified, or IfNotPresent otherwise. Cannot be updated. More info: https://kubernetes.io/docs/concepts/containers/images#updating-images\n\nPossible enum values:\n - `\"Always\"` means that kubelet always attempts to pull the latest image. Container will fail If the pull fails.\n - `\"IfNotPresent\"` means that kubelet pulls if the image isn't present on disk. Container will fail if the image isn't present and the pull fails.\n - `\"Never\"` means that kubelet never pulls an image, but only uses a local image. Container will fail if the image isn't present", Type: []string{"string"}, Format: "", - }, + Enum: []interface{}{"Always", "IfNotPresent", "Never"}}, }, "securityContext": { SchemaProps: spec.SchemaProps{ - Description: "SecurityContext is not allowed for ephemeral containers.", + Description: "Optional: SecurityContext defines the security options the ephemeral container should be run with. If set, the fields of SecurityContext override the equivalent fields of PodSecurityContext.", Ref: ref("k8s.io/api/core/v1.SecurityContext"), }, }, @@ -5277,7 +5505,7 @@ func schema_k8sio_api_core_v1_EphemeralContainer(ref common.ReferenceCallback) c }, "targetContainerName": { SchemaProps: spec.SchemaProps{ - Description: "If set, the name of the container from PodSpec that this ephemeral container targets. The ephemeral container will be run in the namespaces (IPC, PID, etc) of this container. If not set then the ephemeral container is run in whatever namespaces are shared for the pod. Note that the container runtime must support this feature.", + Description: "If set, the name of the container from PodSpec that this ephemeral container targets. The ephemeral container will be run in the namespaces (IPC, PID, etc) of this container. If not set then the ephemeral container uses the namespaces configured in the Pod spec.\n\nThe container runtime must implement support for this feature. If the runtime does not support namespace targeting then the result of setting this field is undefined.", Type: []string{"string"}, Format: "", }, @@ -5308,14 +5536,14 @@ func schema_k8sio_api_core_v1_EphemeralContainerCommon(ref common.ReferenceCallb }, "image": { SchemaProps: spec.SchemaProps{ - Description: "Docker image name. More info: https://kubernetes.io/docs/concepts/containers/images", + Description: "Container image name. More info: https://kubernetes.io/docs/concepts/containers/images", Type: []string{"string"}, Format: "", }, }, "command": { SchemaProps: spec.SchemaProps{ - Description: "Entrypoint array. Not executed within a shell. The docker image's ENTRYPOINT is used if this is not provided. Variable references $(VAR_NAME) are expanded using the container's environment. If a variable cannot be resolved, the reference in the input string will be unchanged. The $(VAR_NAME) syntax can be escaped with a double $$, ie: $$(VAR_NAME). Escaped references will never be expanded, regardless of whether the variable exists or not. Cannot be updated. More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell", + Description: "Entrypoint array. Not executed within a shell. The image's ENTRYPOINT is used if this is not provided. Variable references $(VAR_NAME) are expanded using the container's environment. If a variable cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. \"$$(VAR_NAME)\" will produce the string literal \"$(VAR_NAME)\". Escaped references will never be expanded, regardless of whether the variable exists or not. Cannot be updated. More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ @@ -5330,7 +5558,7 @@ func schema_k8sio_api_core_v1_EphemeralContainerCommon(ref common.ReferenceCallb }, "args": { SchemaProps: spec.SchemaProps{ - Description: "Arguments to the entrypoint. The docker image's CMD is used if this is not provided. Variable references $(VAR_NAME) are expanded using the container's environment. If a variable cannot be resolved, the reference in the input string will be unchanged. The $(VAR_NAME) syntax can be escaped with a double $$, ie: $$(VAR_NAME). Escaped references will never be expanded, regardless of whether the variable exists or not. Cannot be updated. More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell", + Description: "Arguments to the entrypoint. The image's CMD is used if this is not provided. Variable references $(VAR_NAME) are expanded using the container's environment. If a variable cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. \"$$(VAR_NAME)\" will produce the string literal \"$(VAR_NAME)\". Escaped references will never be expanded, regardless of whether the variable exists or not. Cannot be updated. More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ @@ -5351,6 +5579,17 @@ func schema_k8sio_api_core_v1_EphemeralContainerCommon(ref common.ReferenceCallb }, }, "ports": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-map-keys": []interface{}{ + "containerPort", + "protocol", + }, + "x-kubernetes-list-type": "map", + "x-kubernetes-patch-merge-key": "containerPort", + "x-kubernetes-patch-strategy": "merge", + }, + }, SchemaProps: spec.SchemaProps{ Description: "Ports are not allowed for ephemeral containers.", Type: []string{"array"}, @@ -5413,7 +5652,7 @@ func schema_k8sio_api_core_v1_EphemeralContainerCommon(ref common.ReferenceCallb }, }, SchemaProps: spec.SchemaProps{ - Description: "Pod volumes to mount into the container's filesystem. Cannot be updated.", + Description: "Pod volumes to mount into the container's filesystem. Subpath mounts are not allowed for ephemeral containers. Cannot be updated.", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ @@ -5478,21 +5717,21 @@ func schema_k8sio_api_core_v1_EphemeralContainerCommon(ref common.ReferenceCallb }, "terminationMessagePolicy": { SchemaProps: spec.SchemaProps{ - Description: "Indicate how the termination message should be populated. File will use the contents of terminationMessagePath to populate the container status message on both success and failure. FallbackToLogsOnError will use the last chunk of container log output if the termination message file is empty and the container exited with an error. The log output is limited to 2048 bytes or 80 lines, whichever is smaller. Defaults to File. Cannot be updated.", + Description: "Indicate how the termination message should be populated. File will use the contents of terminationMessagePath to populate the container status message on both success and failure. FallbackToLogsOnError will use the last chunk of container log output if the termination message file is empty and the container exited with an error. The log output is limited to 2048 bytes or 80 lines, whichever is smaller. Defaults to File. Cannot be updated.\n\nPossible enum values:\n - `\"FallbackToLogsOnError\"` will read the most recent contents of the container logs for the container status message when the container exits with an error and the terminationMessagePath has no contents.\n - `\"File\"` is the default behavior and will set the container status message to the contents of the container's terminationMessagePath when the container exits.", Type: []string{"string"}, Format: "", - }, + Enum: []interface{}{"FallbackToLogsOnError", "File"}}, }, "imagePullPolicy": { SchemaProps: spec.SchemaProps{ - Description: "Image pull policy. One of Always, Never, IfNotPresent. Defaults to Always if :latest tag is specified, or IfNotPresent otherwise. Cannot be updated. More info: https://kubernetes.io/docs/concepts/containers/images#updating-images", + Description: "Image pull policy. One of Always, Never, IfNotPresent. Defaults to Always if :latest tag is specified, or IfNotPresent otherwise. Cannot be updated. More info: https://kubernetes.io/docs/concepts/containers/images#updating-images\n\nPossible enum values:\n - `\"Always\"` means that kubelet always attempts to pull the latest image. Container will fail If the pull fails.\n - `\"IfNotPresent\"` means that kubelet pulls if the image isn't present on disk. Container will fail if the image isn't present and the pull fails.\n - `\"Never\"` means that kubelet never pulls an image, but only uses a local image. Container will fail if the image isn't present", Type: []string{"string"}, Format: "", - }, + Enum: []interface{}{"Always", "IfNotPresent", "Never"}}, }, "securityContext": { SchemaProps: spec.SchemaProps{ - Description: "SecurityContext is not allowed for ephemeral containers.", + Description: "Optional: SecurityContext defines the security options the ephemeral container should be run with. If set, the fields of SecurityContext override the equivalent fields of PodSecurityContext.", Ref: ref("k8s.io/api/core/v1.SecurityContext"), }, }, @@ -5526,62 +5765,6 @@ func schema_k8sio_api_core_v1_EphemeralContainerCommon(ref common.ReferenceCallb } } -func schema_k8sio_api_core_v1_EphemeralContainers(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "A list of ephemeral containers used with the Pod ephemeralcontainers subresource.", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "kind": { - SchemaProps: spec.SchemaProps{ - Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", - Type: []string{"string"}, - Format: "", - }, - }, - "apiVersion": { - SchemaProps: spec.SchemaProps{ - Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", - Type: []string{"string"}, - Format: "", - }, - }, - "metadata": { - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"), - }, - }, - "ephemeralContainers": { - VendorExtensible: spec.VendorExtensible{ - Extensions: spec.Extensions{ - "x-kubernetes-patch-merge-key": "name", - "x-kubernetes-patch-strategy": "merge", - }, - }, - SchemaProps: spec.SchemaProps{ - Description: "A list of ephemeral containers associated with this pod. New ephemeral containers may be appended to this list, but existing ephemeral containers may not be removed or modified.", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("k8s.io/api/core/v1.EphemeralContainer"), - }, - }, - }, - }, - }, - }, - Required: []string{"ephemeralContainers"}, - }, - }, - Dependencies: []string{ - "k8s.io/api/core/v1.EphemeralContainer", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"}, - } -} - func schema_k8sio_api_core_v1_EphemeralVolumeSource(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ @@ -5882,7 +6065,7 @@ func schema_k8sio_api_core_v1_FCVolumeSource(ref common.ReferenceCallback) commo Properties: map[string]spec.Schema{ "targetWWNs": { SchemaProps: spec.SchemaProps{ - Description: "Optional: FC target worldwide names (WWNs)", + Description: "targetWWNs is Optional: FC target worldwide names (WWNs)", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ @@ -5897,28 +6080,28 @@ func schema_k8sio_api_core_v1_FCVolumeSource(ref common.ReferenceCallback) commo }, "lun": { SchemaProps: spec.SchemaProps{ - Description: "Optional: FC target lun number", + Description: "lun is Optional: FC target lun number", Type: []string{"integer"}, Format: "int32", }, }, "fsType": { SchemaProps: spec.SchemaProps{ - Description: "Filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified.", + Description: "fsType is the filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified.", Type: []string{"string"}, Format: "", }, }, "readOnly": { SchemaProps: spec.SchemaProps{ - Description: "Optional: Defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts.", + Description: "readOnly is Optional: Defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts.", Type: []string{"boolean"}, Format: "", }, }, "wwids": { SchemaProps: spec.SchemaProps{ - Description: "Optional: FC volume world wide identifiers (wwids) Either wwids or combination of targetWWNs and lun must be set, but not both simultaneously.", + Description: "wwids Optional: FC volume world wide identifiers (wwids) Either wwids or combination of targetWWNs and lun must be set, but not both simultaneously.", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ @@ -5946,7 +6129,7 @@ func schema_k8sio_api_core_v1_FlexPersistentVolumeSource(ref common.ReferenceCal Properties: map[string]spec.Schema{ "driver": { SchemaProps: spec.SchemaProps{ - Description: "Driver is the name of the driver to use for this volume.", + Description: "driver is the name of the driver to use for this volume.", Default: "", Type: []string{"string"}, Format: "", @@ -5954,27 +6137,27 @@ func schema_k8sio_api_core_v1_FlexPersistentVolumeSource(ref common.ReferenceCal }, "fsType": { SchemaProps: spec.SchemaProps{ - Description: "Filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. \"ext4\", \"xfs\", \"ntfs\". The default filesystem depends on FlexVolume script.", + Description: "fsType is the Filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. \"ext4\", \"xfs\", \"ntfs\". The default filesystem depends on FlexVolume script.", Type: []string{"string"}, Format: "", }, }, "secretRef": { SchemaProps: spec.SchemaProps{ - Description: "Optional: SecretRef is reference to the secret object containing sensitive information to pass to the plugin scripts. This may be empty if no secret object is specified. If the secret object contains more than one secret, all secrets are passed to the plugin scripts.", + Description: "secretRef is Optional: SecretRef is reference to the secret object containing sensitive information to pass to the plugin scripts. This may be empty if no secret object is specified. If the secret object contains more than one secret, all secrets are passed to the plugin scripts.", Ref: ref("k8s.io/api/core/v1.SecretReference"), }, }, "readOnly": { SchemaProps: spec.SchemaProps{ - Description: "Optional: Defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts.", + Description: "readOnly is Optional: defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts.", Type: []string{"boolean"}, Format: "", }, }, "options": { SchemaProps: spec.SchemaProps{ - Description: "Optional: Extra command options if any.", + Description: "options is Optional: this field holds extra command options if any.", Type: []string{"object"}, AdditionalProperties: &spec.SchemaOrBool{ Allows: true, @@ -6006,7 +6189,7 @@ func schema_k8sio_api_core_v1_FlexVolumeSource(ref common.ReferenceCallback) com Properties: map[string]spec.Schema{ "driver": { SchemaProps: spec.SchemaProps{ - Description: "Driver is the name of the driver to use for this volume.", + Description: "driver is the name of the driver to use for this volume.", Default: "", Type: []string{"string"}, Format: "", @@ -6014,27 +6197,27 @@ func schema_k8sio_api_core_v1_FlexVolumeSource(ref common.ReferenceCallback) com }, "fsType": { SchemaProps: spec.SchemaProps{ - Description: "Filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. \"ext4\", \"xfs\", \"ntfs\". The default filesystem depends on FlexVolume script.", + Description: "fsType is the filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. \"ext4\", \"xfs\", \"ntfs\". The default filesystem depends on FlexVolume script.", Type: []string{"string"}, Format: "", }, }, "secretRef": { SchemaProps: spec.SchemaProps{ - Description: "Optional: SecretRef is reference to the secret object containing sensitive information to pass to the plugin scripts. This may be empty if no secret object is specified. If the secret object contains more than one secret, all secrets are passed to the plugin scripts.", + Description: "secretRef is Optional: secretRef is reference to the secret object containing sensitive information to pass to the plugin scripts. This may be empty if no secret object is specified. If the secret object contains more than one secret, all secrets are passed to the plugin scripts.", Ref: ref("k8s.io/api/core/v1.LocalObjectReference"), }, }, "readOnly": { SchemaProps: spec.SchemaProps{ - Description: "Optional: Defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts.", + Description: "readOnly is Optional: defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts.", Type: []string{"boolean"}, Format: "", }, }, "options": { SchemaProps: spec.SchemaProps{ - Description: "Optional: Extra command options if any.", + Description: "options is Optional: this field holds extra command options if any.", Type: []string{"object"}, AdditionalProperties: &spec.SchemaOrBool{ Allows: true, @@ -6066,14 +6249,14 @@ func schema_k8sio_api_core_v1_FlockerVolumeSource(ref common.ReferenceCallback) Properties: map[string]spec.Schema{ "datasetName": { SchemaProps: spec.SchemaProps{ - Description: "Name of the dataset stored as metadata -> name on the dataset for Flocker should be considered as deprecated", + Description: "datasetName is Name of the dataset stored as metadata -> name on the dataset for Flocker should be considered as deprecated", Type: []string{"string"}, Format: "", }, }, "datasetUUID": { SchemaProps: spec.SchemaProps{ - Description: "UUID of the dataset. This is unique identifier of a Flocker dataset", + Description: "datasetUUID is the UUID of the dataset. This is unique identifier of a Flocker dataset", Type: []string{"string"}, Format: "", }, @@ -6093,7 +6276,7 @@ func schema_k8sio_api_core_v1_GCEPersistentDiskVolumeSource(ref common.Reference Properties: map[string]spec.Schema{ "pdName": { SchemaProps: spec.SchemaProps{ - Description: "Unique name of the PD resource in GCE. Used to identify the disk in GCE. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk", + Description: "pdName is unique name of the PD resource in GCE. Used to identify the disk in GCE. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk", Default: "", Type: []string{"string"}, Format: "", @@ -6101,21 +6284,21 @@ func schema_k8sio_api_core_v1_GCEPersistentDiskVolumeSource(ref common.Reference }, "fsType": { SchemaProps: spec.SchemaProps{ - Description: "Filesystem type of the volume that you want to mount. Tip: Ensure that the filesystem type is supported by the host operating system. Examples: \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk", + Description: "fsType is filesystem type of the volume that you want to mount. Tip: Ensure that the filesystem type is supported by the host operating system. Examples: \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk", Type: []string{"string"}, Format: "", }, }, "partition": { SchemaProps: spec.SchemaProps{ - Description: "The partition in the volume that you want to mount. If omitted, the default is to mount by volume name. Examples: For volume /dev/sda1, you specify the partition as \"1\". Similarly, the volume partition for /dev/sda is \"0\" (or you can leave the property empty). More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk", + Description: "partition is the partition in the volume that you want to mount. If omitted, the default is to mount by volume name. Examples: For volume /dev/sda1, you specify the partition as \"1\". Similarly, the volume partition for /dev/sda is \"0\" (or you can leave the property empty). More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk", Type: []string{"integer"}, Format: "int32", }, }, "readOnly": { SchemaProps: spec.SchemaProps{ - Description: "ReadOnly here will force the ReadOnly setting in VolumeMounts. Defaults to false. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk", + Description: "readOnly here will force the ReadOnly setting in VolumeMounts. Defaults to false. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk", Type: []string{"boolean"}, Format: "", }, @@ -6127,6 +6310,35 @@ func schema_k8sio_api_core_v1_GCEPersistentDiskVolumeSource(ref common.Reference } } +func schema_k8sio_api_core_v1_GRPCAction(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "port": { + SchemaProps: spec.SchemaProps{ + Description: "Port number of the gRPC service. Number must be in the range 1 to 65535.", + Default: 0, + Type: []string{"integer"}, + Format: "int32", + }, + }, + "service": { + SchemaProps: spec.SchemaProps{ + Description: "Service is the name of the service to place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md).\n\nIf this is not specified, the default behavior is defined by gRPC.", + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + Required: []string{"port"}, + }, + }, + } +} + func schema_k8sio_api_core_v1_GitRepoVolumeSource(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ @@ -6136,7 +6348,7 @@ func schema_k8sio_api_core_v1_GitRepoVolumeSource(ref common.ReferenceCallback) Properties: map[string]spec.Schema{ "repository": { SchemaProps: spec.SchemaProps{ - Description: "Repository URL", + Description: "repository is the URL", Default: "", Type: []string{"string"}, Format: "", @@ -6144,14 +6356,14 @@ func schema_k8sio_api_core_v1_GitRepoVolumeSource(ref common.ReferenceCallback) }, "revision": { SchemaProps: spec.SchemaProps{ - Description: "Commit hash for the specified revision.", + Description: "revision is the commit hash for the specified revision.", Type: []string{"string"}, Format: "", }, }, "directory": { SchemaProps: spec.SchemaProps{ - Description: "Target directory name. Must not contain or start with '..'. If '.' is supplied, the volume directory will be the git repository. Otherwise, if specified, the volume will contain the git repository in the subdirectory with the given name.", + Description: "directory is the target directory name. Must not contain or start with '..'. If '.' is supplied, the volume directory will be the git repository. Otherwise, if specified, the volume will contain the git repository in the subdirectory with the given name.", Type: []string{"string"}, Format: "", }, @@ -6172,7 +6384,7 @@ func schema_k8sio_api_core_v1_GlusterfsPersistentVolumeSource(ref common.Referen Properties: map[string]spec.Schema{ "endpoints": { SchemaProps: spec.SchemaProps{ - Description: "EndpointsName is the endpoint name that details Glusterfs topology. More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod", + Description: "endpoints is the endpoint name that details Glusterfs topology. More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod", Default: "", Type: []string{"string"}, Format: "", @@ -6180,7 +6392,7 @@ func schema_k8sio_api_core_v1_GlusterfsPersistentVolumeSource(ref common.Referen }, "path": { SchemaProps: spec.SchemaProps{ - Description: "Path is the Glusterfs volume path. More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod", + Description: "path is the Glusterfs volume path. More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod", Default: "", Type: []string{"string"}, Format: "", @@ -6188,14 +6400,14 @@ func schema_k8sio_api_core_v1_GlusterfsPersistentVolumeSource(ref common.Referen }, "readOnly": { SchemaProps: spec.SchemaProps{ - Description: "ReadOnly here will force the Glusterfs volume to be mounted with read-only permissions. Defaults to false. More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod", + Description: "readOnly here will force the Glusterfs volume to be mounted with read-only permissions. Defaults to false. More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod", Type: []string{"boolean"}, Format: "", }, }, "endpointsNamespace": { SchemaProps: spec.SchemaProps{ - Description: "EndpointsNamespace is the namespace that contains Glusterfs endpoint. If this field is empty, the EndpointNamespace defaults to the same namespace as the bound PVC. More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod", + Description: "endpointsNamespace is the namespace that contains Glusterfs endpoint. If this field is empty, the EndpointNamespace defaults to the same namespace as the bound PVC. More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod", Type: []string{"string"}, Format: "", }, @@ -6216,7 +6428,7 @@ func schema_k8sio_api_core_v1_GlusterfsVolumeSource(ref common.ReferenceCallback Properties: map[string]spec.Schema{ "endpoints": { SchemaProps: spec.SchemaProps{ - Description: "EndpointsName is the endpoint name that details Glusterfs topology. More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod", + Description: "endpoints is the endpoint name that details Glusterfs topology. More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod", Default: "", Type: []string{"string"}, Format: "", @@ -6224,7 +6436,7 @@ func schema_k8sio_api_core_v1_GlusterfsVolumeSource(ref common.ReferenceCallback }, "path": { SchemaProps: spec.SchemaProps{ - Description: "Path is the Glusterfs volume path. More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod", + Description: "path is the Glusterfs volume path. More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod", Default: "", Type: []string{"string"}, Format: "", @@ -6232,7 +6444,7 @@ func schema_k8sio_api_core_v1_GlusterfsVolumeSource(ref common.ReferenceCallback }, "readOnly": { SchemaProps: spec.SchemaProps{ - Description: "ReadOnly here will force the Glusterfs volume to be mounted with read-only permissions. Defaults to false. More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod", + Description: "readOnly here will force the Glusterfs volume to be mounted with read-only permissions. Defaults to false. More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod", Type: []string{"boolean"}, Format: "", }, @@ -6274,10 +6486,10 @@ func schema_k8sio_api_core_v1_HTTPGetAction(ref common.ReferenceCallback) common }, "scheme": { SchemaProps: spec.SchemaProps{ - Description: "Scheme to use for connecting to the host. Defaults to HTTP.", + Description: "Scheme to use for connecting to the host. Defaults to HTTP.\n\nPossible enum values:\n - `\"HTTP\"` means that the scheme used will be http://\n - `\"HTTPS\"` means that the scheme used will be https://", Type: []string{"string"}, Format: "", - }, + Enum: []interface{}{"HTTP", "HTTPS"}}, }, "httpHeaders": { SchemaProps: spec.SchemaProps{ @@ -6332,39 +6544,6 @@ func schema_k8sio_api_core_v1_HTTPHeader(ref common.ReferenceCallback) common.Op } } -func schema_k8sio_api_core_v1_Handler(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "Handler defines a specific action that should be taken", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "exec": { - SchemaProps: spec.SchemaProps{ - Description: "One and only one of the following should be specified. Exec specifies the action to take.", - Ref: ref("k8s.io/api/core/v1.ExecAction"), - }, - }, - "httpGet": { - SchemaProps: spec.SchemaProps{ - Description: "HTTPGet specifies the http request to perform.", - Ref: ref("k8s.io/api/core/v1.HTTPGetAction"), - }, - }, - "tcpSocket": { - SchemaProps: spec.SchemaProps{ - Description: "TCPSocket specifies an action involving a TCP port. TCP hooks not yet supported", - Ref: ref("k8s.io/api/core/v1.TCPSocketAction"), - }, - }, - }, - }, - }, - Dependencies: []string{ - "k8s.io/api/core/v1.ExecAction", "k8s.io/api/core/v1.HTTPGetAction", "k8s.io/api/core/v1.TCPSocketAction"}, - } -} - func schema_k8sio_api_core_v1_HostAlias(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ @@ -6409,7 +6588,7 @@ func schema_k8sio_api_core_v1_HostPathVolumeSource(ref common.ReferenceCallback) Properties: map[string]spec.Schema{ "path": { SchemaProps: spec.SchemaProps{ - Description: "Path of the directory on the host. If the path is a symlink, it will follow the link to the real path. More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath", + Description: "path of the directory on the host. If the path is a symlink, it will follow the link to the real path. More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath", Default: "", Type: []string{"string"}, Format: "", @@ -6417,7 +6596,7 @@ func schema_k8sio_api_core_v1_HostPathVolumeSource(ref common.ReferenceCallback) }, "type": { SchemaProps: spec.SchemaProps{ - Description: "Type for HostPath Volume Defaults to \"\" More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath", + Description: "type for HostPath Volume Defaults to \"\" More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath", Type: []string{"string"}, Format: "", }, @@ -6438,7 +6617,7 @@ func schema_k8sio_api_core_v1_ISCSIPersistentVolumeSource(ref common.ReferenceCa Properties: map[string]spec.Schema{ "targetPortal": { SchemaProps: spec.SchemaProps{ - Description: "iSCSI Target Portal. The Portal is either an IP or ip_addr:port if the port is other than default (typically TCP ports 860 and 3260).", + Description: "targetPortal is iSCSI Target Portal. The Portal is either an IP or ip_addr:port if the port is other than default (typically TCP ports 860 and 3260).", Default: "", Type: []string{"string"}, Format: "", @@ -6446,7 +6625,7 @@ func schema_k8sio_api_core_v1_ISCSIPersistentVolumeSource(ref common.ReferenceCa }, "iqn": { SchemaProps: spec.SchemaProps{ - Description: "Target iSCSI Qualified Name.", + Description: "iqn is Target iSCSI Qualified Name.", Default: "", Type: []string{"string"}, Format: "", @@ -6454,7 +6633,7 @@ func schema_k8sio_api_core_v1_ISCSIPersistentVolumeSource(ref common.ReferenceCa }, "lun": { SchemaProps: spec.SchemaProps{ - Description: "iSCSI Target Lun number.", + Description: "lun is iSCSI Target Lun number.", Default: 0, Type: []string{"integer"}, Format: "int32", @@ -6462,28 +6641,28 @@ func schema_k8sio_api_core_v1_ISCSIPersistentVolumeSource(ref common.ReferenceCa }, "iscsiInterface": { SchemaProps: spec.SchemaProps{ - Description: "iSCSI Interface Name that uses an iSCSI transport. Defaults to 'default' (tcp).", + Description: "iscsiInterface is the interface Name that uses an iSCSI transport. Defaults to 'default' (tcp).", Type: []string{"string"}, Format: "", }, }, "fsType": { SchemaProps: spec.SchemaProps{ - Description: "Filesystem type of the volume that you want to mount. Tip: Ensure that the filesystem type is supported by the host operating system. Examples: \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#iscsi", + Description: "fsType is the filesystem type of the volume that you want to mount. Tip: Ensure that the filesystem type is supported by the host operating system. Examples: \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#iscsi", Type: []string{"string"}, Format: "", }, }, "readOnly": { SchemaProps: spec.SchemaProps{ - Description: "ReadOnly here will force the ReadOnly setting in VolumeMounts. Defaults to false.", + Description: "readOnly here will force the ReadOnly setting in VolumeMounts. Defaults to false.", Type: []string{"boolean"}, Format: "", }, }, "portals": { SchemaProps: spec.SchemaProps{ - Description: "iSCSI Target Portal List. The Portal is either an IP or ip_addr:port if the port is other than default (typically TCP ports 860 and 3260).", + Description: "portals is the iSCSI Target Portal List. The Portal is either an IP or ip_addr:port if the port is other than default (typically TCP ports 860 and 3260).", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ @@ -6498,27 +6677,27 @@ func schema_k8sio_api_core_v1_ISCSIPersistentVolumeSource(ref common.ReferenceCa }, "chapAuthDiscovery": { SchemaProps: spec.SchemaProps{ - Description: "whether support iSCSI Discovery CHAP authentication", + Description: "chapAuthDiscovery defines whether support iSCSI Discovery CHAP authentication", Type: []string{"boolean"}, Format: "", }, }, "chapAuthSession": { SchemaProps: spec.SchemaProps{ - Description: "whether support iSCSI Session CHAP authentication", + Description: "chapAuthSession defines whether support iSCSI Session CHAP authentication", Type: []string{"boolean"}, Format: "", }, }, "secretRef": { SchemaProps: spec.SchemaProps{ - Description: "CHAP Secret for iSCSI target and initiator authentication", + Description: "secretRef is the CHAP Secret for iSCSI target and initiator authentication", Ref: ref("k8s.io/api/core/v1.SecretReference"), }, }, "initiatorName": { SchemaProps: spec.SchemaProps{ - Description: "Custom iSCSI Initiator Name. If initiatorName is specified with iscsiInterface simultaneously, new iSCSI interface : will be created for the connection.", + Description: "initiatorName is the custom iSCSI Initiator Name. If initiatorName is specified with iscsiInterface simultaneously, new iSCSI interface : will be created for the connection.", Type: []string{"string"}, Format: "", }, @@ -6541,7 +6720,7 @@ func schema_k8sio_api_core_v1_ISCSIVolumeSource(ref common.ReferenceCallback) co Properties: map[string]spec.Schema{ "targetPortal": { SchemaProps: spec.SchemaProps{ - Description: "iSCSI Target Portal. The Portal is either an IP or ip_addr:port if the port is other than default (typically TCP ports 860 and 3260).", + Description: "targetPortal is iSCSI Target Portal. The Portal is either an IP or ip_addr:port if the port is other than default (typically TCP ports 860 and 3260).", Default: "", Type: []string{"string"}, Format: "", @@ -6549,7 +6728,7 @@ func schema_k8sio_api_core_v1_ISCSIVolumeSource(ref common.ReferenceCallback) co }, "iqn": { SchemaProps: spec.SchemaProps{ - Description: "Target iSCSI Qualified Name.", + Description: "iqn is the target iSCSI Qualified Name.", Default: "", Type: []string{"string"}, Format: "", @@ -6557,7 +6736,7 @@ func schema_k8sio_api_core_v1_ISCSIVolumeSource(ref common.ReferenceCallback) co }, "lun": { SchemaProps: spec.SchemaProps{ - Description: "iSCSI Target Lun number.", + Description: "lun represents iSCSI Target Lun number.", Default: 0, Type: []string{"integer"}, Format: "int32", @@ -6565,28 +6744,28 @@ func schema_k8sio_api_core_v1_ISCSIVolumeSource(ref common.ReferenceCallback) co }, "iscsiInterface": { SchemaProps: spec.SchemaProps{ - Description: "iSCSI Interface Name that uses an iSCSI transport. Defaults to 'default' (tcp).", + Description: "iscsiInterface is the interface Name that uses an iSCSI transport. Defaults to 'default' (tcp).", Type: []string{"string"}, Format: "", }, }, "fsType": { SchemaProps: spec.SchemaProps{ - Description: "Filesystem type of the volume that you want to mount. Tip: Ensure that the filesystem type is supported by the host operating system. Examples: \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#iscsi", + Description: "fsType is the filesystem type of the volume that you want to mount. Tip: Ensure that the filesystem type is supported by the host operating system. Examples: \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#iscsi", Type: []string{"string"}, Format: "", }, }, "readOnly": { SchemaProps: spec.SchemaProps{ - Description: "ReadOnly here will force the ReadOnly setting in VolumeMounts. Defaults to false.", + Description: "readOnly here will force the ReadOnly setting in VolumeMounts. Defaults to false.", Type: []string{"boolean"}, Format: "", }, }, "portals": { SchemaProps: spec.SchemaProps{ - Description: "iSCSI Target Portal List. The portal is either an IP or ip_addr:port if the port is other than default (typically TCP ports 860 and 3260).", + Description: "portals is the iSCSI Target Portal List. The portal is either an IP or ip_addr:port if the port is other than default (typically TCP ports 860 and 3260).", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ @@ -6601,27 +6780,27 @@ func schema_k8sio_api_core_v1_ISCSIVolumeSource(ref common.ReferenceCallback) co }, "chapAuthDiscovery": { SchemaProps: spec.SchemaProps{ - Description: "whether support iSCSI Discovery CHAP authentication", + Description: "chapAuthDiscovery defines whether support iSCSI Discovery CHAP authentication", Type: []string{"boolean"}, Format: "", }, }, "chapAuthSession": { SchemaProps: spec.SchemaProps{ - Description: "whether support iSCSI Session CHAP authentication", + Description: "chapAuthSession defines whether support iSCSI Session CHAP authentication", Type: []string{"boolean"}, Format: "", }, }, "secretRef": { SchemaProps: spec.SchemaProps{ - Description: "CHAP Secret for iSCSI target and initiator authentication", + Description: "secretRef is the CHAP Secret for iSCSI target and initiator authentication", Ref: ref("k8s.io/api/core/v1.LocalObjectReference"), }, }, "initiatorName": { SchemaProps: spec.SchemaProps{ - Description: "Custom iSCSI Initiator Name. If initiatorName is specified with iscsiInterface simultaneously, new iSCSI interface : will be created for the connection.", + Description: "initiatorName is the custom iSCSI Initiator Name. If initiatorName is specified with iscsiInterface simultaneously, new iSCSI interface : will be created for the connection.", Type: []string{"string"}, Format: "", }, @@ -6644,7 +6823,7 @@ func schema_k8sio_api_core_v1_KeyToPath(ref common.ReferenceCallback) common.Ope Properties: map[string]spec.Schema{ "key": { SchemaProps: spec.SchemaProps{ - Description: "The key to project.", + Description: "key is the key to project.", Default: "", Type: []string{"string"}, Format: "", @@ -6652,50 +6831,83 @@ func schema_k8sio_api_core_v1_KeyToPath(ref common.ReferenceCallback) common.Ope }, "path": { SchemaProps: spec.SchemaProps{ - Description: "The relative path of the file to map the key to. May not be an absolute path. May not contain the path element '..'. May not start with the string '..'.", - Default: "", - Type: []string{"string"}, - Format: "", + Description: "path is the relative path of the file to map the key to. May not be an absolute path. May not contain the path element '..'. May not start with the string '..'.", + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "mode": { + SchemaProps: spec.SchemaProps{ + Description: "mode is Optional: mode bits used to set permissions on this file. Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.", + Type: []string{"integer"}, + Format: "int32", + }, + }, + }, + Required: []string{"key", "path"}, + }, + }, + } +} + +func schema_k8sio_api_core_v1_Lifecycle(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "Lifecycle describes actions that the management system should take in response to container lifecycle events. For the PostStart and PreStop lifecycle handlers, management of the container blocks until the action is complete, unless the container process fails, in which case the handler is aborted.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "postStart": { + SchemaProps: spec.SchemaProps{ + Description: "PostStart is called immediately after a container is created. If the handler fails, the container is terminated and restarted according to its restart policy. Other management of the container blocks until the hook completes. More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks", + Ref: ref("k8s.io/api/core/v1.LifecycleHandler"), }, }, - "mode": { + "preStop": { SchemaProps: spec.SchemaProps{ - Description: "Optional: mode bits used to set permissions on this file. Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.", - Type: []string{"integer"}, - Format: "int32", + Description: "PreStop is called immediately before a container is terminated due to an API request or management event such as liveness/startup probe failure, preemption, resource contention, etc. The handler is not called if the container crashes or exits. The Pod's termination grace period countdown begins before the PreStop hook is executed. Regardless of the outcome of the handler, the container will eventually terminate within the Pod's termination grace period (unless delayed by finalizers). Other management of the container blocks until the hook completes or until the termination grace period is reached. More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks", + Ref: ref("k8s.io/api/core/v1.LifecycleHandler"), }, }, }, - Required: []string{"key", "path"}, }, }, + Dependencies: []string{ + "k8s.io/api/core/v1.LifecycleHandler"}, } } -func schema_k8sio_api_core_v1_Lifecycle(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_k8sio_api_core_v1_LifecycleHandler(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "Lifecycle describes actions that the management system should take in response to container lifecycle events. For the PostStart and PreStop lifecycle handlers, management of the container blocks until the action is complete, unless the container process fails, in which case the handler is aborted.", + Description: "LifecycleHandler defines a specific action that should be taken in a lifecycle hook. One and only one of the fields, except TCPSocket must be specified.", Type: []string{"object"}, Properties: map[string]spec.Schema{ - "postStart": { + "exec": { SchemaProps: spec.SchemaProps{ - Description: "PostStart is called immediately after a container is created. If the handler fails, the container is terminated and restarted according to its restart policy. Other management of the container blocks until the hook completes. More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks", - Ref: ref("k8s.io/api/core/v1.Handler"), + Description: "Exec specifies the action to take.", + Ref: ref("k8s.io/api/core/v1.ExecAction"), }, }, - "preStop": { + "httpGet": { + SchemaProps: spec.SchemaProps{ + Description: "HTTPGet specifies the http request to perform.", + Ref: ref("k8s.io/api/core/v1.HTTPGetAction"), + }, + }, + "tcpSocket": { SchemaProps: spec.SchemaProps{ - Description: "PreStop is called immediately before a container is terminated due to an API request or management event such as liveness/startup probe failure, preemption, resource contention, etc. The handler is not called if the container crashes or exits. The reason for termination is passed to the handler. The Pod's termination grace period countdown begins before the PreStop hooked is executed. Regardless of the outcome of the handler, the container will eventually terminate within the Pod's termination grace period. Other management of the container blocks until the hook completes or until the termination grace period is reached. More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks", - Ref: ref("k8s.io/api/core/v1.Handler"), + Description: "Deprecated. TCPSocket is NOT supported as a LifecycleHandler and kept for the backward compatibility. There are no validation of this field and lifecycle hooks will fail in runtime when tcp handler is specified.", + Ref: ref("k8s.io/api/core/v1.TCPSocketAction"), }, }, }, }, }, Dependencies: []string{ - "k8s.io/api/core/v1.Handler"}, + "k8s.io/api/core/v1.ExecAction", "k8s.io/api/core/v1.HTTPGetAction", "k8s.io/api/core/v1.TCPSocketAction"}, } } @@ -7066,6 +7278,11 @@ func schema_k8sio_api_core_v1_LocalObjectReference(ref common.ReferenceCallback) }, }, }, + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-map-type": "atomic", + }, + }, }, } } @@ -7079,7 +7296,7 @@ func schema_k8sio_api_core_v1_LocalVolumeSource(ref common.ReferenceCallback) co Properties: map[string]spec.Schema{ "path": { SchemaProps: spec.SchemaProps{ - Description: "The full path to the volume on the node. It can be either a directory or block device (disk, partition, ...).", + Description: "path of the full path to the volume on the node. It can be either a directory or block device (disk, partition, ...).", Default: "", Type: []string{"string"}, Format: "", @@ -7087,7 +7304,7 @@ func schema_k8sio_api_core_v1_LocalVolumeSource(ref common.ReferenceCallback) co }, "fsType": { SchemaProps: spec.SchemaProps{ - Description: "Filesystem type to mount. It applies only when the Path is a block device. Must be a filesystem type supported by the host operating system. Ex. \"ext4\", \"xfs\", \"ntfs\". The default value is to auto-select a fileystem if unspecified.", + Description: "fsType is the filesystem type to mount. It applies only when the Path is a block device. Must be a filesystem type supported by the host operating system. Ex. \"ext4\", \"xfs\", \"ntfs\". The default value is to auto-select a filesystem if unspecified.", Type: []string{"string"}, Format: "", }, @@ -7108,7 +7325,7 @@ func schema_k8sio_api_core_v1_NFSVolumeSource(ref common.ReferenceCallback) comm Properties: map[string]spec.Schema{ "server": { SchemaProps: spec.SchemaProps{ - Description: "Server is the hostname or IP address of the NFS server. More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs", + Description: "server is the hostname or IP address of the NFS server. More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs", Default: "", Type: []string{"string"}, Format: "", @@ -7116,7 +7333,7 @@ func schema_k8sio_api_core_v1_NFSVolumeSource(ref common.ReferenceCallback) comm }, "path": { SchemaProps: spec.SchemaProps{ - Description: "Path that is exported by the NFS server. More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs", + Description: "path that is exported by the NFS server. More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs", Default: "", Type: []string{"string"}, Format: "", @@ -7124,7 +7341,7 @@ func schema_k8sio_api_core_v1_NFSVolumeSource(ref common.ReferenceCallback) comm }, "readOnly": { SchemaProps: spec.SchemaProps{ - Description: "ReadOnly here will force the NFS export to be mounted with read-only permissions. Defaults to false. More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs", + Description: "readOnly here will force the NFS export to be mounted with read-only permissions. Defaults to false. More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs", Type: []string{"boolean"}, Format: "", }, @@ -7324,10 +7541,10 @@ func schema_k8sio_api_core_v1_NamespaceStatus(ref common.ReferenceCallback) comm Properties: map[string]spec.Schema{ "phase": { SchemaProps: spec.SchemaProps{ - Description: "Phase is the current lifecycle phase of the namespace. More info: https://kubernetes.io/docs/tasks/administer-cluster/namespaces/", + Description: "Phase is the current lifecycle phase of the namespace. More info: https://kubernetes.io/docs/tasks/administer-cluster/namespaces/\n\nPossible enum values:\n - `\"Active\"` means the namespace is available for use in the system\n - `\"Terminating\"` means the namespace is undergoing graceful termination", Type: []string{"string"}, Format: "", - }, + Enum: []interface{}{"Active", "Terminating"}}, }, "conditions": { VendorExtensible: spec.VendorExtensible{ @@ -7536,7 +7753,7 @@ func schema_k8sio_api_core_v1_NodeConfigSource(ref common.ReferenceCallback) com return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "NodeConfigSource specifies a source of node configuration. Exactly one subfield (excluding metadata) must be non-nil.", + Description: "NodeConfigSource specifies a source of node configuration. Exactly one subfield (excluding metadata) must be non-nil. This API is deprecated since 1.22", Type: []string{"object"}, Properties: map[string]spec.Schema{ "configMap": { @@ -7755,6 +7972,11 @@ func schema_k8sio_api_core_v1_NodeSelector(ref common.ReferenceCallback) common. }, Required: []string{"nodeSelectorTerms"}, }, + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-map-type": "atomic", + }, + }, }, Dependencies: []string{ "k8s.io/api/core/v1.NodeSelectorTerm"}, @@ -7778,11 +8000,11 @@ func schema_k8sio_api_core_v1_NodeSelectorRequirement(ref common.ReferenceCallba }, "operator": { SchemaProps: spec.SchemaProps{ - Description: "Represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt.", + Description: "Represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt.\n\nPossible enum values:\n - `\"DoesNotExist\"`\n - `\"Exists\"`\n - `\"Gt\"`\n - `\"In\"`\n - `\"Lt\"`\n - `\"NotIn\"`", Default: "", Type: []string{"string"}, Format: "", - }, + Enum: []interface{}{"DoesNotExist", "Exists", "Gt", "In", "Lt", "NotIn"}}, }, "values": { SchemaProps: spec.SchemaProps{ @@ -7843,6 +8065,11 @@ func schema_k8sio_api_core_v1_NodeSelectorTerm(ref common.ReferenceCallback) com }, }, }, + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-map-type": "atomic", + }, + }, }, Dependencies: []string{ "k8s.io/api/core/v1.NodeSelectorRequirement"}, @@ -7913,7 +8140,7 @@ func schema_k8sio_api_core_v1_NodeSpec(ref common.ReferenceCallback) common.Open }, "configSource": { SchemaProps: spec.SchemaProps{ - Description: "If specified, the source to get node configuration from The DynamicKubeletConfig feature gate must be enabled for the Kubelet to use this field", + Description: "Deprecated: Previously used to specify the source of the node's configuration for the DynamicKubeletConfig feature. This feature is removed from Kubelets as of 1.24 and will be fully removed in 1.26.", Ref: ref("k8s.io/api/core/v1.NodeConfigSource"), }, }, @@ -7971,10 +8198,10 @@ func schema_k8sio_api_core_v1_NodeStatus(ref common.ReferenceCallback) common.Op }, "phase": { SchemaProps: spec.SchemaProps{ - Description: "NodePhase is the recently observed lifecycle phase of the node. More info: https://kubernetes.io/docs/concepts/nodes/node/#phase The field is never populated, and now is deprecated.", + Description: "NodePhase is the recently observed lifecycle phase of the node. More info: https://kubernetes.io/docs/concepts/nodes/node/#phase The field is never populated, and now is deprecated.\n\nPossible enum values:\n - `\"Pending\"` means the node has been created/added by the system, but not configured.\n - `\"Running\"` means the node has been configured and has Kubernetes components running.\n - `\"Terminated\"` means the node has been removed from the cluster.", Type: []string{"string"}, Format: "", - }, + Enum: []interface{}{"Pending", "Running", "Terminated"}}, }, "conditions": { VendorExtensible: spec.VendorExtensible{ @@ -8136,7 +8363,7 @@ func schema_k8sio_api_core_v1_NodeSystemInfo(ref common.ReferenceCallback) commo }, "containerRuntimeVersion": { SchemaProps: spec.SchemaProps{ - Description: "ContainerRuntime Version reported by the node through runtime remote API (e.g. docker://1.5.0).", + Description: "ContainerRuntime Version reported by the node through runtime remote API (e.g. containerd://1.4.2).", Default: "", Type: []string{"string"}, Format: "", @@ -8206,6 +8433,11 @@ func schema_k8sio_api_core_v1_ObjectFieldSelector(ref common.ReferenceCallback) }, Required: []string{"fieldPath"}, }, + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-map-type": "atomic", + }, + }, }, } } @@ -8268,6 +8500,11 @@ func schema_k8sio_api_core_v1_ObjectReference(ref common.ReferenceCallback) comm }, }, }, + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-map-type": "atomic", + }, + }, }, } } @@ -8302,14 +8539,14 @@ func schema_k8sio_api_core_v1_PersistentVolume(ref common.ReferenceCallback) com }, "spec": { SchemaProps: spec.SchemaProps{ - Description: "Spec defines a specification of a persistent volume owned by the cluster. Provisioned by an administrator. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistent-volumes", + Description: "spec defines a specification of a persistent volume owned by the cluster. Provisioned by an administrator. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistent-volumes", Default: map[string]interface{}{}, Ref: ref("k8s.io/api/core/v1.PersistentVolumeSpec"), }, }, "status": { SchemaProps: spec.SchemaProps{ - Description: "Status represents the current information/status for the persistent volume. Populated by the system. Read-only. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistent-volumes", + Description: "status represents the current information/status for the persistent volume. Populated by the system. Read-only. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistent-volumes", Default: map[string]interface{}{}, Ref: ref("k8s.io/api/core/v1.PersistentVolumeStatus"), }, @@ -8352,14 +8589,14 @@ func schema_k8sio_api_core_v1_PersistentVolumeClaim(ref common.ReferenceCallback }, "spec": { SchemaProps: spec.SchemaProps{ - Description: "Spec defines the desired characteristics of a volume requested by a pod author. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims", + Description: "spec defines the desired characteristics of a volume requested by a pod author. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims", Default: map[string]interface{}{}, Ref: ref("k8s.io/api/core/v1.PersistentVolumeClaimSpec"), }, }, "status": { SchemaProps: spec.SchemaProps{ - Description: "Status represents the current information/status of a persistent volume claim. Read-only. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims", + Description: "status represents the current information/status of a persistent volume claim. Read-only. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims", Default: map[string]interface{}{}, Ref: ref("k8s.io/api/core/v1.PersistentVolumeClaimStatus"), }, @@ -8395,28 +8632,28 @@ func schema_k8sio_api_core_v1_PersistentVolumeClaimCondition(ref common.Referenc }, "lastProbeTime": { SchemaProps: spec.SchemaProps{ - Description: "Last time we probed the condition.", + Description: "lastProbeTime is the time we probed the condition.", Default: map[string]interface{}{}, Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), }, }, "lastTransitionTime": { SchemaProps: spec.SchemaProps{ - Description: "Last time the condition transitioned from one status to another.", + Description: "lastTransitionTime is the time the condition transitioned from one status to another.", Default: map[string]interface{}{}, Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), }, }, "reason": { SchemaProps: spec.SchemaProps{ - Description: "Unique, this should be a short, machine understandable string that gives the reason for condition's last transition. If it reports \"ResizeStarted\" that means the underlying persistent volume is being resized.", + Description: "reason is a unique, this should be a short, machine understandable string that gives the reason for condition's last transition. If it reports \"ResizeStarted\" that means the underlying persistent volume is being resized.", Type: []string{"string"}, Format: "", }, }, "message": { SchemaProps: spec.SchemaProps{ - Description: "Human-readable message indicating details about last transition.", + Description: "message is the human-readable message indicating details about last transition.", Type: []string{"string"}, Format: "", }, @@ -8460,7 +8697,7 @@ func schema_k8sio_api_core_v1_PersistentVolumeClaimList(ref common.ReferenceCall }, "items": { SchemaProps: spec.SchemaProps{ - Description: "A list of persistent volume claims. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims", + Description: "items is a list of persistent volume claims. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ @@ -8490,7 +8727,7 @@ func schema_k8sio_api_core_v1_PersistentVolumeClaimSpec(ref common.ReferenceCall Properties: map[string]spec.Schema{ "accessModes": { SchemaProps: spec.SchemaProps{ - Description: "AccessModes contains the desired access modes the volume should have. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1", + Description: "accessModes contains the desired access modes the volume should have. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ @@ -8505,27 +8742,27 @@ func schema_k8sio_api_core_v1_PersistentVolumeClaimSpec(ref common.ReferenceCall }, "selector": { SchemaProps: spec.SchemaProps{ - Description: "A label query over volumes to consider for binding.", + Description: "selector is a label query over volumes to consider for binding.", Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.LabelSelector"), }, }, "resources": { SchemaProps: spec.SchemaProps{ - Description: "Resources represents the minimum resources the volume should have. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources", + Description: "resources represents the minimum resources the volume should have. If RecoverVolumeExpansionFailure feature is enabled users are allowed to specify resource requirements that are lower than previous value but must still be higher than capacity recorded in the status field of the claim. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources", Default: map[string]interface{}{}, Ref: ref("k8s.io/api/core/v1.ResourceRequirements"), }, }, "volumeName": { SchemaProps: spec.SchemaProps{ - Description: "VolumeName is the binding reference to the PersistentVolume backing this claim.", + Description: "volumeName is the binding reference to the PersistentVolume backing this claim.", Type: []string{"string"}, Format: "", }, }, "storageClassName": { SchemaProps: spec.SchemaProps{ - Description: "Name of the StorageClass required by the claim. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1", + Description: "storageClassName is the name of the StorageClass required by the claim. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1", Type: []string{"string"}, Format: "", }, @@ -8539,7 +8776,13 @@ func schema_k8sio_api_core_v1_PersistentVolumeClaimSpec(ref common.ReferenceCall }, "dataSource": { SchemaProps: spec.SchemaProps{ - Description: "This field can be used to specify either: * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) * An existing PVC (PersistentVolumeClaim) * An existing custom resource that implements data population (Alpha) In order to use custom resource types that implement data population, the AnyVolumeDataSource feature gate must be enabled. If the provisioner or an external controller can support the specified data source, it will create a new volume based on the contents of the specified data source.", + Description: "dataSource field can be used to specify either: * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) * An existing PVC (PersistentVolumeClaim) If the provisioner or an external controller can support the specified data source, it will create a new volume based on the contents of the specified data source. If the AnyVolumeDataSource feature gate is enabled, this field will always have the same contents as the DataSourceRef field.", + Ref: ref("k8s.io/api/core/v1.TypedLocalObjectReference"), + }, + }, + "dataSourceRef": { + SchemaProps: spec.SchemaProps{ + Description: "dataSourceRef specifies the object from which to populate the volume with data, if a non-empty volume is desired. This may be any local object from a non-empty API group (non core object) or a PersistentVolumeClaim object. When this field is specified, volume binding will only succeed if the type of the specified object matches some installed volume populator or dynamic provisioner. This field will replace the functionality of the DataSource field and as such if both fields are non-empty, they must have the same value. For backwards compatibility, both fields (DataSource and DataSourceRef) will be set to the same value automatically if one of them is empty and the other is non-empty. There are two important differences between DataSource and DataSourceRef: * While DataSource only allows two specific types of objects, DataSourceRef\n allows any non-core object, as well as PersistentVolumeClaim objects.\n* While DataSource ignores disallowed values (dropping them), DataSourceRef\n preserves all values, and generates an error if a disallowed value is\n specified.\n(Beta) Using this field requires the AnyVolumeDataSource feature gate to be enabled.", Ref: ref("k8s.io/api/core/v1.TypedLocalObjectReference"), }, }, @@ -8560,14 +8803,14 @@ func schema_k8sio_api_core_v1_PersistentVolumeClaimStatus(ref common.ReferenceCa Properties: map[string]spec.Schema{ "phase": { SchemaProps: spec.SchemaProps{ - Description: "Phase represents the current phase of PersistentVolumeClaim.", + Description: "phase represents the current phase of PersistentVolumeClaim.\n\nPossible enum values:\n - `\"Bound\"` used for PersistentVolumeClaims that are bound\n - `\"Lost\"` used for PersistentVolumeClaims that lost their underlying PersistentVolume. The claim was bound to a PersistentVolume and this volume does not exist any longer and all data on it was lost.\n - `\"Pending\"` used for PersistentVolumeClaims that are not yet bound", Type: []string{"string"}, Format: "", - }, + Enum: []interface{}{"Bound", "Lost", "Pending"}}, }, "accessModes": { SchemaProps: spec.SchemaProps{ - Description: "AccessModes contains the actual access modes the volume backing the PVC has. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1", + Description: "accessModes contains the actual access modes the volume backing the PVC has. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ @@ -8582,7 +8825,7 @@ func schema_k8sio_api_core_v1_PersistentVolumeClaimStatus(ref common.ReferenceCa }, "capacity": { SchemaProps: spec.SchemaProps{ - Description: "Represents the actual resources of the underlying volume.", + Description: "capacity represents the actual resources of the underlying volume.", Type: []string{"object"}, AdditionalProperties: &spec.SchemaOrBool{ Allows: true, @@ -8603,7 +8846,7 @@ func schema_k8sio_api_core_v1_PersistentVolumeClaimStatus(ref common.ReferenceCa }, }, SchemaProps: spec.SchemaProps{ - Description: "Current Condition of persistent volume claim. If underlying persistent volume is being resized then the Condition will be set to 'ResizeStarted'.", + Description: "conditions is the current Condition of persistent volume claim. If underlying persistent volume is being resized then the Condition will be set to 'ResizeStarted'.", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ @@ -8615,6 +8858,28 @@ func schema_k8sio_api_core_v1_PersistentVolumeClaimStatus(ref common.ReferenceCa }, }, }, + "allocatedResources": { + SchemaProps: spec.SchemaProps{ + Description: "allocatedResources is the storage resource within AllocatedResources tracks the capacity allocated to a PVC. It may be larger than the actual capacity when a volume expansion operation is requested. For storage quota, the larger value from allocatedResources and PVC.spec.resources is used. If allocatedResources is not set, PVC.spec.resources alone is used for quota calculation. If a volume expansion capacity request is lowered, allocatedResources is only lowered if there are no expansion operations in progress and if the actual volume capacity is equal or lower than the requested capacity. This is an alpha field and requires enabling RecoverVolumeExpansionFailure feature.", + Type: []string{"object"}, + AdditionalProperties: &spec.SchemaOrBool{ + Allows: true, + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/api/resource.Quantity"), + }, + }, + }, + }, + }, + "resizeStatus": { + SchemaProps: spec.SchemaProps{ + Description: "resizeStatus stores status of resize operation. ResizeStatus is not set by default but when expansion is complete resizeStatus is set to empty string by resize controller or kubelet. This is an alpha field and requires enabling RecoverVolumeExpansionFailure feature.", + Type: []string{"string"}, + Format: "", + }, + }, }, }, }, @@ -8662,7 +8927,7 @@ func schema_k8sio_api_core_v1_PersistentVolumeClaimVolumeSource(ref common.Refer Properties: map[string]spec.Schema{ "claimName": { SchemaProps: spec.SchemaProps{ - Description: "ClaimName is the name of a PersistentVolumeClaim in the same namespace as the pod using this volume. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims", + Description: "claimName is the name of a PersistentVolumeClaim in the same namespace as the pod using this volume. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims", Default: "", Type: []string{"string"}, Format: "", @@ -8670,7 +8935,7 @@ func schema_k8sio_api_core_v1_PersistentVolumeClaimVolumeSource(ref common.Refer }, "readOnly": { SchemaProps: spec.SchemaProps{ - Description: "Will force the ReadOnly setting in VolumeMounts. Default false.", + Description: "readOnly Will force the ReadOnly setting in VolumeMounts. Default false.", Type: []string{"boolean"}, Format: "", }, @@ -8712,7 +8977,7 @@ func schema_k8sio_api_core_v1_PersistentVolumeList(ref common.ReferenceCallback) }, "items": { SchemaProps: spec.SchemaProps{ - Description: "List of persistent volumes. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes", + Description: "items is a list of persistent volumes. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ @@ -8742,133 +9007,133 @@ func schema_k8sio_api_core_v1_PersistentVolumeSource(ref common.ReferenceCallbac Properties: map[string]spec.Schema{ "gcePersistentDisk": { SchemaProps: spec.SchemaProps{ - Description: "GCEPersistentDisk represents a GCE Disk resource that is attached to a kubelet's host machine and then exposed to the pod. Provisioned by an admin. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk", + Description: "gcePersistentDisk represents a GCE Disk resource that is attached to a kubelet's host machine and then exposed to the pod. Provisioned by an admin. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk", Ref: ref("k8s.io/api/core/v1.GCEPersistentDiskVolumeSource"), }, }, "awsElasticBlockStore": { SchemaProps: spec.SchemaProps{ - Description: "AWSElasticBlockStore represents an AWS Disk resource that is attached to a kubelet's host machine and then exposed to the pod. More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore", + Description: "awsElasticBlockStore represents an AWS Disk resource that is attached to a kubelet's host machine and then exposed to the pod. More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore", Ref: ref("k8s.io/api/core/v1.AWSElasticBlockStoreVolumeSource"), }, }, "hostPath": { SchemaProps: spec.SchemaProps{ - Description: "HostPath represents a directory on the host. Provisioned by a developer or tester. This is useful for single-node development and testing only! On-host storage is not supported in any way and WILL NOT WORK in a multi-node cluster. More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath", + Description: "hostPath represents a directory on the host. Provisioned by a developer or tester. This is useful for single-node development and testing only! On-host storage is not supported in any way and WILL NOT WORK in a multi-node cluster. More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath", Ref: ref("k8s.io/api/core/v1.HostPathVolumeSource"), }, }, "glusterfs": { SchemaProps: spec.SchemaProps{ - Description: "Glusterfs represents a Glusterfs volume that is attached to a host and exposed to the pod. Provisioned by an admin. More info: https://examples.k8s.io/volumes/glusterfs/README.md", + Description: "glusterfs represents a Glusterfs volume that is attached to a host and exposed to the pod. Provisioned by an admin. More info: https://examples.k8s.io/volumes/glusterfs/README.md", Ref: ref("k8s.io/api/core/v1.GlusterfsPersistentVolumeSource"), }, }, "nfs": { SchemaProps: spec.SchemaProps{ - Description: "NFS represents an NFS mount on the host. Provisioned by an admin. More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs", + Description: "nfs represents an NFS mount on the host. Provisioned by an admin. More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs", Ref: ref("k8s.io/api/core/v1.NFSVolumeSource"), }, }, "rbd": { SchemaProps: spec.SchemaProps{ - Description: "RBD represents a Rados Block Device mount on the host that shares a pod's lifetime. More info: https://examples.k8s.io/volumes/rbd/README.md", + Description: "rbd represents a Rados Block Device mount on the host that shares a pod's lifetime. More info: https://examples.k8s.io/volumes/rbd/README.md", Ref: ref("k8s.io/api/core/v1.RBDPersistentVolumeSource"), }, }, "iscsi": { SchemaProps: spec.SchemaProps{ - Description: "ISCSI represents an ISCSI Disk resource that is attached to a kubelet's host machine and then exposed to the pod. Provisioned by an admin.", + Description: "iscsi represents an ISCSI Disk resource that is attached to a kubelet's host machine and then exposed to the pod. Provisioned by an admin.", Ref: ref("k8s.io/api/core/v1.ISCSIPersistentVolumeSource"), }, }, "cinder": { SchemaProps: spec.SchemaProps{ - Description: "Cinder represents a cinder volume attached and mounted on kubelets host machine. More info: https://examples.k8s.io/mysql-cinder-pd/README.md", + Description: "cinder represents a cinder volume attached and mounted on kubelets host machine. More info: https://examples.k8s.io/mysql-cinder-pd/README.md", Ref: ref("k8s.io/api/core/v1.CinderPersistentVolumeSource"), }, }, "cephfs": { SchemaProps: spec.SchemaProps{ - Description: "CephFS represents a Ceph FS mount on the host that shares a pod's lifetime", + Description: "cephFS represents a Ceph FS mount on the host that shares a pod's lifetime", Ref: ref("k8s.io/api/core/v1.CephFSPersistentVolumeSource"), }, }, "fc": { SchemaProps: spec.SchemaProps{ - Description: "FC represents a Fibre Channel resource that is attached to a kubelet's host machine and then exposed to the pod.", + Description: "fc represents a Fibre Channel resource that is attached to a kubelet's host machine and then exposed to the pod.", Ref: ref("k8s.io/api/core/v1.FCVolumeSource"), }, }, "flocker": { SchemaProps: spec.SchemaProps{ - Description: "Flocker represents a Flocker volume attached to a kubelet's host machine and exposed to the pod for its usage. This depends on the Flocker control service being running", + Description: "flocker represents a Flocker volume attached to a kubelet's host machine and exposed to the pod for its usage. This depends on the Flocker control service being running", Ref: ref("k8s.io/api/core/v1.FlockerVolumeSource"), }, }, "flexVolume": { SchemaProps: spec.SchemaProps{ - Description: "FlexVolume represents a generic volume resource that is provisioned/attached using an exec based plugin.", + Description: "flexVolume represents a generic volume resource that is provisioned/attached using an exec based plugin.", Ref: ref("k8s.io/api/core/v1.FlexPersistentVolumeSource"), }, }, "azureFile": { SchemaProps: spec.SchemaProps{ - Description: "AzureFile represents an Azure File Service mount on the host and bind mount to the pod.", + Description: "azureFile represents an Azure File Service mount on the host and bind mount to the pod.", Ref: ref("k8s.io/api/core/v1.AzureFilePersistentVolumeSource"), }, }, "vsphereVolume": { SchemaProps: spec.SchemaProps{ - Description: "VsphereVolume represents a vSphere volume attached and mounted on kubelets host machine", + Description: "vsphereVolume represents a vSphere volume attached and mounted on kubelets host machine", Ref: ref("k8s.io/api/core/v1.VsphereVirtualDiskVolumeSource"), }, }, "quobyte": { SchemaProps: spec.SchemaProps{ - Description: "Quobyte represents a Quobyte mount on the host that shares a pod's lifetime", + Description: "quobyte represents a Quobyte mount on the host that shares a pod's lifetime", Ref: ref("k8s.io/api/core/v1.QuobyteVolumeSource"), }, }, "azureDisk": { SchemaProps: spec.SchemaProps{ - Description: "AzureDisk represents an Azure Data Disk mount on the host and bind mount to the pod.", + Description: "azureDisk represents an Azure Data Disk mount on the host and bind mount to the pod.", Ref: ref("k8s.io/api/core/v1.AzureDiskVolumeSource"), }, }, "photonPersistentDisk": { SchemaProps: spec.SchemaProps{ - Description: "PhotonPersistentDisk represents a PhotonController persistent disk attached and mounted on kubelets host machine", + Description: "photonPersistentDisk represents a PhotonController persistent disk attached and mounted on kubelets host machine", Ref: ref("k8s.io/api/core/v1.PhotonPersistentDiskVolumeSource"), }, }, "portworxVolume": { SchemaProps: spec.SchemaProps{ - Description: "PortworxVolume represents a portworx volume attached and mounted on kubelets host machine", + Description: "portworxVolume represents a portworx volume attached and mounted on kubelets host machine", Ref: ref("k8s.io/api/core/v1.PortworxVolumeSource"), }, }, "scaleIO": { SchemaProps: spec.SchemaProps{ - Description: "ScaleIO represents a ScaleIO persistent volume attached and mounted on Kubernetes nodes.", + Description: "scaleIO represents a ScaleIO persistent volume attached and mounted on Kubernetes nodes.", Ref: ref("k8s.io/api/core/v1.ScaleIOPersistentVolumeSource"), }, }, "local": { SchemaProps: spec.SchemaProps{ - Description: "Local represents directly-attached storage with node affinity", + Description: "local represents directly-attached storage with node affinity", Ref: ref("k8s.io/api/core/v1.LocalVolumeSource"), }, }, "storageos": { SchemaProps: spec.SchemaProps{ - Description: "StorageOS represents a StorageOS volume that is attached to the kubelet's host machine and mounted into the pod More info: https://examples.k8s.io/volumes/storageos/README.md", + Description: "storageOS represents a StorageOS volume that is attached to the kubelet's host machine and mounted into the pod More info: https://examples.k8s.io/volumes/storageos/README.md", Ref: ref("k8s.io/api/core/v1.StorageOSPersistentVolumeSource"), }, }, "csi": { SchemaProps: spec.SchemaProps{ - Description: "CSI represents storage that is handled by an external CSI driver (Beta feature).", + Description: "csi represents storage that is handled by an external CSI driver (Beta feature).", Ref: ref("k8s.io/api/core/v1.CSIPersistentVolumeSource"), }, }, @@ -8889,7 +9154,7 @@ func schema_k8sio_api_core_v1_PersistentVolumeSpec(ref common.ReferenceCallback) Properties: map[string]spec.Schema{ "capacity": { SchemaProps: spec.SchemaProps{ - Description: "A description of the persistent volume's resources and capacity. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#capacity", + Description: "capacity is the description of the persistent volume's resources and capacity. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#capacity", Type: []string{"object"}, AdditionalProperties: &spec.SchemaOrBool{ Allows: true, @@ -8904,139 +9169,139 @@ func schema_k8sio_api_core_v1_PersistentVolumeSpec(ref common.ReferenceCallback) }, "gcePersistentDisk": { SchemaProps: spec.SchemaProps{ - Description: "GCEPersistentDisk represents a GCE Disk resource that is attached to a kubelet's host machine and then exposed to the pod. Provisioned by an admin. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk", + Description: "gcePersistentDisk represents a GCE Disk resource that is attached to a kubelet's host machine and then exposed to the pod. Provisioned by an admin. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk", Ref: ref("k8s.io/api/core/v1.GCEPersistentDiskVolumeSource"), }, }, "awsElasticBlockStore": { SchemaProps: spec.SchemaProps{ - Description: "AWSElasticBlockStore represents an AWS Disk resource that is attached to a kubelet's host machine and then exposed to the pod. More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore", + Description: "awsElasticBlockStore represents an AWS Disk resource that is attached to a kubelet's host machine and then exposed to the pod. More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore", Ref: ref("k8s.io/api/core/v1.AWSElasticBlockStoreVolumeSource"), }, }, "hostPath": { SchemaProps: spec.SchemaProps{ - Description: "HostPath represents a directory on the host. Provisioned by a developer or tester. This is useful for single-node development and testing only! On-host storage is not supported in any way and WILL NOT WORK in a multi-node cluster. More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath", + Description: "hostPath represents a directory on the host. Provisioned by a developer or tester. This is useful for single-node development and testing only! On-host storage is not supported in any way and WILL NOT WORK in a multi-node cluster. More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath", Ref: ref("k8s.io/api/core/v1.HostPathVolumeSource"), }, }, "glusterfs": { SchemaProps: spec.SchemaProps{ - Description: "Glusterfs represents a Glusterfs volume that is attached to a host and exposed to the pod. Provisioned by an admin. More info: https://examples.k8s.io/volumes/glusterfs/README.md", + Description: "glusterfs represents a Glusterfs volume that is attached to a host and exposed to the pod. Provisioned by an admin. More info: https://examples.k8s.io/volumes/glusterfs/README.md", Ref: ref("k8s.io/api/core/v1.GlusterfsPersistentVolumeSource"), }, }, "nfs": { SchemaProps: spec.SchemaProps{ - Description: "NFS represents an NFS mount on the host. Provisioned by an admin. More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs", + Description: "nfs represents an NFS mount on the host. Provisioned by an admin. More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs", Ref: ref("k8s.io/api/core/v1.NFSVolumeSource"), }, }, "rbd": { SchemaProps: spec.SchemaProps{ - Description: "RBD represents a Rados Block Device mount on the host that shares a pod's lifetime. More info: https://examples.k8s.io/volumes/rbd/README.md", + Description: "rbd represents a Rados Block Device mount on the host that shares a pod's lifetime. More info: https://examples.k8s.io/volumes/rbd/README.md", Ref: ref("k8s.io/api/core/v1.RBDPersistentVolumeSource"), }, }, "iscsi": { SchemaProps: spec.SchemaProps{ - Description: "ISCSI represents an ISCSI Disk resource that is attached to a kubelet's host machine and then exposed to the pod. Provisioned by an admin.", + Description: "iscsi represents an ISCSI Disk resource that is attached to a kubelet's host machine and then exposed to the pod. Provisioned by an admin.", Ref: ref("k8s.io/api/core/v1.ISCSIPersistentVolumeSource"), }, }, "cinder": { SchemaProps: spec.SchemaProps{ - Description: "Cinder represents a cinder volume attached and mounted on kubelets host machine. More info: https://examples.k8s.io/mysql-cinder-pd/README.md", + Description: "cinder represents a cinder volume attached and mounted on kubelets host machine. More info: https://examples.k8s.io/mysql-cinder-pd/README.md", Ref: ref("k8s.io/api/core/v1.CinderPersistentVolumeSource"), }, }, "cephfs": { SchemaProps: spec.SchemaProps{ - Description: "CephFS represents a Ceph FS mount on the host that shares a pod's lifetime", + Description: "cephFS represents a Ceph FS mount on the host that shares a pod's lifetime", Ref: ref("k8s.io/api/core/v1.CephFSPersistentVolumeSource"), }, }, "fc": { SchemaProps: spec.SchemaProps{ - Description: "FC represents a Fibre Channel resource that is attached to a kubelet's host machine and then exposed to the pod.", + Description: "fc represents a Fibre Channel resource that is attached to a kubelet's host machine and then exposed to the pod.", Ref: ref("k8s.io/api/core/v1.FCVolumeSource"), }, }, "flocker": { SchemaProps: spec.SchemaProps{ - Description: "Flocker represents a Flocker volume attached to a kubelet's host machine and exposed to the pod for its usage. This depends on the Flocker control service being running", + Description: "flocker represents a Flocker volume attached to a kubelet's host machine and exposed to the pod for its usage. This depends on the Flocker control service being running", Ref: ref("k8s.io/api/core/v1.FlockerVolumeSource"), }, }, "flexVolume": { SchemaProps: spec.SchemaProps{ - Description: "FlexVolume represents a generic volume resource that is provisioned/attached using an exec based plugin.", + Description: "flexVolume represents a generic volume resource that is provisioned/attached using an exec based plugin.", Ref: ref("k8s.io/api/core/v1.FlexPersistentVolumeSource"), }, }, "azureFile": { SchemaProps: spec.SchemaProps{ - Description: "AzureFile represents an Azure File Service mount on the host and bind mount to the pod.", + Description: "azureFile represents an Azure File Service mount on the host and bind mount to the pod.", Ref: ref("k8s.io/api/core/v1.AzureFilePersistentVolumeSource"), }, }, "vsphereVolume": { SchemaProps: spec.SchemaProps{ - Description: "VsphereVolume represents a vSphere volume attached and mounted on kubelets host machine", + Description: "vsphereVolume represents a vSphere volume attached and mounted on kubelets host machine", Ref: ref("k8s.io/api/core/v1.VsphereVirtualDiskVolumeSource"), }, }, "quobyte": { SchemaProps: spec.SchemaProps{ - Description: "Quobyte represents a Quobyte mount on the host that shares a pod's lifetime", + Description: "quobyte represents a Quobyte mount on the host that shares a pod's lifetime", Ref: ref("k8s.io/api/core/v1.QuobyteVolumeSource"), }, }, "azureDisk": { SchemaProps: spec.SchemaProps{ - Description: "AzureDisk represents an Azure Data Disk mount on the host and bind mount to the pod.", + Description: "azureDisk represents an Azure Data Disk mount on the host and bind mount to the pod.", Ref: ref("k8s.io/api/core/v1.AzureDiskVolumeSource"), }, }, "photonPersistentDisk": { SchemaProps: spec.SchemaProps{ - Description: "PhotonPersistentDisk represents a PhotonController persistent disk attached and mounted on kubelets host machine", + Description: "photonPersistentDisk represents a PhotonController persistent disk attached and mounted on kubelets host machine", Ref: ref("k8s.io/api/core/v1.PhotonPersistentDiskVolumeSource"), }, }, "portworxVolume": { SchemaProps: spec.SchemaProps{ - Description: "PortworxVolume represents a portworx volume attached and mounted on kubelets host machine", + Description: "portworxVolume represents a portworx volume attached and mounted on kubelets host machine", Ref: ref("k8s.io/api/core/v1.PortworxVolumeSource"), }, }, "scaleIO": { SchemaProps: spec.SchemaProps{ - Description: "ScaleIO represents a ScaleIO persistent volume attached and mounted on Kubernetes nodes.", + Description: "scaleIO represents a ScaleIO persistent volume attached and mounted on Kubernetes nodes.", Ref: ref("k8s.io/api/core/v1.ScaleIOPersistentVolumeSource"), }, }, "local": { SchemaProps: spec.SchemaProps{ - Description: "Local represents directly-attached storage with node affinity", + Description: "local represents directly-attached storage with node affinity", Ref: ref("k8s.io/api/core/v1.LocalVolumeSource"), }, }, "storageos": { SchemaProps: spec.SchemaProps{ - Description: "StorageOS represents a StorageOS volume that is attached to the kubelet's host machine and mounted into the pod More info: https://examples.k8s.io/volumes/storageos/README.md", + Description: "storageOS represents a StorageOS volume that is attached to the kubelet's host machine and mounted into the pod More info: https://examples.k8s.io/volumes/storageos/README.md", Ref: ref("k8s.io/api/core/v1.StorageOSPersistentVolumeSource"), }, }, "csi": { SchemaProps: spec.SchemaProps{ - Description: "CSI represents storage that is handled by an external CSI driver (Beta feature).", + Description: "csi represents storage that is handled by an external CSI driver (Beta feature).", Ref: ref("k8s.io/api/core/v1.CSIPersistentVolumeSource"), }, }, "accessModes": { SchemaProps: spec.SchemaProps{ - Description: "AccessModes contains all ways the volume can be mounted. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes", + Description: "accessModes contains all ways the volume can be mounted. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ @@ -9051,27 +9316,27 @@ func schema_k8sio_api_core_v1_PersistentVolumeSpec(ref common.ReferenceCallback) }, "claimRef": { SchemaProps: spec.SchemaProps{ - Description: "ClaimRef is part of a bi-directional binding between PersistentVolume and PersistentVolumeClaim. Expected to be non-nil when bound. claim.VolumeName is the authoritative bind between PV and PVC. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#binding", + Description: "claimRef is part of a bi-directional binding between PersistentVolume and PersistentVolumeClaim. Expected to be non-nil when bound. claim.VolumeName is the authoritative bind between PV and PVC. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#binding", Ref: ref("k8s.io/api/core/v1.ObjectReference"), }, }, "persistentVolumeReclaimPolicy": { SchemaProps: spec.SchemaProps{ - Description: "What happens to a persistent volume when released from its claim. Valid options are Retain (default for manually created PersistentVolumes), Delete (default for dynamically provisioned PersistentVolumes), and Recycle (deprecated). Recycle must be supported by the volume plugin underlying this PersistentVolume. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#reclaiming", + Description: "persistentVolumeReclaimPolicy defines what happens to a persistent volume when released from its claim. Valid options are Retain (default for manually created PersistentVolumes), Delete (default for dynamically provisioned PersistentVolumes), and Recycle (deprecated). Recycle must be supported by the volume plugin underlying this PersistentVolume. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#reclaiming\n\nPossible enum values:\n - `\"Delete\"` means the volume will be deleted from Kubernetes on release from its claim. The volume plugin must support Deletion.\n - `\"Recycle\"` means the volume will be recycled back into the pool of unbound persistent volumes on release from its claim. The volume plugin must support Recycling.\n - `\"Retain\"` means the volume will be left in its current phase (Released) for manual reclamation by the administrator. The default policy is Retain.", Type: []string{"string"}, Format: "", - }, + Enum: []interface{}{"Delete", "Recycle", "Retain"}}, }, "storageClassName": { SchemaProps: spec.SchemaProps{ - Description: "Name of StorageClass to which this persistent volume belongs. Empty value means that this volume does not belong to any StorageClass.", + Description: "storageClassName is the name of StorageClass to which this persistent volume belongs. Empty value means that this volume does not belong to any StorageClass.", Type: []string{"string"}, Format: "", }, }, "mountOptions": { SchemaProps: spec.SchemaProps{ - Description: "A list of mount options, e.g. [\"ro\", \"soft\"]. Not validated - mount will simply fail if one is invalid. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes/#mount-options", + Description: "mountOptions is the list of mount options, e.g. [\"ro\", \"soft\"]. Not validated - mount will simply fail if one is invalid. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes/#mount-options", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ @@ -9093,7 +9358,7 @@ func schema_k8sio_api_core_v1_PersistentVolumeSpec(ref common.ReferenceCallback) }, "nodeAffinity": { SchemaProps: spec.SchemaProps{ - Description: "NodeAffinity defines constraints that limit what nodes this volume can be accessed from. This field influences the scheduling of pods that use this volume.", + Description: "nodeAffinity defines constraints that limit what nodes this volume can be accessed from. This field influences the scheduling of pods that use this volume.", Ref: ref("k8s.io/api/core/v1.VolumeNodeAffinity"), }, }, @@ -9114,21 +9379,21 @@ func schema_k8sio_api_core_v1_PersistentVolumeStatus(ref common.ReferenceCallbac Properties: map[string]spec.Schema{ "phase": { SchemaProps: spec.SchemaProps{ - Description: "Phase indicates if a volume is available, bound to a claim, or released by a claim. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#phase", + Description: "phase indicates if a volume is available, bound to a claim, or released by a claim. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#phase\n\nPossible enum values:\n - `\"Available\"` used for PersistentVolumes that are not yet bound Available volumes are held by the binder and matched to PersistentVolumeClaims\n - `\"Bound\"` used for PersistentVolumes that are bound\n - `\"Failed\"` used for PersistentVolumes that failed to be correctly recycled or deleted after being released from a claim\n - `\"Pending\"` used for PersistentVolumes that are not available\n - `\"Released\"` used for PersistentVolumes where the bound PersistentVolumeClaim was deleted released volumes must be recycled before becoming available again this phase is used by the persistent volume claim binder to signal to another process to reclaim the resource", Type: []string{"string"}, Format: "", - }, + Enum: []interface{}{"Available", "Bound", "Failed", "Pending", "Released"}}, }, "message": { SchemaProps: spec.SchemaProps{ - Description: "A human-readable message indicating details about why the volume is in this state.", + Description: "message is a human-readable message indicating details about why the volume is in this state.", Type: []string{"string"}, Format: "", }, }, "reason": { SchemaProps: spec.SchemaProps{ - Description: "Reason is a brief CamelCase string that describes any failure and is meant for machine parsing and tidy display in the CLI.", + Description: "reason is a brief CamelCase string that describes any failure and is meant for machine parsing and tidy display in the CLI.", Type: []string{"string"}, Format: "", }, @@ -9148,7 +9413,7 @@ func schema_k8sio_api_core_v1_PhotonPersistentDiskVolumeSource(ref common.Refere Properties: map[string]spec.Schema{ "pdID": { SchemaProps: spec.SchemaProps{ - Description: "ID that identifies Photon Controller persistent disk", + Description: "pdID is the ID that identifies Photon Controller persistent disk", Default: "", Type: []string{"string"}, Format: "", @@ -9156,7 +9421,7 @@ func schema_k8sio_api_core_v1_PhotonPersistentDiskVolumeSource(ref common.Refere }, "fsType": { SchemaProps: spec.SchemaProps{ - Description: "Filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified.", + Description: "fsType is the filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified.", Type: []string{"string"}, Format: "", }, @@ -9276,7 +9541,7 @@ func schema_k8sio_api_core_v1_PodAffinityTerm(ref common.ReferenceCallback) comm }, "namespaces": { SchemaProps: spec.SchemaProps{ - Description: "namespaces specifies a static list of namespace names that the term applies to. The term is applied to the union of the namespaces listed in this field and the ones selected by namespaceSelector. null or empty namespaces list and null namespaceSelector means \"this pod's namespace\"", + Description: "namespaces specifies a static list of namespace names that the term applies to. The term is applied to the union of the namespaces listed in this field and the ones selected by namespaceSelector. null or empty namespaces list and null namespaceSelector means \"this pod's namespace\".", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ @@ -9299,7 +9564,7 @@ func schema_k8sio_api_core_v1_PodAffinityTerm(ref common.ReferenceCallback) comm }, "namespaceSelector": { SchemaProps: spec.SchemaProps{ - Description: "A label query over the set of namespaces that the term applies to. The term is applied to the union of the namespaces selected by this field and the ones listed in the namespaces field. null selector and null or empty namespaces list means \"this pod's namespace\". An empty selector ({}) matches all namespaces. This field is alpha-level and is only honored when PodAffinityNamespaceSelector feature is enabled.", + Description: "A label query over the set of namespaces that the term applies to. The term is applied to the union of the namespaces selected by this field and the ones listed in the namespaces field. null selector and null or empty namespaces list means \"this pod's namespace\". An empty selector ({}) matches all namespaces.", Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.LabelSelector"), }, }, @@ -9592,14 +9857,14 @@ func schema_k8sio_api_core_v1_PodExecOptions(ref common.ReferenceCallback) commo }, "stdout": { SchemaProps: spec.SchemaProps{ - Description: "Redirect the standard output stream of the pod for this call. Defaults to true.", + Description: "Redirect the standard output stream of the pod for this call.", Type: []string{"boolean"}, Format: "", }, }, "stderr": { SchemaProps: spec.SchemaProps{ - Description: "Redirect the standard error stream of the pod for this call. Defaults to true.", + Description: "Redirect the standard error stream of the pod for this call.", Type: []string{"boolean"}, Format: "", }, @@ -9802,6 +10067,28 @@ func schema_k8sio_api_core_v1_PodLogOptions(ref common.ReferenceCallback) common } } +func schema_k8sio_api_core_v1_PodOS(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "PodOS defines the OS parameters of a pod.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "name": { + SchemaProps: spec.SchemaProps{ + Description: "Name is the name of the operating system. The currently supported values are linux and windows. Additional value may be defined in future and can be one of: https://github.com/opencontainers/runtime-spec/blob/master/config.md#platform-specific-configuration Clients should expect to handle additional values and treat unrecognized values in this field as os: null", + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + Required: []string{"name"}, + }, + }, + } +} + func schema_k8sio_api_core_v1_PodPortForwardOptions(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ @@ -9909,26 +10196,26 @@ func schema_k8sio_api_core_v1_PodSecurityContext(ref common.ReferenceCallback) c Properties: map[string]spec.Schema{ "seLinuxOptions": { SchemaProps: spec.SchemaProps{ - Description: "The SELinux context to be applied to all containers. If unspecified, the container runtime will allocate a random SELinux context for each container. May also be set in SecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence for that container.", + Description: "The SELinux context to be applied to all containers. If unspecified, the container runtime will allocate a random SELinux context for each container. May also be set in SecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence for that container. Note that this field cannot be set when spec.os.name is windows.", Ref: ref("k8s.io/api/core/v1.SELinuxOptions"), }, }, "windowsOptions": { SchemaProps: spec.SchemaProps{ - Description: "The Windows specific settings applied to all containers. If unspecified, the options within a container's SecurityContext will be used. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence.", + Description: "The Windows specific settings applied to all containers. If unspecified, the options within a container's SecurityContext will be used. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. Note that this field cannot be set when spec.os.name is linux.", Ref: ref("k8s.io/api/core/v1.WindowsSecurityContextOptions"), }, }, "runAsUser": { SchemaProps: spec.SchemaProps{ - Description: "The UID to run the entrypoint of the container process. Defaults to user specified in image metadata if unspecified. May also be set in SecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence for that container.", + Description: "The UID to run the entrypoint of the container process. Defaults to user specified in image metadata if unspecified. May also be set in SecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence for that container. Note that this field cannot be set when spec.os.name is windows.", Type: []string{"integer"}, Format: "int64", }, }, "runAsGroup": { SchemaProps: spec.SchemaProps{ - Description: "The GID to run the entrypoint of the container process. Uses runtime default if unset. May also be set in SecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence for that container.", + Description: "The GID to run the entrypoint of the container process. Uses runtime default if unset. May also be set in SecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence for that container. Note that this field cannot be set when spec.os.name is windows.", Type: []string{"integer"}, Format: "int64", }, @@ -9942,7 +10229,7 @@ func schema_k8sio_api_core_v1_PodSecurityContext(ref common.ReferenceCallback) c }, "supplementalGroups": { SchemaProps: spec.SchemaProps{ - Description: "A list of groups applied to the first process run in each container, in addition to the container's primary GID. If unspecified, no groups will be added to any container.", + Description: "A list of groups applied to the first process run in each container, in addition to the container's primary GID. If unspecified, no groups will be added to any container. Note that this field cannot be set when spec.os.name is windows.", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ @@ -9957,14 +10244,14 @@ func schema_k8sio_api_core_v1_PodSecurityContext(ref common.ReferenceCallback) c }, "fsGroup": { SchemaProps: spec.SchemaProps{ - Description: "A special supplemental group that applies to all containers in a pod. Some volume types allow the Kubelet to change the ownership of that volume to be owned by the pod:\n\n1. The owning GID will be the FSGroup 2. The setgid bit is set (new files created in the volume will be owned by FSGroup) 3. The permission bits are OR'd with rw-rw----\n\nIf unset, the Kubelet will not modify the ownership and permissions of any volume.", + Description: "A special supplemental group that applies to all containers in a pod. Some volume types allow the Kubelet to change the ownership of that volume to be owned by the pod:\n\n1. The owning GID will be the FSGroup 2. The setgid bit is set (new files created in the volume will be owned by FSGroup) 3. The permission bits are OR'd with rw-rw----\n\nIf unset, the Kubelet will not modify the ownership and permissions of any volume. Note that this field cannot be set when spec.os.name is windows.", Type: []string{"integer"}, Format: "int64", }, }, "sysctls": { SchemaProps: spec.SchemaProps{ - Description: "Sysctls hold a list of namespaced sysctls used for the pod. Pods with unsupported sysctls (by the container runtime) might fail to launch.", + Description: "Sysctls hold a list of namespaced sysctls used for the pod. Pods with unsupported sysctls (by the container runtime) might fail to launch. Note that this field cannot be set when spec.os.name is windows.", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ @@ -9978,14 +10265,14 @@ func schema_k8sio_api_core_v1_PodSecurityContext(ref common.ReferenceCallback) c }, "fsGroupChangePolicy": { SchemaProps: spec.SchemaProps{ - Description: "fsGroupChangePolicy defines behavior of changing ownership and permission of the volume before being exposed inside Pod. This field will only apply to volume types which support fsGroup based ownership(and permissions). It will have no effect on ephemeral volume types such as: secret, configmaps and emptydir. Valid values are \"OnRootMismatch\" and \"Always\". If not specified, \"Always\" is used.", + Description: "fsGroupChangePolicy defines behavior of changing ownership and permission of the volume before being exposed inside Pod. This field will only apply to volume types which support fsGroup based ownership(and permissions). It will have no effect on ephemeral volume types such as: secret, configmaps and emptydir. Valid values are \"OnRootMismatch\" and \"Always\". If not specified, \"Always\" is used. Note that this field cannot be set when spec.os.name is windows.", Type: []string{"string"}, Format: "", }, }, "seccompProfile": { SchemaProps: spec.SchemaProps{ - Description: "The seccomp options to use by the containers in this pod.", + Description: "The seccomp options to use by the containers in this pod. Note that this field cannot be set when spec.os.name is windows.", Ref: ref("k8s.io/api/core/v1.SeccompProfile"), }, }, @@ -10093,7 +10380,7 @@ func schema_k8sio_api_core_v1_PodSpec(ref common.ReferenceCallback) common.OpenA }, }, SchemaProps: spec.SchemaProps{ - Description: "List of ephemeral containers run in this pod. Ephemeral containers may be run in an existing pod to perform user-initiated actions such as debugging. This list cannot be specified when creating a pod, and it cannot be modified by updating the pod spec. In order to add an ephemeral container to an existing pod, use the pod's ephemeralcontainers subresource. This field is alpha-level and is only honored by servers that enable the EphemeralContainers feature.", + Description: "List of ephemeral containers run in this pod. Ephemeral containers may be run in an existing pod to perform user-initiated actions such as debugging. This list cannot be specified when creating a pod, and it cannot be modified by updating the pod spec. In order to add an ephemeral container to an existing pod, use the pod's ephemeralcontainers subresource. This field is beta-level and available on clusters that haven't disabled the EphemeralContainers feature gate.", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ @@ -10107,10 +10394,10 @@ func schema_k8sio_api_core_v1_PodSpec(ref common.ReferenceCallback) common.OpenA }, "restartPolicy": { SchemaProps: spec.SchemaProps{ - Description: "Restart policy for all containers within the pod. One of Always, OnFailure, Never. Default to Always. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#restart-policy", + Description: "Restart policy for all containers within the pod. One of Always, OnFailure, Never. Default to Always. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#restart-policy\n\nPossible enum values:\n - `\"Always\"`\n - `\"Never\"`\n - `\"OnFailure\"`", Type: []string{"string"}, Format: "", - }, + Enum: []interface{}{"Always", "Never", "OnFailure"}}, }, "terminationGracePeriodSeconds": { SchemaProps: spec.SchemaProps{ @@ -10128,12 +10415,17 @@ func schema_k8sio_api_core_v1_PodSpec(ref common.ReferenceCallback) common.OpenA }, "dnsPolicy": { SchemaProps: spec.SchemaProps{ - Description: "Set DNS policy for the pod. Defaults to \"ClusterFirst\". Valid values are 'ClusterFirstWithHostNet', 'ClusterFirst', 'Default' or 'None'. DNS parameters given in DNSConfig will be merged with the policy selected with DNSPolicy. To have DNS options set along with hostNetwork, you have to specify DNS policy explicitly to 'ClusterFirstWithHostNet'.", + Description: "Set DNS policy for the pod. Defaults to \"ClusterFirst\". Valid values are 'ClusterFirstWithHostNet', 'ClusterFirst', 'Default' or 'None'. DNS parameters given in DNSConfig will be merged with the policy selected with DNSPolicy. To have DNS options set along with hostNetwork, you have to specify DNS policy explicitly to 'ClusterFirstWithHostNet'.\n\nPossible enum values:\n - `\"ClusterFirst\"` indicates that the pod should use cluster DNS first unless hostNetwork is true, if it is available, then fall back on the default (as determined by kubelet) DNS settings.\n - `\"ClusterFirstWithHostNet\"` indicates that the pod should use cluster DNS first, if it is available, then fall back on the default (as determined by kubelet) DNS settings.\n - `\"Default\"` indicates that the pod should use the default (as determined by kubelet) DNS settings.\n - `\"None\"` indicates that the pod should use empty DNS settings. DNS parameters such as nameservers and search paths should be defined via DNSConfig.", Type: []string{"string"}, Format: "", - }, + Enum: []interface{}{"ClusterFirst", "ClusterFirstWithHostNet", "Default", "None"}}, }, "nodeSelector": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-map-type": "atomic", + }, + }, SchemaProps: spec.SchemaProps{ Description: "NodeSelector is a selector which must be true for the pod to fit on a node. Selector which must match a node's labels for the pod to be scheduled on that node. More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/", Type: []string{"object"}, @@ -10219,7 +10511,7 @@ func schema_k8sio_api_core_v1_PodSpec(ref common.ReferenceCallback) common.OpenA }, }, SchemaProps: spec.SchemaProps{ - Description: "ImagePullSecrets is an optional list of references to secrets in the same namespace to use for pulling any of the images used by this PodSpec. If specified, these secrets will be passed to individual puller implementations for them to use. For example, in the case of docker, only DockerConfig type secrets are honored. More info: https://kubernetes.io/docs/concepts/containers/images#specifying-imagepullsecrets-on-a-pod", + Description: "ImagePullSecrets is an optional list of references to secrets in the same namespace to use for pulling any of the images used by this PodSpec. If specified, these secrets will be passed to individual puller implementations for them to use. More info: https://kubernetes.io/docs/concepts/containers/images#specifying-imagepullsecrets-on-a-pod", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ @@ -10314,7 +10606,7 @@ func schema_k8sio_api_core_v1_PodSpec(ref common.ReferenceCallback) common.OpenA }, "readinessGates": { SchemaProps: spec.SchemaProps{ - Description: "If specified, all readiness gates will be evaluated for pod readiness. A pod is ready when all its containers are ready AND all conditions specified in the readiness gates have status equal to \"True\" More info: https://git.k8s.io/enhancements/keps/sig-network/0007-pod-ready%2B%2B.md", + Description: "If specified, all readiness gates will be evaluated for pod readiness. A pod is ready when all its containers are ready AND all conditions specified in the readiness gates have status equal to \"True\" More info: https://git.k8s.io/enhancements/keps/sig-network/580-pod-readiness-gates", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ @@ -10328,7 +10620,7 @@ func schema_k8sio_api_core_v1_PodSpec(ref common.ReferenceCallback) common.OpenA }, "runtimeClassName": { SchemaProps: spec.SchemaProps{ - Description: "RuntimeClassName refers to a RuntimeClass object in the node.k8s.io group, which should be used to run this pod. If no RuntimeClass resource matches the named class, the pod will not be run. If unset or empty, the \"legacy\" RuntimeClass will be used, which is an implicit class with an empty definition that uses the default runtime handler. More info: https://git.k8s.io/enhancements/keps/sig-node/runtime-class.md This is a beta feature as of Kubernetes v1.14.", + Description: "RuntimeClassName refers to a RuntimeClass object in the node.k8s.io group, which should be used to run this pod. If no RuntimeClass resource matches the named class, the pod will not be run. If unset or empty, the \"legacy\" RuntimeClass will be used, which is an implicit class with an empty definition that uses the default runtime handler. More info: https://git.k8s.io/enhancements/keps/sig-node/585-runtime-class", Type: []string{"string"}, Format: "", }, @@ -10342,14 +10634,14 @@ func schema_k8sio_api_core_v1_PodSpec(ref common.ReferenceCallback) common.OpenA }, "preemptionPolicy": { SchemaProps: spec.SchemaProps{ - Description: "PreemptionPolicy is the Policy for preempting pods with lower priority. One of Never, PreemptLowerPriority. Defaults to PreemptLowerPriority if unset. This field is beta-level, gated by the NonPreemptingPriority feature-gate.", + Description: "PreemptionPolicy is the Policy for preempting pods with lower priority. One of Never, PreemptLowerPriority. Defaults to PreemptLowerPriority if unset.", Type: []string{"string"}, Format: "", }, }, "overhead": { SchemaProps: spec.SchemaProps{ - Description: "Overhead represents the resource overhead associated with running a pod for a given RuntimeClass. This field will be autopopulated at admission time by the RuntimeClass admission controller. If the RuntimeClass admission controller is enabled, overhead must not be set in Pod create requests. The RuntimeClass admission controller will reject Pod create requests which have the overhead already set. If RuntimeClass is configured and selected in the PodSpec, Overhead will be set to the value defined in the corresponding RuntimeClass, otherwise it will remain unset and treated as zero. More info: https://git.k8s.io/enhancements/keps/sig-node/20190226-pod-overhead.md This field is alpha-level as of Kubernetes v1.16, and is only honored by servers that enable the PodOverhead feature.", + Description: "Overhead represents the resource overhead associated with running a pod for a given RuntimeClass. This field will be autopopulated at admission time by the RuntimeClass admission controller. If the RuntimeClass admission controller is enabled, overhead must not be set in Pod create requests. The RuntimeClass admission controller will reject Pod create requests which have the overhead already set. If RuntimeClass is configured and selected in the PodSpec, Overhead will be set to the value defined in the corresponding RuntimeClass, otherwise it will remain unset and treated as zero. More info: https://git.k8s.io/enhancements/keps/sig-node/688-pod-overhead/README.md", Type: []string{"object"}, AdditionalProperties: &spec.SchemaOrBool{ Allows: true, @@ -10394,12 +10686,18 @@ func schema_k8sio_api_core_v1_PodSpec(ref common.ReferenceCallback) common.OpenA Format: "", }, }, + "os": { + SchemaProps: spec.SchemaProps{ + Description: "Specifies the OS of the containers in the pod. Some pod and container fields are restricted if this is set.\n\nIf the OS field is set to linux, the following fields must be unset: -securityContext.windowsOptions\n\nIf the OS field is set to windows, following fields must be unset: - spec.hostPID - spec.hostIPC - spec.securityContext.seLinuxOptions - spec.securityContext.seccompProfile - spec.securityContext.fsGroup - spec.securityContext.fsGroupChangePolicy - spec.securityContext.sysctls - spec.shareProcessNamespace - spec.securityContext.runAsUser - spec.securityContext.runAsGroup - spec.securityContext.supplementalGroups - spec.containers[*].securityContext.seLinuxOptions - spec.containers[*].securityContext.seccompProfile - spec.containers[*].securityContext.capabilities - spec.containers[*].securityContext.readOnlyRootFilesystem - spec.containers[*].securityContext.privileged - spec.containers[*].securityContext.allowPrivilegeEscalation - spec.containers[*].securityContext.procMount - spec.containers[*].securityContext.runAsUser - spec.containers[*].securityContext.runAsGroup This is a beta field and requires the IdentifyPodOS feature", + Ref: ref("k8s.io/api/core/v1.PodOS"), + }, + }, }, Required: []string{"containers"}, }, }, Dependencies: []string{ - "k8s.io/api/core/v1.Affinity", "k8s.io/api/core/v1.Container", "k8s.io/api/core/v1.EphemeralContainer", "k8s.io/api/core/v1.HostAlias", "k8s.io/api/core/v1.LocalObjectReference", "k8s.io/api/core/v1.PodDNSConfig", "k8s.io/api/core/v1.PodReadinessGate", "k8s.io/api/core/v1.PodSecurityContext", "k8s.io/api/core/v1.Toleration", "k8s.io/api/core/v1.TopologySpreadConstraint", "k8s.io/api/core/v1.Volume", "k8s.io/apimachinery/pkg/api/resource.Quantity"}, + "k8s.io/api/core/v1.Affinity", "k8s.io/api/core/v1.Container", "k8s.io/api/core/v1.EphemeralContainer", "k8s.io/api/core/v1.HostAlias", "k8s.io/api/core/v1.LocalObjectReference", "k8s.io/api/core/v1.PodDNSConfig", "k8s.io/api/core/v1.PodOS", "k8s.io/api/core/v1.PodReadinessGate", "k8s.io/api/core/v1.PodSecurityContext", "k8s.io/api/core/v1.Toleration", "k8s.io/api/core/v1.TopologySpreadConstraint", "k8s.io/api/core/v1.Volume", "k8s.io/apimachinery/pkg/api/resource.Quantity"}, } } @@ -10412,10 +10710,10 @@ func schema_k8sio_api_core_v1_PodStatus(ref common.ReferenceCallback) common.Ope Properties: map[string]spec.Schema{ "phase": { SchemaProps: spec.SchemaProps{ - Description: "The phase of a Pod is a simple, high-level summary of where the Pod is in its lifecycle. The conditions array, the reason and message fields, and the individual container status arrays contain more detail about the pod's status. There are five possible phase values:\n\nPending: The pod has been accepted by the Kubernetes system, but one or more of the container images has not been created. This includes time before being scheduled as well as time spent downloading images over the network, which could take a while. Running: The pod has been bound to a node, and all of the containers have been created. At least one container is still running, or is in the process of starting or restarting. Succeeded: All containers in the pod have terminated in success, and will not be restarted. Failed: All containers in the pod have terminated, and at least one container has terminated in failure. The container either exited with non-zero status or was terminated by the system. Unknown: For some reason the state of the pod could not be obtained, typically due to an error in communicating with the host of the pod.\n\nMore info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#pod-phase", + Description: "The phase of a Pod is a simple, high-level summary of where the Pod is in its lifecycle. The conditions array, the reason and message fields, and the individual container status arrays contain more detail about the pod's status. There are five possible phase values:\n\nPending: The pod has been accepted by the Kubernetes system, but one or more of the container images has not been created. This includes time before being scheduled as well as time spent downloading images over the network, which could take a while. Running: The pod has been bound to a node, and all of the containers have been created. At least one container is still running, or is in the process of starting or restarting. Succeeded: All containers in the pod have terminated in success, and will not be restarted. Failed: All containers in the pod have terminated, and at least one container has terminated in failure. The container either exited with non-zero status or was terminated by the system. Unknown: For some reason the state of the pod could not be obtained, typically due to an error in communicating with the host of the pod.\n\nMore info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#pod-phase\n\nPossible enum values:\n - `\"Failed\"` means that all containers in the pod have terminated, and at least one container has terminated in a failure (exited with a non-zero exit code or was stopped by the system).\n - `\"Pending\"` means the pod has been accepted by the system, but one or more of the containers has not been started. This includes time before being bound to a node, as well as time spent pulling images onto the host.\n - `\"Running\"` means the pod has been bound to a node and all of the containers have been started. At least one container is still running or is in the process of being restarted.\n - `\"Succeeded\"` means that all containers in the pod have voluntarily terminated with a container exit code of 0, and the system is not going to restart any of these containers.\n - `\"Unknown\"` means that for some reason the state of the pod could not be obtained, typically due to an error in communicating with the host of the pod. Deprecated: It isn't being set since 2015 (74da3b14b0c0f658b3bb8d2def5094686d0e9095)", Type: []string{"string"}, Format: "", - }, + Enum: []interface{}{"Failed", "Pending", "Running", "Succeeded", "Unknown"}}, }, "conditions": { VendorExtensible: spec.VendorExtensible{ @@ -10514,7 +10812,7 @@ func schema_k8sio_api_core_v1_PodStatus(ref common.ReferenceCallback) common.Ope }, "containerStatuses": { SchemaProps: spec.SchemaProps{ - Description: "The list has one entry per container in the manifest. Each entry is currently the output of `docker inspect`. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#pod-and-container-status", + Description: "The list has one entry per container in the manifest. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#pod-and-container-status", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ @@ -10528,14 +10826,14 @@ func schema_k8sio_api_core_v1_PodStatus(ref common.ReferenceCallback) common.Ope }, "qosClass": { SchemaProps: spec.SchemaProps{ - Description: "The Quality of Service (QOS) classification assigned to the pod based on resource requirements See PodQOSClass type for available QOS classes More info: https://git.k8s.io/community/contributors/design-proposals/node/resource-qos.md", + Description: "The Quality of Service (QOS) classification assigned to the pod based on resource requirements See PodQOSClass type for available QOS classes More info: https://git.k8s.io/community/contributors/design-proposals/node/resource-qos.md\n\nPossible enum values:\n - `\"BestEffort\"` is the BestEffort qos class.\n - `\"Burstable\"` is the Burstable qos class.\n - `\"Guaranteed\"` is the Guaranteed qos class.", Type: []string{"string"}, Format: "", - }, + Enum: []interface{}{"BestEffort", "Burstable", "Guaranteed"}}, }, "ephemeralContainerStatuses": { SchemaProps: spec.SchemaProps{ - Description: "Status for any ephemeral containers that have run in this pod. This field is alpha-level and is only populated by servers that enable the EphemeralContainers feature.", + Description: "Status for any ephemeral containers that have run in this pod. This field is beta-level and available on clusters that haven't disabled the EphemeralContainers feature gate.", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ @@ -10737,11 +11035,11 @@ func schema_k8sio_api_core_v1_PortStatus(ref common.ReferenceCallback) common.Op }, "protocol": { SchemaProps: spec.SchemaProps{ - Description: "Protocol is the protocol of the service port of which status is recorded here The supported values are: \"TCP\", \"UDP\", \"SCTP\"", + Description: "Protocol is the protocol of the service port of which status is recorded here The supported values are: \"TCP\", \"UDP\", \"SCTP\"\n\nPossible enum values:\n - `\"SCTP\"` is the SCTP protocol.\n - `\"TCP\"` is the TCP protocol.\n - `\"UDP\"` is the UDP protocol.", Default: "", Type: []string{"string"}, Format: "", - }, + Enum: []interface{}{"SCTP", "TCP", "UDP"}}, }, "error": { SchemaProps: spec.SchemaProps{ @@ -10766,7 +11064,7 @@ func schema_k8sio_api_core_v1_PortworxVolumeSource(ref common.ReferenceCallback) Properties: map[string]spec.Schema{ "volumeID": { SchemaProps: spec.SchemaProps{ - Description: "VolumeID uniquely identifies a Portworx volume", + Description: "volumeID uniquely identifies a Portworx volume", Default: "", Type: []string{"string"}, Format: "", @@ -10774,14 +11072,14 @@ func schema_k8sio_api_core_v1_PortworxVolumeSource(ref common.ReferenceCallback) }, "fsType": { SchemaProps: spec.SchemaProps{ - Description: "FSType represents the filesystem type to mount Must be a filesystem type supported by the host operating system. Ex. \"ext4\", \"xfs\". Implicitly inferred to be \"ext4\" if unspecified.", + Description: "fSType represents the filesystem type to mount Must be a filesystem type supported by the host operating system. Ex. \"ext4\", \"xfs\". Implicitly inferred to be \"ext4\" if unspecified.", Type: []string{"string"}, Format: "", }, }, "readOnly": { SchemaProps: spec.SchemaProps{ - Description: "Defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts.", + Description: "readOnly defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts.", Type: []string{"boolean"}, Format: "", }, @@ -10877,7 +11175,7 @@ func schema_k8sio_api_core_v1_Probe(ref common.ReferenceCallback) common.OpenAPI Properties: map[string]spec.Schema{ "exec": { SchemaProps: spec.SchemaProps{ - Description: "One and only one of the following should be specified. Exec specifies the action to take.", + Description: "Exec specifies the action to take.", Ref: ref("k8s.io/api/core/v1.ExecAction"), }, }, @@ -10889,10 +11187,16 @@ func schema_k8sio_api_core_v1_Probe(ref common.ReferenceCallback) common.OpenAPI }, "tcpSocket": { SchemaProps: spec.SchemaProps{ - Description: "TCPSocket specifies an action involving a TCP port. TCP hooks not yet supported", + Description: "TCPSocket specifies an action involving a TCP port.", Ref: ref("k8s.io/api/core/v1.TCPSocketAction"), }, }, + "grpc": { + SchemaProps: spec.SchemaProps{ + Description: "GRPC specifies an action involving a GRPC port. This is a beta field and requires enabling GRPCContainerProbe feature gate.", + Ref: ref("k8s.io/api/core/v1.GRPCAction"), + }, + }, "initialDelaySeconds": { SchemaProps: spec.SchemaProps{ Description: "Number of seconds after the container has started before liveness probes are initiated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes", @@ -10930,7 +11234,7 @@ func schema_k8sio_api_core_v1_Probe(ref common.ReferenceCallback) common.OpenAPI }, "terminationGracePeriodSeconds": { SchemaProps: spec.SchemaProps{ - Description: "Optional duration in seconds the pod needs to terminate gracefully upon probe failure. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this value overrides the value provided by the pod spec. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). This is an alpha field and requires enabling ProbeTerminationGracePeriod feature gate.", + Description: "Optional duration in seconds the pod needs to terminate gracefully upon probe failure. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this value overrides the value provided by the pod spec. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). This is a beta field and requires enabling ProbeTerminationGracePeriod feature gate. Minimum value is 1. spec.terminationGracePeriodSeconds is used if unset.", Type: []string{"integer"}, Format: "int64", }, @@ -10939,7 +11243,46 @@ func schema_k8sio_api_core_v1_Probe(ref common.ReferenceCallback) common.OpenAPI }, }, Dependencies: []string{ - "k8s.io/api/core/v1.ExecAction", "k8s.io/api/core/v1.HTTPGetAction", "k8s.io/api/core/v1.TCPSocketAction"}, + "k8s.io/api/core/v1.ExecAction", "k8s.io/api/core/v1.GRPCAction", "k8s.io/api/core/v1.HTTPGetAction", "k8s.io/api/core/v1.TCPSocketAction"}, + } +} + +func schema_k8sio_api_core_v1_ProbeHandler(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "ProbeHandler defines a specific action that should be taken in a probe. One and only one of the fields must be specified.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "exec": { + SchemaProps: spec.SchemaProps{ + Description: "Exec specifies the action to take.", + Ref: ref("k8s.io/api/core/v1.ExecAction"), + }, + }, + "httpGet": { + SchemaProps: spec.SchemaProps{ + Description: "HTTPGet specifies the http request to perform.", + Ref: ref("k8s.io/api/core/v1.HTTPGetAction"), + }, + }, + "tcpSocket": { + SchemaProps: spec.SchemaProps{ + Description: "TCPSocket specifies an action involving a TCP port.", + Ref: ref("k8s.io/api/core/v1.TCPSocketAction"), + }, + }, + "grpc": { + SchemaProps: spec.SchemaProps{ + Description: "GRPC specifies an action involving a GRPC port. This is a beta field and requires enabling GRPCContainerProbe feature gate.", + Ref: ref("k8s.io/api/core/v1.GRPCAction"), + }, + }, + }, + }, + }, + Dependencies: []string{ + "k8s.io/api/core/v1.ExecAction", "k8s.io/api/core/v1.GRPCAction", "k8s.io/api/core/v1.HTTPGetAction", "k8s.io/api/core/v1.TCPSocketAction"}, } } @@ -10952,7 +11295,7 @@ func schema_k8sio_api_core_v1_ProjectedVolumeSource(ref common.ReferenceCallback Properties: map[string]spec.Schema{ "sources": { SchemaProps: spec.SchemaProps{ - Description: "list of volume projections", + Description: "sources is the list of volume projections", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ @@ -10966,7 +11309,7 @@ func schema_k8sio_api_core_v1_ProjectedVolumeSource(ref common.ReferenceCallback }, "defaultMode": { SchemaProps: spec.SchemaProps{ - Description: "Mode bits used to set permissions on created files by default. Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. Directories within the path are not affected by this setting. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.", + Description: "defaultMode are the mode bits used to set permissions on created files by default. Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. Directories within the path are not affected by this setting. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.", Type: []string{"integer"}, Format: "int32", }, @@ -10988,7 +11331,7 @@ func schema_k8sio_api_core_v1_QuobyteVolumeSource(ref common.ReferenceCallback) Properties: map[string]spec.Schema{ "registry": { SchemaProps: spec.SchemaProps{ - Description: "Registry represents a single or multiple Quobyte Registry services specified as a string as host:port pair (multiple entries are separated with commas) which acts as the central registry for volumes", + Description: "registry represents a single or multiple Quobyte Registry services specified as a string as host:port pair (multiple entries are separated with commas) which acts as the central registry for volumes", Default: "", Type: []string{"string"}, Format: "", @@ -10996,7 +11339,7 @@ func schema_k8sio_api_core_v1_QuobyteVolumeSource(ref common.ReferenceCallback) }, "volume": { SchemaProps: spec.SchemaProps{ - Description: "Volume is a string that references an already created Quobyte volume by name.", + Description: "volume is a string that references an already created Quobyte volume by name.", Default: "", Type: []string{"string"}, Format: "", @@ -11004,28 +11347,28 @@ func schema_k8sio_api_core_v1_QuobyteVolumeSource(ref common.ReferenceCallback) }, "readOnly": { SchemaProps: spec.SchemaProps{ - Description: "ReadOnly here will force the Quobyte volume to be mounted with read-only permissions. Defaults to false.", + Description: "readOnly here will force the Quobyte volume to be mounted with read-only permissions. Defaults to false.", Type: []string{"boolean"}, Format: "", }, }, "user": { SchemaProps: spec.SchemaProps{ - Description: "User to map volume access to Defaults to serivceaccount user", + Description: "user to map volume access to Defaults to serivceaccount user", Type: []string{"string"}, Format: "", }, }, "group": { SchemaProps: spec.SchemaProps{ - Description: "Group to map volume access to Default is no group", + Description: "group to map volume access to Default is no group", Type: []string{"string"}, Format: "", }, }, "tenant": { SchemaProps: spec.SchemaProps{ - Description: "Tenant owning the given Quobyte volume in the Backend Used with dynamically provisioned Quobyte volumes, value is set by the plugin", + Description: "tenant owning the given Quobyte volume in the Backend Used with dynamically provisioned Quobyte volumes, value is set by the plugin", Type: []string{"string"}, Format: "", }, @@ -11046,7 +11389,7 @@ func schema_k8sio_api_core_v1_RBDPersistentVolumeSource(ref common.ReferenceCall Properties: map[string]spec.Schema{ "monitors": { SchemaProps: spec.SchemaProps{ - Description: "A collection of Ceph monitors. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it", + Description: "monitors is a collection of Ceph monitors. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ @@ -11061,7 +11404,7 @@ func schema_k8sio_api_core_v1_RBDPersistentVolumeSource(ref common.ReferenceCall }, "image": { SchemaProps: spec.SchemaProps{ - Description: "The rados image name. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it", + Description: "image is the rados image name. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it", Default: "", Type: []string{"string"}, Format: "", @@ -11069,41 +11412,41 @@ func schema_k8sio_api_core_v1_RBDPersistentVolumeSource(ref common.ReferenceCall }, "fsType": { SchemaProps: spec.SchemaProps{ - Description: "Filesystem type of the volume that you want to mount. Tip: Ensure that the filesystem type is supported by the host operating system. Examples: \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#rbd", + Description: "fsType is the filesystem type of the volume that you want to mount. Tip: Ensure that the filesystem type is supported by the host operating system. Examples: \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#rbd", Type: []string{"string"}, Format: "", }, }, "pool": { SchemaProps: spec.SchemaProps{ - Description: "The rados pool name. Default is rbd. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it", + Description: "pool is the rados pool name. Default is rbd. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it", Type: []string{"string"}, Format: "", }, }, "user": { SchemaProps: spec.SchemaProps{ - Description: "The rados user name. Default is admin. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it", + Description: "user is the rados user name. Default is admin. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it", Type: []string{"string"}, Format: "", }, }, "keyring": { SchemaProps: spec.SchemaProps{ - Description: "Keyring is the path to key ring for RBDUser. Default is /etc/ceph/keyring. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it", + Description: "keyring is the path to key ring for RBDUser. Default is /etc/ceph/keyring. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it", Type: []string{"string"}, Format: "", }, }, "secretRef": { SchemaProps: spec.SchemaProps{ - Description: "SecretRef is name of the authentication secret for RBDUser. If provided overrides keyring. Default is nil. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it", + Description: "secretRef is name of the authentication secret for RBDUser. If provided overrides keyring. Default is nil. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it", Ref: ref("k8s.io/api/core/v1.SecretReference"), }, }, "readOnly": { SchemaProps: spec.SchemaProps{ - Description: "ReadOnly here will force the ReadOnly setting in VolumeMounts. Defaults to false. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it", + Description: "readOnly here will force the ReadOnly setting in VolumeMounts. Defaults to false. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it", Type: []string{"boolean"}, Format: "", }, @@ -11126,7 +11469,7 @@ func schema_k8sio_api_core_v1_RBDVolumeSource(ref common.ReferenceCallback) comm Properties: map[string]spec.Schema{ "monitors": { SchemaProps: spec.SchemaProps{ - Description: "A collection of Ceph monitors. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it", + Description: "monitors is a collection of Ceph monitors. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ @@ -11141,7 +11484,7 @@ func schema_k8sio_api_core_v1_RBDVolumeSource(ref common.ReferenceCallback) comm }, "image": { SchemaProps: spec.SchemaProps{ - Description: "The rados image name. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it", + Description: "image is the rados image name. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it", Default: "", Type: []string{"string"}, Format: "", @@ -11149,41 +11492,41 @@ func schema_k8sio_api_core_v1_RBDVolumeSource(ref common.ReferenceCallback) comm }, "fsType": { SchemaProps: spec.SchemaProps{ - Description: "Filesystem type of the volume that you want to mount. Tip: Ensure that the filesystem type is supported by the host operating system. Examples: \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#rbd", + Description: "fsType is the filesystem type of the volume that you want to mount. Tip: Ensure that the filesystem type is supported by the host operating system. Examples: \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#rbd", Type: []string{"string"}, Format: "", }, }, "pool": { SchemaProps: spec.SchemaProps{ - Description: "The rados pool name. Default is rbd. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it", + Description: "pool is the rados pool name. Default is rbd. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it", Type: []string{"string"}, Format: "", }, }, "user": { SchemaProps: spec.SchemaProps{ - Description: "The rados user name. Default is admin. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it", + Description: "user is the rados user name. Default is admin. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it", Type: []string{"string"}, Format: "", }, }, "keyring": { SchemaProps: spec.SchemaProps{ - Description: "Keyring is the path to key ring for RBDUser. Default is /etc/ceph/keyring. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it", + Description: "keyring is the path to key ring for RBDUser. Default is /etc/ceph/keyring. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it", Type: []string{"string"}, Format: "", }, }, "secretRef": { SchemaProps: spec.SchemaProps{ - Description: "SecretRef is name of the authentication secret for RBDUser. If provided overrides keyring. Default is nil. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it", + Description: "secretRef is name of the authentication secret for RBDUser. If provided overrides keyring. Default is nil. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it", Ref: ref("k8s.io/api/core/v1.LocalObjectReference"), }, }, "readOnly": { SchemaProps: spec.SchemaProps{ - Description: "ReadOnly here will force the ReadOnly setting in VolumeMounts. Defaults to false. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it", + Description: "readOnly here will force the ReadOnly setting in VolumeMounts. Defaults to false. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it", Type: []string{"boolean"}, Format: "", }, @@ -11425,6 +11768,11 @@ func schema_k8sio_api_core_v1_ReplicationControllerSpec(ref common.ReferenceCall }, }, "selector": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-map-type": "atomic", + }, + }, SchemaProps: spec.SchemaProps{ Description: "Selector is a label query over pods that should match the Replicas count. If Selector is empty, it is defaulted to the labels present on the Pod template. Label keys and values that must match in order to be controlled by this replication controller, if empty defaulted to labels on Pod template. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors", Type: []string{"object"}, @@ -11558,6 +11906,11 @@ func schema_k8sio_api_core_v1_ResourceFieldSelector(ref common.ReferenceCallback }, Required: []string{"resource"}, }, + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-map-type": "atomic", + }, + }, }, Dependencies: []string{ "k8s.io/apimachinery/pkg/api/resource.Quantity"}, @@ -11856,7 +12209,7 @@ func schema_k8sio_api_core_v1_ScaleIOPersistentVolumeSource(ref common.Reference Properties: map[string]spec.Schema{ "gateway": { SchemaProps: spec.SchemaProps{ - Description: "The host address of the ScaleIO API Gateway.", + Description: "gateway is the host address of the ScaleIO API Gateway.", Default: "", Type: []string{"string"}, Format: "", @@ -11864,7 +12217,7 @@ func schema_k8sio_api_core_v1_ScaleIOPersistentVolumeSource(ref common.Reference }, "system": { SchemaProps: spec.SchemaProps{ - Description: "The name of the storage system as configured in ScaleIO.", + Description: "system is the name of the storage system as configured in ScaleIO.", Default: "", Type: []string{"string"}, Format: "", @@ -11872,55 +12225,55 @@ func schema_k8sio_api_core_v1_ScaleIOPersistentVolumeSource(ref common.Reference }, "secretRef": { SchemaProps: spec.SchemaProps{ - Description: "SecretRef references to the secret for ScaleIO user and other sensitive information. If this is not provided, Login operation will fail.", + Description: "secretRef references to the secret for ScaleIO user and other sensitive information. If this is not provided, Login operation will fail.", Ref: ref("k8s.io/api/core/v1.SecretReference"), }, }, "sslEnabled": { SchemaProps: spec.SchemaProps{ - Description: "Flag to enable/disable SSL communication with Gateway, default false", + Description: "sslEnabled is the flag to enable/disable SSL communication with Gateway, default false", Type: []string{"boolean"}, Format: "", }, }, "protectionDomain": { SchemaProps: spec.SchemaProps{ - Description: "The name of the ScaleIO Protection Domain for the configured storage.", + Description: "protectionDomain is the name of the ScaleIO Protection Domain for the configured storage.", Type: []string{"string"}, Format: "", }, }, "storagePool": { SchemaProps: spec.SchemaProps{ - Description: "The ScaleIO Storage Pool associated with the protection domain.", + Description: "storagePool is the ScaleIO Storage Pool associated with the protection domain.", Type: []string{"string"}, Format: "", }, }, "storageMode": { SchemaProps: spec.SchemaProps{ - Description: "Indicates whether the storage for a volume should be ThickProvisioned or ThinProvisioned. Default is ThinProvisioned.", + Description: "storageMode indicates whether the storage for a volume should be ThickProvisioned or ThinProvisioned. Default is ThinProvisioned.", Type: []string{"string"}, Format: "", }, }, "volumeName": { SchemaProps: spec.SchemaProps{ - Description: "The name of a volume already created in the ScaleIO system that is associated with this volume source.", + Description: "volumeName is the name of a volume already created in the ScaleIO system that is associated with this volume source.", Type: []string{"string"}, Format: "", }, }, "fsType": { SchemaProps: spec.SchemaProps{ - Description: "Filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. \"ext4\", \"xfs\", \"ntfs\". Default is \"xfs\"", + Description: "fsType is the filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. \"ext4\", \"xfs\", \"ntfs\". Default is \"xfs\"", Type: []string{"string"}, Format: "", }, }, "readOnly": { SchemaProps: spec.SchemaProps{ - Description: "Defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts.", + Description: "readOnly defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts.", Type: []string{"boolean"}, Format: "", }, @@ -11943,7 +12296,7 @@ func schema_k8sio_api_core_v1_ScaleIOVolumeSource(ref common.ReferenceCallback) Properties: map[string]spec.Schema{ "gateway": { SchemaProps: spec.SchemaProps{ - Description: "The host address of the ScaleIO API Gateway.", + Description: "gateway is the host address of the ScaleIO API Gateway.", Default: "", Type: []string{"string"}, Format: "", @@ -11951,7 +12304,7 @@ func schema_k8sio_api_core_v1_ScaleIOVolumeSource(ref common.ReferenceCallback) }, "system": { SchemaProps: spec.SchemaProps{ - Description: "The name of the storage system as configured in ScaleIO.", + Description: "system is the name of the storage system as configured in ScaleIO.", Default: "", Type: []string{"string"}, Format: "", @@ -11959,55 +12312,55 @@ func schema_k8sio_api_core_v1_ScaleIOVolumeSource(ref common.ReferenceCallback) }, "secretRef": { SchemaProps: spec.SchemaProps{ - Description: "SecretRef references to the secret for ScaleIO user and other sensitive information. If this is not provided, Login operation will fail.", + Description: "secretRef references to the secret for ScaleIO user and other sensitive information. If this is not provided, Login operation will fail.", Ref: ref("k8s.io/api/core/v1.LocalObjectReference"), }, }, "sslEnabled": { SchemaProps: spec.SchemaProps{ - Description: "Flag to enable/disable SSL communication with Gateway, default false", + Description: "sslEnabled Flag enable/disable SSL communication with Gateway, default false", Type: []string{"boolean"}, Format: "", }, }, "protectionDomain": { SchemaProps: spec.SchemaProps{ - Description: "The name of the ScaleIO Protection Domain for the configured storage.", + Description: "protectionDomain is the name of the ScaleIO Protection Domain for the configured storage.", Type: []string{"string"}, Format: "", }, }, "storagePool": { SchemaProps: spec.SchemaProps{ - Description: "The ScaleIO Storage Pool associated with the protection domain.", + Description: "storagePool is the ScaleIO Storage Pool associated with the protection domain.", Type: []string{"string"}, Format: "", }, }, "storageMode": { SchemaProps: spec.SchemaProps{ - Description: "Indicates whether the storage for a volume should be ThickProvisioned or ThinProvisioned. Default is ThinProvisioned.", + Description: "storageMode indicates whether the storage for a volume should be ThickProvisioned or ThinProvisioned. Default is ThinProvisioned.", Type: []string{"string"}, Format: "", }, }, "volumeName": { SchemaProps: spec.SchemaProps{ - Description: "The name of a volume already created in the ScaleIO system that is associated with this volume source.", + Description: "volumeName is the name of a volume already created in the ScaleIO system that is associated with this volume source.", Type: []string{"string"}, Format: "", }, }, "fsType": { SchemaProps: spec.SchemaProps{ - Description: "Filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. \"ext4\", \"xfs\", \"ntfs\". Default is \"xfs\".", + Description: "fsType is the filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. \"ext4\", \"xfs\", \"ntfs\". Default is \"xfs\".", Type: []string{"string"}, Format: "", }, }, "readOnly": { SchemaProps: spec.SchemaProps{ - Description: "Defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts.", + Description: "readOnly Defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts.", Type: []string{"boolean"}, Format: "", }, @@ -12044,6 +12397,11 @@ func schema_k8sio_api_core_v1_ScopeSelector(ref common.ReferenceCallback) common }, }, }, + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-map-type": "atomic", + }, + }, }, Dependencies: []string{ "k8s.io/api/core/v1.ScopedResourceSelectorRequirement"}, @@ -12059,19 +12417,19 @@ func schema_k8sio_api_core_v1_ScopedResourceSelectorRequirement(ref common.Refer Properties: map[string]spec.Schema{ "scopeName": { SchemaProps: spec.SchemaProps{ - Description: "The name of the scope that the selector applies to.", + Description: "The name of the scope that the selector applies to.\n\nPossible enum values:\n - `\"BestEffort\"` Match all pod objects that have best effort quality of service\n - `\"CrossNamespacePodAffinity\"` Match all pod objects that have cross-namespace pod (anti)affinity mentioned.\n - `\"NotBestEffort\"` Match all pod objects that do not have best effort quality of service\n - `\"NotTerminating\"` Match all pod objects where spec.activeDeadlineSeconds is nil\n - `\"PriorityClass\"` Match all pod objects that have priority class mentioned\n - `\"Terminating\"` Match all pod objects where spec.activeDeadlineSeconds >=0", Default: "", Type: []string{"string"}, Format: "", - }, + Enum: []interface{}{"BestEffort", "CrossNamespacePodAffinity", "NotBestEffort", "NotTerminating", "PriorityClass", "Terminating"}}, }, "operator": { SchemaProps: spec.SchemaProps{ - Description: "Represents a scope's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist.", + Description: "Represents a scope's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist.\n\nPossible enum values:\n - `\"DoesNotExist\"`\n - `\"Exists\"`\n - `\"In\"`\n - `\"NotIn\"`", Default: "", Type: []string{"string"}, Format: "", - }, + Enum: []interface{}{"DoesNotExist", "Exists", "In", "NotIn"}}, }, "values": { SchemaProps: spec.SchemaProps{ @@ -12104,11 +12462,11 @@ func schema_k8sio_api_core_v1_SeccompProfile(ref common.ReferenceCallback) commo Properties: map[string]spec.Schema{ "type": { SchemaProps: spec.SchemaProps{ - Description: "type indicates which kind of seccomp profile will be applied. Valid options are:\n\nLocalhost - a profile defined in a file on the node should be used. RuntimeDefault - the container runtime default profile should be used. Unconfined - no profile should be applied.", + Description: "type indicates which kind of seccomp profile will be applied. Valid options are:\n\nLocalhost - a profile defined in a file on the node should be used. RuntimeDefault - the container runtime default profile should be used. Unconfined - no profile should be applied.\n\nPossible enum values:\n - `\"Localhost\"` indicates a profile defined in a file on the node should be used. The file's location relative to /seccomp.\n - `\"RuntimeDefault\"` represents the default container runtime seccomp profile.\n - `\"Unconfined\"` indicates no seccomp profile is applied (A.K.A. unconfined).", Default: "", Type: []string{"string"}, Format: "", - }, + Enum: []interface{}{"Localhost", "RuntimeDefault", "Unconfined"}}, }, "localhostProfile": { SchemaProps: spec.SchemaProps{ @@ -12204,7 +12562,7 @@ func schema_k8sio_api_core_v1_Secret(ref common.ReferenceCallback) common.OpenAP }, "type": { SchemaProps: spec.SchemaProps{ - Description: "Used to facilitate programmatic handling of secret data.", + Description: "Used to facilitate programmatic handling of secret data. More info: https://kubernetes.io/docs/concepts/configuration/secret/#secret-types", Type: []string{"string"}, Format: "", }, @@ -12276,6 +12634,11 @@ func schema_k8sio_api_core_v1_SecretKeySelector(ref common.ReferenceCallback) co }, Required: []string{"key"}, }, + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-map-type": "atomic", + }, + }, }, } } @@ -12347,7 +12710,7 @@ func schema_k8sio_api_core_v1_SecretProjection(ref common.ReferenceCallback) com }, "items": { SchemaProps: spec.SchemaProps{ - Description: "If unspecified, each key-value pair in the Data field of the referenced Secret will be projected into the volume as a file whose name is the key and content is the value. If specified, the listed keys will be projected into the specified paths, and unlisted keys will not be present. If a key is specified which is not present in the Secret, the volume setup will error unless it is marked optional. Paths must be relative and may not contain the '..' path or start with '..'.", + Description: "items if unspecified, each key-value pair in the Data field of the referenced Secret will be projected into the volume as a file whose name is the key and content is the value. If specified, the listed keys will be projected into the specified paths, and unlisted keys will not be present. If a key is specified which is not present in the Secret, the volume setup will error unless it is marked optional. Paths must be relative and may not contain the '..' path or start with '..'.", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ @@ -12361,7 +12724,7 @@ func schema_k8sio_api_core_v1_SecretProjection(ref common.ReferenceCallback) com }, "optional": { SchemaProps: spec.SchemaProps{ - Description: "Specify whether the Secret or its key must be defined", + Description: "optional field specify whether the Secret or its key must be defined", Type: []string{"boolean"}, Format: "", }, @@ -12383,20 +12746,25 @@ func schema_k8sio_api_core_v1_SecretReference(ref common.ReferenceCallback) comm Properties: map[string]spec.Schema{ "name": { SchemaProps: spec.SchemaProps{ - Description: "Name is unique within a namespace to reference a secret resource.", + Description: "name is unique within a namespace to reference a secret resource.", Type: []string{"string"}, Format: "", }, }, "namespace": { SchemaProps: spec.SchemaProps{ - Description: "Namespace defines the space within which the secret name must be unique.", + Description: "namespace defines the space within which the secret name must be unique.", Type: []string{"string"}, Format: "", }, }, }, }, + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-map-type": "atomic", + }, + }, }, } } @@ -12410,14 +12778,14 @@ func schema_k8sio_api_core_v1_SecretVolumeSource(ref common.ReferenceCallback) c Properties: map[string]spec.Schema{ "secretName": { SchemaProps: spec.SchemaProps{ - Description: "Name of the secret in the pod's namespace to use. More info: https://kubernetes.io/docs/concepts/storage/volumes#secret", + Description: "secretName is the name of the secret in the pod's namespace to use. More info: https://kubernetes.io/docs/concepts/storage/volumes#secret", Type: []string{"string"}, Format: "", }, }, "items": { SchemaProps: spec.SchemaProps{ - Description: "If unspecified, each key-value pair in the Data field of the referenced Secret will be projected into the volume as a file whose name is the key and content is the value. If specified, the listed keys will be projected into the specified paths, and unlisted keys will not be present. If a key is specified which is not present in the Secret, the volume setup will error unless it is marked optional. Paths must be relative and may not contain the '..' path or start with '..'.", + Description: "items If unspecified, each key-value pair in the Data field of the referenced Secret will be projected into the volume as a file whose name is the key and content is the value. If specified, the listed keys will be projected into the specified paths, and unlisted keys will not be present. If a key is specified which is not present in the Secret, the volume setup will error unless it is marked optional. Paths must be relative and may not contain the '..' path or start with '..'.", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ @@ -12431,14 +12799,14 @@ func schema_k8sio_api_core_v1_SecretVolumeSource(ref common.ReferenceCallback) c }, "defaultMode": { SchemaProps: spec.SchemaProps{ - Description: "Optional: mode bits used to set permissions on created files by default. Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. Defaults to 0644. Directories within the path are not affected by this setting. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.", + Description: "defaultMode is Optional: mode bits used to set permissions on created files by default. Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. Defaults to 0644. Directories within the path are not affected by this setting. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.", Type: []string{"integer"}, Format: "int32", }, }, "optional": { SchemaProps: spec.SchemaProps{ - Description: "Specify whether the Secret or its keys must be defined", + Description: "optional field specify whether the Secret or its keys must be defined", Type: []string{"boolean"}, Format: "", }, @@ -12460,39 +12828,39 @@ func schema_k8sio_api_core_v1_SecurityContext(ref common.ReferenceCallback) comm Properties: map[string]spec.Schema{ "capabilities": { SchemaProps: spec.SchemaProps{ - Description: "The capabilities to add/drop when running containers. Defaults to the default set of capabilities granted by the container runtime.", + Description: "The capabilities to add/drop when running containers. Defaults to the default set of capabilities granted by the container runtime. Note that this field cannot be set when spec.os.name is windows.", Ref: ref("k8s.io/api/core/v1.Capabilities"), }, }, "privileged": { SchemaProps: spec.SchemaProps{ - Description: "Run container in privileged mode. Processes in privileged containers are essentially equivalent to root on the host. Defaults to false.", + Description: "Run container in privileged mode. Processes in privileged containers are essentially equivalent to root on the host. Defaults to false. Note that this field cannot be set when spec.os.name is windows.", Type: []string{"boolean"}, Format: "", }, }, "seLinuxOptions": { SchemaProps: spec.SchemaProps{ - Description: "The SELinux context to be applied to the container. If unspecified, the container runtime will allocate a random SELinux context for each container. May also be set in PodSecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence.", + Description: "The SELinux context to be applied to the container. If unspecified, the container runtime will allocate a random SELinux context for each container. May also be set in PodSecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. Note that this field cannot be set when spec.os.name is windows.", Ref: ref("k8s.io/api/core/v1.SELinuxOptions"), }, }, "windowsOptions": { SchemaProps: spec.SchemaProps{ - Description: "The Windows specific settings applied to all containers. If unspecified, the options from the PodSecurityContext will be used. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence.", + Description: "The Windows specific settings applied to all containers. If unspecified, the options from the PodSecurityContext will be used. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. Note that this field cannot be set when spec.os.name is linux.", Ref: ref("k8s.io/api/core/v1.WindowsSecurityContextOptions"), }, }, "runAsUser": { SchemaProps: spec.SchemaProps{ - Description: "The UID to run the entrypoint of the container process. Defaults to user specified in image metadata if unspecified. May also be set in PodSecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence.", + Description: "The UID to run the entrypoint of the container process. Defaults to user specified in image metadata if unspecified. May also be set in PodSecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. Note that this field cannot be set when spec.os.name is windows.", Type: []string{"integer"}, Format: "int64", }, }, "runAsGroup": { SchemaProps: spec.SchemaProps{ - Description: "The GID to run the entrypoint of the container process. Uses runtime default if unset. May also be set in PodSecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence.", + Description: "The GID to run the entrypoint of the container process. Uses runtime default if unset. May also be set in PodSecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. Note that this field cannot be set when spec.os.name is windows.", Type: []string{"integer"}, Format: "int64", }, @@ -12506,28 +12874,28 @@ func schema_k8sio_api_core_v1_SecurityContext(ref common.ReferenceCallback) comm }, "readOnlyRootFilesystem": { SchemaProps: spec.SchemaProps{ - Description: "Whether this container has a read-only root filesystem. Default is false.", + Description: "Whether this container has a read-only root filesystem. Default is false. Note that this field cannot be set when spec.os.name is windows.", Type: []string{"boolean"}, Format: "", }, }, "allowPrivilegeEscalation": { SchemaProps: spec.SchemaProps{ - Description: "AllowPrivilegeEscalation controls whether a process can gain more privileges than its parent process. This bool directly controls if the no_new_privs flag will be set on the container process. AllowPrivilegeEscalation is true always when the container is: 1) run as Privileged 2) has CAP_SYS_ADMIN", + Description: "AllowPrivilegeEscalation controls whether a process can gain more privileges than its parent process. This bool directly controls if the no_new_privs flag will be set on the container process. AllowPrivilegeEscalation is true always when the container is: 1) run as Privileged 2) has CAP_SYS_ADMIN Note that this field cannot be set when spec.os.name is windows.", Type: []string{"boolean"}, Format: "", }, }, "procMount": { SchemaProps: spec.SchemaProps{ - Description: "procMount denotes the type of proc mount to use for the containers. The default is DefaultProcMount which uses the container runtime defaults for readonly paths and masked paths. This requires the ProcMountType feature flag to be enabled.", + Description: "procMount denotes the type of proc mount to use for the containers. The default is DefaultProcMount which uses the container runtime defaults for readonly paths and masked paths. This requires the ProcMountType feature flag to be enabled. Note that this field cannot be set when spec.os.name is windows.", Type: []string{"string"}, Format: "", }, }, "seccompProfile": { SchemaProps: spec.SchemaProps{ - Description: "The seccomp options to use by this container. If seccomp options are provided at both the pod & container level, the container options override the pod options.", + Description: "The seccomp options to use by this container. If seccomp options are provided at both the pod & container level, the container options override the pod options. Note that this field cannot be set when spec.os.name is windows.", Ref: ref("k8s.io/api/core/v1.SeccompProfile"), }, }, @@ -12661,7 +13029,7 @@ func schema_k8sio_api_core_v1_ServiceAccount(ref common.ReferenceCallback) commo }, }, SchemaProps: spec.SchemaProps{ - Description: "Secrets is the list of secrets allowed to be used by pods running using this ServiceAccount. More info: https://kubernetes.io/docs/concepts/configuration/secret", + Description: "Secrets is a list of the secrets in the same namespace that pods running using this ServiceAccount are allowed to use. Pods are only limited to this list if this service account has a \"kubernetes.io/enforce-mountable-secrets\" annotation set to \"true\". This field should not be used to find auto-generated service account token secrets for use outside of pods. Instead, tokens can be requested directly using the TokenRequest API, or service account token secrets can be manually created. More info: https://kubernetes.io/docs/concepts/configuration/secret", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ @@ -12762,21 +13130,21 @@ func schema_k8sio_api_core_v1_ServiceAccountTokenProjection(ref common.Reference Properties: map[string]spec.Schema{ "audience": { SchemaProps: spec.SchemaProps{ - Description: "Audience is the intended audience of the token. A recipient of a token must identify itself with an identifier specified in the audience of the token, and otherwise should reject the token. The audience defaults to the identifier of the apiserver.", + Description: "audience is the intended audience of the token. A recipient of a token must identify itself with an identifier specified in the audience of the token, and otherwise should reject the token. The audience defaults to the identifier of the apiserver.", Type: []string{"string"}, Format: "", }, }, "expirationSeconds": { SchemaProps: spec.SchemaProps{ - Description: "ExpirationSeconds is the requested duration of validity of the service account token. As the token approaches expiration, the kubelet volume plugin will proactively rotate the service account token. The kubelet will start trying to rotate the token if the token is older than 80 percent of its time to live or if the token is older than 24 hours.Defaults to 1 hour and must be at least 10 minutes.", + Description: "expirationSeconds is the requested duration of validity of the service account token. As the token approaches expiration, the kubelet volume plugin will proactively rotate the service account token. The kubelet will start trying to rotate the token if the token is older than 80 percent of its time to live or if the token is older than 24 hours.Defaults to 1 hour and must be at least 10 minutes.", Type: []string{"integer"}, Format: "int64", }, }, "path": { SchemaProps: spec.SchemaProps{ - Description: "Path is the path relative to the mount point of the file to project the token into.", + Description: "path is the path relative to the mount point of the file to project the token into.", Default: "", Type: []string{"string"}, Format: "", @@ -12856,15 +13224,15 @@ func schema_k8sio_api_core_v1_ServicePort(ref common.ReferenceCallback) common.O }, "protocol": { SchemaProps: spec.SchemaProps{ - Description: "The IP protocol for this port. Supports \"TCP\", \"UDP\", and \"SCTP\". Default is TCP.", + Description: "The IP protocol for this port. Supports \"TCP\", \"UDP\", and \"SCTP\". Default is TCP.\n\nPossible enum values:\n - `\"SCTP\"` is the SCTP protocol.\n - `\"TCP\"` is the TCP protocol.\n - `\"UDP\"` is the UDP protocol.", Default: "TCP", Type: []string{"string"}, Format: "", - }, + Enum: []interface{}{"SCTP", "TCP", "UDP"}}, }, "appProtocol": { SchemaProps: spec.SchemaProps{ - Description: "The application protocol for this port. This field follows standard Kubernetes label syntax. Un-prefixed names are reserved for IANA standard service names (as per RFC-6335 and http://www.iana.org/assignments/service-names). Non-standard protocols should use prefixed names such as mycompany.com/my-custom-protocol. This is a beta field that is guarded by the ServiceAppProtocol feature gate and enabled by default.", + Description: "The application protocol for this port. This field follows standard Kubernetes label syntax. Un-prefixed names are reserved for IANA standard service names (as per RFC-6335 and https://www.iana.org/assignments/service-names). Non-standard protocols should use prefixed names such as mycompany.com/my-custom-protocol.", Type: []string{"string"}, Format: "", }, @@ -12967,6 +13335,11 @@ func schema_k8sio_api_core_v1_ServiceSpec(ref common.ReferenceCallback) common.O }, }, "selector": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-map-type": "atomic", + }, + }, SchemaProps: spec.SchemaProps{ Description: "Route service traffic to pods with label keys and values matching this selector. If empty or not present, the service is assumed to have an external process managing its endpoints, which Kubernetes will not modify. Only applies to types ClusterIP, NodePort, and LoadBalancer. Ignored if type is ExternalName. More info: https://kubernetes.io/docs/concepts/services-networking/service/", Type: []string{"object"}, @@ -12996,7 +13369,7 @@ func schema_k8sio_api_core_v1_ServiceSpec(ref common.ReferenceCallback) common.O }, }, SchemaProps: spec.SchemaProps{ - Description: "ClusterIPs is a list of IP addresses assigned to this service, and are usually assigned randomly. If an address is specified manually, is in-range (as per system configuration), and is not in use, it will be allocated to the service; otherwise creation of the service will fail. This field may not be changed through updates unless the type field is also being changed to ExternalName (which requires this field to be empty) or the type field is being changed from ExternalName (in which case this field may optionally be specified, as describe above). Valid values are \"None\", empty string (\"\"), or a valid IP address. Setting this to \"None\" makes a \"headless service\" (no virtual IP), which is useful when direct endpoint connections are preferred and proxying is not required. Only applies to types ClusterIP, NodePort, and LoadBalancer. If this field is specified when creating a Service of type ExternalName, creation will fail. This field will be wiped when updating a Service to type ExternalName. If this field is not specified, it will be initialized from the clusterIP field. If this field is specified, clients must ensure that clusterIPs[0] and clusterIP have the same value.\n\nUnless the \"IPv6DualStack\" feature gate is enabled, this field is limited to one value, which must be the same as the clusterIP field. If the feature gate is enabled, this field may hold a maximum of two entries (dual-stack IPs, in either order). These IPs must correspond to the values of the ipFamilies field. Both clusterIPs and ipFamilies are governed by the ipFamilyPolicy field. More info: https://kubernetes.io/docs/concepts/services-networking/service/#virtual-ips-and-service-proxies", + Description: "ClusterIPs is a list of IP addresses assigned to this service, and are usually assigned randomly. If an address is specified manually, is in-range (as per system configuration), and is not in use, it will be allocated to the service; otherwise creation of the service will fail. This field may not be changed through updates unless the type field is also being changed to ExternalName (which requires this field to be empty) or the type field is being changed from ExternalName (in which case this field may optionally be specified, as describe above). Valid values are \"None\", empty string (\"\"), or a valid IP address. Setting this to \"None\" makes a \"headless service\" (no virtual IP), which is useful when direct endpoint connections are preferred and proxying is not required. Only applies to types ClusterIP, NodePort, and LoadBalancer. If this field is specified when creating a Service of type ExternalName, creation will fail. This field will be wiped when updating a Service to type ExternalName. If this field is not specified, it will be initialized from the clusterIP field. If this field is specified, clients must ensure that clusterIPs[0] and clusterIP have the same value.\n\nThis field may hold a maximum of two entries (dual-stack IPs, in either order). These IPs must correspond to the values of the ipFamilies field. Both clusterIPs and ipFamilies are governed by the ipFamilyPolicy field. More info: https://kubernetes.io/docs/concepts/services-networking/service/#virtual-ips-and-service-proxies", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ @@ -13011,10 +13384,10 @@ func schema_k8sio_api_core_v1_ServiceSpec(ref common.ReferenceCallback) common.O }, "type": { SchemaProps: spec.SchemaProps{ - Description: "type determines how the Service is exposed. Defaults to ClusterIP. Valid options are ExternalName, ClusterIP, NodePort, and LoadBalancer. \"ClusterIP\" allocates a cluster-internal IP address for load-balancing to endpoints. Endpoints are determined by the selector or if that is not specified, by manual construction of an Endpoints object or EndpointSlice objects. If clusterIP is \"None\", no virtual IP is allocated and the endpoints are published as a set of endpoints rather than a virtual IP. \"NodePort\" builds on ClusterIP and allocates a port on every node which routes to the same endpoints as the clusterIP. \"LoadBalancer\" builds on NodePort and creates an external load-balancer (if supported in the current cloud) which routes to the same endpoints as the clusterIP. \"ExternalName\" aliases this service to the specified externalName. Several other fields do not apply to ExternalName services. More info: https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services-service-types", + Description: "type determines how the Service is exposed. Defaults to ClusterIP. Valid options are ExternalName, ClusterIP, NodePort, and LoadBalancer. \"ClusterIP\" allocates a cluster-internal IP address for load-balancing to endpoints. Endpoints are determined by the selector or if that is not specified, by manual construction of an Endpoints object or EndpointSlice objects. If clusterIP is \"None\", no virtual IP is allocated and the endpoints are published as a set of endpoints rather than a virtual IP. \"NodePort\" builds on ClusterIP and allocates a port on every node which routes to the same endpoints as the clusterIP. \"LoadBalancer\" builds on NodePort and creates an external load-balancer (if supported in the current cloud) which routes to the same endpoints as the clusterIP. \"ExternalName\" aliases this service to the specified externalName. Several other fields do not apply to ExternalName services. More info: https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services-service-types\n\nPossible enum values:\n - `\"ClusterIP\"` means a service will only be accessible inside the cluster, via the cluster IP.\n - `\"ExternalName\"` means a service consists of only a reference to an external name that kubedns or equivalent will return as a CNAME record, with no exposing or proxying of any pods involved.\n - `\"LoadBalancer\"` means a service will be exposed via an external load balancer (if the cloud provider supports it), in addition to 'NodePort' type.\n - `\"NodePort\"` means a service will be exposed on one port of every node, in addition to 'ClusterIP' type.", Type: []string{"string"}, Format: "", - }, + Enum: []interface{}{"ClusterIP", "ExternalName", "LoadBalancer", "NodePort"}}, }, "externalIPs": { SchemaProps: spec.SchemaProps{ @@ -13033,21 +13406,21 @@ func schema_k8sio_api_core_v1_ServiceSpec(ref common.ReferenceCallback) common.O }, "sessionAffinity": { SchemaProps: spec.SchemaProps{ - Description: "Supports \"ClientIP\" and \"None\". Used to maintain session affinity. Enable client IP based session affinity. Must be ClientIP or None. Defaults to None. More info: https://kubernetes.io/docs/concepts/services-networking/service/#virtual-ips-and-service-proxies", + Description: "Supports \"ClientIP\" and \"None\". Used to maintain session affinity. Enable client IP based session affinity. Must be ClientIP or None. Defaults to None. More info: https://kubernetes.io/docs/concepts/services-networking/service/#virtual-ips-and-service-proxies\n\nPossible enum values:\n - `\"ClientIP\"` is the Client IP based.\n - `\"None\"` - no session affinity.", Type: []string{"string"}, Format: "", - }, + Enum: []interface{}{"ClientIP", "None"}}, }, "loadBalancerIP": { SchemaProps: spec.SchemaProps{ - Description: "Only applies to Service Type: LoadBalancer LoadBalancer will get created with the IP specified in this field. This feature depends on whether the underlying cloud-provider supports specifying the loadBalancerIP when a load balancer is created. This field will be ignored if the cloud-provider does not support the feature.", + Description: "Only applies to Service Type: LoadBalancer. This feature depends on whether the underlying cloud-provider supports specifying the loadBalancerIP when a load balancer is created. This field will be ignored if the cloud-provider does not support the feature. Deprecated: This field was under-specified and its meaning varies across implementations, and it cannot support dual-stack. As of Kubernetes v1.24, users are encouraged to use implementation-specific annotations when available. This field may be removed in a future API version.", Type: []string{"string"}, Format: "", }, }, "loadBalancerSourceRanges": { SchemaProps: spec.SchemaProps{ - Description: "If specified and supported by the platform, this will restrict traffic through the cloud-provider load-balancer will be restricted to the specified client IPs. This field will be ignored if the cloud-provider does not support the feature.\" More info: https://kubernetes.io/docs/tasks/access-application-cluster/configure-cloud-provider-firewall/", + Description: "If specified and supported by the platform, this will restrict traffic through the cloud-provider load-balancer will be restricted to the specified client IPs. This field will be ignored if the cloud-provider does not support the feature.\" More info: https://kubernetes.io/docs/tasks/access-application-cluster/create-external-load-balancer/", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ @@ -13069,10 +13442,10 @@ func schema_k8sio_api_core_v1_ServiceSpec(ref common.ReferenceCallback) common.O }, "externalTrafficPolicy": { SchemaProps: spec.SchemaProps{ - Description: "externalTrafficPolicy denotes if this Service desires to route external traffic to node-local or cluster-wide endpoints. \"Local\" preserves the client source IP and avoids a second hop for LoadBalancer and Nodeport type services, but risks potentially imbalanced traffic spreading. \"Cluster\" obscures the client source IP and may cause a second hop to another node, but should have good overall load-spreading.", + Description: "externalTrafficPolicy denotes if this Service desires to route external traffic to node-local or cluster-wide endpoints. \"Local\" preserves the client source IP and avoids a second hop for LoadBalancer and Nodeport type services, but risks potentially imbalanced traffic spreading. \"Cluster\" obscures the client source IP and may cause a second hop to another node, but should have good overall load-spreading.\n\nPossible enum values:\n - `\"Cluster\"` specifies node-global (legacy) behavior.\n - `\"Local\"` specifies node-local endpoints behavior.", Type: []string{"string"}, Format: "", - }, + Enum: []interface{}{"Cluster", "Local"}}, }, "healthCheckNodePort": { SchemaProps: spec.SchemaProps{ @@ -13094,21 +13467,6 @@ func schema_k8sio_api_core_v1_ServiceSpec(ref common.ReferenceCallback) common.O Ref: ref("k8s.io/api/core/v1.SessionAffinityConfig"), }, }, - "topologyKeys": { - SchemaProps: spec.SchemaProps{ - Description: "topologyKeys is a preference-order list of topology keys which implementations of services should use to preferentially sort endpoints when accessing this Service, it can not be used at the same time as externalTrafficPolicy=Local. Topology keys must be valid label keys and at most 16 keys may be specified. Endpoints are chosen based on the first topology key with available backends. If this field is specified and all entries have no backends that match the topology of the client, the service has no backends for that client and connections should fail. The special value \"*\" may be used to mean \"any topology\". This catch-all value, if used, only makes sense as the last value in the list. If this is not specified or empty, no topology constraints will be applied. This field is alpha-level and is only honored by servers that enable the ServiceTopology feature. This field is deprecated and will be removed in a future version.", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - }, - }, - }, "ipFamilies": { VendorExtensible: spec.VendorExtensible{ Extensions: spec.Extensions{ @@ -13116,7 +13474,7 @@ func schema_k8sio_api_core_v1_ServiceSpec(ref common.ReferenceCallback) common.O }, }, SchemaProps: spec.SchemaProps{ - Description: "IPFamilies is a list of IP families (e.g. IPv4, IPv6) assigned to this service, and is gated by the \"IPv6DualStack\" feature gate. This field is usually assigned automatically based on cluster configuration and the ipFamilyPolicy field. If this field is specified manually, the requested family is available in the cluster, and ipFamilyPolicy allows it, it will be used; otherwise creation of the service will fail. This field is conditionally mutable: it allows for adding or removing a secondary IP family, but it does not allow changing the primary IP family of the Service. Valid values are \"IPv4\" and \"IPv6\". This field only applies to Services of types ClusterIP, NodePort, and LoadBalancer, and does apply to \"headless\" services. This field will be wiped when updating a Service to type ExternalName.\n\nThis field may hold a maximum of two entries (dual-stack families, in either order). These families must correspond to the values of the clusterIPs field, if specified. Both clusterIPs and ipFamilies are governed by the ipFamilyPolicy field.", + Description: "IPFamilies is a list of IP families (e.g. IPv4, IPv6) assigned to this service. This field is usually assigned automatically based on cluster configuration and the ipFamilyPolicy field. If this field is specified manually, the requested family is available in the cluster, and ipFamilyPolicy allows it, it will be used; otherwise creation of the service will fail. This field is conditionally mutable: it allows for adding or removing a secondary IP family, but it does not allow changing the primary IP family of the Service. Valid values are \"IPv4\" and \"IPv6\". This field only applies to Services of types ClusterIP, NodePort, and LoadBalancer, and does apply to \"headless\" services. This field will be wiped when updating a Service to type ExternalName.\n\nThis field may hold a maximum of two entries (dual-stack families, in either order). These families must correspond to the values of the clusterIPs field, if specified. Both clusterIPs and ipFamilies are governed by the ipFamilyPolicy field.", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ @@ -13131,14 +13489,14 @@ func schema_k8sio_api_core_v1_ServiceSpec(ref common.ReferenceCallback) common.O }, "ipFamilyPolicy": { SchemaProps: spec.SchemaProps{ - Description: "IPFamilyPolicy represents the dual-stack-ness requested or required by this Service, and is gated by the \"IPv6DualStack\" feature gate. If there is no value provided, then this field will be set to SingleStack. Services can be \"SingleStack\" (a single IP family), \"PreferDualStack\" (two IP families on dual-stack configured clusters or a single IP family on single-stack clusters), or \"RequireDualStack\" (two IP families on dual-stack configured clusters, otherwise fail). The ipFamilies and clusterIPs fields depend on the value of this field. This field will be wiped when updating a service to type ExternalName.", + Description: "IPFamilyPolicy represents the dual-stack-ness requested or required by this Service. If there is no value provided, then this field will be set to SingleStack. Services can be \"SingleStack\" (a single IP family), \"PreferDualStack\" (two IP families on dual-stack configured clusters or a single IP family on single-stack clusters), or \"RequireDualStack\" (two IP families on dual-stack configured clusters, otherwise fail). The ipFamilies and clusterIPs fields depend on the value of this field. This field will be wiped when updating a service to type ExternalName.", Type: []string{"string"}, Format: "", }, }, "allocateLoadBalancerNodePorts": { SchemaProps: spec.SchemaProps{ - Description: "allocateLoadBalancerNodePorts defines if NodePorts will be automatically allocated for services with type LoadBalancer. Default is \"true\". It may be set to \"false\" if the cluster load-balancer does not rely on NodePorts. allocateLoadBalancerNodePorts may only be set for services with type LoadBalancer and will be cleared if the type is changed to any other type. This field is alpha-level and is only honored by servers that enable the ServiceLBNodePortControl feature.", + Description: "allocateLoadBalancerNodePorts defines if NodePorts will be automatically allocated for services with type LoadBalancer. Default is \"true\". It may be set to \"false\" if the cluster load-balancer does not rely on NodePorts. If the caller requests specific NodePorts (by specifying a value), those requests will be respected, regardless of this field. This field may only be set for services with type LoadBalancer and will be cleared if the type is changed to any other type.", Type: []string{"boolean"}, Format: "", }, @@ -13241,35 +13599,35 @@ func schema_k8sio_api_core_v1_StorageOSPersistentVolumeSource(ref common.Referen Properties: map[string]spec.Schema{ "volumeName": { SchemaProps: spec.SchemaProps{ - Description: "VolumeName is the human-readable name of the StorageOS volume. Volume names are only unique within a namespace.", + Description: "volumeName is the human-readable name of the StorageOS volume. Volume names are only unique within a namespace.", Type: []string{"string"}, Format: "", }, }, "volumeNamespace": { SchemaProps: spec.SchemaProps{ - Description: "VolumeNamespace specifies the scope of the volume within StorageOS. If no namespace is specified then the Pod's namespace will be used. This allows the Kubernetes name scoping to be mirrored within StorageOS for tighter integration. Set VolumeName to any name to override the default behaviour. Set to \"default\" if you are not using namespaces within StorageOS. Namespaces that do not pre-exist within StorageOS will be created.", + Description: "volumeNamespace specifies the scope of the volume within StorageOS. If no namespace is specified then the Pod's namespace will be used. This allows the Kubernetes name scoping to be mirrored within StorageOS for tighter integration. Set VolumeName to any name to override the default behaviour. Set to \"default\" if you are not using namespaces within StorageOS. Namespaces that do not pre-exist within StorageOS will be created.", Type: []string{"string"}, Format: "", }, }, "fsType": { SchemaProps: spec.SchemaProps{ - Description: "Filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified.", + Description: "fsType is the filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified.", Type: []string{"string"}, Format: "", }, }, "readOnly": { SchemaProps: spec.SchemaProps{ - Description: "Defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts.", + Description: "readOnly defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts.", Type: []string{"boolean"}, Format: "", }, }, "secretRef": { SchemaProps: spec.SchemaProps{ - Description: "SecretRef specifies the secret to use for obtaining the StorageOS API credentials. If not specified, default values will be attempted.", + Description: "secretRef specifies the secret to use for obtaining the StorageOS API credentials. If not specified, default values will be attempted.", Ref: ref("k8s.io/api/core/v1.ObjectReference"), }, }, @@ -13290,35 +13648,35 @@ func schema_k8sio_api_core_v1_StorageOSVolumeSource(ref common.ReferenceCallback Properties: map[string]spec.Schema{ "volumeName": { SchemaProps: spec.SchemaProps{ - Description: "VolumeName is the human-readable name of the StorageOS volume. Volume names are only unique within a namespace.", + Description: "volumeName is the human-readable name of the StorageOS volume. Volume names are only unique within a namespace.", Type: []string{"string"}, Format: "", }, }, "volumeNamespace": { SchemaProps: spec.SchemaProps{ - Description: "VolumeNamespace specifies the scope of the volume within StorageOS. If no namespace is specified then the Pod's namespace will be used. This allows the Kubernetes name scoping to be mirrored within StorageOS for tighter integration. Set VolumeName to any name to override the default behaviour. Set to \"default\" if you are not using namespaces within StorageOS. Namespaces that do not pre-exist within StorageOS will be created.", + Description: "volumeNamespace specifies the scope of the volume within StorageOS. If no namespace is specified then the Pod's namespace will be used. This allows the Kubernetes name scoping to be mirrored within StorageOS for tighter integration. Set VolumeName to any name to override the default behaviour. Set to \"default\" if you are not using namespaces within StorageOS. Namespaces that do not pre-exist within StorageOS will be created.", Type: []string{"string"}, Format: "", }, }, "fsType": { SchemaProps: spec.SchemaProps{ - Description: "Filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified.", + Description: "fsType is the filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified.", Type: []string{"string"}, Format: "", }, }, "readOnly": { SchemaProps: spec.SchemaProps{ - Description: "Defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts.", + Description: "readOnly defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts.", Type: []string{"boolean"}, Format: "", }, }, "secretRef": { SchemaProps: spec.SchemaProps{ - Description: "SecretRef specifies the secret to use for obtaining the StorageOS API credentials. If not specified, default values will be attempted.", + Description: "secretRef specifies the secret to use for obtaining the StorageOS API credentials. If not specified, default values will be attempted.", Ref: ref("k8s.io/api/core/v1.LocalObjectReference"), }, }, @@ -13414,11 +13772,11 @@ func schema_k8sio_api_core_v1_Taint(ref common.ReferenceCallback) common.OpenAPI }, "effect": { SchemaProps: spec.SchemaProps{ - Description: "Required. The effect of the taint on pods that do not tolerate the taint. Valid effects are NoSchedule, PreferNoSchedule and NoExecute.", + Description: "Required. The effect of the taint on pods that do not tolerate the taint. Valid effects are NoSchedule, PreferNoSchedule and NoExecute.\n\nPossible enum values:\n - `\"NoExecute\"` Evict any already-running pods that do not tolerate the taint. Currently enforced by NodeController.\n - `\"NoSchedule\"` Do not allow new pods to schedule onto the node unless they tolerate the taint, but allow all pods submitted to Kubelet without going through the scheduler to start, and allow all already-running pods to continue running. Enforced by the scheduler.\n - `\"PreferNoSchedule\"` Like TaintEffectNoSchedule, but the scheduler tries not to schedule new pods onto the node, rather than prohibiting new pods from scheduling onto the node entirely. Enforced by the scheduler.", Default: "", Type: []string{"string"}, Format: "", - }, + Enum: []interface{}{"NoExecute", "NoSchedule", "PreferNoSchedule"}}, }, "timeAdded": { SchemaProps: spec.SchemaProps{ @@ -13451,10 +13809,10 @@ func schema_k8sio_api_core_v1_Toleration(ref common.ReferenceCallback) common.Op }, "operator": { SchemaProps: spec.SchemaProps{ - Description: "Operator represents a key's relationship to the value. Valid operators are Exists and Equal. Defaults to Equal. Exists is equivalent to wildcard for value, so that a pod can tolerate all taints of a particular category.", + Description: "Operator represents a key's relationship to the value. Valid operators are Exists and Equal. Defaults to Equal. Exists is equivalent to wildcard for value, so that a pod can tolerate all taints of a particular category.\n\nPossible enum values:\n - `\"Equal\"`\n - `\"Exists\"`", Type: []string{"string"}, Format: "", - }, + Enum: []interface{}{"Equal", "Exists"}}, }, "value": { SchemaProps: spec.SchemaProps{ @@ -13465,10 +13823,10 @@ func schema_k8sio_api_core_v1_Toleration(ref common.ReferenceCallback) common.Op }, "effect": { SchemaProps: spec.SchemaProps{ - Description: "Effect indicates the taint effect to match. Empty means match all taint effects. When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute.", + Description: "Effect indicates the taint effect to match. Empty means match all taint effects. When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute.\n\nPossible enum values:\n - `\"NoExecute\"` Evict any already-running pods that do not tolerate the taint. Currently enforced by NodeController.\n - `\"NoSchedule\"` Do not allow new pods to schedule onto the node unless they tolerate the taint, but allow all pods submitted to Kubelet without going through the scheduler to start, and allow all already-running pods to continue running. Enforced by the scheduler.\n - `\"PreferNoSchedule\"` Like TaintEffectNoSchedule, but the scheduler tries not to schedule new pods onto the node, rather than prohibiting new pods from scheduling onto the node entirely. Enforced by the scheduler.", Type: []string{"string"}, Format: "", - }, + Enum: []interface{}{"NoExecute", "NoSchedule", "PreferNoSchedule"}}, }, "tolerationSeconds": { SchemaProps: spec.SchemaProps{ @@ -13543,6 +13901,11 @@ func schema_k8sio_api_core_v1_TopologySelectorTerm(ref common.ReferenceCallback) }, }, }, + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-map-type": "atomic", + }, + }, }, Dependencies: []string{ "k8s.io/api/core/v1.TopologySelectorLabelRequirement"}, @@ -13558,7 +13921,7 @@ func schema_k8sio_api_core_v1_TopologySpreadConstraint(ref common.ReferenceCallb Properties: map[string]spec.Schema{ "maxSkew": { SchemaProps: spec.SchemaProps{ - Description: "MaxSkew describes the degree to which pods may be unevenly distributed. When `whenUnsatisfiable=DoNotSchedule`, it is the maximum permitted difference between the number of matching pods in the target topology and the global minimum. For example, in a 3-zone cluster, MaxSkew is set to 1, and pods with the same labelSelector spread as 1/1/0: | zone1 | zone2 | zone3 | | P | P | | - if MaxSkew is 1, incoming pod can only be scheduled to zone3 to become 1/1/1; scheduling it onto zone1(zone2) would make the ActualSkew(2-0) on zone1(zone2) violate MaxSkew(1). - if MaxSkew is 2, incoming pod can be scheduled onto any zone. When `whenUnsatisfiable=ScheduleAnyway`, it is used to give higher precedence to topologies that satisfy it. It's a required field. Default value is 1 and 0 is not allowed.", + Description: "MaxSkew describes the degree to which pods may be unevenly distributed. When `whenUnsatisfiable=DoNotSchedule`, it is the maximum permitted difference between the number of matching pods in the target topology and the global minimum. The global minimum is the minimum number of matching pods in an eligible domain or zero if the number of eligible domains is less than MinDomains. For example, in a 3-zone cluster, MaxSkew is set to 1, and pods with the same labelSelector spread as 2/2/1: In this case, the global minimum is 1. | zone1 | zone2 | zone3 | | P P | P P | P | - if MaxSkew is 1, incoming pod can only be scheduled to zone3 to become 2/2/2; scheduling it onto zone1(zone2) would make the ActualSkew(3-1) on zone1(zone2) violate MaxSkew(1). - if MaxSkew is 2, incoming pod can be scheduled onto any zone. When `whenUnsatisfiable=ScheduleAnyway`, it is used to give higher precedence to topologies that satisfy it. It's a required field. Default value is 1 and 0 is not allowed.", Default: 0, Type: []string{"integer"}, Format: "int32", @@ -13566,7 +13929,7 @@ func schema_k8sio_api_core_v1_TopologySpreadConstraint(ref common.ReferenceCallb }, "topologyKey": { SchemaProps: spec.SchemaProps{ - Description: "TopologyKey is the key of node labels. Nodes that have a label with this key and identical values are considered to be in the same topology. We consider each as a \"bucket\", and try to put balanced number of pods into each bucket. It's a required field.", + Description: "TopologyKey is the key of node labels. Nodes that have a label with this key and identical values are considered to be in the same topology. We consider each as a \"bucket\", and try to put balanced number of pods into each bucket. We define a domain as a particular instance of a topology. Also, we define an eligible domain as a domain whose nodes match the node selector. e.g. If TopologyKey is \"kubernetes.io/hostname\", each Node is a domain of that topology. And, if TopologyKey is \"topology.kubernetes.io/zone\", each zone is a domain of that topology. It's a required field.", Default: "", Type: []string{"string"}, Format: "", @@ -13574,11 +13937,11 @@ func schema_k8sio_api_core_v1_TopologySpreadConstraint(ref common.ReferenceCallb }, "whenUnsatisfiable": { SchemaProps: spec.SchemaProps{ - Description: "WhenUnsatisfiable indicates how to deal with a pod if it doesn't satisfy the spread constraint. - DoNotSchedule (default) tells the scheduler not to schedule it. - ScheduleAnyway tells the scheduler to schedule the pod in any location,\n but giving higher precedence to topologies that would help reduce the\n skew.\nA constraint is considered \"Unsatisfiable\" for an incoming pod if and only if every possible node assigment for that pod would violate \"MaxSkew\" on some topology. For example, in a 3-zone cluster, MaxSkew is set to 1, and pods with the same labelSelector spread as 3/1/1: | zone1 | zone2 | zone3 | | P P P | P | P | If WhenUnsatisfiable is set to DoNotSchedule, incoming pod can only be scheduled to zone2(zone3) to become 3/2/1(3/1/2) as ActualSkew(2-1) on zone2(zone3) satisfies MaxSkew(1). In other words, the cluster can still be imbalanced, but scheduler won't make it *more* imbalanced. It's a required field.", + Description: "WhenUnsatisfiable indicates how to deal with a pod if it doesn't satisfy the spread constraint. - DoNotSchedule (default) tells the scheduler not to schedule it. - ScheduleAnyway tells the scheduler to schedule the pod in any location,\n but giving higher precedence to topologies that would help reduce the\n skew.\nA constraint is considered \"Unsatisfiable\" for an incoming pod if and only if every possible node assignment for that pod would violate \"MaxSkew\" on some topology. For example, in a 3-zone cluster, MaxSkew is set to 1, and pods with the same labelSelector spread as 3/1/1: | zone1 | zone2 | zone3 | | P P P | P | P | If WhenUnsatisfiable is set to DoNotSchedule, incoming pod can only be scheduled to zone2(zone3) to become 3/2/1(3/1/2) as ActualSkew(2-1) on zone2(zone3) satisfies MaxSkew(1). In other words, the cluster can still be imbalanced, but scheduler won't make it *more* imbalanced. It's a required field.\n\nPossible enum values:\n - `\"DoNotSchedule\"` instructs the scheduler not to schedule the pod when constraints are not satisfied.\n - `\"ScheduleAnyway\"` instructs the scheduler to schedule the pod even if constraints are not satisfied.", Default: "", Type: []string{"string"}, Format: "", - }, + Enum: []interface{}{"DoNotSchedule", "ScheduleAnyway"}}, }, "labelSelector": { SchemaProps: spec.SchemaProps{ @@ -13586,6 +13949,13 @@ func schema_k8sio_api_core_v1_TopologySpreadConstraint(ref common.ReferenceCallb Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.LabelSelector"), }, }, + "minDomains": { + SchemaProps: spec.SchemaProps{ + Description: "MinDomains indicates a minimum number of eligible domains. When the number of eligible domains with matching topology keys is less than minDomains, Pod Topology Spread treats \"global minimum\" as 0, and then the calculation of Skew is performed. And when the number of eligible domains with matching topology keys equals or greater than minDomains, this value has no effect on scheduling. As a result, when the number of eligible domains is less than minDomains, scheduler won't schedule more than maxSkew Pods to those domains. If value is nil, the constraint behaves as if MinDomains is equal to 1. Valid values are integers greater than 0. When value is not nil, WhenUnsatisfiable must be DoNotSchedule.\n\nFor example, in a 3-zone cluster, MaxSkew is set to 2, MinDomains is set to 5 and pods with the same labelSelector spread as 2/2/2: | zone1 | zone2 | zone3 | | P P | P P | P P | The number of domains is less than 5(MinDomains), so \"global minimum\" is treated as 0. In this situation, new pod with the same labelSelector cannot be scheduled, because computed skew will be 3(3 - 0) if new Pod is scheduled to any of the three zones, it will violate MaxSkew.\n\nThis is an alpha field and requires enabling MinDomainsInPodTopologySpread feature gate.", + Type: []string{"integer"}, + Format: "int32", + }, + }, }, Required: []string{"maxSkew", "topologyKey", "whenUnsatisfiable"}, }, @@ -13628,6 +13998,11 @@ func schema_k8sio_api_core_v1_TypedLocalObjectReference(ref common.ReferenceCall }, Required: []string{"kind", "name"}, }, + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-map-type": "atomic", + }, + }, }, } } @@ -13641,7 +14016,7 @@ func schema_k8sio_api_core_v1_Volume(ref common.ReferenceCallback) common.OpenAP Properties: map[string]spec.Schema{ "name": { SchemaProps: spec.SchemaProps{ - Description: "Volume's name. Must be a DNS_LABEL and unique within the pod. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names", + Description: "name of the volume. Must be a DNS_LABEL and unique within the pod. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names", Default: "", Type: []string{"string"}, Format: "", @@ -13649,175 +14024,175 @@ func schema_k8sio_api_core_v1_Volume(ref common.ReferenceCallback) common.OpenAP }, "hostPath": { SchemaProps: spec.SchemaProps{ - Description: "HostPath represents a pre-existing file or directory on the host machine that is directly exposed to the container. This is generally used for system agents or other privileged things that are allowed to see the host machine. Most containers will NOT need this. More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath", + Description: "hostPath represents a pre-existing file or directory on the host machine that is directly exposed to the container. This is generally used for system agents or other privileged things that are allowed to see the host machine. Most containers will NOT need this. More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath", Ref: ref("k8s.io/api/core/v1.HostPathVolumeSource"), }, }, "emptyDir": { SchemaProps: spec.SchemaProps{ - Description: "EmptyDir represents a temporary directory that shares a pod's lifetime. More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir", + Description: "emptyDir represents a temporary directory that shares a pod's lifetime. More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir", Ref: ref("k8s.io/api/core/v1.EmptyDirVolumeSource"), }, }, "gcePersistentDisk": { SchemaProps: spec.SchemaProps{ - Description: "GCEPersistentDisk represents a GCE Disk resource that is attached to a kubelet's host machine and then exposed to the pod. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk", + Description: "gcePersistentDisk represents a GCE Disk resource that is attached to a kubelet's host machine and then exposed to the pod. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk", Ref: ref("k8s.io/api/core/v1.GCEPersistentDiskVolumeSource"), }, }, "awsElasticBlockStore": { SchemaProps: spec.SchemaProps{ - Description: "AWSElasticBlockStore represents an AWS Disk resource that is attached to a kubelet's host machine and then exposed to the pod. More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore", + Description: "awsElasticBlockStore represents an AWS Disk resource that is attached to a kubelet's host machine and then exposed to the pod. More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore", Ref: ref("k8s.io/api/core/v1.AWSElasticBlockStoreVolumeSource"), }, }, "gitRepo": { SchemaProps: spec.SchemaProps{ - Description: "GitRepo represents a git repository at a particular revision. DEPRECATED: GitRepo is deprecated. To provision a container with a git repo, mount an EmptyDir into an InitContainer that clones the repo using git, then mount the EmptyDir into the Pod's container.", + Description: "gitRepo represents a git repository at a particular revision. DEPRECATED: GitRepo is deprecated. To provision a container with a git repo, mount an EmptyDir into an InitContainer that clones the repo using git, then mount the EmptyDir into the Pod's container.", Ref: ref("k8s.io/api/core/v1.GitRepoVolumeSource"), }, }, "secret": { SchemaProps: spec.SchemaProps{ - Description: "Secret represents a secret that should populate this volume. More info: https://kubernetes.io/docs/concepts/storage/volumes#secret", + Description: "secret represents a secret that should populate this volume. More info: https://kubernetes.io/docs/concepts/storage/volumes#secret", Ref: ref("k8s.io/api/core/v1.SecretVolumeSource"), }, }, "nfs": { SchemaProps: spec.SchemaProps{ - Description: "NFS represents an NFS mount on the host that shares a pod's lifetime More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs", + Description: "nfs represents an NFS mount on the host that shares a pod's lifetime More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs", Ref: ref("k8s.io/api/core/v1.NFSVolumeSource"), }, }, "iscsi": { SchemaProps: spec.SchemaProps{ - Description: "ISCSI represents an ISCSI Disk resource that is attached to a kubelet's host machine and then exposed to the pod. More info: https://examples.k8s.io/volumes/iscsi/README.md", + Description: "iscsi represents an ISCSI Disk resource that is attached to a kubelet's host machine and then exposed to the pod. More info: https://examples.k8s.io/volumes/iscsi/README.md", Ref: ref("k8s.io/api/core/v1.ISCSIVolumeSource"), }, }, "glusterfs": { SchemaProps: spec.SchemaProps{ - Description: "Glusterfs represents a Glusterfs mount on the host that shares a pod's lifetime. More info: https://examples.k8s.io/volumes/glusterfs/README.md", + Description: "glusterfs represents a Glusterfs mount on the host that shares a pod's lifetime. More info: https://examples.k8s.io/volumes/glusterfs/README.md", Ref: ref("k8s.io/api/core/v1.GlusterfsVolumeSource"), }, }, "persistentVolumeClaim": { SchemaProps: spec.SchemaProps{ - Description: "PersistentVolumeClaimVolumeSource represents a reference to a PersistentVolumeClaim in the same namespace. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims", + Description: "persistentVolumeClaimVolumeSource represents a reference to a PersistentVolumeClaim in the same namespace. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims", Ref: ref("k8s.io/api/core/v1.PersistentVolumeClaimVolumeSource"), }, }, "rbd": { SchemaProps: spec.SchemaProps{ - Description: "RBD represents a Rados Block Device mount on the host that shares a pod's lifetime. More info: https://examples.k8s.io/volumes/rbd/README.md", + Description: "rbd represents a Rados Block Device mount on the host that shares a pod's lifetime. More info: https://examples.k8s.io/volumes/rbd/README.md", Ref: ref("k8s.io/api/core/v1.RBDVolumeSource"), }, }, "flexVolume": { SchemaProps: spec.SchemaProps{ - Description: "FlexVolume represents a generic volume resource that is provisioned/attached using an exec based plugin.", + Description: "flexVolume represents a generic volume resource that is provisioned/attached using an exec based plugin.", Ref: ref("k8s.io/api/core/v1.FlexVolumeSource"), }, }, "cinder": { SchemaProps: spec.SchemaProps{ - Description: "Cinder represents a cinder volume attached and mounted on kubelets host machine. More info: https://examples.k8s.io/mysql-cinder-pd/README.md", + Description: "cinder represents a cinder volume attached and mounted on kubelets host machine. More info: https://examples.k8s.io/mysql-cinder-pd/README.md", Ref: ref("k8s.io/api/core/v1.CinderVolumeSource"), }, }, "cephfs": { SchemaProps: spec.SchemaProps{ - Description: "CephFS represents a Ceph FS mount on the host that shares a pod's lifetime", + Description: "cephFS represents a Ceph FS mount on the host that shares a pod's lifetime", Ref: ref("k8s.io/api/core/v1.CephFSVolumeSource"), }, }, "flocker": { SchemaProps: spec.SchemaProps{ - Description: "Flocker represents a Flocker volume attached to a kubelet's host machine. This depends on the Flocker control service being running", + Description: "flocker represents a Flocker volume attached to a kubelet's host machine. This depends on the Flocker control service being running", Ref: ref("k8s.io/api/core/v1.FlockerVolumeSource"), }, }, "downwardAPI": { SchemaProps: spec.SchemaProps{ - Description: "DownwardAPI represents downward API about the pod that should populate this volume", + Description: "downwardAPI represents downward API about the pod that should populate this volume", Ref: ref("k8s.io/api/core/v1.DownwardAPIVolumeSource"), }, }, "fc": { SchemaProps: spec.SchemaProps{ - Description: "FC represents a Fibre Channel resource that is attached to a kubelet's host machine and then exposed to the pod.", + Description: "fc represents a Fibre Channel resource that is attached to a kubelet's host machine and then exposed to the pod.", Ref: ref("k8s.io/api/core/v1.FCVolumeSource"), }, }, "azureFile": { SchemaProps: spec.SchemaProps{ - Description: "AzureFile represents an Azure File Service mount on the host and bind mount to the pod.", + Description: "azureFile represents an Azure File Service mount on the host and bind mount to the pod.", Ref: ref("k8s.io/api/core/v1.AzureFileVolumeSource"), }, }, "configMap": { SchemaProps: spec.SchemaProps{ - Description: "ConfigMap represents a configMap that should populate this volume", + Description: "configMap represents a configMap that should populate this volume", Ref: ref("k8s.io/api/core/v1.ConfigMapVolumeSource"), }, }, "vsphereVolume": { SchemaProps: spec.SchemaProps{ - Description: "VsphereVolume represents a vSphere volume attached and mounted on kubelets host machine", + Description: "vsphereVolume represents a vSphere volume attached and mounted on kubelets host machine", Ref: ref("k8s.io/api/core/v1.VsphereVirtualDiskVolumeSource"), }, }, "quobyte": { SchemaProps: spec.SchemaProps{ - Description: "Quobyte represents a Quobyte mount on the host that shares a pod's lifetime", + Description: "quobyte represents a Quobyte mount on the host that shares a pod's lifetime", Ref: ref("k8s.io/api/core/v1.QuobyteVolumeSource"), }, }, "azureDisk": { SchemaProps: spec.SchemaProps{ - Description: "AzureDisk represents an Azure Data Disk mount on the host and bind mount to the pod.", + Description: "azureDisk represents an Azure Data Disk mount on the host and bind mount to the pod.", Ref: ref("k8s.io/api/core/v1.AzureDiskVolumeSource"), }, }, "photonPersistentDisk": { SchemaProps: spec.SchemaProps{ - Description: "PhotonPersistentDisk represents a PhotonController persistent disk attached and mounted on kubelets host machine", + Description: "photonPersistentDisk represents a PhotonController persistent disk attached and mounted on kubelets host machine", Ref: ref("k8s.io/api/core/v1.PhotonPersistentDiskVolumeSource"), }, }, "projected": { SchemaProps: spec.SchemaProps{ - Description: "Items for all in one resources secrets, configmaps, and downward API", + Description: "projected items for all in one resources secrets, configmaps, and downward API", Ref: ref("k8s.io/api/core/v1.ProjectedVolumeSource"), }, }, "portworxVolume": { SchemaProps: spec.SchemaProps{ - Description: "PortworxVolume represents a portworx volume attached and mounted on kubelets host machine", + Description: "portworxVolume represents a portworx volume attached and mounted on kubelets host machine", Ref: ref("k8s.io/api/core/v1.PortworxVolumeSource"), }, }, "scaleIO": { SchemaProps: spec.SchemaProps{ - Description: "ScaleIO represents a ScaleIO persistent volume attached and mounted on Kubernetes nodes.", + Description: "scaleIO represents a ScaleIO persistent volume attached and mounted on Kubernetes nodes.", Ref: ref("k8s.io/api/core/v1.ScaleIOVolumeSource"), }, }, "storageos": { SchemaProps: spec.SchemaProps{ - Description: "StorageOS represents a StorageOS volume attached and mounted on Kubernetes nodes.", + Description: "storageOS represents a StorageOS volume attached and mounted on Kubernetes nodes.", Ref: ref("k8s.io/api/core/v1.StorageOSVolumeSource"), }, }, "csi": { SchemaProps: spec.SchemaProps{ - Description: "CSI (Container Storage Interface) represents ephemeral storage that is handled by certain external CSI drivers (Beta feature).", + Description: "csi (Container Storage Interface) represents ephemeral storage that is handled by certain external CSI drivers (Beta feature).", Ref: ref("k8s.io/api/core/v1.CSIVolumeSource"), }, }, "ephemeral": { SchemaProps: spec.SchemaProps{ - Description: "Ephemeral represents a volume that is handled by a cluster storage driver. The volume's lifecycle is tied to the pod that defines it - it will be created before the pod starts, and deleted when the pod is removed.\n\nUse this if: a) the volume is only needed while the pod runs, b) features of normal volumes like restoring from snapshot or capacity\n tracking are needed,\nc) the storage driver is specified through a storage class, and d) the storage driver supports dynamic volume provisioning through\n a PersistentVolumeClaim (see EphemeralVolumeSource for more\n information on the connection between this volume type\n and PersistentVolumeClaim).\n\nUse PersistentVolumeClaim or one of the vendor-specific APIs for volumes that persist for longer than the lifecycle of an individual pod.\n\nUse CSI for light-weight local ephemeral volumes if the CSI driver is meant to be used that way - see the documentation of the driver for more information.\n\nA pod can use both types of ephemeral volumes and persistent volumes at the same time.\n\nThis is a beta feature and only available when the GenericEphemeralVolume feature gate is enabled.", + Description: "ephemeral represents a volume that is handled by a cluster storage driver. The volume's lifecycle is tied to the pod that defines it - it will be created before the pod starts, and deleted when the pod is removed.\n\nUse this if: a) the volume is only needed while the pod runs, b) features of normal volumes like restoring from snapshot or capacity\n tracking are needed,\nc) the storage driver is specified through a storage class, and d) the storage driver supports dynamic volume provisioning through\n a PersistentVolumeClaim (see EphemeralVolumeSource for more\n information on the connection between this volume type\n and PersistentVolumeClaim).\n\nUse PersistentVolumeClaim or one of the vendor-specific APIs for volumes that persist for longer than the lifecycle of an individual pod.\n\nUse CSI for light-weight local ephemeral volumes if the CSI driver is meant to be used that way - see the documentation of the driver for more information.\n\nA pod can use both types of ephemeral volumes and persistent volumes at the same time.", Ref: ref("k8s.io/api/core/v1.EphemeralVolumeSource"), }, }, @@ -13927,7 +14302,7 @@ func schema_k8sio_api_core_v1_VolumeNodeAffinity(ref common.ReferenceCallback) c Properties: map[string]spec.Schema{ "required": { SchemaProps: spec.SchemaProps{ - Description: "Required specifies hard node constraints that must be met.", + Description: "required specifies hard node constraints that must be met.", Ref: ref("k8s.io/api/core/v1.NodeSelector"), }, }, @@ -13948,25 +14323,25 @@ func schema_k8sio_api_core_v1_VolumeProjection(ref common.ReferenceCallback) com Properties: map[string]spec.Schema{ "secret": { SchemaProps: spec.SchemaProps{ - Description: "information about the secret data to project", + Description: "secret information about the secret data to project", Ref: ref("k8s.io/api/core/v1.SecretProjection"), }, }, "downwardAPI": { SchemaProps: spec.SchemaProps{ - Description: "information about the downwardAPI data to project", + Description: "downwardAPI information about the downwardAPI data to project", Ref: ref("k8s.io/api/core/v1.DownwardAPIProjection"), }, }, "configMap": { SchemaProps: spec.SchemaProps{ - Description: "information about the configMap data to project", + Description: "configMap information about the configMap data to project", Ref: ref("k8s.io/api/core/v1.ConfigMapProjection"), }, }, "serviceAccountToken": { SchemaProps: spec.SchemaProps{ - Description: "information about the serviceAccountToken data to project", + Description: "serviceAccountToken is information about the serviceAccountToken data to project", Ref: ref("k8s.io/api/core/v1.ServiceAccountTokenProjection"), }, }, @@ -13987,175 +14362,175 @@ func schema_k8sio_api_core_v1_VolumeSource(ref common.ReferenceCallback) common. Properties: map[string]spec.Schema{ "hostPath": { SchemaProps: spec.SchemaProps{ - Description: "HostPath represents a pre-existing file or directory on the host machine that is directly exposed to the container. This is generally used for system agents or other privileged things that are allowed to see the host machine. Most containers will NOT need this. More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath", + Description: "hostPath represents a pre-existing file or directory on the host machine that is directly exposed to the container. This is generally used for system agents or other privileged things that are allowed to see the host machine. Most containers will NOT need this. More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath", Ref: ref("k8s.io/api/core/v1.HostPathVolumeSource"), }, }, "emptyDir": { SchemaProps: spec.SchemaProps{ - Description: "EmptyDir represents a temporary directory that shares a pod's lifetime. More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir", + Description: "emptyDir represents a temporary directory that shares a pod's lifetime. More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir", Ref: ref("k8s.io/api/core/v1.EmptyDirVolumeSource"), }, }, "gcePersistentDisk": { SchemaProps: spec.SchemaProps{ - Description: "GCEPersistentDisk represents a GCE Disk resource that is attached to a kubelet's host machine and then exposed to the pod. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk", + Description: "gcePersistentDisk represents a GCE Disk resource that is attached to a kubelet's host machine and then exposed to the pod. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk", Ref: ref("k8s.io/api/core/v1.GCEPersistentDiskVolumeSource"), }, }, "awsElasticBlockStore": { SchemaProps: spec.SchemaProps{ - Description: "AWSElasticBlockStore represents an AWS Disk resource that is attached to a kubelet's host machine and then exposed to the pod. More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore", + Description: "awsElasticBlockStore represents an AWS Disk resource that is attached to a kubelet's host machine and then exposed to the pod. More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore", Ref: ref("k8s.io/api/core/v1.AWSElasticBlockStoreVolumeSource"), }, }, "gitRepo": { SchemaProps: spec.SchemaProps{ - Description: "GitRepo represents a git repository at a particular revision. DEPRECATED: GitRepo is deprecated. To provision a container with a git repo, mount an EmptyDir into an InitContainer that clones the repo using git, then mount the EmptyDir into the Pod's container.", + Description: "gitRepo represents a git repository at a particular revision. DEPRECATED: GitRepo is deprecated. To provision a container with a git repo, mount an EmptyDir into an InitContainer that clones the repo using git, then mount the EmptyDir into the Pod's container.", Ref: ref("k8s.io/api/core/v1.GitRepoVolumeSource"), }, }, "secret": { SchemaProps: spec.SchemaProps{ - Description: "Secret represents a secret that should populate this volume. More info: https://kubernetes.io/docs/concepts/storage/volumes#secret", + Description: "secret represents a secret that should populate this volume. More info: https://kubernetes.io/docs/concepts/storage/volumes#secret", Ref: ref("k8s.io/api/core/v1.SecretVolumeSource"), }, }, "nfs": { SchemaProps: spec.SchemaProps{ - Description: "NFS represents an NFS mount on the host that shares a pod's lifetime More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs", + Description: "nfs represents an NFS mount on the host that shares a pod's lifetime More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs", Ref: ref("k8s.io/api/core/v1.NFSVolumeSource"), }, }, "iscsi": { SchemaProps: spec.SchemaProps{ - Description: "ISCSI represents an ISCSI Disk resource that is attached to a kubelet's host machine and then exposed to the pod. More info: https://examples.k8s.io/volumes/iscsi/README.md", + Description: "iscsi represents an ISCSI Disk resource that is attached to a kubelet's host machine and then exposed to the pod. More info: https://examples.k8s.io/volumes/iscsi/README.md", Ref: ref("k8s.io/api/core/v1.ISCSIVolumeSource"), }, }, "glusterfs": { SchemaProps: spec.SchemaProps{ - Description: "Glusterfs represents a Glusterfs mount on the host that shares a pod's lifetime. More info: https://examples.k8s.io/volumes/glusterfs/README.md", + Description: "glusterfs represents a Glusterfs mount on the host that shares a pod's lifetime. More info: https://examples.k8s.io/volumes/glusterfs/README.md", Ref: ref("k8s.io/api/core/v1.GlusterfsVolumeSource"), }, }, "persistentVolumeClaim": { SchemaProps: spec.SchemaProps{ - Description: "PersistentVolumeClaimVolumeSource represents a reference to a PersistentVolumeClaim in the same namespace. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims", + Description: "persistentVolumeClaimVolumeSource represents a reference to a PersistentVolumeClaim in the same namespace. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims", Ref: ref("k8s.io/api/core/v1.PersistentVolumeClaimVolumeSource"), }, }, "rbd": { SchemaProps: spec.SchemaProps{ - Description: "RBD represents a Rados Block Device mount on the host that shares a pod's lifetime. More info: https://examples.k8s.io/volumes/rbd/README.md", + Description: "rbd represents a Rados Block Device mount on the host that shares a pod's lifetime. More info: https://examples.k8s.io/volumes/rbd/README.md", Ref: ref("k8s.io/api/core/v1.RBDVolumeSource"), }, }, "flexVolume": { SchemaProps: spec.SchemaProps{ - Description: "FlexVolume represents a generic volume resource that is provisioned/attached using an exec based plugin.", + Description: "flexVolume represents a generic volume resource that is provisioned/attached using an exec based plugin.", Ref: ref("k8s.io/api/core/v1.FlexVolumeSource"), }, }, "cinder": { SchemaProps: spec.SchemaProps{ - Description: "Cinder represents a cinder volume attached and mounted on kubelets host machine. More info: https://examples.k8s.io/mysql-cinder-pd/README.md", + Description: "cinder represents a cinder volume attached and mounted on kubelets host machine. More info: https://examples.k8s.io/mysql-cinder-pd/README.md", Ref: ref("k8s.io/api/core/v1.CinderVolumeSource"), }, }, "cephfs": { SchemaProps: spec.SchemaProps{ - Description: "CephFS represents a Ceph FS mount on the host that shares a pod's lifetime", + Description: "cephFS represents a Ceph FS mount on the host that shares a pod's lifetime", Ref: ref("k8s.io/api/core/v1.CephFSVolumeSource"), }, }, "flocker": { SchemaProps: spec.SchemaProps{ - Description: "Flocker represents a Flocker volume attached to a kubelet's host machine. This depends on the Flocker control service being running", + Description: "flocker represents a Flocker volume attached to a kubelet's host machine. This depends on the Flocker control service being running", Ref: ref("k8s.io/api/core/v1.FlockerVolumeSource"), }, }, "downwardAPI": { SchemaProps: spec.SchemaProps{ - Description: "DownwardAPI represents downward API about the pod that should populate this volume", + Description: "downwardAPI represents downward API about the pod that should populate this volume", Ref: ref("k8s.io/api/core/v1.DownwardAPIVolumeSource"), }, }, "fc": { SchemaProps: spec.SchemaProps{ - Description: "FC represents a Fibre Channel resource that is attached to a kubelet's host machine and then exposed to the pod.", + Description: "fc represents a Fibre Channel resource that is attached to a kubelet's host machine and then exposed to the pod.", Ref: ref("k8s.io/api/core/v1.FCVolumeSource"), }, }, "azureFile": { SchemaProps: spec.SchemaProps{ - Description: "AzureFile represents an Azure File Service mount on the host and bind mount to the pod.", + Description: "azureFile represents an Azure File Service mount on the host and bind mount to the pod.", Ref: ref("k8s.io/api/core/v1.AzureFileVolumeSource"), }, }, "configMap": { SchemaProps: spec.SchemaProps{ - Description: "ConfigMap represents a configMap that should populate this volume", + Description: "configMap represents a configMap that should populate this volume", Ref: ref("k8s.io/api/core/v1.ConfigMapVolumeSource"), }, }, "vsphereVolume": { SchemaProps: spec.SchemaProps{ - Description: "VsphereVolume represents a vSphere volume attached and mounted on kubelets host machine", + Description: "vsphereVolume represents a vSphere volume attached and mounted on kubelets host machine", Ref: ref("k8s.io/api/core/v1.VsphereVirtualDiskVolumeSource"), }, }, "quobyte": { SchemaProps: spec.SchemaProps{ - Description: "Quobyte represents a Quobyte mount on the host that shares a pod's lifetime", + Description: "quobyte represents a Quobyte mount on the host that shares a pod's lifetime", Ref: ref("k8s.io/api/core/v1.QuobyteVolumeSource"), }, }, "azureDisk": { SchemaProps: spec.SchemaProps{ - Description: "AzureDisk represents an Azure Data Disk mount on the host and bind mount to the pod.", + Description: "azureDisk represents an Azure Data Disk mount on the host and bind mount to the pod.", Ref: ref("k8s.io/api/core/v1.AzureDiskVolumeSource"), }, }, "photonPersistentDisk": { SchemaProps: spec.SchemaProps{ - Description: "PhotonPersistentDisk represents a PhotonController persistent disk attached and mounted on kubelets host machine", + Description: "photonPersistentDisk represents a PhotonController persistent disk attached and mounted on kubelets host machine", Ref: ref("k8s.io/api/core/v1.PhotonPersistentDiskVolumeSource"), }, }, "projected": { SchemaProps: spec.SchemaProps{ - Description: "Items for all in one resources secrets, configmaps, and downward API", + Description: "projected items for all in one resources secrets, configmaps, and downward API", Ref: ref("k8s.io/api/core/v1.ProjectedVolumeSource"), }, }, "portworxVolume": { SchemaProps: spec.SchemaProps{ - Description: "PortworxVolume represents a portworx volume attached and mounted on kubelets host machine", + Description: "portworxVolume represents a portworx volume attached and mounted on kubelets host machine", Ref: ref("k8s.io/api/core/v1.PortworxVolumeSource"), }, }, "scaleIO": { SchemaProps: spec.SchemaProps{ - Description: "ScaleIO represents a ScaleIO persistent volume attached and mounted on Kubernetes nodes.", + Description: "scaleIO represents a ScaleIO persistent volume attached and mounted on Kubernetes nodes.", Ref: ref("k8s.io/api/core/v1.ScaleIOVolumeSource"), }, }, "storageos": { SchemaProps: spec.SchemaProps{ - Description: "StorageOS represents a StorageOS volume attached and mounted on Kubernetes nodes.", + Description: "storageOS represents a StorageOS volume attached and mounted on Kubernetes nodes.", Ref: ref("k8s.io/api/core/v1.StorageOSVolumeSource"), }, }, "csi": { SchemaProps: spec.SchemaProps{ - Description: "CSI (Container Storage Interface) represents ephemeral storage that is handled by certain external CSI drivers (Beta feature).", + Description: "csi (Container Storage Interface) represents ephemeral storage that is handled by certain external CSI drivers (Beta feature).", Ref: ref("k8s.io/api/core/v1.CSIVolumeSource"), }, }, "ephemeral": { SchemaProps: spec.SchemaProps{ - Description: "Ephemeral represents a volume that is handled by a cluster storage driver. The volume's lifecycle is tied to the pod that defines it - it will be created before the pod starts, and deleted when the pod is removed.\n\nUse this if: a) the volume is only needed while the pod runs, b) features of normal volumes like restoring from snapshot or capacity\n tracking are needed,\nc) the storage driver is specified through a storage class, and d) the storage driver supports dynamic volume provisioning through\n a PersistentVolumeClaim (see EphemeralVolumeSource for more\n information on the connection between this volume type\n and PersistentVolumeClaim).\n\nUse PersistentVolumeClaim or one of the vendor-specific APIs for volumes that persist for longer than the lifecycle of an individual pod.\n\nUse CSI for light-weight local ephemeral volumes if the CSI driver is meant to be used that way - see the documentation of the driver for more information.\n\nA pod can use both types of ephemeral volumes and persistent volumes at the same time.\n\nThis is a beta feature and only available when the GenericEphemeralVolume feature gate is enabled.", + Description: "ephemeral represents a volume that is handled by a cluster storage driver. The volume's lifecycle is tied to the pod that defines it - it will be created before the pod starts, and deleted when the pod is removed.\n\nUse this if: a) the volume is only needed while the pod runs, b) features of normal volumes like restoring from snapshot or capacity\n tracking are needed,\nc) the storage driver is specified through a storage class, and d) the storage driver supports dynamic volume provisioning through\n a PersistentVolumeClaim (see EphemeralVolumeSource for more\n information on the connection between this volume type\n and PersistentVolumeClaim).\n\nUse PersistentVolumeClaim or one of the vendor-specific APIs for volumes that persist for longer than the lifecycle of an individual pod.\n\nUse CSI for light-weight local ephemeral volumes if the CSI driver is meant to be used that way - see the documentation of the driver for more information.\n\nA pod can use both types of ephemeral volumes and persistent volumes at the same time.", Ref: ref("k8s.io/api/core/v1.EphemeralVolumeSource"), }, }, @@ -14176,7 +14551,7 @@ func schema_k8sio_api_core_v1_VsphereVirtualDiskVolumeSource(ref common.Referenc Properties: map[string]spec.Schema{ "volumePath": { SchemaProps: spec.SchemaProps{ - Description: "Path that identifies vSphere volume vmdk", + Description: "volumePath is the path that identifies vSphere volume vmdk", Default: "", Type: []string{"string"}, Format: "", @@ -14184,21 +14559,21 @@ func schema_k8sio_api_core_v1_VsphereVirtualDiskVolumeSource(ref common.Referenc }, "fsType": { SchemaProps: spec.SchemaProps{ - Description: "Filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified.", + Description: "fsType is filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified.", Type: []string{"string"}, Format: "", }, }, "storagePolicyName": { SchemaProps: spec.SchemaProps{ - Description: "Storage Policy Based Management (SPBM) profile name.", + Description: "storagePolicyName is the storage Policy Based Management (SPBM) profile name.", Type: []string{"string"}, Format: "", }, }, "storagePolicyID": { SchemaProps: spec.SchemaProps{ - Description: "Storage Policy Based Management (SPBM) profile ID associated with the StoragePolicyName.", + Description: "storagePolicyID is the storage Policy Based Management (SPBM) profile ID associated with the StoragePolicyName.", Type: []string{"string"}, Format: "", }, @@ -14269,6 +14644,13 @@ func schema_k8sio_api_core_v1_WindowsSecurityContextOptions(ref common.Reference Format: "", }, }, + "hostProcess": { + SchemaProps: spec.SchemaProps{ + Description: "HostProcess determines if a container should be run as a 'Host Process' container. This field is alpha-level and will only be honored by components that enable the WindowsHostProcessContainers feature flag. Setting this field without the feature flag will result in errors when validating the Pod. All of a Pod's containers must have the same effective HostProcess value (it is not allowed to have a mix of HostProcess containers and non-HostProcess containers). In addition, if HostProcess is true then HostNetwork must also be set to true.", + Type: []string{"boolean"}, + Format: "", + }, + }, }, }, }, @@ -14779,6 +15161,13 @@ func schema_pkg_apis_meta_v1_CreateOptions(ref common.ReferenceCallback) common. Format: "", }, }, + "fieldValidation": { + SchemaProps: spec.SchemaProps{ + Description: "fieldValidation instructs the server on how to handle objects in the request (POST/PUT/PATCH) containing unknown or duplicate fields, provided that the `ServerSideFieldValidation` feature gate is also enabled. Valid values are: - Ignore: This will ignore any unknown fields that are silently dropped from the object, and will ignore all but the last duplicate field that the decoder encounters. This is the default behavior prior to v1.23 and is the default behavior when the `ServerSideFieldValidation` feature gate is disabled. - Warn: This will send a warning via the standard warning response header for each unknown field that is dropped from the object, and for each duplicate field that is encountered. The request will still succeed if there are no other errors, and will only persist the last of any duplicate fields. This is the default when the `ServerSideFieldValidation` feature gate is enabled. - Strict: This will fail the request with a BadRequest error if any unknown fields would be dropped from the object, or if any duplicate fields are present. The error returned from the server will contain all unknown and duplicate fields encountered.", + Type: []string{"string"}, + Format: "", + }, + }, }, }, }, @@ -15031,7 +15420,7 @@ func schema_pkg_apis_meta_v1_GroupVersionKind(ref common.ReferenceCallback) comm return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "GroupVersionKind unambiguously identifies a kind. It doesn't anonymously include GroupVersion to avoid automatic coersion. It doesn't use a GroupVersion to avoid custom marshalling", + Description: "GroupVersionKind unambiguously identifies a kind. It doesn't anonymously include GroupVersion to avoid automatic coercion. It doesn't use a GroupVersion to avoid custom marshalling", Type: []string{"object"}, Properties: map[string]spec.Schema{ "group": { @@ -15066,7 +15455,7 @@ func schema_pkg_apis_meta_v1_GroupVersionResource(ref common.ReferenceCallback) return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "GroupVersionResource unambiguously identifies a resource. It doesn't anonymously include GroupVersion to avoid automatic coersion. It doesn't use a GroupVersion to avoid custom marshalling", + Description: "GroupVersionResource unambiguously identifies a resource. It doesn't anonymously include GroupVersion to avoid automatic coercion. It doesn't use a GroupVersion to avoid custom marshalling", Type: []string{"object"}, Properties: map[string]spec.Schema{ "group": { @@ -15287,7 +15676,7 @@ func schema_pkg_apis_meta_v1_ListMeta(ref common.ReferenceCallback) common.OpenA Properties: map[string]spec.Schema{ "selfLink": { SchemaProps: spec.SchemaProps{ - Description: "selfLink is a URL representing this object. Populated by the system. Read-only.\n\nDEPRECATED Kubernetes will stop propagating this field in 1.20 release and the field is planned to be removed in 1.21 release.", + Description: "Deprecated: selfLink is a legacy read-only field that is no longer populated by the system.", Type: []string{"string"}, Format: "", }, @@ -15363,7 +15752,7 @@ func schema_pkg_apis_meta_v1_ListOptions(ref common.ReferenceCallback) common.Op }, "allowWatchBookmarks": { SchemaProps: spec.SchemaProps{ - Description: "allowWatchBookmarks requests watch events with type \"BOOKMARK\". Servers that do not implement bookmarks may ignore this flag and bookmarks are sent at the server's discretion. Clients should not assume bookmarks are returned at any specific interval, nor may they assume the server will send any BOOKMARK event during a session. If this is not a watch, this field is ignored. If the feature gate WatchBookmarks is not enabled in apiserver, this field is ignored.", + Description: "allowWatchBookmarks requests watch events with type \"BOOKMARK\". Servers that do not implement bookmarks may ignore this flag and bookmarks are sent at the server's discretion. Clients should not assume bookmarks are returned at any specific interval, nor may they assume the server will send any BOOKMARK event during a session. If this is not a watch, this field is ignored.", Type: []string{"boolean"}, Format: "", }, @@ -15439,7 +15828,7 @@ func schema_pkg_apis_meta_v1_ManagedFieldsEntry(ref common.ReferenceCallback) co }, "time": { SchemaProps: spec.SchemaProps{ - Description: "Time is timestamp of when these fields were set. It should always be empty if Operation is 'Apply'", + Description: "Time is the timestamp of when the ManagedFields entry was added. The timestamp will also be updated if a field is added, the manager changes any of the owned fields value or removes a field. The timestamp does not update when a field is removed from the entry because another manager took it over.", Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), }, }, @@ -15456,6 +15845,13 @@ func schema_pkg_apis_meta_v1_ManagedFieldsEntry(ref common.ReferenceCallback) co Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.FieldsV1"), }, }, + "subresource": { + SchemaProps: spec.SchemaProps{ + Description: "Subresource is the name of the subresource used to update that object, or empty string if the object was updated through the main resource. The value of this field is used to distinguish between managers, even if they share the same name. For example, a status update will be distinct from a regular update using the same manager name. Note that the APIVersion field is not related to the Subresource field and it always corresponds to the version of the main resource.", + Type: []string{"string"}, + Format: "", + }, + }, }, }, }, @@ -15492,7 +15888,7 @@ func schema_pkg_apis_meta_v1_ObjectMeta(ref common.ReferenceCallback) common.Ope }, "generateName": { SchemaProps: spec.SchemaProps{ - Description: "GenerateName is an optional prefix, used by the server, to generate a unique name ONLY IF the Name field has not been provided. If this field is used, the name returned to the client will be different than the name passed. This value will also be combined with a unique suffix. The provided value has the same validation rules as the Name field, and may be truncated by the length of the suffix required to make the value unique on the server.\n\nIf this field is specified and the generated name exists, the server will NOT return a 409 - instead, it will either return 201 Created or 500 with Reason ServerTimeout indicating a unique name could not be found in the time allotted, and the client should retry (optionally after the time indicated in the Retry-After header).\n\nApplied only if Name is not specified. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#idempotency", + Description: "GenerateName is an optional prefix, used by the server, to generate a unique name ONLY IF the Name field has not been provided. If this field is used, the name returned to the client will be different than the name passed. This value will also be combined with a unique suffix. The provided value has the same validation rules as the Name field, and may be truncated by the length of the suffix required to make the value unique on the server.\n\nIf this field is specified and the generated name exists, the server will return a 409.\n\nApplied only if Name is not specified. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#idempotency", Type: []string{"string"}, Format: "", }, @@ -15506,7 +15902,7 @@ func schema_pkg_apis_meta_v1_ObjectMeta(ref common.ReferenceCallback) common.Ope }, "selfLink": { SchemaProps: spec.SchemaProps{ - Description: "SelfLink is a URL representing this object. Populated by the system. Read-only.\n\nDEPRECATED Kubernetes will stop propagating this field in 1.20 release and the field is planned to be removed in 1.21 release.", + Description: "Deprecated: selfLink is a legacy read-only field that is no longer populated by the system.", Type: []string{"string"}, Format: "", }, @@ -15626,7 +16022,7 @@ func schema_pkg_apis_meta_v1_ObjectMeta(ref common.ReferenceCallback) common.Ope }, "clusterName": { SchemaProps: spec.SchemaProps{ - Description: "The name of the cluster which the object belongs to. This is used to distinguish resources with same name and namespace in different clusters. This field is not set anywhere right now and apiserver is going to ignore it if set in create or update request.", + Description: "Deprecated: ClusterName is a legacy field that was always cleared by the system and never used; it will be removed completely in 1.25.\n\nThe name in the go struct is changed to help clients detect accidental use.", Type: []string{"string"}, Format: "", }, @@ -15701,7 +16097,7 @@ func schema_pkg_apis_meta_v1_OwnerReference(ref common.ReferenceCallback) common }, "blockOwnerDeletion": { SchemaProps: spec.SchemaProps{ - Description: "If true, AND if the owner has the \"foregroundDeletion\" finalizer, then the owner cannot be deleted from the key-value store until this reference is removed. Defaults to false. To set this field, a user needs \"delete\" permission of the owner, otherwise 422 (Unprocessable Entity) will be returned.", + Description: "If true, AND if the owner has the \"foregroundDeletion\" finalizer, then the owner cannot be deleted from the key-value store until this reference is removed. See https://kubernetes.io/docs/concepts/architecture/garbage-collection/#foreground-deletion for how the garbage collector interacts with this field and enforces the foreground deletion. Defaults to false. To set this field, a user needs \"delete\" permission of the owner, otherwise 422 (Unprocessable Entity) will be returned.", Type: []string{"boolean"}, Format: "", }, @@ -15709,6 +16105,11 @@ func schema_pkg_apis_meta_v1_OwnerReference(ref common.ReferenceCallback) common }, Required: []string{"apiVersion", "kind", "name", "uid"}, }, + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-map-type": "atomic", + }, + }, }, } } @@ -15861,6 +16262,13 @@ func schema_pkg_apis_meta_v1_PatchOptions(ref common.ReferenceCallback) common.O Format: "", }, }, + "fieldValidation": { + SchemaProps: spec.SchemaProps{ + Description: "fieldValidation instructs the server on how to handle objects in the request (POST/PUT/PATCH) containing unknown or duplicate fields, provided that the `ServerSideFieldValidation` feature gate is also enabled. Valid values are: - Ignore: This will ignore any unknown fields that are silently dropped from the object, and will ignore all but the last duplicate field that the decoder encounters. This is the default behavior prior to v1.23 and is the default behavior when the `ServerSideFieldValidation` feature gate is disabled. - Warn: This will send a warning via the standard warning response header for each unknown field that is dropped from the object, and for each duplicate field that is encountered. The request will still succeed if there are no other errors, and will only persist the last of any duplicate fields. This is the default when the `ServerSideFieldValidation` feature gate is enabled. - Strict: This will fail the request with a BadRequest error if any unknown fields would be dropped from the object, or if any duplicate fields are present. The error returned from the server will contain all unknown and duplicate fields encountered.", + Type: []string{"string"}, + Format: "", + }, + }, }, }, }, @@ -16481,6 +16889,13 @@ func schema_pkg_apis_meta_v1_UpdateOptions(ref common.ReferenceCallback) common. Format: "", }, }, + "fieldValidation": { + SchemaProps: spec.SchemaProps{ + Description: "fieldValidation instructs the server on how to handle objects in the request (POST/PUT/PATCH) containing unknown or duplicate fields, provided that the `ServerSideFieldValidation` feature gate is also enabled. Valid values are: - Ignore: This will ignore any unknown fields that are silently dropped from the object, and will ignore all but the last duplicate field that the decoder encounters. This is the default behavior prior to v1.23 and is the default behavior when the `ServerSideFieldValidation` feature gate is disabled. - Warn: This will send a warning via the standard warning response header for each unknown field that is dropped from the object, and for each duplicate field that is encountered. The request will still succeed if there are no other errors, and will only persist the last of any duplicate fields. This is the default when the `ServerSideFieldValidation` feature gate is enabled. - Strict: This will fail the request with a BadRequest error if any unknown fields would be dropped from the object, or if any duplicate fields are present. The error returned from the server will contain all unknown and duplicate fields encountered.", + Type: []string{"string"}, + Format: "", + }, + }, }, }, }, @@ -16603,7 +17018,15 @@ func schema_k8sio_apimachinery_pkg_runtime_Unknown(ref common.ReferenceCallback) } func schema_apimachinery_pkg_util_intstr_IntOrString(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ + return common.EmbedOpenAPIDefinitionIntoV2Extension(common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "IntOrString is a type that can hold an int32 or a string. When used in JSON or YAML marshalling and unmarshalling, it produces or consumes the inner type. This allows you to have, for example, a JSON field that can accept a name or number.", + OneOf: common.GenerateOpenAPIV3OneOfSchema(intstr.IntOrString{}.OpenAPIV3OneOfTypes()), + Format: intstr.IntOrString{}.OpenAPISchemaFormat(), + }, + }, + }, common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ Description: "IntOrString is a type that can hold an int32 or a string. When used in JSON or YAML marshalling and unmarshalling, it produces or consumes the inner type. This allows you to have, for example, a JSON field that can accept a name or number.", @@ -16611,5 +17034,5 @@ func schema_apimachinery_pkg_util_intstr_IntOrString(ref common.ReferenceCallbac Format: intstr.IntOrString{}.OpenAPISchemaFormat(), }, }, - } + }) } diff --git a/pkg/apiserver/registry/stats/antreaclusternetworkpolicystats/rest.go b/pkg/apiserver/registry/stats/antreaclusternetworkpolicystats/rest.go index 4892dea3834..98506c7a66c 100644 --- a/pkg/apiserver/registry/stats/antreaclusternetworkpolicystats/rest.go +++ b/pkg/apiserver/registry/stats/antreaclusternetworkpolicystats/rest.go @@ -113,13 +113,11 @@ func (r *REST) ConvertToTable(ctx context.Context, obj runtime.Object, tableOpti } if m, err := meta.ListAccessor(obj); err == nil { table.ResourceVersion = m.GetResourceVersion() - table.SelfLink = m.GetSelfLink() table.Continue = m.GetContinue() table.RemainingItemCount = m.GetRemainingItemCount() } else { if m, err := meta.CommonAccessor(obj); err == nil { table.ResourceVersion = m.GetResourceVersion() - table.SelfLink = m.GetSelfLink() } } diff --git a/pkg/apiserver/registry/stats/antreanetworkpolicystats/rest.go b/pkg/apiserver/registry/stats/antreanetworkpolicystats/rest.go index 7f5f0a385a7..755214568d9 100644 --- a/pkg/apiserver/registry/stats/antreanetworkpolicystats/rest.go +++ b/pkg/apiserver/registry/stats/antreanetworkpolicystats/rest.go @@ -119,13 +119,11 @@ func (r *REST) ConvertToTable(ctx context.Context, obj runtime.Object, tableOpti } if m, err := meta.ListAccessor(obj); err == nil { table.ResourceVersion = m.GetResourceVersion() - table.SelfLink = m.GetSelfLink() table.Continue = m.GetContinue() table.RemainingItemCount = m.GetRemainingItemCount() } else { if m, err := meta.CommonAccessor(obj); err == nil { table.ResourceVersion = m.GetResourceVersion() - table.SelfLink = m.GetSelfLink() } } diff --git a/pkg/apiserver/registry/stats/networkpolicystats/rest.go b/pkg/apiserver/registry/stats/networkpolicystats/rest.go index 6edfadc524e..7c0e549b980 100644 --- a/pkg/apiserver/registry/stats/networkpolicystats/rest.go +++ b/pkg/apiserver/registry/stats/networkpolicystats/rest.go @@ -113,13 +113,11 @@ func (r *REST) ConvertToTable(ctx context.Context, obj runtime.Object, tableOpti } if m, err := meta.ListAccessor(obj); err == nil { table.ResourceVersion = m.GetResourceVersion() - table.SelfLink = m.GetSelfLink() table.Continue = m.GetContinue() table.RemainingItemCount = m.GetRemainingItemCount() } else { if m, err := meta.CommonAccessor(obj); err == nil { table.ResourceVersion = m.GetResourceVersion() - table.SelfLink = m.GetSelfLink() } } diff --git a/pkg/client/clientset/versioned/clientset.go b/pkg/client/clientset/versioned/clientset.go index 9e71bc04280..88395079b61 100644 --- a/pkg/client/clientset/versioned/clientset.go +++ b/pkg/client/clientset/versioned/clientset.go @@ -1,4 +1,4 @@ -// Copyright 2021 Antrea Authors +// Copyright 2022 Antrea Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -18,6 +18,7 @@ package versioned import ( "fmt" + "net/http" controlplanev1beta2 "antrea.io/antrea/pkg/client/clientset/versioned/typed/controlplane/v1beta2" crdv1alpha1 "antrea.io/antrea/pkg/client/clientset/versioned/typed/crd/v1alpha1" @@ -101,46 +102,69 @@ func (c *Clientset) Discovery() discovery.DiscoveryInterface { // NewForConfig creates a new Clientset for the given config. // If config's RateLimiter is not set and QPS and Burst are acceptable, // NewForConfig will generate a rate-limiter in configShallowCopy. +// NewForConfig is equivalent to NewForConfigAndClient(c, httpClient), +// where httpClient was generated with rest.HTTPClientFor(c). func NewForConfig(c *rest.Config) (*Clientset, error) { configShallowCopy := *c + + if configShallowCopy.UserAgent == "" { + configShallowCopy.UserAgent = rest.DefaultKubernetesUserAgent() + } + + // share the transport between all clients + httpClient, err := rest.HTTPClientFor(&configShallowCopy) + if err != nil { + return nil, err + } + + return NewForConfigAndClient(&configShallowCopy, httpClient) +} + +// NewForConfigAndClient creates a new Clientset for the given config and http client. +// Note the http client provided takes precedence over the configured transport values. +// If config's RateLimiter is not set and QPS and Burst are acceptable, +// NewForConfigAndClient will generate a rate-limiter in configShallowCopy. +func NewForConfigAndClient(c *rest.Config, httpClient *http.Client) (*Clientset, error) { + configShallowCopy := *c if configShallowCopy.RateLimiter == nil && configShallowCopy.QPS > 0 { if configShallowCopy.Burst <= 0 { return nil, fmt.Errorf("burst is required to be greater than 0 when RateLimiter is not set and QPS is set to greater than 0") } configShallowCopy.RateLimiter = flowcontrol.NewTokenBucketRateLimiter(configShallowCopy.QPS, configShallowCopy.Burst) } + var cs Clientset var err error - cs.controlplaneV1beta2, err = controlplanev1beta2.NewForConfig(&configShallowCopy) + cs.controlplaneV1beta2, err = controlplanev1beta2.NewForConfigAndClient(&configShallowCopy, httpClient) if err != nil { return nil, err } - cs.crdV1alpha1, err = crdv1alpha1.NewForConfig(&configShallowCopy) + cs.crdV1alpha1, err = crdv1alpha1.NewForConfigAndClient(&configShallowCopy, httpClient) if err != nil { return nil, err } - cs.crdV1alpha2, err = crdv1alpha2.NewForConfig(&configShallowCopy) + cs.crdV1alpha2, err = crdv1alpha2.NewForConfigAndClient(&configShallowCopy, httpClient) if err != nil { return nil, err } - cs.crdV1alpha3, err = crdv1alpha3.NewForConfig(&configShallowCopy) + cs.crdV1alpha3, err = crdv1alpha3.NewForConfigAndClient(&configShallowCopy, httpClient) if err != nil { return nil, err } - cs.crdV1beta1, err = crdv1beta1.NewForConfig(&configShallowCopy) + cs.crdV1beta1, err = crdv1beta1.NewForConfigAndClient(&configShallowCopy, httpClient) if err != nil { return nil, err } - cs.statsV1alpha1, err = statsv1alpha1.NewForConfig(&configShallowCopy) + cs.statsV1alpha1, err = statsv1alpha1.NewForConfigAndClient(&configShallowCopy, httpClient) if err != nil { return nil, err } - cs.systemV1beta1, err = systemv1beta1.NewForConfig(&configShallowCopy) + cs.systemV1beta1, err = systemv1beta1.NewForConfigAndClient(&configShallowCopy, httpClient) if err != nil { return nil, err } - cs.DiscoveryClient, err = discovery.NewDiscoveryClientForConfig(&configShallowCopy) + cs.DiscoveryClient, err = discovery.NewDiscoveryClientForConfigAndClient(&configShallowCopy, httpClient) if err != nil { return nil, err } @@ -150,17 +174,11 @@ func NewForConfig(c *rest.Config) (*Clientset, error) { // NewForConfigOrDie creates a new Clientset for the given config and // panics if there is an error in the config. func NewForConfigOrDie(c *rest.Config) *Clientset { - var cs Clientset - cs.controlplaneV1beta2 = controlplanev1beta2.NewForConfigOrDie(c) - cs.crdV1alpha1 = crdv1alpha1.NewForConfigOrDie(c) - cs.crdV1alpha2 = crdv1alpha2.NewForConfigOrDie(c) - cs.crdV1alpha3 = crdv1alpha3.NewForConfigOrDie(c) - cs.crdV1beta1 = crdv1beta1.NewForConfigOrDie(c) - cs.statsV1alpha1 = statsv1alpha1.NewForConfigOrDie(c) - cs.systemV1beta1 = systemv1beta1.NewForConfigOrDie(c) - - cs.DiscoveryClient = discovery.NewDiscoveryClientForConfigOrDie(c) - return &cs + cs, err := NewForConfig(c) + if err != nil { + panic(err) + } + return cs } // New creates a new Clientset for the given RESTClient. diff --git a/pkg/client/clientset/versioned/fake/clientset_generated.go b/pkg/client/clientset/versioned/fake/clientset_generated.go index c8905363cbd..65a7f173715 100644 --- a/pkg/client/clientset/versioned/fake/clientset_generated.go +++ b/pkg/client/clientset/versioned/fake/clientset_generated.go @@ -1,4 +1,4 @@ -// Copyright 2021 Antrea Authors +// Copyright 2022 Antrea Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -84,7 +84,10 @@ func (c *Clientset) Tracker() testing.ObjectTracker { return c.tracker } -var _ clientset.Interface = &Clientset{} +var ( + _ clientset.Interface = &Clientset{} + _ testing.FakeClient = &Clientset{} +) // ControlplaneV1beta2 retrieves the ControlplaneV1beta2Client func (c *Clientset) ControlplaneV1beta2() controlplanev1beta2.ControlplaneV1beta2Interface { diff --git a/pkg/client/clientset/versioned/typed/controlplane/v1beta2/controlplane_client.go b/pkg/client/clientset/versioned/typed/controlplane/v1beta2/controlplane_client.go index 91b00cffa1c..5e8ab80f57c 100644 --- a/pkg/client/clientset/versioned/typed/controlplane/v1beta2/controlplane_client.go +++ b/pkg/client/clientset/versioned/typed/controlplane/v1beta2/controlplane_client.go @@ -1,4 +1,4 @@ -// Copyright 2021 Antrea Authors +// Copyright 2022 Antrea Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -17,6 +17,8 @@ package v1beta2 import ( + "net/http" + v1beta2 "antrea.io/antrea/pkg/apis/controlplane/v1beta2" "antrea.io/antrea/pkg/client/clientset/versioned/scheme" rest "k8s.io/client-go/rest" @@ -67,12 +69,28 @@ func (c *ControlplaneV1beta2Client) NodeStatsSummaries() NodeStatsSummaryInterfa } // NewForConfig creates a new ControlplaneV1beta2Client for the given config. +// NewForConfig is equivalent to NewForConfigAndClient(c, httpClient), +// where httpClient was generated with rest.HTTPClientFor(c). func NewForConfig(c *rest.Config) (*ControlplaneV1beta2Client, error) { config := *c if err := setConfigDefaults(&config); err != nil { return nil, err } - client, err := rest.RESTClientFor(&config) + httpClient, err := rest.HTTPClientFor(&config) + if err != nil { + return nil, err + } + return NewForConfigAndClient(&config, httpClient) +} + +// NewForConfigAndClient creates a new ControlplaneV1beta2Client for the given config and http client. +// Note the http client provided takes precedence over the configured transport values. +func NewForConfigAndClient(c *rest.Config, h *http.Client) (*ControlplaneV1beta2Client, error) { + config := *c + if err := setConfigDefaults(&config); err != nil { + return nil, err + } + client, err := rest.RESTClientForConfigAndClient(&config, h) if err != nil { return nil, err } diff --git a/pkg/client/clientset/versioned/typed/crd/v1alpha1/crd_client.go b/pkg/client/clientset/versioned/typed/crd/v1alpha1/crd_client.go index e31e7d6831b..f2a72e1cd15 100644 --- a/pkg/client/clientset/versioned/typed/crd/v1alpha1/crd_client.go +++ b/pkg/client/clientset/versioned/typed/crd/v1alpha1/crd_client.go @@ -1,4 +1,4 @@ -// Copyright 2021 Antrea Authors +// Copyright 2022 Antrea Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -17,6 +17,8 @@ package v1alpha1 import ( + "net/http" + v1alpha1 "antrea.io/antrea/pkg/apis/crd/v1alpha1" "antrea.io/antrea/pkg/client/clientset/versioned/scheme" rest "k8s.io/client-go/rest" @@ -52,12 +54,28 @@ func (c *CrdV1alpha1Client) Traceflows() TraceflowInterface { } // NewForConfig creates a new CrdV1alpha1Client for the given config. +// NewForConfig is equivalent to NewForConfigAndClient(c, httpClient), +// where httpClient was generated with rest.HTTPClientFor(c). func NewForConfig(c *rest.Config) (*CrdV1alpha1Client, error) { config := *c if err := setConfigDefaults(&config); err != nil { return nil, err } - client, err := rest.RESTClientFor(&config) + httpClient, err := rest.HTTPClientFor(&config) + if err != nil { + return nil, err + } + return NewForConfigAndClient(&config, httpClient) +} + +// NewForConfigAndClient creates a new CrdV1alpha1Client for the given config and http client. +// Note the http client provided takes precedence over the configured transport values. +func NewForConfigAndClient(c *rest.Config, h *http.Client) (*CrdV1alpha1Client, error) { + config := *c + if err := setConfigDefaults(&config); err != nil { + return nil, err + } + client, err := rest.RESTClientForConfigAndClient(&config, h) if err != nil { return nil, err } diff --git a/pkg/client/clientset/versioned/typed/crd/v1alpha1/fake/fake_clusternetworkpolicy.go b/pkg/client/clientset/versioned/typed/crd/v1alpha1/fake/fake_clusternetworkpolicy.go index 9061e3c6ff6..e68734a3567 100644 --- a/pkg/client/clientset/versioned/typed/crd/v1alpha1/fake/fake_clusternetworkpolicy.go +++ b/pkg/client/clientset/versioned/typed/crd/v1alpha1/fake/fake_clusternetworkpolicy.go @@ -1,4 +1,4 @@ -// Copyright 2021 Antrea Authors +// Copyright 2022 Antrea Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -108,7 +108,7 @@ func (c *FakeClusterNetworkPolicies) UpdateStatus(ctx context.Context, clusterNe // Delete takes name of the clusterNetworkPolicy and deletes it. Returns an error if one occurs. func (c *FakeClusterNetworkPolicies) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { _, err := c.Fake. - Invokes(testing.NewRootDeleteAction(clusternetworkpoliciesResource, name), &v1alpha1.ClusterNetworkPolicy{}) + Invokes(testing.NewRootDeleteActionWithOptions(clusternetworkpoliciesResource, name, opts), &v1alpha1.ClusterNetworkPolicy{}) return err } diff --git a/pkg/client/clientset/versioned/typed/crd/v1alpha1/fake/fake_networkpolicy.go b/pkg/client/clientset/versioned/typed/crd/v1alpha1/fake/fake_networkpolicy.go index d6995c7141d..dbb2313822a 100644 --- a/pkg/client/clientset/versioned/typed/crd/v1alpha1/fake/fake_networkpolicy.go +++ b/pkg/client/clientset/versioned/typed/crd/v1alpha1/fake/fake_networkpolicy.go @@ -1,4 +1,4 @@ -// Copyright 2021 Antrea Authors +// Copyright 2022 Antrea Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -115,7 +115,7 @@ func (c *FakeNetworkPolicies) UpdateStatus(ctx context.Context, networkPolicy *v // Delete takes name of the networkPolicy and deletes it. Returns an error if one occurs. func (c *FakeNetworkPolicies) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { _, err := c.Fake. - Invokes(testing.NewDeleteAction(networkpoliciesResource, c.ns, name), &v1alpha1.NetworkPolicy{}) + Invokes(testing.NewDeleteActionWithOptions(networkpoliciesResource, c.ns, name, opts), &v1alpha1.NetworkPolicy{}) return err } diff --git a/pkg/client/clientset/versioned/typed/crd/v1alpha1/fake/fake_tier.go b/pkg/client/clientset/versioned/typed/crd/v1alpha1/fake/fake_tier.go index ab254f83d73..e4b60d99d04 100644 --- a/pkg/client/clientset/versioned/typed/crd/v1alpha1/fake/fake_tier.go +++ b/pkg/client/clientset/versioned/typed/crd/v1alpha1/fake/fake_tier.go @@ -1,4 +1,4 @@ -// Copyright 2021 Antrea Authors +// Copyright 2022 Antrea Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -97,7 +97,7 @@ func (c *FakeTiers) Update(ctx context.Context, tier *v1alpha1.Tier, opts v1.Upd // Delete takes name of the tier and deletes it. Returns an error if one occurs. func (c *FakeTiers) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { _, err := c.Fake. - Invokes(testing.NewRootDeleteAction(tiersResource, name), &v1alpha1.Tier{}) + Invokes(testing.NewRootDeleteActionWithOptions(tiersResource, name, opts), &v1alpha1.Tier{}) return err } diff --git a/pkg/client/clientset/versioned/typed/crd/v1alpha1/fake/fake_traceflow.go b/pkg/client/clientset/versioned/typed/crd/v1alpha1/fake/fake_traceflow.go index 3069b507217..add08a136e4 100644 --- a/pkg/client/clientset/versioned/typed/crd/v1alpha1/fake/fake_traceflow.go +++ b/pkg/client/clientset/versioned/typed/crd/v1alpha1/fake/fake_traceflow.go @@ -1,4 +1,4 @@ -// Copyright 2021 Antrea Authors +// Copyright 2022 Antrea Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -108,7 +108,7 @@ func (c *FakeTraceflows) UpdateStatus(ctx context.Context, traceflow *v1alpha1.T // Delete takes name of the traceflow and deletes it. Returns an error if one occurs. func (c *FakeTraceflows) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { _, err := c.Fake. - Invokes(testing.NewRootDeleteAction(traceflowsResource, name), &v1alpha1.Traceflow{}) + Invokes(testing.NewRootDeleteActionWithOptions(traceflowsResource, name, opts), &v1alpha1.Traceflow{}) return err } diff --git a/pkg/client/clientset/versioned/typed/crd/v1alpha2/crd_client.go b/pkg/client/clientset/versioned/typed/crd/v1alpha2/crd_client.go index 38c83aebaf1..b486fca3717 100644 --- a/pkg/client/clientset/versioned/typed/crd/v1alpha2/crd_client.go +++ b/pkg/client/clientset/versioned/typed/crd/v1alpha2/crd_client.go @@ -1,4 +1,4 @@ -// Copyright 2021 Antrea Authors +// Copyright 2022 Antrea Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -17,6 +17,8 @@ package v1alpha2 import ( + "net/http" + v1alpha2 "antrea.io/antrea/pkg/apis/crd/v1alpha2" "antrea.io/antrea/pkg/client/clientset/versioned/scheme" rest "k8s.io/client-go/rest" @@ -29,6 +31,7 @@ type CrdV1alpha2Interface interface { ExternalEntitiesGetter ExternalIPPoolsGetter IPPoolsGetter + TrafficControlsGetter } // CrdV1alpha2Client is used to interact with features provided by the crd.antrea.io group. @@ -56,13 +59,33 @@ func (c *CrdV1alpha2Client) IPPools() IPPoolInterface { return newIPPools(c) } +func (c *CrdV1alpha2Client) TrafficControls() TrafficControlInterface { + return newTrafficControls(c) +} + // NewForConfig creates a new CrdV1alpha2Client for the given config. +// NewForConfig is equivalent to NewForConfigAndClient(c, httpClient), +// where httpClient was generated with rest.HTTPClientFor(c). func NewForConfig(c *rest.Config) (*CrdV1alpha2Client, error) { config := *c if err := setConfigDefaults(&config); err != nil { return nil, err } - client, err := rest.RESTClientFor(&config) + httpClient, err := rest.HTTPClientFor(&config) + if err != nil { + return nil, err + } + return NewForConfigAndClient(&config, httpClient) +} + +// NewForConfigAndClient creates a new CrdV1alpha2Client for the given config and http client. +// Note the http client provided takes precedence over the configured transport values. +func NewForConfigAndClient(c *rest.Config, h *http.Client) (*CrdV1alpha2Client, error) { + config := *c + if err := setConfigDefaults(&config); err != nil { + return nil, err + } + client, err := rest.RESTClientForConfigAndClient(&config, h) if err != nil { return nil, err } diff --git a/pkg/client/clientset/versioned/typed/crd/v1alpha2/fake/fake_clustergroup.go b/pkg/client/clientset/versioned/typed/crd/v1alpha2/fake/fake_clustergroup.go index 65bafe53acc..750a9492a2b 100644 --- a/pkg/client/clientset/versioned/typed/crd/v1alpha2/fake/fake_clustergroup.go +++ b/pkg/client/clientset/versioned/typed/crd/v1alpha2/fake/fake_clustergroup.go @@ -1,4 +1,4 @@ -// Copyright 2021 Antrea Authors +// Copyright 2022 Antrea Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -108,7 +108,7 @@ func (c *FakeClusterGroups) UpdateStatus(ctx context.Context, clusterGroup *v1al // Delete takes name of the clusterGroup and deletes it. Returns an error if one occurs. func (c *FakeClusterGroups) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { _, err := c.Fake. - Invokes(testing.NewRootDeleteAction(clustergroupsResource, name), &v1alpha2.ClusterGroup{}) + Invokes(testing.NewRootDeleteActionWithOptions(clustergroupsResource, name, opts), &v1alpha2.ClusterGroup{}) return err } diff --git a/pkg/client/clientset/versioned/typed/crd/v1alpha2/fake/fake_crd_client.go b/pkg/client/clientset/versioned/typed/crd/v1alpha2/fake/fake_crd_client.go index b814a2d96c5..9e616b87e44 100644 --- a/pkg/client/clientset/versioned/typed/crd/v1alpha2/fake/fake_crd_client.go +++ b/pkg/client/clientset/versioned/typed/crd/v1alpha2/fake/fake_crd_client.go @@ -1,4 +1,4 @@ -// Copyright 2021 Antrea Authors +// Copyright 2022 Antrea Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -46,6 +46,10 @@ func (c *FakeCrdV1alpha2) IPPools() v1alpha2.IPPoolInterface { return &FakeIPPools{c} } +func (c *FakeCrdV1alpha2) TrafficControls() v1alpha2.TrafficControlInterface { + return &FakeTrafficControls{c} +} + // RESTClient returns a RESTClient that is used to communicate // with API server by this client implementation. func (c *FakeCrdV1alpha2) RESTClient() rest.Interface { diff --git a/pkg/client/clientset/versioned/typed/crd/v1alpha2/fake/fake_egress.go b/pkg/client/clientset/versioned/typed/crd/v1alpha2/fake/fake_egress.go index 9c463ebf406..4ff778d92c7 100644 --- a/pkg/client/clientset/versioned/typed/crd/v1alpha2/fake/fake_egress.go +++ b/pkg/client/clientset/versioned/typed/crd/v1alpha2/fake/fake_egress.go @@ -1,4 +1,4 @@ -// Copyright 2021 Antrea Authors +// Copyright 2022 Antrea Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -108,7 +108,7 @@ func (c *FakeEgresses) UpdateStatus(ctx context.Context, egress *v1alpha2.Egress // Delete takes name of the egress and deletes it. Returns an error if one occurs. func (c *FakeEgresses) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { _, err := c.Fake. - Invokes(testing.NewRootDeleteAction(egressesResource, name), &v1alpha2.Egress{}) + Invokes(testing.NewRootDeleteActionWithOptions(egressesResource, name, opts), &v1alpha2.Egress{}) return err } diff --git a/pkg/client/clientset/versioned/typed/crd/v1alpha2/fake/fake_externalentity.go b/pkg/client/clientset/versioned/typed/crd/v1alpha2/fake/fake_externalentity.go index 5400d36c187..874b7917da4 100644 --- a/pkg/client/clientset/versioned/typed/crd/v1alpha2/fake/fake_externalentity.go +++ b/pkg/client/clientset/versioned/typed/crd/v1alpha2/fake/fake_externalentity.go @@ -1,4 +1,4 @@ -// Copyright 2021 Antrea Authors +// Copyright 2022 Antrea Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -103,7 +103,7 @@ func (c *FakeExternalEntities) Update(ctx context.Context, externalEntity *v1alp // Delete takes name of the externalEntity and deletes it. Returns an error if one occurs. func (c *FakeExternalEntities) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { _, err := c.Fake. - Invokes(testing.NewDeleteAction(externalentitiesResource, c.ns, name), &v1alpha2.ExternalEntity{}) + Invokes(testing.NewDeleteActionWithOptions(externalentitiesResource, c.ns, name, opts), &v1alpha2.ExternalEntity{}) return err } diff --git a/pkg/client/clientset/versioned/typed/crd/v1alpha2/fake/fake_externalippool.go b/pkg/client/clientset/versioned/typed/crd/v1alpha2/fake/fake_externalippool.go index f2b91ba0055..eef3998d402 100644 --- a/pkg/client/clientset/versioned/typed/crd/v1alpha2/fake/fake_externalippool.go +++ b/pkg/client/clientset/versioned/typed/crd/v1alpha2/fake/fake_externalippool.go @@ -1,4 +1,4 @@ -// Copyright 2021 Antrea Authors +// Copyright 2022 Antrea Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -108,7 +108,7 @@ func (c *FakeExternalIPPools) UpdateStatus(ctx context.Context, externalIPPool * // Delete takes name of the externalIPPool and deletes it. Returns an error if one occurs. func (c *FakeExternalIPPools) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { _, err := c.Fake. - Invokes(testing.NewRootDeleteAction(externalippoolsResource, name), &v1alpha2.ExternalIPPool{}) + Invokes(testing.NewRootDeleteActionWithOptions(externalippoolsResource, name, opts), &v1alpha2.ExternalIPPool{}) return err } diff --git a/pkg/client/clientset/versioned/typed/crd/v1alpha2/fake/fake_ippool.go b/pkg/client/clientset/versioned/typed/crd/v1alpha2/fake/fake_ippool.go index 701e20fbed6..60b3e11f2c5 100644 --- a/pkg/client/clientset/versioned/typed/crd/v1alpha2/fake/fake_ippool.go +++ b/pkg/client/clientset/versioned/typed/crd/v1alpha2/fake/fake_ippool.go @@ -1,4 +1,4 @@ -// Copyright 2021 Antrea Authors +// Copyright 2022 Antrea Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -108,7 +108,7 @@ func (c *FakeIPPools) UpdateStatus(ctx context.Context, iPPool *v1alpha2.IPPool, // Delete takes name of the iPPool and deletes it. Returns an error if one occurs. func (c *FakeIPPools) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { _, err := c.Fake. - Invokes(testing.NewRootDeleteAction(ippoolsResource, name), &v1alpha2.IPPool{}) + Invokes(testing.NewRootDeleteActionWithOptions(ippoolsResource, name, opts), &v1alpha2.IPPool{}) return err } diff --git a/pkg/client/clientset/versioned/typed/crd/v1alpha2/fake/fake_trafficcontrol.go b/pkg/client/clientset/versioned/typed/crd/v1alpha2/fake/fake_trafficcontrol.go new file mode 100644 index 00000000000..e216d668ab1 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/crd/v1alpha2/fake/fake_trafficcontrol.go @@ -0,0 +1,120 @@ +// Copyright 2022 Antrea Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + + v1alpha2 "antrea.io/antrea/pkg/apis/crd/v1alpha2" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + testing "k8s.io/client-go/testing" +) + +// FakeTrafficControls implements TrafficControlInterface +type FakeTrafficControls struct { + Fake *FakeCrdV1alpha2 +} + +var trafficcontrolsResource = schema.GroupVersionResource{Group: "crd.antrea.io", Version: "v1alpha2", Resource: "trafficcontrols"} + +var trafficcontrolsKind = schema.GroupVersionKind{Group: "crd.antrea.io", Version: "v1alpha2", Kind: "TrafficControl"} + +// Get takes name of the trafficControl, and returns the corresponding trafficControl object, and an error if there is any. +func (c *FakeTrafficControls) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha2.TrafficControl, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootGetAction(trafficcontrolsResource, name), &v1alpha2.TrafficControl{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha2.TrafficControl), err +} + +// List takes label and field selectors, and returns the list of TrafficControls that match those selectors. +func (c *FakeTrafficControls) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha2.TrafficControlList, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootListAction(trafficcontrolsResource, trafficcontrolsKind, opts), &v1alpha2.TrafficControlList{}) + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1alpha2.TrafficControlList{ListMeta: obj.(*v1alpha2.TrafficControlList).ListMeta} + for _, item := range obj.(*v1alpha2.TrafficControlList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested trafficControls. +func (c *FakeTrafficControls) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewRootWatchAction(trafficcontrolsResource, opts)) +} + +// Create takes the representation of a trafficControl and creates it. Returns the server's representation of the trafficControl, and an error, if there is any. +func (c *FakeTrafficControls) Create(ctx context.Context, trafficControl *v1alpha2.TrafficControl, opts v1.CreateOptions) (result *v1alpha2.TrafficControl, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootCreateAction(trafficcontrolsResource, trafficControl), &v1alpha2.TrafficControl{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha2.TrafficControl), err +} + +// Update takes the representation of a trafficControl and updates it. Returns the server's representation of the trafficControl, and an error, if there is any. +func (c *FakeTrafficControls) Update(ctx context.Context, trafficControl *v1alpha2.TrafficControl, opts v1.UpdateOptions) (result *v1alpha2.TrafficControl, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateAction(trafficcontrolsResource, trafficControl), &v1alpha2.TrafficControl{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha2.TrafficControl), err +} + +// Delete takes name of the trafficControl and deletes it. Returns an error if one occurs. +func (c *FakeTrafficControls) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewRootDeleteActionWithOptions(trafficcontrolsResource, name, opts), &v1alpha2.TrafficControl{}) + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeTrafficControls) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewRootDeleteCollectionAction(trafficcontrolsResource, listOpts) + + _, err := c.Fake.Invokes(action, &v1alpha2.TrafficControlList{}) + return err +} + +// Patch applies the patch and returns the patched trafficControl. +func (c *FakeTrafficControls) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha2.TrafficControl, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(trafficcontrolsResource, name, pt, data, subresources...), &v1alpha2.TrafficControl{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha2.TrafficControl), err +} diff --git a/pkg/client/clientset/versioned/typed/crd/v1alpha2/generated_expansion.go b/pkg/client/clientset/versioned/typed/crd/v1alpha2/generated_expansion.go index 2103fbb17bc..83ac45a1e33 100644 --- a/pkg/client/clientset/versioned/typed/crd/v1alpha2/generated_expansion.go +++ b/pkg/client/clientset/versioned/typed/crd/v1alpha2/generated_expansion.go @@ -1,4 +1,4 @@ -// Copyright 2021 Antrea Authors +// Copyright 2022 Antrea Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -25,3 +25,5 @@ type ExternalEntityExpansion interface{} type ExternalIPPoolExpansion interface{} type IPPoolExpansion interface{} + +type TrafficControlExpansion interface{} diff --git a/pkg/client/clientset/versioned/typed/crd/v1alpha2/trafficcontrol.go b/pkg/client/clientset/versioned/typed/crd/v1alpha2/trafficcontrol.go new file mode 100644 index 00000000000..22145d61ce6 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/crd/v1alpha2/trafficcontrol.go @@ -0,0 +1,166 @@ +// Copyright 2022 Antrea Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by client-gen. DO NOT EDIT. + +package v1alpha2 + +import ( + "context" + "time" + + v1alpha2 "antrea.io/antrea/pkg/apis/crd/v1alpha2" + scheme "antrea.io/antrea/pkg/client/clientset/versioned/scheme" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + rest "k8s.io/client-go/rest" +) + +// TrafficControlsGetter has a method to return a TrafficControlInterface. +// A group's client should implement this interface. +type TrafficControlsGetter interface { + TrafficControls() TrafficControlInterface +} + +// TrafficControlInterface has methods to work with TrafficControl resources. +type TrafficControlInterface interface { + Create(ctx context.Context, trafficControl *v1alpha2.TrafficControl, opts v1.CreateOptions) (*v1alpha2.TrafficControl, error) + Update(ctx context.Context, trafficControl *v1alpha2.TrafficControl, opts v1.UpdateOptions) (*v1alpha2.TrafficControl, error) + Delete(ctx context.Context, name string, opts v1.DeleteOptions) error + DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error + Get(ctx context.Context, name string, opts v1.GetOptions) (*v1alpha2.TrafficControl, error) + List(ctx context.Context, opts v1.ListOptions) (*v1alpha2.TrafficControlList, error) + Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) + Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha2.TrafficControl, err error) + TrafficControlExpansion +} + +// trafficControls implements TrafficControlInterface +type trafficControls struct { + client rest.Interface +} + +// newTrafficControls returns a TrafficControls +func newTrafficControls(c *CrdV1alpha2Client) *trafficControls { + return &trafficControls{ + client: c.RESTClient(), + } +} + +// Get takes name of the trafficControl, and returns the corresponding trafficControl object, and an error if there is any. +func (c *trafficControls) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha2.TrafficControl, err error) { + result = &v1alpha2.TrafficControl{} + err = c.client.Get(). + Resource("trafficcontrols"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(ctx). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of TrafficControls that match those selectors. +func (c *trafficControls) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha2.TrafficControlList, err error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + result = &v1alpha2.TrafficControlList{} + err = c.client.Get(). + Resource("trafficcontrols"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Do(ctx). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested trafficControls. +func (c *trafficControls) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + opts.Watch = true + return c.client.Get(). + Resource("trafficcontrols"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Watch(ctx) +} + +// Create takes the representation of a trafficControl and creates it. Returns the server's representation of the trafficControl, and an error, if there is any. +func (c *trafficControls) Create(ctx context.Context, trafficControl *v1alpha2.TrafficControl, opts v1.CreateOptions) (result *v1alpha2.TrafficControl, err error) { + result = &v1alpha2.TrafficControl{} + err = c.client.Post(). + Resource("trafficcontrols"). + VersionedParams(&opts, scheme.ParameterCodec). + Body(trafficControl). + Do(ctx). + Into(result) + return +} + +// Update takes the representation of a trafficControl and updates it. Returns the server's representation of the trafficControl, and an error, if there is any. +func (c *trafficControls) Update(ctx context.Context, trafficControl *v1alpha2.TrafficControl, opts v1.UpdateOptions) (result *v1alpha2.TrafficControl, err error) { + result = &v1alpha2.TrafficControl{} + err = c.client.Put(). + Resource("trafficcontrols"). + Name(trafficControl.Name). + VersionedParams(&opts, scheme.ParameterCodec). + Body(trafficControl). + Do(ctx). + Into(result) + return +} + +// Delete takes name of the trafficControl and deletes it. Returns an error if one occurs. +func (c *trafficControls) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + return c.client.Delete(). + Resource("trafficcontrols"). + Name(name). + Body(&opts). + Do(ctx). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *trafficControls) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + var timeout time.Duration + if listOpts.TimeoutSeconds != nil { + timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second + } + return c.client.Delete(). + Resource("trafficcontrols"). + VersionedParams(&listOpts, scheme.ParameterCodec). + Timeout(timeout). + Body(&opts). + Do(ctx). + Error() +} + +// Patch applies the patch and returns the patched trafficControl. +func (c *trafficControls) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha2.TrafficControl, err error) { + result = &v1alpha2.TrafficControl{} + err = c.client.Patch(pt). + Resource("trafficcontrols"). + Name(name). + SubResource(subresources...). + VersionedParams(&opts, scheme.ParameterCodec). + Body(data). + Do(ctx). + Into(result) + return +} diff --git a/pkg/client/clientset/versioned/typed/crd/v1alpha3/crd_client.go b/pkg/client/clientset/versioned/typed/crd/v1alpha3/crd_client.go index 34fbc38ca17..4a696db8938 100644 --- a/pkg/client/clientset/versioned/typed/crd/v1alpha3/crd_client.go +++ b/pkg/client/clientset/versioned/typed/crd/v1alpha3/crd_client.go @@ -1,4 +1,4 @@ -// Copyright 2021 Antrea Authors +// Copyright 2022 Antrea Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -17,6 +17,8 @@ package v1alpha3 import ( + "net/http" + v1alpha3 "antrea.io/antrea/pkg/apis/crd/v1alpha3" "antrea.io/antrea/pkg/client/clientset/versioned/scheme" rest "k8s.io/client-go/rest" @@ -37,12 +39,28 @@ func (c *CrdV1alpha3Client) ClusterGroups() ClusterGroupInterface { } // NewForConfig creates a new CrdV1alpha3Client for the given config. +// NewForConfig is equivalent to NewForConfigAndClient(c, httpClient), +// where httpClient was generated with rest.HTTPClientFor(c). func NewForConfig(c *rest.Config) (*CrdV1alpha3Client, error) { config := *c if err := setConfigDefaults(&config); err != nil { return nil, err } - client, err := rest.RESTClientFor(&config) + httpClient, err := rest.HTTPClientFor(&config) + if err != nil { + return nil, err + } + return NewForConfigAndClient(&config, httpClient) +} + +// NewForConfigAndClient creates a new CrdV1alpha3Client for the given config and http client. +// Note the http client provided takes precedence over the configured transport values. +func NewForConfigAndClient(c *rest.Config, h *http.Client) (*CrdV1alpha3Client, error) { + config := *c + if err := setConfigDefaults(&config); err != nil { + return nil, err + } + client, err := rest.RESTClientForConfigAndClient(&config, h) if err != nil { return nil, err } diff --git a/pkg/client/clientset/versioned/typed/crd/v1alpha3/fake/fake_clustergroup.go b/pkg/client/clientset/versioned/typed/crd/v1alpha3/fake/fake_clustergroup.go index f775397c74f..7df0e4fa0a6 100644 --- a/pkg/client/clientset/versioned/typed/crd/v1alpha3/fake/fake_clustergroup.go +++ b/pkg/client/clientset/versioned/typed/crd/v1alpha3/fake/fake_clustergroup.go @@ -1,4 +1,4 @@ -// Copyright 2021 Antrea Authors +// Copyright 2022 Antrea Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -108,7 +108,7 @@ func (c *FakeClusterGroups) UpdateStatus(ctx context.Context, clusterGroup *v1al // Delete takes name of the clusterGroup and deletes it. Returns an error if one occurs. func (c *FakeClusterGroups) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { _, err := c.Fake. - Invokes(testing.NewRootDeleteAction(clustergroupsResource, name), &v1alpha3.ClusterGroup{}) + Invokes(testing.NewRootDeleteActionWithOptions(clustergroupsResource, name, opts), &v1alpha3.ClusterGroup{}) return err } diff --git a/pkg/client/clientset/versioned/typed/crd/v1beta1/crd_client.go b/pkg/client/clientset/versioned/typed/crd/v1beta1/crd_client.go index d471d936b46..672e970dcba 100644 --- a/pkg/client/clientset/versioned/typed/crd/v1beta1/crd_client.go +++ b/pkg/client/clientset/versioned/typed/crd/v1beta1/crd_client.go @@ -1,4 +1,4 @@ -// Copyright 2021 Antrea Authors +// Copyright 2022 Antrea Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -17,6 +17,8 @@ package v1beta1 import ( + "net/http" + v1beta1 "antrea.io/antrea/pkg/apis/crd/v1beta1" "antrea.io/antrea/pkg/client/clientset/versioned/scheme" rest "k8s.io/client-go/rest" @@ -42,12 +44,28 @@ func (c *CrdV1beta1Client) AntreaControllerInfos() AntreaControllerInfoInterface } // NewForConfig creates a new CrdV1beta1Client for the given config. +// NewForConfig is equivalent to NewForConfigAndClient(c, httpClient), +// where httpClient was generated with rest.HTTPClientFor(c). func NewForConfig(c *rest.Config) (*CrdV1beta1Client, error) { config := *c if err := setConfigDefaults(&config); err != nil { return nil, err } - client, err := rest.RESTClientFor(&config) + httpClient, err := rest.HTTPClientFor(&config) + if err != nil { + return nil, err + } + return NewForConfigAndClient(&config, httpClient) +} + +// NewForConfigAndClient creates a new CrdV1beta1Client for the given config and http client. +// Note the http client provided takes precedence over the configured transport values. +func NewForConfigAndClient(c *rest.Config, h *http.Client) (*CrdV1beta1Client, error) { + config := *c + if err := setConfigDefaults(&config); err != nil { + return nil, err + } + client, err := rest.RESTClientForConfigAndClient(&config, h) if err != nil { return nil, err } diff --git a/pkg/client/clientset/versioned/typed/crd/v1beta1/fake/fake_antreaagentinfo.go b/pkg/client/clientset/versioned/typed/crd/v1beta1/fake/fake_antreaagentinfo.go index ad32e3d8b0b..ebe0a3d2c70 100644 --- a/pkg/client/clientset/versioned/typed/crd/v1beta1/fake/fake_antreaagentinfo.go +++ b/pkg/client/clientset/versioned/typed/crd/v1beta1/fake/fake_antreaagentinfo.go @@ -1,4 +1,4 @@ -// Copyright 2021 Antrea Authors +// Copyright 2022 Antrea Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -97,7 +97,7 @@ func (c *FakeAntreaAgentInfos) Update(ctx context.Context, antreaAgentInfo *v1be // Delete takes name of the antreaAgentInfo and deletes it. Returns an error if one occurs. func (c *FakeAntreaAgentInfos) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { _, err := c.Fake. - Invokes(testing.NewRootDeleteAction(antreaagentinfosResource, name), &v1beta1.AntreaAgentInfo{}) + Invokes(testing.NewRootDeleteActionWithOptions(antreaagentinfosResource, name, opts), &v1beta1.AntreaAgentInfo{}) return err } diff --git a/pkg/client/clientset/versioned/typed/crd/v1beta1/fake/fake_antreacontrollerinfo.go b/pkg/client/clientset/versioned/typed/crd/v1beta1/fake/fake_antreacontrollerinfo.go index 0191ff90625..5592700a736 100644 --- a/pkg/client/clientset/versioned/typed/crd/v1beta1/fake/fake_antreacontrollerinfo.go +++ b/pkg/client/clientset/versioned/typed/crd/v1beta1/fake/fake_antreacontrollerinfo.go @@ -1,4 +1,4 @@ -// Copyright 2021 Antrea Authors +// Copyright 2022 Antrea Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -97,7 +97,7 @@ func (c *FakeAntreaControllerInfos) Update(ctx context.Context, antreaController // Delete takes name of the antreaControllerInfo and deletes it. Returns an error if one occurs. func (c *FakeAntreaControllerInfos) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { _, err := c.Fake. - Invokes(testing.NewRootDeleteAction(antreacontrollerinfosResource, name), &v1beta1.AntreaControllerInfo{}) + Invokes(testing.NewRootDeleteActionWithOptions(antreacontrollerinfosResource, name, opts), &v1beta1.AntreaControllerInfo{}) return err } diff --git a/pkg/client/clientset/versioned/typed/stats/v1alpha1/fake/fake_multicastgroup.go b/pkg/client/clientset/versioned/typed/stats/v1alpha1/fake/fake_multicastgroup.go new file mode 100644 index 00000000000..81c8cfecf0e --- /dev/null +++ b/pkg/client/clientset/versioned/typed/stats/v1alpha1/fake/fake_multicastgroup.go @@ -0,0 +1,74 @@ +// Copyright 2022 Antrea Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + + v1alpha1 "antrea.io/antrea/pkg/apis/stats/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + watch "k8s.io/apimachinery/pkg/watch" + testing "k8s.io/client-go/testing" +) + +// FakeMulticastGroups implements MulticastGroupInterface +type FakeMulticastGroups struct { + Fake *FakeStatsV1alpha1 +} + +var multicastgroupsResource = schema.GroupVersionResource{Group: "stats.antrea.io", Version: "v1alpha1", Resource: "multicastgroups"} + +var multicastgroupsKind = schema.GroupVersionKind{Group: "stats.antrea.io", Version: "v1alpha1", Kind: "MulticastGroup"} + +// Get takes name of the multicastGroup, and returns the corresponding multicastGroup object, and an error if there is any. +func (c *FakeMulticastGroups) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.MulticastGroup, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootGetAction(multicastgroupsResource, name), &v1alpha1.MulticastGroup{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.MulticastGroup), err +} + +// List takes label and field selectors, and returns the list of MulticastGroups that match those selectors. +func (c *FakeMulticastGroups) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.MulticastGroupList, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootListAction(multicastgroupsResource, multicastgroupsKind, opts), &v1alpha1.MulticastGroupList{}) + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1alpha1.MulticastGroupList{ListMeta: obj.(*v1alpha1.MulticastGroupList).ListMeta} + for _, item := range obj.(*v1alpha1.MulticastGroupList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested multicastGroups. +func (c *FakeMulticastGroups) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewRootWatchAction(multicastgroupsResource, opts)) +} diff --git a/pkg/client/clientset/versioned/typed/stats/v1alpha1/fake/fake_stats_client.go b/pkg/client/clientset/versioned/typed/stats/v1alpha1/fake/fake_stats_client.go index 07158ff9e2e..1d4a10166fd 100644 --- a/pkg/client/clientset/versioned/typed/stats/v1alpha1/fake/fake_stats_client.go +++ b/pkg/client/clientset/versioned/typed/stats/v1alpha1/fake/fake_stats_client.go @@ -1,4 +1,4 @@ -// Copyright 2021 Antrea Authors +// Copyright 2022 Antrea Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -34,6 +34,10 @@ func (c *FakeStatsV1alpha1) AntreaNetworkPolicyStats(namespace string) v1alpha1. return &FakeAntreaNetworkPolicyStats{c, namespace} } +func (c *FakeStatsV1alpha1) MulticastGroups() v1alpha1.MulticastGroupInterface { + return &FakeMulticastGroups{c} +} + func (c *FakeStatsV1alpha1) NetworkPolicyStats(namespace string) v1alpha1.NetworkPolicyStatsInterface { return &FakeNetworkPolicyStats{c, namespace} } diff --git a/pkg/client/clientset/versioned/typed/stats/v1alpha1/generated_expansion.go b/pkg/client/clientset/versioned/typed/stats/v1alpha1/generated_expansion.go index 293e0ee75db..152ec4a23fa 100644 --- a/pkg/client/clientset/versioned/typed/stats/v1alpha1/generated_expansion.go +++ b/pkg/client/clientset/versioned/typed/stats/v1alpha1/generated_expansion.go @@ -1,4 +1,4 @@ -// Copyright 2021 Antrea Authors +// Copyright 2022 Antrea Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -20,4 +20,6 @@ type AntreaClusterNetworkPolicyStatsExpansion interface{} type AntreaNetworkPolicyStatsExpansion interface{} +type MulticastGroupExpansion interface{} + type NetworkPolicyStatsExpansion interface{} diff --git a/pkg/client/clientset/versioned/typed/stats/v1alpha1/multicastgroup.go b/pkg/client/clientset/versioned/typed/stats/v1alpha1/multicastgroup.go new file mode 100644 index 00000000000..ee3b92db191 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/stats/v1alpha1/multicastgroup.go @@ -0,0 +1,96 @@ +// Copyright 2022 Antrea Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by client-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + "context" + "time" + + v1alpha1 "antrea.io/antrea/pkg/apis/stats/v1alpha1" + scheme "antrea.io/antrea/pkg/client/clientset/versioned/scheme" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + watch "k8s.io/apimachinery/pkg/watch" + rest "k8s.io/client-go/rest" +) + +// MulticastGroupsGetter has a method to return a MulticastGroupInterface. +// A group's client should implement this interface. +type MulticastGroupsGetter interface { + MulticastGroups() MulticastGroupInterface +} + +// MulticastGroupInterface has methods to work with MulticastGroup resources. +type MulticastGroupInterface interface { + Get(ctx context.Context, name string, opts v1.GetOptions) (*v1alpha1.MulticastGroup, error) + List(ctx context.Context, opts v1.ListOptions) (*v1alpha1.MulticastGroupList, error) + Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) + MulticastGroupExpansion +} + +// multicastGroups implements MulticastGroupInterface +type multicastGroups struct { + client rest.Interface +} + +// newMulticastGroups returns a MulticastGroups +func newMulticastGroups(c *StatsV1alpha1Client) *multicastGroups { + return &multicastGroups{ + client: c.RESTClient(), + } +} + +// Get takes name of the multicastGroup, and returns the corresponding multicastGroup object, and an error if there is any. +func (c *multicastGroups) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.MulticastGroup, err error) { + result = &v1alpha1.MulticastGroup{} + err = c.client.Get(). + Resource("multicastgroups"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(ctx). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of MulticastGroups that match those selectors. +func (c *multicastGroups) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.MulticastGroupList, err error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + result = &v1alpha1.MulticastGroupList{} + err = c.client.Get(). + Resource("multicastgroups"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Do(ctx). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested multicastGroups. +func (c *multicastGroups) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + opts.Watch = true + return c.client.Get(). + Resource("multicastgroups"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Watch(ctx) +} diff --git a/pkg/client/clientset/versioned/typed/stats/v1alpha1/stats_client.go b/pkg/client/clientset/versioned/typed/stats/v1alpha1/stats_client.go index 99f985c82b6..88d009e10a9 100644 --- a/pkg/client/clientset/versioned/typed/stats/v1alpha1/stats_client.go +++ b/pkg/client/clientset/versioned/typed/stats/v1alpha1/stats_client.go @@ -1,4 +1,4 @@ -// Copyright 2021 Antrea Authors +// Copyright 2022 Antrea Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -17,6 +17,8 @@ package v1alpha1 import ( + "net/http" + v1alpha1 "antrea.io/antrea/pkg/apis/stats/v1alpha1" "antrea.io/antrea/pkg/client/clientset/versioned/scheme" rest "k8s.io/client-go/rest" @@ -26,6 +28,7 @@ type StatsV1alpha1Interface interface { RESTClient() rest.Interface AntreaClusterNetworkPolicyStatsGetter AntreaNetworkPolicyStatsGetter + MulticastGroupsGetter NetworkPolicyStatsGetter } @@ -42,17 +45,37 @@ func (c *StatsV1alpha1Client) AntreaNetworkPolicyStats(namespace string) AntreaN return newAntreaNetworkPolicyStats(c, namespace) } +func (c *StatsV1alpha1Client) MulticastGroups() MulticastGroupInterface { + return newMulticastGroups(c) +} + func (c *StatsV1alpha1Client) NetworkPolicyStats(namespace string) NetworkPolicyStatsInterface { return newNetworkPolicyStats(c, namespace) } // NewForConfig creates a new StatsV1alpha1Client for the given config. +// NewForConfig is equivalent to NewForConfigAndClient(c, httpClient), +// where httpClient was generated with rest.HTTPClientFor(c). func NewForConfig(c *rest.Config) (*StatsV1alpha1Client, error) { config := *c if err := setConfigDefaults(&config); err != nil { return nil, err } - client, err := rest.RESTClientFor(&config) + httpClient, err := rest.HTTPClientFor(&config) + if err != nil { + return nil, err + } + return NewForConfigAndClient(&config, httpClient) +} + +// NewForConfigAndClient creates a new StatsV1alpha1Client for the given config and http client. +// Note the http client provided takes precedence over the configured transport values. +func NewForConfigAndClient(c *rest.Config, h *http.Client) (*StatsV1alpha1Client, error) { + config := *c + if err := setConfigDefaults(&config); err != nil { + return nil, err + } + client, err := rest.RESTClientForConfigAndClient(&config, h) if err != nil { return nil, err } diff --git a/pkg/client/clientset/versioned/typed/system/v1beta1/fake/fake_supportbundle.go b/pkg/client/clientset/versioned/typed/system/v1beta1/fake/fake_supportbundle.go index 6cb13cff6d2..027cb8e5e9b 100644 --- a/pkg/client/clientset/versioned/typed/system/v1beta1/fake/fake_supportbundle.go +++ b/pkg/client/clientset/versioned/typed/system/v1beta1/fake/fake_supportbundle.go @@ -1,4 +1,4 @@ -// Copyright 2021 Antrea Authors +// Copyright 2022 Antrea Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -57,6 +57,6 @@ func (c *FakeSupportBundles) Create(ctx context.Context, supportBundle *v1beta1. // Delete takes name of the supportBundle and deletes it. Returns an error if one occurs. func (c *FakeSupportBundles) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { _, err := c.Fake. - Invokes(testing.NewRootDeleteAction(supportbundlesResource, name), &v1beta1.SupportBundle{}) + Invokes(testing.NewRootDeleteActionWithOptions(supportbundlesResource, name, opts), &v1beta1.SupportBundle{}) return err } diff --git a/pkg/client/clientset/versioned/typed/system/v1beta1/system_client.go b/pkg/client/clientset/versioned/typed/system/v1beta1/system_client.go index 387d2acd8a0..afca13e8af0 100644 --- a/pkg/client/clientset/versioned/typed/system/v1beta1/system_client.go +++ b/pkg/client/clientset/versioned/typed/system/v1beta1/system_client.go @@ -1,4 +1,4 @@ -// Copyright 2021 Antrea Authors +// Copyright 2022 Antrea Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -17,6 +17,8 @@ package v1beta1 import ( + "net/http" + v1beta1 "antrea.io/antrea/pkg/apis/system/v1beta1" "antrea.io/antrea/pkg/client/clientset/versioned/scheme" rest "k8s.io/client-go/rest" @@ -37,12 +39,28 @@ func (c *SystemV1beta1Client) SupportBundles() SupportBundleInterface { } // NewForConfig creates a new SystemV1beta1Client for the given config. +// NewForConfig is equivalent to NewForConfigAndClient(c, httpClient), +// where httpClient was generated with rest.HTTPClientFor(c). func NewForConfig(c *rest.Config) (*SystemV1beta1Client, error) { config := *c if err := setConfigDefaults(&config); err != nil { return nil, err } - client, err := rest.RESTClientFor(&config) + httpClient, err := rest.HTTPClientFor(&config) + if err != nil { + return nil, err + } + return NewForConfigAndClient(&config, httpClient) +} + +// NewForConfigAndClient creates a new SystemV1beta1Client for the given config and http client. +// Note the http client provided takes precedence over the configured transport values. +func NewForConfigAndClient(c *rest.Config, h *http.Client) (*SystemV1beta1Client, error) { + config := *c + if err := setConfigDefaults(&config); err != nil { + return nil, err + } + client, err := rest.RESTClientForConfigAndClient(&config, h) if err != nil { return nil, err } diff --git a/pkg/client/informers/externalversions/crd/v1alpha2/interface.go b/pkg/client/informers/externalversions/crd/v1alpha2/interface.go index 648f8a62313..cf2fef7feb2 100644 --- a/pkg/client/informers/externalversions/crd/v1alpha2/interface.go +++ b/pkg/client/informers/externalversions/crd/v1alpha2/interface.go @@ -1,4 +1,4 @@ -// Copyright 2021 Antrea Authors +// Copyright 2022 Antrea Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -32,6 +32,8 @@ type Interface interface { ExternalIPPools() ExternalIPPoolInformer // IPPools returns a IPPoolInformer. IPPools() IPPoolInformer + // TrafficControls returns a TrafficControlInformer. + TrafficControls() TrafficControlInformer } type version struct { @@ -69,3 +71,8 @@ func (v *version) ExternalIPPools() ExternalIPPoolInformer { func (v *version) IPPools() IPPoolInformer { return &iPPoolInformer{factory: v.factory, tweakListOptions: v.tweakListOptions} } + +// TrafficControls returns a TrafficControlInformer. +func (v *version) TrafficControls() TrafficControlInformer { + return &trafficControlInformer{factory: v.factory, tweakListOptions: v.tweakListOptions} +} diff --git a/pkg/client/informers/externalversions/crd/v1alpha2/trafficcontrol.go b/pkg/client/informers/externalversions/crd/v1alpha2/trafficcontrol.go new file mode 100644 index 00000000000..9b504ddda33 --- /dev/null +++ b/pkg/client/informers/externalversions/crd/v1alpha2/trafficcontrol.go @@ -0,0 +1,87 @@ +// Copyright 2022 Antrea Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by informer-gen. DO NOT EDIT. + +package v1alpha2 + +import ( + "context" + time "time" + + crdv1alpha2 "antrea.io/antrea/pkg/apis/crd/v1alpha2" + versioned "antrea.io/antrea/pkg/client/clientset/versioned" + internalinterfaces "antrea.io/antrea/pkg/client/informers/externalversions/internalinterfaces" + v1alpha2 "antrea.io/antrea/pkg/client/listers/crd/v1alpha2" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" +) + +// TrafficControlInformer provides access to a shared informer and lister for +// TrafficControls. +type TrafficControlInformer interface { + Informer() cache.SharedIndexInformer + Lister() v1alpha2.TrafficControlLister +} + +type trafficControlInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// NewTrafficControlInformer constructs a new informer for TrafficControl type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewTrafficControlInformer(client versioned.Interface, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredTrafficControlInformer(client, resyncPeriod, indexers, nil) +} + +// NewFilteredTrafficControlInformer constructs a new informer for TrafficControl type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFilteredTrafficControlInformer(client versioned.Interface, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options v1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.CrdV1alpha2().TrafficControls().List(context.TODO(), options) + }, + WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.CrdV1alpha2().TrafficControls().Watch(context.TODO(), options) + }, + }, + &crdv1alpha2.TrafficControl{}, + resyncPeriod, + indexers, + ) +} + +func (f *trafficControlInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredTrafficControlInformer(client, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *trafficControlInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&crdv1alpha2.TrafficControl{}, f.defaultInformer) +} + +func (f *trafficControlInformer) Lister() v1alpha2.TrafficControlLister { + return v1alpha2.NewTrafficControlLister(f.Informer().GetIndexer()) +} diff --git a/pkg/client/informers/externalversions/generic.go b/pkg/client/informers/externalversions/generic.go index 8c8ee1ab463..0378c370c15 100644 --- a/pkg/client/informers/externalversions/generic.go +++ b/pkg/client/informers/externalversions/generic.go @@ -1,4 +1,4 @@ -// Copyright 2021 Antrea Authors +// Copyright 2022 Antrea Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -74,6 +74,8 @@ func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource return &genericInformer{resource: resource.GroupResource(), informer: f.Crd().V1alpha2().ExternalIPPools().Informer()}, nil case v1alpha2.SchemeGroupVersion.WithResource("ippools"): return &genericInformer{resource: resource.GroupResource(), informer: f.Crd().V1alpha2().IPPools().Informer()}, nil + case v1alpha2.SchemeGroupVersion.WithResource("trafficcontrols"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Crd().V1alpha2().TrafficControls().Informer()}, nil // Group=crd.antrea.io, Version=v1alpha3 case v1alpha3.SchemeGroupVersion.WithResource("clustergroups"): diff --git a/pkg/client/listers/crd/v1alpha2/expansion_generated.go b/pkg/client/listers/crd/v1alpha2/expansion_generated.go index e7120eb239a..6cc05d345cb 100644 --- a/pkg/client/listers/crd/v1alpha2/expansion_generated.go +++ b/pkg/client/listers/crd/v1alpha2/expansion_generated.go @@ -1,4 +1,4 @@ -// Copyright 2021 Antrea Authors +// Copyright 2022 Antrea Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -39,3 +39,7 @@ type ExternalIPPoolListerExpansion interface{} // IPPoolListerExpansion allows custom methods to be added to // IPPoolLister. type IPPoolListerExpansion interface{} + +// TrafficControlListerExpansion allows custom methods to be added to +// TrafficControlLister. +type TrafficControlListerExpansion interface{} diff --git a/pkg/client/listers/crd/v1alpha2/trafficcontrol.go b/pkg/client/listers/crd/v1alpha2/trafficcontrol.go new file mode 100644 index 00000000000..c8d15b0757a --- /dev/null +++ b/pkg/client/listers/crd/v1alpha2/trafficcontrol.go @@ -0,0 +1,66 @@ +// Copyright 2022 Antrea Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by lister-gen. DO NOT EDIT. + +package v1alpha2 + +import ( + v1alpha2 "antrea.io/antrea/pkg/apis/crd/v1alpha2" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/tools/cache" +) + +// TrafficControlLister helps list TrafficControls. +// All objects returned here must be treated as read-only. +type TrafficControlLister interface { + // List lists all TrafficControls in the indexer. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*v1alpha2.TrafficControl, err error) + // Get retrieves the TrafficControl from the index for a given name. + // Objects returned here must be treated as read-only. + Get(name string) (*v1alpha2.TrafficControl, error) + TrafficControlListerExpansion +} + +// trafficControlLister implements the TrafficControlLister interface. +type trafficControlLister struct { + indexer cache.Indexer +} + +// NewTrafficControlLister returns a new TrafficControlLister. +func NewTrafficControlLister(indexer cache.Indexer) TrafficControlLister { + return &trafficControlLister{indexer: indexer} +} + +// List lists all TrafficControls in the indexer. +func (s *trafficControlLister) List(selector labels.Selector) (ret []*v1alpha2.TrafficControl, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*v1alpha2.TrafficControl)) + }) + return ret, err +} + +// Get retrieves the TrafficControl from the index for a given name. +func (s *trafficControlLister) Get(name string) (*v1alpha2.TrafficControl, error) { + obj, exists, err := s.indexer.GetByKey(name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(v1alpha2.Resource("trafficcontrol"), name) + } + return obj.(*v1alpha2.TrafficControl), nil +} diff --git a/pkg/config/agent/config.go b/pkg/config/agent/config.go index 2d5dbe2a272..0c913d191f0 100644 --- a/pkg/config/agent/config.go +++ b/pkg/config/agent/config.go @@ -104,13 +104,17 @@ type AgentConfig struct { // WireGuard related configurations. WireGuard WireGuardConfig `yaml:"wireGuard"` // Enable bridging mode of Pod network on Nodes, in which the Node's transport interface is connected - // to the OVS bridge, and cross-Node/VLAN traffic from AntreaIPAM Pods (Pods whose IP addresses are - // allocated by AntreaIPAM from IPPools) is sent to the underlay network via the uplink, and - // forwarded/routed by the underlay network. + // to the OVS bridge, and cross-Node/VLAN traffic of AntreaIPAM Pods (Pods whose IP addresses are + // allocated by AntreaIPAM from IPPools) is sent to the underlay network, and forwarded/routed by the + // underlay network. // This option requires the `AntreaIPAM` feature gate to be enabled. At this moment, it supports only // IPv4 and Linux Nodes, and can be enabled only when `ovsDatapathType` is `system`, // `trafficEncapMode` is `noEncap`, and `noSNAT` is true. EnableBridgingMode bool `yaml:"enableBridgingMode,omitempty"` + // Disable TX checksum offloading for container network interfaces. It's supposed to be set to true when the + // datapath doesn't support TX checksum offloading, which causes packets to be dropped due to bad checksum. + // It affects Pods running on Linux Nodes only. + DisableTXChecksumOffload bool `yaml:"disableTXChecksumOffload,omitempty"` // APIPort is the port for the antrea-agent APIServer to serve on. // Defaults to 10350. APIPort int `yaml:"apiPort,omitempty"` @@ -182,9 +186,8 @@ type AgentConfig struct { // 2. TransportInterfaceCIDRs // 3. The Node IP TransportInterfaceCIDRs []string `yaml:"transportInterfaceCIDRs,omitempty"` - // The names of the interfaces on Nodes that are used to forward multicast traffic. - // Defaults to transport interface if not set. - MulticastInterfaces []string `yaml:"multicastInterfaces,omitempty"` + // Multicast configuration options. + Multicast MulticastConfig `yaml:"multicast,omitempty"` // AntreaProxy contains AntreaProxy related configuration options. AntreaProxy AntreaProxyConfig `yaml:"antreaProxy,omitempty"` // Egress related configurations. @@ -231,6 +234,15 @@ type NodePortLocalConfig struct { PortRange string `yaml:"portRange,omitempty"` } +type MulticastConfig struct { + // The names of the interfaces on Nodes that are used to forward multicast traffic. + // Defaults to transport interface if not set. + MulticastInterfaces []string `yaml:"multicastInterfaces,omitempty"` + // The interval for antrea-agent to send IGMP queries to Pods. + // Defaults to 125 seconds. + IGMPQueryInterval string `yaml:"igmpQueryInterval"` +} + type EgressConfig struct { ExceptCIDRs []string `yaml:"exceptCIDRs,omitempty"` } diff --git a/pkg/config/controller/config.go b/pkg/config/controller/config.go index d7e08a358a1..643d7e476cb 100644 --- a/pkg/config/controller/config.go +++ b/pkg/config/controller/config.go @@ -51,12 +51,10 @@ type ControllerConfig struct { // Defaults to true. EnablePrometheusMetrics *bool `yaml:"enablePrometheusMetrics,omitempty"` // Indicates whether to use auto-generated self-signed TLS certificate. - // If false, A Secret named "antrea-controller-tls" must be provided with the following keys: + // If false, a Secret named "antrea-controller-tls" must be provided with the following keys: // ca.crt: // tls.crt: // tls.key: - // And the Secret must be mounted to directory "/var/run/antrea/antrea-controller-tls" of the - // antrea-controller container. // Defaults to true. SelfSignedCert *bool `yaml:"selfSignedCert,omitempty"` // Cipher suites to use. diff --git a/pkg/controller/ipam/antrea_ipam_controller.go b/pkg/controller/ipam/antrea_ipam_controller.go index da8522c0d28..14b4b597905 100644 --- a/pkg/controller/ipam/antrea_ipam_controller.go +++ b/pkg/controller/ipam/antrea_ipam_controller.go @@ -18,12 +18,14 @@ package ipam import ( + "context" "fmt" "strings" "time" appsv1 "k8s.io/api/apps/v1" "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/util/sets" "k8s.io/apimachinery/pkg/util/wait" @@ -52,13 +54,13 @@ const ( minRetryDelay = 5 * time.Second maxRetryDelay = 300 * time.Second + + garbageCollectionInterval = 10 * time.Minute ) -// AntreaIPAMController is responsible for IP address cleanup -// for StatefulSet objects. -// In future, it will also be responsible for pre-allocation of -// continuous IP range for StatefulSets that do not have dedicated -// IP Pool annotation. +// AntreaIPAMController is responsible for: +// * reserving continuous IP address space for StatefulSet (if available) +// * periodical cleanup of IP Pools in case stale addresses are present type AntreaIPAMController struct { // crdClient is the clientset for CRD API group. crdClient versioned.Interface @@ -74,6 +76,10 @@ type AntreaIPAMController struct { statefulSetInformer appsinformers.StatefulSetInformer statefulSetListerSynced cache.InformerSynced + // follow changes for Pods + podLister corelisters.PodLister + podInformerSynced cache.InformerSynced + // follow changes for IP Pool objects ipPoolInformer crdinformers.IPPoolInformer ipPoolLister crdlisters.IPPoolLister @@ -102,6 +108,7 @@ func NewAntreaIPAMController(crdClient versioned.Interface, ipPoolInformer.Informer().AddIndexers(cache.Indexers{statefulSetIndex: statefulSetIndexFunc}) namespaceInformer := informerFactory.Core().V1().Namespaces() + podInformer := informerFactory.Core().V1().Pods() statefulSetInformer := informerFactory.Apps().V1().StatefulSets() @@ -112,6 +119,8 @@ func NewAntreaIPAMController(crdClient versioned.Interface, namespaceListerSynced: namespaceInformer.Informer().HasSynced, statefulSetInformer: statefulSetInformer, statefulSetListerSynced: statefulSetInformer.Informer().HasSynced, + podLister: podInformer.Lister(), + podInformerSynced: podInformer.Informer().HasSynced, ipPoolInformer: ipPoolInformer, ipPoolLister: ipPoolInformer.Lister(), ipPoolListerSynced: ipPoolInformer.Informer().HasSynced, @@ -152,31 +161,67 @@ func (c *AntreaIPAMController) enqueueStatefulSetDeleteEvent(obj interface{}) { // Inspect all IPPools for stale IP Address entries. // This may happen if controller was down during StatefulSet delete event. // If such entry is found, enqueue cleanup event for this StatefulSet. -func (c *AntreaIPAMController) cleanupStaleStatefulSets() { +func (c *AntreaIPAMController) cleanupStaleAddresses() { pools, _ := c.ipPoolLister.List(labels.Everything()) lister := c.statefulSetInformer.Lister() statefulSets, _ := lister.List(labels.Everything()) statefulSetMap := make(map[string]bool) + klog.InfoS("Cleanup job for IP Pools started") + for _, ss := range statefulSets { // Prepare map of existing StatefulSets for quick reference below statefulSetMap[k8s.NamespacedName(ss.Namespace, ss.Name)] = true } + poolsUpdated := 0 for _, ipPool := range pools { - for _, address := range ipPool.Status.IPAddresses { + updateNeeded := false + ipPoolCopy := ipPool.DeepCopy() + var newList []crdv1a2.IPAddressState + for _, address := range ipPoolCopy.Status.IPAddresses { + // Cleanup reserved addresses + if address.Owner.Pod != nil { + _, err := c.podLister.Pods(address.Owner.Pod.Namespace).Get(address.Owner.Pod.Name) + if err != nil && errors.IsNotFound(err) { + klog.InfoS("IPPool contains stale IPAddress for Pod that no longer exists", "IPPool", ipPool.Name, "Namespace", address.Owner.Pod.Namespace, "Pod", address.Owner.Pod.Name) + address.Owner.Pod = nil + if address.Owner.StatefulSet != nil { + address.Phase = crdv1a2.IPAddressPhaseReserved + } + updateNeeded = true + } + } if address.Owner.StatefulSet != nil { key := k8s.NamespacedName(address.Owner.StatefulSet.Namespace, address.Owner.StatefulSet.Name) if _, ok := statefulSetMap[key]; !ok { // This entry refers to StatefulSet that no longer exists - klog.InfoS("IPPool contains stale IPAddress for StatefulSet that no longer exists", "IPPool", ipPool.Name, "StatefulSet", key) - c.statefulSetQueue.Add(key) - // Mark this entry in map to ensure cleanup is enqueued only once - statefulSetMap[key] = true + klog.InfoS("IPPool contains stale IPAddress for StatefulSet that no longer exists", "IPPool", ipPool.Name, "Namespace", address.Owner.StatefulSet.Namespace, "StatefulSet", address.Owner.StatefulSet.Name) + address.Owner.StatefulSet = nil + updateNeeded = true + } } + + if address.Owner.StatefulSet != nil || address.Owner.Pod != nil { + newList = append(newList, address) + } + } + + if updateNeeded { + ipPoolCopy.Status.IPAddresses = newList + _, err := c.crdClient.CrdV1alpha2().IPPools().UpdateStatus(context.TODO(), ipPoolCopy, metav1.UpdateOptions{}) + if err != nil { + // Next cleanup job will retry + klog.ErrorS(err, "Updating IP Pool status failed", "IPPool", ipPool.Name) + } else { + poolsUpdated += 1 + } + } } + + klog.InfoS("Cleanup job for IP Pools finished", "updated", poolsUpdated) } // Look for an IP Pool associated with this StatefulSet. @@ -263,9 +308,11 @@ func (c *AntreaIPAMController) preallocateIPPoolForStatefulSet(ss *appsv1.Statef // Note that AllocateStatefulSet would not preallocate IPs if this StatefulSet is already present // in the pool. This safeguards us from double allocation in case agent allocated IP by the time // controller task is executed. Note also that StatefulSet resize will not be handled. - err = allocator.AllocateStatefulSet(ss.Namespace, ss.Name, size) - if err != nil { - return fmt.Errorf("failed to preallocate continuous IP space of size %d from Pool %s: %s", size, ipPoolName, err) + if size > 0 { + err = allocator.AllocateStatefulSet(ss.Namespace, ss.Name, size) + if err != nil { + return fmt.Errorf("failed to preallocate continuous IP space of size %d from Pool %s: %s", size, ipPoolName, err) + } } return nil @@ -323,13 +370,13 @@ func (c *AntreaIPAMController) Run(stopCh <-chan struct{}) { klog.InfoS("Starting", "controller", controllerName) defer klog.InfoS("Shutting down", "controller", controllerName) - cacheSyncs := []cache.InformerSynced{c.namespaceListerSynced, c.statefulSetListerSynced, c.ipPoolListerSynced} + cacheSyncs := []cache.InformerSynced{c.namespaceListerSynced, c.podInformerSynced, c.statefulSetListerSynced, c.ipPoolListerSynced} if !cache.WaitForNamedCacheSync(controllerName, stopCh, cacheSyncs...) { return } - // Make sure any stale StatefulSets that might be present in pools are cleaned up - c.cleanupStaleStatefulSets() + // Periodic cleanup IP Pools of stale IP addresses + go wait.NonSlidingUntil(c.cleanupStaleAddresses, garbageCollectionInterval, stopCh) go wait.Until(c.statefulSetWorker, time.Second, stopCh) diff --git a/pkg/controller/ipam/antrea_ipam_controller_test.go b/pkg/controller/ipam/antrea_ipam_controller_test.go index b59e9fdeffd..89f179a2fca 100644 --- a/pkg/controller/ipam/antrea_ipam_controller_test.go +++ b/pkg/controller/ipam/antrea_ipam_controller_test.go @@ -19,6 +19,7 @@ package ipam import ( "context" + "fmt" "testing" "time" @@ -195,7 +196,7 @@ func TestReleaseStaleAddresses(t *testing.T) { stopCh := make(chan struct{}) defer close(stopCh) - namespace, pool, statefulSet := initTestObjects(true, false, 7) + namespace, pool, statefulSet := initTestObjects(true, false, 0) activeSetOwner := crdv1a2.StatefulSetOwner{ Name: statefulSet.Name, @@ -207,16 +208,26 @@ func TestReleaseStaleAddresses(t *testing.T) { Namespace: namespace.Name, } + stalePodOwner := crdv1a2.PodOwner{ + Name: uuid.New().String(), + Namespace: namespace.Name, + } + addresses := []crdv1a2.IPAddressState{ {IPAddress: "10.2.2.12", Phase: crdv1a2.IPAddressPhaseReserved, Owner: crdv1a2.IPAddressOwner{StatefulSet: &activeSetOwner}}, - {IPAddress: "20.1.1.100", + {IPAddress: "20.2.2.13", Phase: crdv1a2.IPAddressPhaseReserved, Owner: crdv1a2.IPAddressOwner{StatefulSet: &staleSetOwner}}, - {IPAddress: "20.1.1.200", + {IPAddress: "20.2.2.14", Phase: crdv1a2.IPAddressPhaseReserved, Owner: crdv1a2.IPAddressOwner{StatefulSet: &staleSetOwner}}, + {IPAddress: "20.2.2.15", + Phase: crdv1a2.IPAddressPhaseAllocated, + Owner: crdv1a2.IPAddressOwner{StatefulSet: &activeSetOwner, + Pod: &stalePodOwner}, + }, } pool.Status = crdv1a2.IPPoolStatus{ @@ -239,6 +250,26 @@ func TestReleaseStaleAddresses(t *testing.T) { go controller.Run(stopCh) - // after cleanup pool should have single entry - verifyPoolAllocatedSize(t, pool.Name, poolLister, 1) + // verify two stale entries were deleted, one updated to Reserved status + err := wait.PollImmediate(100*time.Millisecond, 2*time.Second, func() (bool, error) { + pool, err := poolLister.Get(pool.Name) + if err != nil { + return false, nil + } + + if len(pool.Status.IPAddresses) != 2 { + t.Logf("IP Pool status: %v", pool.Status.IPAddresses) + return false, nil + } + + for _, addr := range pool.Status.IPAddresses { + if addr.Phase != crdv1a2.IPAddressPhaseReserved { + return true, fmt.Errorf("Incorrect phase %s after cleanup", addr.Phase) + } + } + + return true, nil + }) + + require.NoError(t, err) } diff --git a/pkg/controller/ipam/validate.go b/pkg/controller/ipam/validate.go index abdb04296c4..2fed3f6aa2f 100644 --- a/pkg/controller/ipam/validate.go +++ b/pkg/controller/ipam/validate.go @@ -187,20 +187,31 @@ func ipInRange(rangeStart, rangeEnd, ip net.IP) bool { return bytes.Compare(ip16, rangeStart.To16()) >= 0 && bytes.Compare(ip16, rangeEnd.To16()) <= 0 } -func ipVersion(ip net.IP) int { +func ipVersion(ip net.IP) crdv1alpha2.IPVersion { if ip.To4() != nil { - return 4 + return crdv1alpha2.IPv4 } - return 6 + return crdv1alpha2.IPv6 } -func validateIPRange(r crdv1alpha2.SubnetIPRange, poolIPVersion int) (bool, string) { +func validateIPRange(r crdv1alpha2.SubnetIPRange, poolIPVersion crdv1alpha2.IPVersion) (bool, string) { + if poolIPVersion == crdv1alpha2.IPv4 { + if r.PrefixLength <= 0 || r.PrefixLength >= 32 { + return false, fmt.Sprintf("Invalid prefix length %d", r.PrefixLength) + } + } else if poolIPVersion == crdv1alpha2.IPv6 { + if r.PrefixLength <= 0 || r.PrefixLength >= 128 { + return false, fmt.Sprintf("Invalid prefix length %d", r.PrefixLength) + } + } else { + return false, fmt.Sprintf("Invalid IP version %d", int(poolIPVersion)) + } // Validate the integrity the IP range: // Verify that all the IP ranges have the same IP family as the IP pool // Verify that the gateway IP is reachable from the IP range gateway := net.ParseIP(r.Gateway) var mask net.IPMask - if ipVersion(gateway) == 4 { + if ipVersion(gateway) == crdv1alpha2.IPv4 { mask = net.CIDRMask(int(r.PrefixLength), 32) } else { mask = net.CIDRMask(int(r.PrefixLength), 128) @@ -209,28 +220,27 @@ func validateIPRange(r crdv1alpha2.SubnetIPRange, poolIPVersion int) (bool, stri if r.CIDR != "" { _, cidr, _ := net.ParseCIDR(r.CIDR) - + if ipVersion(cidr.IP) != poolIPVersion { + return false, fmt.Sprintf( + "Range is invalid. IP version of range %s differs from Pool IP version", r.CIDR) + } if !netCIDR.Contains(cidr.IP) { return false, fmt.Sprintf( "Range is invalid. CIDR %s is not contained within subnet %s/%d", r.CIDR, netCIDR.IP.String(), r.PrefixLength) } - if ipVersion(cidr.IP) != poolIPVersion { - return false, fmt.Sprintf( - "Range is invalid. IP version of range %s differs from Pool IP version", r.CIDR) - } } else { rStart := net.ParseIP(r.Start) rEnd := net.ParseIP(r.End) + if ipVersion(rStart) != poolIPVersion || ipVersion(rEnd) != poolIPVersion { + return false, fmt.Sprintf( + "Range is invalid. IP version of range %s-%s differs from Pool IP version", r.Start, r.End) + } if !netCIDR.Contains(rStart) || !netCIDR.Contains(rEnd) { return false, fmt.Sprintf( "Range is invalid. range %s-%s is not contained within subnet %s/%d", r.Start, r.End, netCIDR.IP.String(), r.PrefixLength) } - if ipVersion(rStart) != poolIPVersion || ipVersion(rEnd) != poolIPVersion { - return false, fmt.Sprintf( - "Range is invalid. IP version of range %s-%s differs from Pool IP version", r.Start, r.End) - } } return true, "" } diff --git a/pkg/controller/ipam/validate_test.go b/pkg/controller/ipam/validate_test.go index 8b86d477912..67607821854 100644 --- a/pkg/controller/ipam/validate_test.go +++ b/pkg/controller/ipam/validate_test.go @@ -31,7 +31,7 @@ var testIPPool = &crdv1alpha2.IPPool{ Name: "test-ip-pool", }, Spec: crdv1alpha2.IPPoolSpec{ - IPVersion: 4, + IPVersion: crdv1alpha2.IPv4, IPRanges: []crdv1alpha2.SubnetIPRange{ { IPRange: crdv1alpha2.IPRange{ @@ -92,6 +92,30 @@ func TestEgressControllerValidateExternalIPPool(t *testing.T) { }, expectedResponse: &admv1.AdmissionResponse{Allowed: true}, }, + { + name: "CREATE operation with invalid prefix length should not be allowed", + request: &admv1.AdmissionRequest{ + Name: "foo", + Operation: "CREATE", + Object: runtime.RawExtension{Raw: marshal(copyAndMutateIPPool(testIPPool, func(pool *crdv1alpha2.IPPool) { + pool.Spec.IPRanges = append(pool.Spec.IPRanges, crdv1alpha2.SubnetIPRange{ + IPRange: crdv1alpha2.IPRange{ + CIDR: "192.168.3.0/26", + }, + SubnetInfo: crdv1alpha2.SubnetInfo{ + Gateway: "192.168.3.1", + PrefixLength: 32, + }, + }) + }))}, + }, + expectedResponse: &admv1.AdmissionResponse{ + Allowed: false, + Result: &metav1.Status{ + Message: "Invalid prefix length 32", + }, + }, + }, { name: "CREATE operation with CIDR partially overlap with IP range should not be allowed", request: &admv1.AdmissionRequest{ @@ -152,7 +176,7 @@ func TestEgressControllerValidateExternalIPPool(t *testing.T) { }, SubnetInfo: crdv1alpha2.SubnetInfo{ Gateway: "10:2400::01", - PrefixLength: 64, + PrefixLength: 24, }, }) }))}, diff --git a/pkg/controller/networkpolicy/antreanetworkpolicy.go b/pkg/controller/networkpolicy/antreanetworkpolicy.go index eb0f4d5c54f..4dfac5c3978 100644 --- a/pkg/controller/networkpolicy/antreanetworkpolicy.go +++ b/pkg/controller/networkpolicy/antreanetworkpolicy.go @@ -138,7 +138,7 @@ func (n *NetworkPolicyController) processAntreaNetworkPolicy(np *crdv1alpha1.Net // Compute NetworkPolicyRule for Ingress Rule. for idx, ingressRule := range np.Spec.Ingress { // Set default action to ALLOW to allow traffic. - services, namedPortExists := toAntreaServicesForCRD(ingressRule.Ports) + services, namedPortExists := toAntreaServicesForCRD(ingressRule.Ports, ingressRule.Protocols) var appliedToGroupNamesForRule []string // Create AppliedToGroup for each AppliedTo present in the ingress rule. for _, at := range ingressRule.AppliedTo { @@ -160,7 +160,7 @@ func (n *NetworkPolicyController) processAntreaNetworkPolicy(np *crdv1alpha1.Net // Compute NetworkPolicyRule for Egress Rule. for idx, egressRule := range np.Spec.Egress { // Set default action to ALLOW to allow traffic. - services, namedPortExists := toAntreaServicesForCRD(egressRule.Ports) + services, namedPortExists := toAntreaServicesForCRD(egressRule.Ports, egressRule.Protocols) var appliedToGroupNamesForRule []string // Create AppliedToGroup for each AppliedTo present in the ingress rule. for _, at := range egressRule.AppliedTo { diff --git a/pkg/controller/networkpolicy/antreanetworkpolicy_test.go b/pkg/controller/networkpolicy/antreanetworkpolicy_test.go index 079a21a794b..b64517c9851 100644 --- a/pkg/controller/networkpolicy/antreanetworkpolicy_test.go +++ b/pkg/controller/networkpolicy/antreanetworkpolicy_test.go @@ -32,6 +32,9 @@ var ( selectorB = metav1.LabelSelector{MatchLabels: map[string]string{"foo2": "bar2"}} selectorC = metav1.LabelSelector{MatchLabels: map[string]string{"foo3": "bar3"}} selectorD = metav1.LabelSelector{MatchLabels: map[string]string{"foo4": "bar4"}} + + icmpType8 = int32(8) + icmpCode0 = int32(0) ) func TestProcessAntreaNetworkPolicy(t *testing.T) { @@ -505,6 +508,68 @@ func TestProcessAntreaNetworkPolicy(t *testing.T) { expectedAppliedToGroups: 1, expectedAddressGroups: 1, }, + { + name: "rules-with-icmp-protocol", + inputPolicy: &crdv1alpha1.NetworkPolicy{ + ObjectMeta: metav1.ObjectMeta{Namespace: "ns7", Name: "npG", UID: "uidG"}, + Spec: crdv1alpha1.NetworkPolicySpec{ + AppliedTo: []crdv1alpha1.NetworkPolicyPeer{ + {PodSelector: &selectorA}, + }, + Priority: p10, + Egress: []crdv1alpha1.Rule{ + { + Protocols: []crdv1alpha1.NetworkPolicyProtocol{ + { + ICMP: &crdv1alpha1.ICMPProtocol{ + ICMPType: &icmpType8, + ICMPCode: &icmpCode0, + }, + }, + }, + To: []crdv1alpha1.NetworkPolicyPeer{ + { + NodeSelector: &selectorB, + }, + }, + Action: &allowAction, + }, + }, + }, + }, + expectedPolicy: &antreatypes.NetworkPolicy{ + UID: "uidG", + Name: "uidG", + SourceRef: &controlplane.NetworkPolicyReference{ + Type: controlplane.AntreaNetworkPolicy, + Namespace: "ns7", + Name: "npG", + UID: "uidG", + }, + Priority: &p10, + TierPriority: &DefaultTierPriority, + Rules: []controlplane.NetworkPolicyRule{ + { + Direction: controlplane.DirectionOut, + To: controlplane.NetworkPolicyPeer{ + AddressGroups: []string{getNormalizedUID(antreatypes.NewGroupSelector("", nil, nil, nil, &selectorB).NormalizedName)}, + }, + Services: []controlplane.Service{ + { + Protocol: &protocolICMP, + ICMPType: &icmpType8, + ICMPCode: &icmpCode0, + }, + }, + Priority: 0, + Action: &allowAction, + }, + }, + AppliedToGroups: []string{getNormalizedUID(antreatypes.NewGroupSelector("ns7", &selectorA, nil, nil, nil).NormalizedName)}, + }, + expectedAppliedToGroups: 1, + expectedAddressGroups: 1, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/pkg/controller/networkpolicy/clusternetworkpolicy.go b/pkg/controller/networkpolicy/clusternetworkpolicy.go index 8a781ece2e5..52c67775b93 100644 --- a/pkg/controller/networkpolicy/clusternetworkpolicy.go +++ b/pkg/controller/networkpolicy/clusternetworkpolicy.go @@ -58,7 +58,7 @@ func (n *NetworkPolicyController) updateCNP(old, cur interface{}) { // enqueue task to internal NetworkPolicy Workqueue. curInternalNP := n.processClusterNetworkPolicy(curCNP) klog.V(2).Infof("Updating existing internal NetworkPolicy %s for %s", curInternalNP.Name, curInternalNP.SourceRef.ToString()) - // Retrieve old crdv1alpha1.NetworkPolicy object. + // Retrieve old crdv1alpha1.ClusterNetworkPolicy object. oldCNP := old.(*crdv1alpha1.ClusterNetworkPolicy) // Old and current NetworkPolicy share the same key. key := internalNetworkPolicyKeyFunc(oldCNP) @@ -381,7 +381,7 @@ func (n *NetworkPolicyController) processClusterNetworkPolicy(cnp *crdv1alpha1.C var rules []controlplane.NetworkPolicyRule processRules := func(cnpRules []crdv1alpha1.Rule, direction controlplane.Direction) { for idx, cnpRule := range cnpRules { - services, namedPortExists := toAntreaServicesForCRD(cnpRule.Ports) + services, namedPortExists := toAntreaServicesForCRD(cnpRule.Ports, cnpRule.Protocols) clusterPeers, perNSPeers := splitPeersByScope(cnpRule, direction) addRule := func(peer *controlplane.NetworkPolicyPeer, dir controlplane.Direction, ruleAppliedTos []string) { rule := controlplane.NetworkPolicyRule{ diff --git a/pkg/controller/networkpolicy/clusternetworkpolicy_test.go b/pkg/controller/networkpolicy/clusternetworkpolicy_test.go index 6217bf71b59..9f034454453 100644 --- a/pkg/controller/networkpolicy/clusternetworkpolicy_test.go +++ b/pkg/controller/networkpolicy/clusternetworkpolicy_test.go @@ -1865,6 +1865,95 @@ func TestAddCNP(t *testing.T) { expAppliedToGroups: 1, expAddressGroups: 2, }, + { + name: "rules-with-icmp-protocol", + inputPolicy: &crdv1alpha1.ClusterNetworkPolicy{ + ObjectMeta: metav1.ObjectMeta{Name: "cnpJ", UID: "uidJ"}, + Spec: crdv1alpha1.ClusterNetworkPolicySpec{ + AppliedTo: []crdv1alpha1.NetworkPolicyPeer{ + {PodSelector: &selectorA}, + }, + Priority: p10, + Ingress: []crdv1alpha1.Rule{ + { + Protocols: []crdv1alpha1.NetworkPolicyProtocol{ + { + ICMP: &crdv1alpha1.ICMPProtocol{ + ICMPType: &icmpType8, + ICMPCode: &icmpCode0, + }, + }, + }, + From: []crdv1alpha1.NetworkPolicyPeer{ + { + NodeSelector: &selectorB, + }, + }, + Action: &allowAction, + }, + }, + Egress: []crdv1alpha1.Rule{ + { + Protocols: []crdv1alpha1.NetworkPolicyProtocol{ + { + ICMP: &crdv1alpha1.ICMPProtocol{}, + }, + }, + To: []crdv1alpha1.NetworkPolicyPeer{ + { + NodeSelector: &selectorA, + }, + }, + Action: &allowAction, + }, + }, + }, + }, + expPolicy: &antreatypes.NetworkPolicy{ + UID: "uidJ", + Name: "uidJ", + SourceRef: &controlplane.NetworkPolicyReference{ + Type: controlplane.AntreaClusterNetworkPolicy, + Name: "cnpJ", + UID: "uidJ", + }, + Priority: &p10, + TierPriority: &DefaultTierPriority, + Rules: []controlplane.NetworkPolicyRule{ + { + Direction: controlplane.DirectionIn, + From: controlplane.NetworkPolicyPeer{ + AddressGroups: []string{getNormalizedUID(antreatypes.NewGroupSelector("", nil, nil, nil, &selectorB).NormalizedName)}, + }, + Services: []controlplane.Service{ + { + Protocol: &protocolICMP, + ICMPType: &icmpType8, + ICMPCode: &icmpCode0, + }, + }, + Priority: 0, + Action: &allowAction, + }, + { + Direction: controlplane.DirectionOut, + To: controlplane.NetworkPolicyPeer{ + AddressGroups: []string{getNormalizedUID(antreatypes.NewGroupSelector("", nil, nil, nil, &selectorA).NormalizedName)}, + }, + Services: []controlplane.Service{ + { + Protocol: &protocolICMP, + }, + }, + Priority: 0, + Action: &allowAction, + }, + }, + AppliedToGroups: []string{getNormalizedUID(antreatypes.NewGroupSelector("", &selectorA, nil, nil, nil).NormalizedName)}, + }, + expAppliedToGroups: 1, + expAddressGroups: 2, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -1884,7 +1973,7 @@ func TestAddCNP(t *testing.T) { for _, tt := range tests { npc.addCNP(tt.inputPolicy) } - assert.Equal(t, 8, npc.GetNetworkPolicyNum(), "number of NetworkPolicies do not match") + assert.Equal(t, 9, npc.GetNetworkPolicyNum(), "number of NetworkPolicies do not match") assert.Equal(t, 5, npc.GetAddressGroupNum(), "number of AddressGroups do not match") assert.Equal(t, 1, npc.GetAppliedToGroupNum(), "number of AppliedToGroups do not match") } diff --git a/pkg/controller/networkpolicy/crd_utils.go b/pkg/controller/networkpolicy/crd_utils.go index 3f8f3332afb..5a775708d71 100644 --- a/pkg/controller/networkpolicy/crd_utils.go +++ b/pkg/controller/networkpolicy/crd_utils.go @@ -35,10 +35,11 @@ var ( } ) -// toAntreaServicesForCRD converts a slice of v1alpha1.NetworkPolicyPort -// objects to a slice of Antrea Service objects. A bool is returned along with -// the Service objects to indicate whether any named port exists. -func toAntreaServicesForCRD(npPorts []v1alpha1.NetworkPolicyPort) ([]controlplane.Service, bool) { +// toAntreaServicesForCRD converts a slice of v1alpha1.NetworkPolicyPort objects +// and a slice of v1alpha1.NetworkPolicyProtocol objects to a slice of Antrea +// Service objects. A bool is returned along with the Service objects to indicate +// whether any named port exists. +func toAntreaServicesForCRD(npPorts []v1alpha1.NetworkPolicyPort, npProtocols []v1alpha1.NetworkPolicyProtocol) ([]controlplane.Service, bool) { var antreaServices []controlplane.Service var namedPortExists bool for _, npPort := range npPorts { @@ -51,6 +52,16 @@ func toAntreaServicesForCRD(npPorts []v1alpha1.NetworkPolicyPort) ([]controlplan EndPort: npPort.EndPort, }) } + for _, npProtocol := range npProtocols { + if npProtocol.ICMP != nil { + curProtocol := controlplane.ProtocolICMP + antreaServices = append(antreaServices, controlplane.Service{ + Protocol: &curProtocol, + ICMPType: npProtocol.ICMP.ICMPType, + ICMPCode: npProtocol.ICMP.ICMPCode, + }) + } + } return antreaServices, namedPortExists } diff --git a/pkg/controller/networkpolicy/crd_utils_test.go b/pkg/controller/networkpolicy/crd_utils_test.go index 82ba1abceab..be60d3e3bb3 100644 --- a/pkg/controller/networkpolicy/crd_utils_test.go +++ b/pkg/controller/networkpolicy/crd_utils_test.go @@ -32,6 +32,7 @@ import ( func TestToAntreaServicesForCRD(t *testing.T) { tables := []struct { ports []crdv1alpha1.NetworkPolicyPort + protocols []crdv1alpha1.NetworkPolicyProtocol expServices []controlplane.Service expNamedPortExists bool }{ @@ -82,9 +83,84 @@ func TestToAntreaServicesForCRD(t *testing.T) { }, expNamedPortExists: false, }, + { + protocols: []crdv1alpha1.NetworkPolicyProtocol{ + { + ICMP: &crdv1alpha1.ICMPProtocol{ + ICMPType: &icmpType8, + ICMPCode: &icmpCode0, + }, + }, + }, + expServices: []controlplane.Service{ + { + Protocol: &protocolICMP, + ICMPType: &icmpType8, + ICMPCode: &icmpCode0, + }, + }, + expNamedPortExists: false, + }, + { + protocols: []crdv1alpha1.NetworkPolicyProtocol{ + { + ICMP: &crdv1alpha1.ICMPProtocol{ + ICMPType: &icmpType8, + }, + }, + }, + expServices: []controlplane.Service{ + { + Protocol: &protocolICMP, + ICMPType: &icmpType8, + }, + }, + expNamedPortExists: false, + }, + { + protocols: []crdv1alpha1.NetworkPolicyProtocol{ + { + ICMP: &crdv1alpha1.ICMPProtocol{}, + }, + }, + expServices: []controlplane.Service{ + { + Protocol: &protocolICMP, + }, + }, + expNamedPortExists: false, + }, + { + ports: []crdv1alpha1.NetworkPolicyPort{ + { + Protocol: &k8sProtocolTCP, + Port: &int80, + }, + }, + protocols: []crdv1alpha1.NetworkPolicyProtocol{ + { + ICMP: &crdv1alpha1.ICMPProtocol{ + ICMPType: &icmpType8, + ICMPCode: &icmpCode0, + }, + }, + }, + expServices: []controlplane.Service{ + { + Protocol: toAntreaProtocol(&k8sProtocolTCP), + Port: &int80, + }, + { + Protocol: &protocolICMP, + ICMPType: &icmpType8, + ICMPCode: &icmpCode0, + }, + }, + expNamedPortExists: false, + }, } for _, table := range tables { - services, namedPortExist := toAntreaServicesForCRD(table.ports) + services, namedPortExist := toAntreaServicesForCRD(table.ports, table.protocols) assert.Equal(t, table.expServices, services) assert.Equal(t, table.expNamedPortExists, namedPortExist) } diff --git a/pkg/controller/networkpolicy/networkpolicy_controller_test.go b/pkg/controller/networkpolicy/networkpolicy_controller_test.go index 6da2ff8acec..3524c5fa749 100644 --- a/pkg/controller/networkpolicy/networkpolicy_controller_test.go +++ b/pkg/controller/networkpolicy/networkpolicy_controller_test.go @@ -59,7 +59,8 @@ var ( k8sProtocolTCP = corev1.ProtocolTCP k8sProtocolSCTP = corev1.ProtocolSCTP - protocolTCP = controlplane.ProtocolTCP + protocolTCP = controlplane.ProtocolTCP + protocolICMP = controlplane.ProtocolICMP int80 = intstr.FromInt(80) int81 = intstr.FromInt(81) diff --git a/pkg/controller/networkpolicy/status_controller_test.go b/pkg/controller/networkpolicy/status_controller_test.go index 6155a272b96..32573986eae 100644 --- a/pkg/controller/networkpolicy/status_controller_test.go +++ b/pkg/controller/networkpolicy/status_controller_test.go @@ -69,7 +69,7 @@ func (c *fakeNetworkPolicyControl) getAntreaClusterNetworkPolicyStatus() *crdv1a } func newTestStatusController(initialObjects ...runtime.Object) (*StatusController, antreaclientset.Interface, antreainformers.SharedInformerFactory, storage.Interface, *fakeNetworkPolicyControl) { - //clientset := fake.NewSimpleClientset(initialObjects...) + // clientset := fake.NewSimpleClientset(initialObjects...) networkPolicyStore := store.NewNetworkPolicyStore() antreaClientset := antreafakeclientset.NewSimpleClientset(initialObjects...) antreaInformerFactory := antreainformers.NewSharedInformerFactory(antreaClientset, 0) diff --git a/pkg/controller/networkpolicy/validate.go b/pkg/controller/networkpolicy/validate.go index 1b74687b43b..12cd8551a59 100644 --- a/pkg/controller/networkpolicy/validate.go +++ b/pkg/controller/networkpolicy/validate.go @@ -418,7 +418,6 @@ func (v *antreaPolicyValidator) createValidate(curObj interface{}, userInfo auth if !allowed { return reason, allowed } - if err := v.validatePort(ingress, egress); err != nil { return err.Error(), false } @@ -535,8 +534,8 @@ func (v *antreaPolicyValidator) validatePeers(ingress, egress []crdv1alpha1.Rule if !features.DefaultFeatureGate.Enabled(features.AntreaProxy) { return fmt.Sprintf("`toServices` can only be used when AntreaProxy is enabled"), false } - if (rule.To != nil && len(rule.To) > 0) || rule.Ports != nil { - return fmt.Sprintf("`toServices` can't be used with `to` or `ports`"), false + if (rule.To != nil && len(rule.To) > 0) || rule.Ports != nil || rule.Protocols != nil { + return fmt.Sprintf("`toServices` can't be used with `to`, `ports` or `protocols`"), false } } msg, isValid := checkPeers(rule.To) diff --git a/pkg/controller/networkpolicy/validate_test.go b/pkg/controller/networkpolicy/validate_test.go index e19e8150d44..059b754899a 100644 --- a/pkg/controller/networkpolicy/validate_test.go +++ b/pkg/controller/networkpolicy/validate_test.go @@ -705,7 +705,7 @@ func TestValidateAntreaPolicy(t *testing.T) { }, }, }, - expectedReason: "`toServices` can't be used with `to` or `ports`", + expectedReason: "`toServices` can't be used with `to`, `ports` or `protocols`", }, { name: "acnp-toservice-set-with-ports", @@ -739,7 +739,41 @@ func TestValidateAntreaPolicy(t *testing.T) { }, }, }, - expectedReason: "`toServices` can't be used with `to` or `ports`", + expectedReason: "`toServices` can't be used with `to`, `ports` or `protocols`", + }, + { + name: "acnp-toservice-set-with-protocols", + policy: &crdv1alpha1.ClusterNetworkPolicy{ + ObjectMeta: metav1.ObjectMeta{ + Name: "acnp-toservice-set-with-protocols", + }, + Spec: crdv1alpha1.ClusterNetworkPolicySpec{ + AppliedTo: []crdv1alpha1.NetworkPolicyPeer{ + { + NamespaceSelector: &metav1.LabelSelector{ + MatchLabels: map[string]string{"foo1": "bar1"}, + }, + }, + }, + Egress: []crdv1alpha1.Rule{ + { + Action: &allowAction, + Protocols: []crdv1alpha1.NetworkPolicyProtocol{ + { + ICMP: &crdv1alpha1.ICMPProtocol{}, + }, + }, + ToServices: []crdv1alpha1.NamespacedName{ + { + Name: "foo", + Namespace: "bar", + }, + }, + }, + }, + }, + }, + expectedReason: "`toServices` can't be used with `to`, `ports` or `protocols`", }, { name: "acnp-toservice-alone", @@ -827,10 +861,10 @@ func TestValidateAntreaPolicy(t *testing.T) { expectedReason: "", }, { - name: "acnp-endport-without-port", + name: "acnp-endport-without-port-in-ports", policy: &crdv1alpha1.ClusterNetworkPolicy{ ObjectMeta: metav1.ObjectMeta{ - Name: "acnp-endport-without-port", + Name: "acnp-endport-without-port-in-ports", }, Spec: crdv1alpha1.ClusterNetworkPolicySpec{ AppliedTo: []crdv1alpha1.NetworkPolicyPeer{ @@ -855,10 +889,10 @@ func TestValidateAntreaPolicy(t *testing.T) { expectedReason: "if `endPort` is specified `port` must be specified", }, { - name: "acnp-endport-smaller-port", + name: "acnp-endport-smaller-port-in-ports", policy: &crdv1alpha1.ClusterNetworkPolicy{ ObjectMeta: metav1.ObjectMeta{ - Name: "acnp-endport-smaller-port", + Name: "acnp-endport-smaller-port-in-ports", }, Spec: crdv1alpha1.ClusterNetworkPolicySpec{ AppliedTo: []crdv1alpha1.NetworkPolicyPeer{ @@ -884,10 +918,10 @@ func TestValidateAntreaPolicy(t *testing.T) { expectedReason: "`endPort` should be greater than or equal to `port`", }, { - name: "acnp-named-port-with-endport", + name: "acnp-named-port-with-endport-in-ports", policy: &crdv1alpha1.ClusterNetworkPolicy{ ObjectMeta: metav1.ObjectMeta{ - Name: "acnp-named-port-with-endport", + Name: "acnp-named-port-with-endport-in-ports", }, Spec: crdv1alpha1.ClusterNetworkPolicySpec{ AppliedTo: []crdv1alpha1.NetworkPolicyPeer{ @@ -913,10 +947,10 @@ func TestValidateAntreaPolicy(t *testing.T) { expectedReason: "if `port` is a string `endPort` cannot be specified", }, { - name: "acnp-port-range", + name: "acnp-port-range-in-ports", policy: &crdv1alpha1.ClusterNetworkPolicy{ ObjectMeta: metav1.ObjectMeta{ - Name: "acnp-port-range", + Name: "acnp-port-range-in-ports", }, Spec: crdv1alpha1.ClusterNetworkPolicySpec{ AppliedTo: []crdv1alpha1.NetworkPolicyPeer{ diff --git a/pkg/controller/stats/aggregator.go b/pkg/controller/stats/aggregator.go index e39bc11793d..27de2302924 100644 --- a/pkg/controller/stats/aggregator.go +++ b/pkg/controller/stats/aggregator.go @@ -28,7 +28,7 @@ import ( "antrea.io/antrea/pkg/apis/controlplane" crdv1alpha1 "antrea.io/antrea/pkg/apis/crd/v1alpha1" statsv1alpha1 "antrea.io/antrea/pkg/apis/stats/v1alpha1" - crdvinformers "antrea.io/antrea/pkg/client/informers/externalversions/crd/v1alpha1" + crdinformers "antrea.io/antrea/pkg/client/informers/externalversions/crd/v1alpha1" "antrea.io/antrea/pkg/features" "antrea.io/antrea/pkg/util/k8s" ) @@ -69,7 +69,7 @@ func uidIndexFunc(obj interface{}) ([]string, error) { return []string{string(meta.GetUID())}, nil } -func NewAggregator(networkPolicyInformer networkinginformers.NetworkPolicyInformer, cnpInformer crdvinformers.ClusterNetworkPolicyInformer, anpInformer crdvinformers.NetworkPolicyInformer) *Aggregator { +func NewAggregator(networkPolicyInformer networkinginformers.NetworkPolicyInformer, cnpInformer crdinformers.ClusterNetworkPolicyInformer, anpInformer crdinformers.NetworkPolicyInformer) *Aggregator { aggregator := &Aggregator{ networkPolicyStats: cache.NewIndexer(cache.MetaNamespaceKeyFunc, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc, uidIndex: uidIndexFunc}), dataCh: make(chan *controlplane.NodeStatsSummary, 1000), diff --git a/pkg/features/antrea_features.go b/pkg/features/antrea_features.go index 01cd6ecf536..8e84e090573 100644 --- a/pkg/features/antrea_features.go +++ b/pkg/features/antrea_features.go @@ -15,8 +15,10 @@ package features import ( - "k8s.io/apimachinery/pkg/util/runtime" + k8sruntime "k8s.io/apimachinery/pkg/util/runtime" "k8s.io/component-base/featuregate" + + "antrea.io/antrea/pkg/util/runtime" ) // When editing this file, make sure you edit the documentation as well to keep @@ -75,7 +77,7 @@ const ( NodeIPAM featuregate.Feature = "NodeIPAM" // alpha: v1.4 - // Enable flexible IPAM for Pods. + // Enable AntreaIPAM, which is required by bridging mode Pods and secondary network IPAM. AntreaIPAM featuregate.Feature = "AntreaIPAM" // alpha: v1.5 @@ -89,6 +91,10 @@ const ( // alpha: v1.5 // Enable controlling Services with ExternalIP. ServiceExternalIP featuregate.Feature = "ServiceExternalIP" + + // alpha: v1.7 + // Enable mirroring or redirecting the traffic Pods send or receive. + TrafficControl featuregate.Feature = "TrafficControl" ) var ( @@ -116,6 +122,7 @@ var ( Multicast: {Default: false, PreRelease: featuregate.Alpha}, SecondaryNetwork: {Default: false, PreRelease: featuregate.Alpha}, ServiceExternalIP: {Default: false, PreRelease: featuregate.Alpha}, + TrafficControl: {Default: false, PreRelease: featuregate.Alpha}, } // UnsupportedFeaturesOnWindows records the features not supported on @@ -129,7 +136,6 @@ var ( // can have different FeatureSpecs between Linux and Windows, we should // still define a separate defaultAntreaFeatureGates map for Windows. unsupportedFeaturesOnWindows = map[featuregate.Feature]struct{}{ - NodePortLocal: {}, Egress: {}, AntreaIPAM: {}, Multicast: {}, @@ -139,7 +145,18 @@ var ( ) func init() { - runtime.Must(DefaultMutableFeatureGate.Add(DefaultAntreaFeatureGates)) + if runtime.IsWindowsPlatform() { + for f := range unsupportedFeaturesOnWindows { + // A feature which is enabled by default on Linux might not be supported on + // Windows. So, override the default value here. + fg := DefaultAntreaFeatureGates[f] + if fg.Default { + fg.Default = false + DefaultAntreaFeatureGates[f] = fg + } + } + } + k8sruntime.Must(DefaultMutableFeatureGate.Add(DefaultAntreaFeatureGates)) } // SupportedOnWindows checks whether a feature is supported on a Windows Node. diff --git a/pkg/ipam/poolallocator/allocator.go b/pkg/ipam/poolallocator/allocator.go index 92545a6f4e5..fe7b5a9a1b4 100644 --- a/pkg/ipam/poolallocator/allocator.go +++ b/pkg/ipam/poolallocator/allocator.go @@ -36,7 +36,10 @@ import ( // Pool Allocator assumes that pool with allocated IPs can not be deleted. Pool ranges can // only be extended. type IPPoolAllocator struct { - // Name of IP Pool custom resource + // IP version of the IPPool + IPVersion v1alpha2.IPVersion + + // Name of IPPool custom resource ipPoolName string // crd client to update the pool @@ -48,16 +51,15 @@ type IPPoolAllocator struct { // NewIPPoolAllocator creates an IPPoolAllocator based on the provided IP pool. func NewIPPoolAllocator(poolName string, client crdclientset.Interface, poolLister informers.IPPoolLister) (*IPPoolAllocator, error) { - - // Validate the pool exists - // This has an extra roundtrip cost, however this would allow fallback to - // default IPAM driver if needed - _, err := poolLister.Get(poolName) + // Validate the pool exists. + pool, err := poolLister.Get(poolName) if err != nil { - return nil, err + return nil, fmt.Errorf("failed to get IPPool %s: %v", poolName, err) + } allocator := &IPPoolAllocator{ + IPVersion: pool.Spec.IPVersion, ipPoolName: poolName, crdClient: client, ipPoolLister: poolLister, @@ -248,12 +250,41 @@ func (a *IPPoolAllocator) removeIPAddressState(ipPool *v1alpha2.IPPool, ip net.I } +// getExistingAllocation looks up the existing IP allocation for a Pod network interface, and +// returns the IP address and SubnetInfo if found. +func (a *IPPoolAllocator) getExistingAllocation(podOwner *v1alpha2.PodOwner) (net.IP, *v1alpha2.SubnetInfo, error) { + ip, err := a.GetContainerIP(podOwner.ContainerID, podOwner.IFName) + if err != nil { + return nil, nil, err + } + if ip == nil { + return nil, nil, nil + } + + ipPool, allocators, err := a.getPoolAndInitIPAllocators() + if err != nil { + return nil, nil, err + } + + index := -1 + for i, allocator := range allocators { + if allocator.Has(ip) { + index = i + break + } + } + if index == -1 { + return nil, nil, fmt.Errorf("IP %v does not belong to IPPool %s", ip, a.ipPoolName) + } + return ip, &ipPool.Spec.IPRanges[index].SubnetInfo, nil +} + // AllocateIP allocates the specified IP. It returns error if the IP is not in the range or already // allocated, or in case CRD failed to update its state. // In case of success, IP pool CRD status is updated with allocated IP/state/resource/container. // AllocateIP returns subnet details for the requested IP, as defined in IP pool spec. -func (a *IPPoolAllocator) AllocateIP(ip net.IP, state v1alpha2.IPAddressPhase, owner v1alpha2.IPAddressOwner) (v1alpha2.SubnetInfo, error) { - var subnetSpec v1alpha2.SubnetInfo +func (a *IPPoolAllocator) AllocateIP(ip net.IP, state v1alpha2.IPAddressPhase, owner v1alpha2.IPAddressOwner) (*v1alpha2.SubnetInfo, error) { + var subnetSpec *v1alpha2.SubnetInfo // Retry on CRD update conflict which is caused by multiple agents updating a pool at same time. err := retry.RetryOnConflict(retry.DefaultRetry, func() error { ipPool, allocators, err := a.getPoolAndInitIPAllocators() @@ -278,7 +309,7 @@ func (a *IPPoolAllocator) AllocateIP(ip net.IP, state v1alpha2.IPAddressPhase, o return fmt.Errorf("IP %v does not belong to IP pool %s", ip, a.ipPoolName) } - subnetSpec = ipPool.Spec.IPRanges[index].SubnetInfo + subnetSpec = &ipPool.Spec.IPRanges[index].SubnetInfo err = a.appendPoolUsage(ipPool, ip, state, owner) return err @@ -292,20 +323,22 @@ func (a *IPPoolAllocator) AllocateIP(ip net.IP, state v1alpha2.IPAddressPhase, o // AllocateNext allocates the next available IP. It returns error if pool is exausted, // or in case CRD failed to update its state. -// In case of success, IP pool CRD status is updated with allocated IP/state/resource/container. +// In case of success, IPPool CRD status is updated with allocated IP/state/resource/container. // AllocateIP returns subnet details for the requested IP, as defined in IP pool spec. -func (a *IPPoolAllocator) AllocateNext(state v1alpha2.IPAddressPhase, owner v1alpha2.IPAddressOwner) (net.IP, v1alpha2.SubnetInfo, error) { - var subnetSpec v1alpha2.SubnetInfo - var ip net.IP - // Same resource can not ask for allocation twice without release - // This needs to be verified even at the expense of another API call - exists, err := a.HasContainer(owner.Pod.ContainerID) +func (a *IPPoolAllocator) AllocateNext(state v1alpha2.IPAddressPhase, owner v1alpha2.IPAddressOwner) (net.IP, *v1alpha2.SubnetInfo, error) { + podOwner := owner.Pod + // Same resource can not ask for allocation twice without release. + // This needs to be verified even at the expense of another API call. + ip, subnetSpec, err := a.getExistingAllocation(podOwner) if err != nil { - return ip, subnetSpec, err + return nil, nil, err } - - if exists { - return ip, subnetSpec, fmt.Errorf("container %s was already allocated an address from IP Pool %s", owner.Pod.ContainerID, a.ipPoolName) + if ip != nil { + // This can happen when the container requests IPs from multiple pools, and after an + // allocation failure, not all allocated IPs were successfully released, and then + // CNI ADD is retried. + klog.InfoS("Container already has an IP allocated", "container", podOwner.ContainerID, "interface", podOwner.IFName, "IPPool", a.ipPoolName) + return ip, subnetSpec, err } // Retry on CRD update conflict which is caused by multiple agents updating a pool at same time. @@ -330,7 +363,7 @@ func (a *IPPoolAllocator) AllocateNext(state v1alpha2.IPAddressPhase, owner v1al return fmt.Errorf("failed to allocate IP: Pool %s is exausted", a.ipPoolName) } - subnetSpec = ipPool.Spec.IPRanges[index].SubnetInfo + subnetSpec = &ipPool.Spec.IPRanges[index].SubnetInfo return a.appendPoolUsage(ipPool, ip, state, owner) }) @@ -344,27 +377,26 @@ func (a *IPPoolAllocator) AllocateNext(state v1alpha2.IPAddressPhase, owner v1al // It returns error if pool is exhausted, or in case it fails to update IPPool's state. In case of // success, IP pool status is updated with allocated IP/state/resource/container. // AllocateReservedOrNext returns subnet details for the requested IP, as defined in IP pool spec. -func (a *IPPoolAllocator) AllocateReservedOrNext(state v1alpha2.IPAddressPhase, owner v1alpha2.IPAddressOwner) (net.IP, v1alpha2.SubnetInfo, error) { - var subnetSpec v1alpha2.SubnetInfo - var ip net.IP - +func (a *IPPoolAllocator) AllocateReservedOrNext(state v1alpha2.IPAddressPhase, owner v1alpha2.IPAddressOwner) (net.IP, *v1alpha2.SubnetInfo, error) { ip, err := a.getReservedIP(owner) if err != nil { - return ip, subnetSpec, err + return nil, nil, err } if ip == nil { - // ip is not reserved, allocate next available ip + // IP is not reserved, allocate next available IP. return a.AllocateNext(state, owner) } - // Same resource can not ask for allocation twice without release - // This needs to be verified even at the expense of another API call - exists, err := a.HasContainer(owner.Pod.ContainerID) + var prevIP net.IP + var subnetSpec *v1alpha2.SubnetInfo + podOwner := owner.Pod + prevIP, subnetSpec, err = a.getExistingAllocation(podOwner) if err != nil { - return ip, subnetSpec, err + return nil, nil, err } - if exists { - return ip, subnetSpec, fmt.Errorf("container %s was already allocated an address from IP Pool %s", owner.Pod.ContainerID, a.ipPoolName) + if prevIP != nil { + klog.InfoS("Container already has an IP allocated", "container", podOwner.ContainerID, "interface", podOwner.IFName, "IPPool", a.ipPoolName) + return prevIP, subnetSpec, err } // Retry on CRD update conflict which is caused by multiple agents updating a pool at same time. @@ -384,15 +416,15 @@ func (a *IPPoolAllocator) AllocateReservedOrNext(state v1alpha2.IPAddressPhase, if index == -1 { // Failed to find matching range - return fmt.Errorf("IP %v does not belong to IP pool %s", ip, a.ipPoolName) + return fmt.Errorf("IP %v does not belong to IPPool %s", ip, a.ipPoolName) } - subnetSpec = ipPool.Spec.IPRanges[index].SubnetInfo + subnetSpec = &ipPool.Spec.IPRanges[index].SubnetInfo return a.updateIPAddressState(ipPool, ip, state, owner) }) if err != nil { - klog.ErrorS(err, "Failed to allocate IP address", "ip", ip, "ipPool", a.ipPoolName) + klog.ErrorS(err, "Failed to allocate IP address", "ip", ip, "IPPool", a.ipPoolName) } return ip, subnetSpec, err } @@ -458,37 +490,6 @@ func (a *IPPoolAllocator) Release(ip net.IP) error { return err } -// ReleasePod releases the IP associated with specified Pod. -// It returns error if the pod is not present in state or in case CRD failed to update state. -// In case of success, IP pool CRD status is updated with released entry. -func (a *IPPoolAllocator) ReleasePod(namespace, podName string) error { - - // Retry on CRD update conflict which is caused by multiple agents updating a pool at same time. - err := retry.RetryOnConflict(retry.DefaultRetry, func() error { - ipPool, err := a.getPool() - - if err != nil { - return err - } - - // Mark allocated IPs from pool status as unavailable - for _, ip := range ipPool.Status.IPAddresses { - if ip.Owner.Pod != nil && ip.Owner.Pod.Namespace == namespace && ip.Owner.Pod.Name == podName { - return a.removeIPAddressState(ipPool, net.ParseIP(ip.IPAddress)) - - } - } - - klog.V(4).InfoS("IP Pool state:", "name", a.ipPoolName, "allocation", ipPool.Status.IPAddresses) - return fmt.Errorf("failed to find record of IP allocated to Pod:%s/%s in pool %s", namespace, podName, a.ipPoolName) - }) - - if err != nil { - klog.ErrorS(err, "Failed to release IP address", "Namespace", namespace, "Pod", podName, "IPPool", a.ipPoolName) - } - return err -} - // ReleaseStatefulSet releases all IPs associated with specified StatefulSet. It returns error // in case CRD failed to update its state. // In case of success, IP pool CRD status is updated with released entries. @@ -534,42 +535,42 @@ func (a *IPPoolAllocator) ReleaseStatefulSet(namespace, name string) error { return err } -// ReleaseContainerIfPresent releases the IP associated with specified container ID if present in state. -// It returns error in case CRD failed to update its state, or if pool does not exist. -// In case of success, IP pool CRD status is updated with released entry. -func (a *IPPoolAllocator) ReleaseContainerIfPresent(containerID string) error { - +// ReleaseContainer releases the IP associated with the specified container ID and interface name, +// and updates the IPPool CR status. +// If no IP is allocated to the Pod according to the IPPool CR status, the func just returns with no +// change. +func (a *IPPoolAllocator) ReleaseContainer(containerID, ifName string) error { // Retry on CRD update conflict which is caused by multiple agents updating a pool at same time. err := retry.RetryOnConflict(retry.DefaultRetry, func() error { ipPool, err := a.getPool() - if err != nil { return err } - // Mark allocated IPs from pool status as unavailable + // Mark the released IPs as available in the IPPool status. for _, ip := range ipPool.Status.IPAddresses { - if ip.Owner.Pod != nil && ip.Owner.Pod.ContainerID == containerID { + savedOwner := ip.Owner.Pod + if savedOwner != nil && savedOwner.ContainerID == containerID && savedOwner.IFName == ifName { return a.removeIPAddressState(ipPool, net.ParseIP(ip.IPAddress)) } } - klog.V(4).InfoS("Failed to find allocation record in pool", "container", containerID, "pool", a.ipPoolName, "allocation", ipPool.Status.IPAddresses) + klog.V(4).InfoS("Did not find the allocation record in IPPool", + "container", containerID, "interface", ifName, "pool", a.ipPoolName, "allocation", ipPool.Status.IPAddresses) return nil }) if err != nil { - klog.ErrorS(err, "Failed to release IP address", "Container", containerID, "IPPool", a.ipPoolName) + klog.ErrorS(err, "Failed to release IP address", "Container", containerID, "interface", ifName, "IPPool", a.ipPoolName) } return err } -// HasResource checks whether an IP was associated with specified pod. It returns error if the resource is crd fails to be retrieved. -func (a *IPPoolAllocator) HasPod(namespace, podName string) (bool, error) { - +// hasPod checks whether an IP was associated with specified pod. It returns the error if fails to +// retrieve the IPPool CR. +func (a *IPPoolAllocator) hasPod(namespace, podName string) (bool, error) { ipPool, err := a.getPool() - if err != nil { return false, err } @@ -582,21 +583,19 @@ func (a *IPPoolAllocator) HasPod(namespace, podName string) (bool, error) { return false, nil } -// HasContainer checks whether an IP was associated with specified container. It returns error if the resource crd fails to be retrieved. -func (a *IPPoolAllocator) HasContainer(containerID string) (bool, error) { - +// GetContainerIP returns the IP allocated for the container interface if found. +func (a *IPPoolAllocator) GetContainerIP(containerID, ifName string) (net.IP, error) { ipPool, err := a.getPool() - if err != nil { - return false, err + return nil, err } for _, ip := range ipPool.Status.IPAddresses { - if ip.Owner.Pod != nil && ip.Owner.Pod.ContainerID == containerID { - return true, nil + if ip.Owner.Pod != nil && ip.Owner.Pod.ContainerID == containerID && ip.Owner.Pod.IFName == ifName { + return net.ParseIP(ip.IPAddress), nil } } - return false, nil + return nil, nil } // getReservedIP checks whether an IP was reserved with specified owner. It returns error if the resource crd fails to be retrieved. diff --git a/pkg/ipam/poolallocator/allocator_test.go b/pkg/ipam/poolallocator/allocator_test.go index 19119eb46f0..62725442756 100644 --- a/pkg/ipam/poolallocator/allocator_test.go +++ b/pkg/ipam/poolallocator/allocator_test.go @@ -31,6 +31,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/wait" "k8s.io/client-go/tools/cache" + "k8s.io/client-go/util/retry" "k8s.io/klog/v2" ) @@ -83,7 +84,7 @@ func validateAllocationSequence(t *testing.T, allocator *IPPoolAllocator, subnet ip, returnInfo, err := allocator.AllocateNext(crdv1a2.IPAddressPhaseAllocated, owner) require.NoError(t, err) assert.Equal(t, net.ParseIP(expectedIP), ip) - assert.Equal(t, subnetInfo, returnInfo) + assert.Equal(t, subnetInfo, *returnInfo) i += 1 } } @@ -115,11 +116,11 @@ func TestAllocateIP(t *testing.T) { // Allocate specific IP from the range returnInfo, err := allocator.AllocateIP(net.ParseIP("10.2.2.101"), crdv1a2.IPAddressPhaseAllocated, fakePodOwner) - assert.Equal(t, subnetInfo, returnInfo) + assert.Equal(t, subnetInfo, *returnInfo) require.NoError(t, err) // Validate IP outside the range is not allocated - returnInfo, err = allocator.AllocateIP(net.ParseIP("10.2.2.121"), crdv1a2.IPAddressPhaseAllocated, fakePodOwner) + _, err = allocator.AllocateIP(net.ParseIP("10.2.2.121"), crdv1a2.IPAddressPhaseAllocated, fakePodOwner) require.Error(t, err) // Make sure IP allocated above is not allocated again @@ -128,7 +129,6 @@ func TestAllocateIP(t *testing.T) { // Validate error is returned if IP is already allocated _, err = allocator.AllocateIP(net.ParseIP("10.2.2.102"), crdv1a2.IPAddressPhaseAllocated, fakePodOwner) require.Error(t, err) - } func TestAllocateNext(t *testing.T) { @@ -269,6 +269,34 @@ func TestAllocateReleaseSequence(t *testing.T) { validateAllocationSequence(t, allocator, subnetInfo, []string{"2001::1000", "2001::2", "2001::5"}) } +// releasePod releases the IP associated with the specified Pod, and updates the IPPool CR status. +// The func returns an error, if no IP is allocated to the Pod according to the IPPool CR status. +func (a *IPPoolAllocator) releasePod(namespace, podName string) error { + // Retry on CRD update conflict which is caused by multiple agents updating a pool at same time. + err := retry.RetryOnConflict(retry.DefaultRetry, func() error { + ipPool, err := a.getPool() + if err != nil { + return err + } + + // Mark allocated IPs from pool status as unavailable + for _, ip := range ipPool.Status.IPAddresses { + if ip.Owner.Pod != nil && ip.Owner.Pod.Namespace == namespace && ip.Owner.Pod.Name == podName { + return a.removeIPAddressState(ipPool, net.ParseIP(ip.IPAddress)) + + } + } + + klog.V(4).InfoS("IP Pool state:", "name", a.ipPoolName, "allocation", ipPool.Status.IPAddresses) + return fmt.Errorf("failed to find record of IP allocated to Pod:%s/%s in pool %s", namespace, podName, a.ipPoolName) + }) + + if err != nil { + klog.ErrorS(err, "Failed to release IP address", "Namespace", namespace, "Pod", podName, "IPPool", a.ipPoolName) + } + return err +} + func TestReleaseResource(t *testing.T) { stopCh := make(chan struct{}) defer close(stopCh) @@ -302,7 +330,7 @@ func TestReleaseResource(t *testing.T) { // Release first IP from first range and middle IP from second range for _, podName := range []string{"fakePod2", "fakePod4"} { - err := allocator.ReleasePod(testNamespace, podName) + err := allocator.releasePod(testNamespace, podName) require.NoError(t, err) } @@ -318,6 +346,7 @@ func TestHas(t *testing.T) { Name: "fakePod", Namespace: testNamespace, ContainerID: "fakeContainer", + IFName: "eth1", }, } poolName := uuid.New().String() @@ -344,20 +373,24 @@ func TestHas(t *testing.T) { _, _, err := allocator.AllocateNext(crdv1a2.IPAddressPhaseAllocated, owner) require.NoError(t, err) err = wait.PollImmediate(100*time.Millisecond, 1*time.Second, func() (bool, error) { - has, _ := allocator.HasPod(testNamespace, "fakePod") + has, _ := allocator.hasPod(testNamespace, "fakePod") return has, nil }) require.NoError(t, err) - has, err := allocator.HasPod(testNamespace, "realPod") + has, err := allocator.hasPod(testNamespace, "realPod") require.NoError(t, err) assert.False(t, has) - has, err = allocator.HasContainer("fakeContainer") + var ip net.IP + ip, err = allocator.GetContainerIP("fakeContainer", "eth1") require.NoError(t, err) - assert.True(t, has) - has, err = allocator.HasContainer("realContainer") + assert.NotNil(t, ip) + ip, err = allocator.GetContainerIP("fakeContainer", "") require.NoError(t, err) - assert.False(t, has) + assert.Nil(t, ip) + ip, err = allocator.GetContainerIP("realContainer", "eth1") + require.NoError(t, err) + assert.Nil(t, ip) } func TestAllocateReleaseStatefulSet(t *testing.T) { diff --git a/pkg/log/log.go b/pkg/log/log.go new file mode 100644 index 00000000000..39fba3a8c77 --- /dev/null +++ b/pkg/log/log.go @@ -0,0 +1,83 @@ +// Copyright 2022 Antrea Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package log processes the klog flags, and enforces the maximum log file +// size and maximum log file number limits. +package log + +import ( + "flag" + "time" + + "github.com/spf13/pflag" + "k8s.io/klog/v2" +) + +const ( + logFlushFreqFlag = "log-flush-frequency" +) + +var ( + klogFlags = flag.NewFlagSet("logging", flag.ContinueOnError) + + logFlushFreq time.Duration +) + +func init() { + klog.InitFlags(klogFlags) +} + +func addKlogFlags(fs *pflag.FlagSet) { + klogFlags.VisitAll(func(f *flag.Flag) { + pf := pflag.PFlagFromGoFlag(f) + fs.AddFlag(pf) + }) +} + +func AddFlags(fs *pflag.FlagSet) { + addKlogFlags(fs) + fs.Uint16Var(&maxNumArg, maxNumFlag, maxNumArg, "Maximum number of log files per severity level to be kept. Value 0 means unlimited.") + fs.DurationVar(&logFlushFreq, logFlushFreqFlag, 5*time.Second, "Maximum number of seconds between log flushes") +} + +type Options struct { + withFlushDaemon bool +} + +func WithoutFlushDaemon(options *Options) { + options.withFlushDaemon = false +} + +func initKlog(options *Options) { + if options.withFlushDaemon { + klog.StartFlushDaemon(logFlushFreq) + } + klog.EnableContextualLogging(false) +} + +func InitLogs(fs *pflag.FlagSet, opts ...func(options *Options)) { + options := Options{ + withFlushDaemon: true, + } + for _, opt := range opts { + opt(&options) + } + initKlog(&options) + initLogFileLimits(fs) + initLogLevelManager(fs) +} + +func FlushLogs() { + klog.Flush() +} diff --git a/pkg/log/log_file.go b/pkg/log/log_file.go index e8e066f45c7..f9f58f0c6e1 100644 --- a/pkg/log/log_file.go +++ b/pkg/log/log_file.go @@ -12,8 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Package log processes the klog flags, and enforces the maximum log file -// size and maximum log file number limits. package log import ( @@ -50,13 +48,9 @@ var ( executableName = filepath.Base(os.Args[0]) ) -func AddFlags(fs *pflag.FlagSet) { - fs.Uint16Var(&maxNumArg, maxNumFlag, maxNumArg, "Maximum number of log files per severity level to be kept. Value 0 means unlimited.") -} - -// InitLogFileLimits initializes log file maximum size and maximum number limits based on the +// initLogFileLimits initializes log file maximum size and maximum number limits based on the // command line flags. -func InitLogFileLimits(fs *pflag.FlagSet) { +func initLogFileLimits(fs *pflag.FlagSet) { var err error var logToStdErr bool var logFile string diff --git a/pkg/log/log_file_test.go b/pkg/log/log_file_test.go index f86042db8cb..cac0a5785d3 100644 --- a/pkg/log/log_file_test.go +++ b/pkg/log/log_file_test.go @@ -15,7 +15,6 @@ package log import ( - "flag" "fmt" "io/ioutil" "os" @@ -26,30 +25,34 @@ import ( "github.com/spf13/pflag" "github.com/stretchr/testify/assert" - "k8s.io/component-base/logs" "k8s.io/klog/v2" ) const oneMB = 1 * 1024 * 1024 var ( - testFlags = initFlags() klogDefaultMaxSize = klog.MaxSize ) -func initFlags() *pflag.FlagSet { +func getTestFlags() *pflag.FlagSet { flags := pflag.NewFlagSet("test", pflag.ContinueOnError) AddFlags(flags) - flags.AddGoFlagSet(flag.CommandLine) return flags } func restoreFlagDefaultValues() { - testFlags.Set(logToStdErrFlag, "true") - testFlags.Set(logFileFlag, "") - testFlags.Set(logDirFlag, "") - testFlags.Set(maxSizeFlag, fmt.Sprintf("%d", klogDefaultMaxSize/oneMB)) - testFlags.Set(maxNumFlag, "0") + // The flag values are stored as global variables in klog and the + // initial values for the global variables are used as the flag default + // values. As a consequence, simply re-initializing the klog flags is + // not enough, as the default values are no longer the same after the + // first call to Parse. We need to explicitly set the flags to the known + // default values, which will in turn reset the corresponding klog + // global variables. + klogFlags.Set(logToStdErrFlag, "true") + klogFlags.Set(logFileFlag, "") + klogFlags.Set(logDirFlag, "") + klogFlags.Set(maxSizeFlag, fmt.Sprintf("%d", klogDefaultMaxSize/oneMB)) + klogFlags.Set(maxNumFlag, "0") klog.MaxSize = klogDefaultMaxSize logFileMaxNum = 0 @@ -68,7 +71,7 @@ func testLogging() { klog.Infof("%d: %s", i, string(line)) klog.Warningf("%d: %s", i, string(line)) } - logs.FlushLogs() + FlushLogs() } func TestKlogFileLimits(t *testing.T) { @@ -82,9 +85,9 @@ func TestKlogFileLimits(t *testing.T) { testMaxNum := 2 args := []string{"--logtostderr=false", "--log_dir=" + testLogDir, "--log_file_max_size=1", fmt.Sprintf("--log_file_max_num=%d", testMaxNum)} + testFlags := getTestFlags() testFlags.Parse(args) - InitLogFileLimits(testFlags) - logs.InitLogs() + InitLogs(testFlags) defer restoreFlagDefaultValues() // Should generate about 5 log files (100K * 40 / 1M), though it is hard @@ -187,8 +190,9 @@ func TestFlags(t *testing.T) { } for _, test := range testcases { + testFlags := getTestFlags() testFlags.Parse(test.args) - InitLogFileLimits(testFlags) + InitLogs(testFlags) assert.Equal(t, test.maxSize, klog.MaxSize, test.name) assert.Equal(t, test.maxNum, logFileMaxNum, test.name) assert.Equal(t, test.logDir, logDir, test.name) diff --git a/pkg/log/log_level.go b/pkg/log/log_level.go index e81dca538d7..0f8eafce6b7 100644 --- a/pkg/log/log_level.go +++ b/pkg/log/log_level.go @@ -15,22 +15,33 @@ package log import ( - "flag" + "fmt" + "github.com/spf13/pflag" "k8s.io/klog/v2" ) const logVerbosityFlag = "v" -// GetCurrentLogLevel returns the current log verbosity level. -func GetCurrentLogLevel() string { - return flag.Lookup(logVerbosityFlag).Value.String() +type logLevelManager struct { + // we use this to access the verbosity value at runtime + flag *pflag.Flag } -// SetLogLevel sets the log verbosity level. level must be a string -// representation of a decimal integer. -func SetLogLevel(level string) error { - oldLevel := GetCurrentLogLevel() +var logLevelMgr = &logLevelManager{} + +func (m *logLevelManager) getCurrentLogLevel() string { + if m.flag == nil { + return "UNKNOWN" + } + return m.flag.Value.String() +} + +func (m *logLevelManager) setLogLevel(level string) error { + if m.flag == nil { + return fmt.Errorf("verbosity flag is unknown") + } + oldLevel := m.getCurrentLogLevel() if oldLevel == level { return nil } @@ -40,7 +51,26 @@ func SetLogLevel(level string) error { if err != nil { return err } - klog.Infof("Changed log level from %s to %s", oldLevel, level) + klog.InfoS("Changed log level", "from", oldLevel, "to", level) return nil } + +func initLogLevelManager(fs *pflag.FlagSet) { + flag := fs.Lookup(logVerbosityFlag) + if flag == nil { + klog.ErrorS(nil, "Failed to lookup verbosity flag", "flag", logVerbosityFlag) + } + logLevelMgr.flag = flag +} + +// GetCurrentLogLevel returns the current log verbosity level. +func GetCurrentLogLevel() string { + return logLevelMgr.getCurrentLogLevel() +} + +// SetLogLevel sets the log verbosity level. level must be a string +// representation of a decimal integer. +func SetLogLevel(level string) error { + return logLevelMgr.setLogLevel(level) +} diff --git a/pkg/ovs/openflow/interfaces.go b/pkg/ovs/openflow/interfaces.go index b6511edc0be..74e362e69b0 100644 --- a/pkg/ovs/openflow/interfaces.go +++ b/pkg/ovs/openflow/interfaces.go @@ -94,6 +94,7 @@ type Bridge interface { CreateTable(table Table, next uint8, missAction MissActionType) Table // AddTable adds table on the Bridge. Return true if the operation succeeds, otherwise return false. DeleteTable(id uint8) bool + CreateGroupTypeAll(id GroupIDType) Group CreateGroup(id GroupIDType) Group DeleteGroup(id GroupIDType) bool CreateMeter(id MeterIDType, flags ofctrl.MeterFlag) Meter @@ -203,7 +204,7 @@ type Flow interface { type Action interface { LoadARPOperation(value uint16) FlowBuilder LoadToRegField(field *RegField, value uint32) FlowBuilder - LoadRegMark(mark *RegMark) FlowBuilder + LoadRegMark(marks ...*RegMark) FlowBuilder LoadPktMarkRange(value uint32, to *Range) FlowBuilder LoadIPDSCP(value uint8) FlowBuilder LoadRange(name string, addr uint64, to *Range) FlowBuilder @@ -247,7 +248,7 @@ type FlowBuilder interface { MatchProtocol(name Protocol) FlowBuilder MatchIPProtocolValue(isIPv6 bool, protoValue uint8) FlowBuilder MatchXXReg(regID int, data []byte) FlowBuilder - MatchRegMark(mark *RegMark) FlowBuilder + MatchRegMark(marks ...*RegMark) FlowBuilder MatchRegFieldWithValue(field *RegField, data uint32) FlowBuilder MatchInPort(inPort uint32) FlowBuilder MatchDstIP(ip net.IP) FlowBuilder @@ -270,12 +271,14 @@ type FlowBuilder interface { MatchCTStateInv(isSet bool) FlowBuilder MatchCTStateDNAT(isSet bool) FlowBuilder MatchCTStateSNAT(isSet bool) FlowBuilder - MatchCTMark(mark *CtMark) FlowBuilder + MatchCTMark(marks ...*CtMark) FlowBuilder MatchCTLabelField(high, low uint64, field *CtLabel) FlowBuilder MatchPktMark(value uint32, mask *uint32) FlowBuilder MatchConjID(value uint32) FlowBuilder MatchDstPort(port uint16, portMask *uint16) FlowBuilder MatchSrcPort(port uint16, portMask *uint16) FlowBuilder + MatchICMPType(icmpType byte) FlowBuilder + MatchICMPCode(icmpCode byte) FlowBuilder MatchICMPv6Type(icmp6Type byte) FlowBuilder MatchICMPv6Code(icmp6Code byte) FlowBuilder MatchTunnelDst(dstIP net.IP) FlowBuilder @@ -359,7 +362,7 @@ type MeterBandBuilder interface { type CTAction interface { LoadToMark(value uint32) CTAction - LoadToCtMark(mark *CtMark) CTAction + LoadToCtMark(marks ...*CtMark) CTAction LoadToLabelField(value uint64, labelField *CtLabel) CTAction MoveToLabel(fromName string, fromRng, labelRng *Range) CTAction MoveToCtMarkField(fromRegField *RegField, ctMark *CtMarkField) CTAction diff --git a/pkg/ovs/openflow/ofctrl_action.go b/pkg/ovs/openflow/ofctrl_action.go index 45a69f46d8a..889796fae21 100644 --- a/pkg/ovs/openflow/ofctrl_action.go +++ b/pkg/ovs/openflow/ofctrl_action.go @@ -94,9 +94,11 @@ func (a *ofCTAction) LoadToMark(value uint32) CTAction { return a } -func (a *ofCTAction) LoadToCtMark(mark *CtMark) CTAction { +func (a *ofCTAction) LoadToCtMark(marks ...*CtMark) CTAction { field, _, _ := getFieldRange(NxmFieldCtMark) - a.load(field, uint64(mark.value), mark.field.rng) + for _, mark := range marks { + a.load(field, uint64(mark.value), mark.field.rng) + } return a } @@ -292,8 +294,13 @@ func (a *ofFlowAction) LoadToRegField(field *RegField, value uint32) FlowBuilder return a.builder } -func (a *ofFlowAction) LoadRegMark(mark *RegMark) FlowBuilder { - return a.LoadToRegField(mark.field, mark.value) +func (a *ofFlowAction) LoadRegMark(marks ...*RegMark) FlowBuilder { + var fb FlowBuilder + fb = a.builder + for _, mark := range marks { + fb = a.LoadToRegField(mark.field, mark.value) + } + return fb } // LoadToPktMarkRange is an action to load data into pkt_mark at specified range. diff --git a/pkg/ovs/openflow/ofctrl_bridge.go b/pkg/ovs/openflow/ofctrl_bridge.go index c1b5e11dffb..e5b2b886cfc 100644 --- a/pkg/ovs/openflow/ofctrl_bridge.go +++ b/pkg/ovs/openflow/ofctrl_bridge.go @@ -189,8 +189,16 @@ type OFBridge struct { multipartReplyChs map[uint32]chan *openflow13.MultipartReply } +func (b *OFBridge) CreateGroupTypeAll(id GroupIDType) Group { + return b.createGroupWithType(id, ofctrl.GroupAll) +} + func (b *OFBridge) CreateGroup(id GroupIDType) Group { - ofctrlGroup, err := b.ofSwitch.NewGroup(uint32(id), ofctrl.GroupSelect) + return b.createGroupWithType(id, ofctrl.GroupSelect) +} + +func (b *OFBridge) createGroupWithType(id GroupIDType, groupType ofctrl.GroupType) Group { + ofctrlGroup, err := b.ofSwitch.NewGroup(uint32(id), groupType) if err != nil { // group already exists ofctrlGroup = b.ofSwitch.GetGroup(uint32(id)) } diff --git a/pkg/ovs/openflow/ofctrl_builder.go b/pkg/ovs/openflow/ofctrl_builder.go index e072fadec87..b6b36f52dff 100644 --- a/pkg/ovs/openflow/ofctrl_builder.go +++ b/pkg/ovs/openflow/ofctrl_builder.go @@ -107,8 +107,13 @@ func (b *ofFlowBuilder) matchRegRange(regID int, data uint32, rng *Range) FlowBu return b } -func (b *ofFlowBuilder) MatchRegMark(mark *RegMark) FlowBuilder { - return b.MatchRegFieldWithValue(mark.field, mark.value) +func (b *ofFlowBuilder) MatchRegMark(marks ...*RegMark) FlowBuilder { + var fb FlowBuilder + fb = b + for _, mark := range marks { + fb = b.MatchRegFieldWithValue(mark.field, mark.value) + } + return fb } func (b *ofFlowBuilder) MatchRegFieldWithValue(field *RegField, data uint32) FlowBuilder { @@ -238,17 +243,18 @@ func (b *ofFlowBuilder) MatchCTStateSNAT(set bool) FlowBuilder { return b } -func (b *ofFlowBuilder) MatchCTMark(mark *CtMark) FlowBuilder { - var ctmarkKey string - b.ofFlow.Match.CtMark = mark.GetValue() - if mark.isFullRange() { - b.ofFlow.Match.CtMarkMask = nil - ctmarkKey = fmt.Sprintf("ct_mark=0x%x", mark.value) - } else { - mask := mark.field.rng.ToNXRange().ToUint32Mask() - ctmarkKey = fmt.Sprintf("ct_mark=0x%x/0x%x", mark.GetValue(), mask) - b.ofFlow.Match.CtMarkMask = &mask +func (b *ofFlowBuilder) MatchCTMark(marks ...*CtMark) FlowBuilder { + if len(marks) == 0 { + return b } + var value, mask uint32 + for _, mark := range marks { + value |= mark.GetValue() + mask |= mark.field.rng.ToNXRange().ToUint32Mask() + } + b.ofFlow.Match.CtMark = value + b.ofFlow.Match.CtMarkMask = &mask + ctmarkKey := fmt.Sprintf("ct_mark=0x%x/0x%x", value, mask) b.matchers = append(b.matchers, ctmarkKey) return b } @@ -352,14 +358,26 @@ func (b *ofFlowBuilder) MatchDstIPNet(ipnet net.IPNet) FlowBuilder { return b } +func (b *ofFlowBuilder) MatchICMPType(icmpType byte) FlowBuilder { + b.matchers = append(b.matchers, fmt.Sprintf("icmp_type=%d", icmpType)) + b.Match.Icmp4Type = &icmpType + return b +} + +func (b *ofFlowBuilder) MatchICMPCode(icmpCode byte) FlowBuilder { + b.matchers = append(b.matchers, fmt.Sprintf("icmp_code=%d", icmpCode)) + b.Match.Icmp4Code = &icmpCode + return b +} + func (b *ofFlowBuilder) MatchICMPv6Type(icmp6Type byte) FlowBuilder { - b.matchers = append(b.matchers, fmt.Sprintf("icmp_type=%d", icmp6Type)) + b.matchers = append(b.matchers, fmt.Sprintf("icmpv6_type=%d", icmp6Type)) b.Match.Icmp6Type = &icmp6Type return b } func (b *ofFlowBuilder) MatchICMPv6Code(icmp6Code byte) FlowBuilder { - b.matchers = append(b.matchers, fmt.Sprintf("icmp_code=%d", icmp6Code)) + b.matchers = append(b.matchers, fmt.Sprintf("icmpv6_code=%d", icmp6Code)) b.Match.Icmp6Code = &icmp6Code return b } diff --git a/pkg/ovs/openflow/testing/mock_openflow.go b/pkg/ovs/openflow/testing/mock_openflow.go index f79cafa2cb9..45a1e3f474c 100644 --- a/pkg/ovs/openflow/testing/mock_openflow.go +++ b/pkg/ovs/openflow/testing/mock_openflow.go @@ -134,6 +134,20 @@ func (mr *MockBridgeMockRecorder) CreateGroup(arg0 interface{}) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateGroup", reflect.TypeOf((*MockBridge)(nil).CreateGroup), arg0) } +// CreateGroupTypeAll mocks base method +func (m *MockBridge) CreateGroupTypeAll(arg0 openflow.GroupIDType) openflow.Group { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CreateGroupTypeAll", arg0) + ret0, _ := ret[0].(openflow.Group) + return ret0 +} + +// CreateGroupTypeAll indicates an expected call of CreateGroupTypeAll +func (mr *MockBridgeMockRecorder) CreateGroupTypeAll(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateGroupTypeAll", reflect.TypeOf((*MockBridge)(nil).CreateGroupTypeAll), arg0) +} + // CreateMeter mocks base method func (m *MockBridge) CreateMeter(arg0 openflow.MeterIDType, arg1 ofctrl.MeterFlag) openflow.Meter { m.ctrl.T.Helper() @@ -844,17 +858,21 @@ func (mr *MockActionMockRecorder) LoadRange(arg0, arg1, arg2 interface{}) *gomoc } // LoadRegMark mocks base method -func (m *MockAction) LoadRegMark(arg0 *openflow.RegMark) openflow.FlowBuilder { +func (m *MockAction) LoadRegMark(arg0 ...*openflow.RegMark) openflow.FlowBuilder { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "LoadRegMark", arg0) + varargs := []interface{}{} + for _, a := range arg0 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "LoadRegMark", varargs...) ret0, _ := ret[0].(openflow.FlowBuilder) return ret0 } // LoadRegMark indicates an expected call of LoadRegMark -func (mr *MockActionMockRecorder) LoadRegMark(arg0 interface{}) *gomock.Call { +func (mr *MockActionMockRecorder) LoadRegMark(arg0 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LoadRegMark", reflect.TypeOf((*MockAction)(nil).LoadRegMark), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LoadRegMark", reflect.TypeOf((*MockAction)(nil).LoadRegMark), arg0...) } // LoadToRegField mocks base method @@ -1277,17 +1295,21 @@ func (mr *MockCTActionMockRecorder) DNAT(arg0, arg1 interface{}) *gomock.Call { } // LoadToCtMark mocks base method -func (m *MockCTAction) LoadToCtMark(arg0 *openflow.CtMark) openflow.CTAction { +func (m *MockCTAction) LoadToCtMark(arg0 ...*openflow.CtMark) openflow.CTAction { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "LoadToCtMark", arg0) + varargs := []interface{}{} + for _, a := range arg0 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "LoadToCtMark", varargs...) ret0, _ := ret[0].(openflow.CTAction) return ret0 } // LoadToCtMark indicates an expected call of LoadToCtMark -func (mr *MockCTActionMockRecorder) LoadToCtMark(arg0 interface{}) *gomock.Call { +func (mr *MockCTActionMockRecorder) LoadToCtMark(arg0 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LoadToCtMark", reflect.TypeOf((*MockCTAction)(nil).LoadToCtMark), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LoadToCtMark", reflect.TypeOf((*MockCTAction)(nil).LoadToCtMark), arg0...) } // LoadToLabelField mocks base method @@ -1566,17 +1588,21 @@ func (mr *MockFlowBuilderMockRecorder) MatchCTLabelField(arg0, arg1, arg2 interf } // MatchCTMark mocks base method -func (m *MockFlowBuilder) MatchCTMark(arg0 *openflow.CtMark) openflow.FlowBuilder { +func (m *MockFlowBuilder) MatchCTMark(arg0 ...*openflow.CtMark) openflow.FlowBuilder { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "MatchCTMark", arg0) + varargs := []interface{}{} + for _, a := range arg0 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "MatchCTMark", varargs...) ret0, _ := ret[0].(openflow.FlowBuilder) return ret0 } // MatchCTMark indicates an expected call of MatchCTMark -func (mr *MockFlowBuilderMockRecorder) MatchCTMark(arg0 interface{}) *gomock.Call { +func (mr *MockFlowBuilderMockRecorder) MatchCTMark(arg0 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MatchCTMark", reflect.TypeOf((*MockFlowBuilder)(nil).MatchCTMark), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MatchCTMark", reflect.TypeOf((*MockFlowBuilder)(nil).MatchCTMark), arg0...) } // MatchCTProtocol mocks base method @@ -1817,6 +1843,34 @@ func (mr *MockFlowBuilderMockRecorder) MatchDstPort(arg0, arg1 interface{}) *gom return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MatchDstPort", reflect.TypeOf((*MockFlowBuilder)(nil).MatchDstPort), arg0, arg1) } +// MatchICMPCode mocks base method +func (m *MockFlowBuilder) MatchICMPCode(arg0 byte) openflow.FlowBuilder { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "MatchICMPCode", arg0) + ret0, _ := ret[0].(openflow.FlowBuilder) + return ret0 +} + +// MatchICMPCode indicates an expected call of MatchICMPCode +func (mr *MockFlowBuilderMockRecorder) MatchICMPCode(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MatchICMPCode", reflect.TypeOf((*MockFlowBuilder)(nil).MatchICMPCode), arg0) +} + +// MatchICMPType mocks base method +func (m *MockFlowBuilder) MatchICMPType(arg0 byte) openflow.FlowBuilder { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "MatchICMPType", arg0) + ret0, _ := ret[0].(openflow.FlowBuilder) + return ret0 +} + +// MatchICMPType indicates an expected call of MatchICMPType +func (mr *MockFlowBuilderMockRecorder) MatchICMPType(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MatchICMPType", reflect.TypeOf((*MockFlowBuilder)(nil).MatchICMPType), arg0) +} + // MatchICMPv6Code mocks base method func (m *MockFlowBuilder) MatchICMPv6Code(arg0 byte) openflow.FlowBuilder { m.ctrl.T.Helper() @@ -1944,17 +1998,21 @@ func (mr *MockFlowBuilderMockRecorder) MatchRegFieldWithValue(arg0, arg1 interfa } // MatchRegMark mocks base method -func (m *MockFlowBuilder) MatchRegMark(arg0 *openflow.RegMark) openflow.FlowBuilder { +func (m *MockFlowBuilder) MatchRegMark(arg0 ...*openflow.RegMark) openflow.FlowBuilder { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "MatchRegMark", arg0) + varargs := []interface{}{} + for _, a := range arg0 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "MatchRegMark", varargs...) ret0, _ := ret[0].(openflow.FlowBuilder) return ret0 } // MatchRegMark indicates an expected call of MatchRegMark -func (mr *MockFlowBuilderMockRecorder) MatchRegMark(arg0 interface{}) *gomock.Call { +func (mr *MockFlowBuilderMockRecorder) MatchRegMark(arg0 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MatchRegMark", reflect.TypeOf((*MockFlowBuilder)(nil).MatchRegMark), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MatchRegMark", reflect.TypeOf((*MockFlowBuilder)(nil).MatchRegMark), arg0...) } // MatchSrcIP mocks base method diff --git a/pkg/querier/querier.go b/pkg/querier/querier.go index 29b9ebb3fad..19de222def5 100644 --- a/pkg/querier/querier.go +++ b/pkg/querier/querier.go @@ -90,3 +90,19 @@ type NetworkPolicyQueryFilter struct { // The type of the original NetworkPolicy that the internal NetworkPolicy is created for.(K8sNP, CNP, ANP) SourceType cpv1beta.NetworkPolicyType } + +// ServiceExternalIPStatusQuerier queries the Service external IP status for debugging purposes. +// Ideally, every Node should have consistent results eventually. This should only be used when +// ServiceExternalIP feature is enabled. +type ServiceExternalIPStatusQuerier interface { + GetServiceExternalIPStatus() []ServiceExternalIPInfo +} + +// ServiceExternalIPInfo contains the essential information for Services with type of Loadbalancer managed by Antrea. +type ServiceExternalIPInfo struct { + ServiceName string `json:"serviceName,omitempty" antctl:"name,Name of the Service"` + Namespace string `json:"namespace,omitempty"` + ExternalIP string `json:"externalIP,omitempty"` + ExternalIPPool string `json:"externalIPPool,omitempty"` + AssignedNode string `json:"assignedNode,omitempty"` +} diff --git a/pkg/util/channel/channel.go b/pkg/util/channel/channel.go index b10e9b4d4f3..019eee536d1 100644 --- a/pkg/util/channel/channel.go +++ b/pkg/util/channel/channel.go @@ -25,7 +25,7 @@ const ( notifyTimeout = time.Second ) -type eventHandler func(string) +type eventHandler func(interface{}) type Subscriber interface { // Subscribe registers an eventHandler which will be called when an event is sent to the channel. @@ -37,7 +37,7 @@ type Subscriber interface { type Notifier interface { // Notify sends an event to the channel. - Notify(string) bool + Notify(interface{}) bool } // SubscribableChannel is different from the Go channel which dispatches every event to only single consumer regardless @@ -47,7 +47,7 @@ type SubscribableChannel struct { // The name of the channel, used for logging purpose to differentiate multiple channels. name string // eventCh is the channel used for buffering the pending events. - eventCh chan string + eventCh chan interface{} // handlers is a slice of callbacks registered by consumers. handlers []eventHandler } @@ -55,7 +55,7 @@ type SubscribableChannel struct { func NewSubscribableChannel(name string, bufferSize int) *SubscribableChannel { n := &SubscribableChannel{ name: name, - eventCh: make(chan string, bufferSize), + eventCh: make(chan interface{}, bufferSize), } return n } @@ -64,7 +64,7 @@ func (n *SubscribableChannel) Subscribe(h eventHandler) { n.handlers = append(n.handlers, h) } -func (n *SubscribableChannel) Notify(e string) bool { +func (n *SubscribableChannel) Notify(e interface{}) bool { timer := time.NewTimer(notifyTimeout) defer timer.Stop() select { diff --git a/pkg/util/channel/channel_test.go b/pkg/util/channel/channel_test.go index 2eee503f71f..e848bd0194a 100644 --- a/pkg/util/channel/channel_test.go +++ b/pkg/util/channel/channel_test.go @@ -36,10 +36,10 @@ func newEventReceiver() *eventReceiver { } } -func (r *eventReceiver) receive(e string) { +func (r *eventReceiver) receive(e interface{}) { r.mutex.Lock() defer r.mutex.Unlock() - r.receivedEvents.Insert(e) + r.receivedEvents.Insert(e.(string)) } func (r *eventReceiver) received() sets.String { diff --git a/pkg/util/logdir/logdir_windows.go b/pkg/util/logdir/logdir_windows.go index 341b8ff8300..2b4003c05b9 100644 --- a/pkg/util/logdir/logdir_windows.go +++ b/pkg/util/logdir/logdir_windows.go @@ -17,4 +17,4 @@ package logdir -const antreaWellKnownLogDir = `C:\k\antrea\logs` +const antreaWellKnownLogDir = `C:\var\log\antrea` diff --git a/plugins/flow-visibility/clickhouse-monitor/go.mod b/plugins/flow-visibility/clickhouse-monitor/go.mod index 0204c59c963..f3dd5d76ad2 100644 --- a/plugins/flow-visibility/clickhouse-monitor/go.mod +++ b/plugins/flow-visibility/clickhouse-monitor/go.mod @@ -11,5 +11,7 @@ require ( require ( github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58 // indirect github.com/go-logr/logr v1.2.0 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + gopkg.in/inf.v0 v0.9.1 // indirect k8s.io/utils v0.0.0-20211116205334-6203023598ed // indirect ) diff --git a/plugins/flow-visibility/clickhouse-monitor/go.sum b/plugins/flow-visibility/clickhouse-monitor/go.sum index 60371aec430..d187dd50ae0 100644 --- a/plugins/flow-visibility/clickhouse-monitor/go.sum +++ b/plugins/flow-visibility/clickhouse-monitor/go.sum @@ -35,6 +35,7 @@ github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34 github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= @@ -55,6 +56,7 @@ github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU= @@ -100,6 +102,7 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -202,6 +205,7 @@ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/plugins/flow-visibility/clickhouse-monitor/main.go b/plugins/flow-visibility/clickhouse-monitor/main.go index cc1f6c61e46..4e779c3b9ec 100644 --- a/plugins/flow-visibility/clickhouse-monitor/main.go +++ b/plugins/flow-visibility/clickhouse-monitor/main.go @@ -22,6 +22,7 @@ import ( "time" "github.com/ClickHouse/clickhouse-go" + "k8s.io/apimachinery/pkg/api/resource" "k8s.io/apimachinery/pkg/util/wait" "k8s.io/klog/v2" ) @@ -48,6 +49,8 @@ const ( ) var ( + // Storage size allocated for the ClickHouse in number of bytes + allocatedSpace uint64 // The name of the table to store the flow records tableName = os.Getenv("TABLE_NAME") // The names of the materialized views @@ -58,16 +61,26 @@ var ( func main() { // Check environment variables - if len(tableName) == 0 || len(mvNames) == 0 { - klog.ErrorS(nil, "Unable to load environment variables, TABLE_NAME and MV_NAMES must be defined") + allocatedSpaceStr := os.Getenv("STORAGE_SIZE") + + if len(tableName) == 0 || len(mvNames) == 0 || len(allocatedSpaceStr) == 0 { + klog.ErrorS(nil, "Unable to load environment variables, TABLE_NAME, MV_NAMES and STORAGE_SIZE must be defined") + return + } + var err error + quantity, err := resource.ParseQuantity(allocatedSpaceStr) + if err != nil { + klog.ErrorS(err, "Error when parsing STORAGE_SIZE") return } + allocatedSpace = uint64(quantity.Value()) connect, err := connectLoop() if err != nil { klog.ErrorS(err, "Error when connecting to ClickHouse") os.Exit(1) } + checkStorageCondition(connect) wait.Forever(func() { // The monitor stops working for several rounds after a deletion // as the release of memory space by the ClickHouse MergeTree engine requires time @@ -118,28 +131,69 @@ func connectLoop() (*sql.DB, error) { return connect, nil } -// Checks the memory usage in the ClickHouse, and deletes records when it exceeds the threshold. -func monitorMemory(connect *sql.DB) { +// Check if ClickHouse shares storage space with other software +func checkStorageCondition(connect *sql.DB) { var ( freeSpace uint64 + usedSpace uint64 totalSpace uint64 ) - // Get memory usage from ClickHouse system table + getDiskUsage(connect, &freeSpace, &totalSpace) + getClickHouseUsage(connect, &usedSpace) + availablePercentage := float64(freeSpace+usedSpace) / float64(totalSpace) + klog.InfoS("Low available percentage implies ClickHouse does not save data on a dedicated disk", "availablePercentage", availablePercentage) +} + +func getDiskUsage(connect *sql.DB, freeSpace *uint64, totalSpace *uint64) { + // Get free space from ClickHouse system table + if err := wait.PollImmediate(queryRetryInterval, queryTimeout, func() (bool, error) { + if err := connect.QueryRow("SELECT free_space, total_space FROM system.disks").Scan(freeSpace, totalSpace); err != nil { + klog.ErrorS(err, "Failed to get the disk usage") + return false, nil + } else { + return true, nil + } + }); err != nil { + klog.ErrorS(err, "Failed to get the disk usage", "timeout", queryTimeout) + return + } +} + +func getClickHouseUsage(connect *sql.DB, usedSpace *uint64) { + // Get space usage from ClickHouse system table if err := wait.PollImmediate(queryRetryInterval, queryTimeout, func() (bool, error) { - if err := connect.QueryRow("SELECT free_space, total_space FROM system.disks").Scan(&freeSpace, &totalSpace); err != nil { - klog.ErrorS(err, "Failed to get memory usage for ClickHouse") + if err := connect.QueryRow("SELECT SUM(bytes) FROM system.parts").Scan(usedSpace); err != nil { + klog.ErrorS(err, "Failed to get the used space size by the ClickHouse") return false, nil } else { return true, nil } }); err != nil { - klog.ErrorS(err, "Failed to get memory usage for ClickHouse", "timeout", queryTimeout) + klog.ErrorS(err, "Failed to get the used space size by the ClickHouse", "timeout", queryTimeout) return } +} + +// Checks the memory usage in the ClickHouse, and deletes records when it exceeds the threshold. +func monitorMemory(connect *sql.DB) { + var ( + freeSpace uint64 + usedSpace uint64 + totalSpace uint64 + ) + getDiskUsage(connect, &freeSpace, &totalSpace) + getClickHouseUsage(connect, &usedSpace) + + // Total space for ClickHouse is the smaller one of the user allocated space size and the actual space size on the disk + if (freeSpace + usedSpace) < allocatedSpace { + totalSpace = freeSpace + usedSpace + } else { + totalSpace = allocatedSpace + } // Calculate the memory usage - usagePercentage := float64(totalSpace-freeSpace) / float64(totalSpace) - klog.InfoS("Memory usage", "total", totalSpace, "used", totalSpace-freeSpace, "percentage", usagePercentage) + usagePercentage := float64(usedSpace) / float64(totalSpace) + klog.InfoS("Memory usage", "total", totalSpace, "used", usedSpace, "percentage", usagePercentage) // Delete records when memory usage is larger than threshold if usagePercentage > threshold { timeBoundary, err := getTimeBoundary(connect) diff --git a/plugins/octant/cmd/antrea-octant-plugin/traceflow.go b/plugins/octant/cmd/antrea-octant-plugin/traceflow.go index 508cecdb7f4..2e3a708a16c 100644 --- a/plugins/octant/cmd/antrea-octant-plugin/traceflow.go +++ b/plugins/octant/cmd/antrea-octant-plugin/traceflow.go @@ -529,7 +529,7 @@ func checkTimeout(request *service.ActionRequest) (bool, uint16) { func updateIPHeader(tf *crdv1alpha1.Traceflow, hasSrcPort bool, hasDstPort bool, srcPort uint16, dstPort uint16) { switch tf.Spec.Packet.IPHeader.Protocol { - case crdv1alpha1.TCPProtocol: + case crdv1alpha1.TCPProtocolNumber: tf.Spec.Packet.TransportHeader.TCP = &crdv1alpha1.TCPHeader{ Flags: 2, } @@ -539,7 +539,7 @@ func updateIPHeader(tf *crdv1alpha1.Traceflow, hasSrcPort bool, hasDstPort bool, if hasDstPort { tf.Spec.Packet.TransportHeader.TCP.DstPort = int32(dstPort) } - case crdv1alpha1.UDPProtocol: + case crdv1alpha1.UDPProtocolNumber: tf.Spec.Packet.TransportHeader.UDP = &crdv1alpha1.UDPHeader{} if hasSrcPort { tf.Spec.Packet.TransportHeader.UDP.SrcPort = int32(srcPort) @@ -547,7 +547,7 @@ func updateIPHeader(tf *crdv1alpha1.Traceflow, hasSrcPort bool, hasDstPort bool, if hasDstPort { tf.Spec.Packet.TransportHeader.UDP.DstPort = int32(dstPort) } - case crdv1alpha1.ICMPProtocol: + case crdv1alpha1.ICMPProtocolNumber: tf.Spec.Packet.TransportHeader.ICMP = &crdv1alpha1.ICMPEchoRequestHeader{ ID: 0, Sequence: 0, diff --git a/plugins/octant/go.mod b/plugins/octant/go.mod index c02d974da1c..eacd5a2d983 100644 --- a/plugins/octant/go.mod +++ b/plugins/octant/go.mod @@ -5,7 +5,7 @@ go 1.17 require ( antrea.io/antrea v0.0.0 github.com/vmware-tanzu/octant v0.24.0 - k8s.io/apimachinery v0.21.3 + k8s.io/apimachinery v0.24.0 ) require ( @@ -15,7 +15,7 @@ require ( github.com/awalterschulze/gographviz v2.0.1+incompatible // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bits-and-blooms/bitset v1.2.0 // indirect - github.com/cespare/xxhash/v2 v2.1.1 // indirect + github.com/cespare/xxhash/v2 v2.1.2 // indirect github.com/containerd/cgroups v1.0.1 // indirect github.com/containerd/containerd v1.5.1 // indirect github.com/containers/image/v5 v5.14.0 // indirect @@ -24,7 +24,7 @@ require ( github.com/containers/storage v1.32.6 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/dlclark/regexp2 v1.2.0 // indirect - github.com/docker/distribution v2.7.1+incompatible // indirect + github.com/docker/distribution v2.8.1+incompatible // indirect github.com/docker/docker v1.4.2-0.20191219165747-a9416c67da9f // indirect github.com/docker/docker-credential-helpers v0.6.4 // indirect github.com/docker/go-connections v0.4.0 // indirect @@ -35,13 +35,14 @@ require ( github.com/fatih/color v1.10.0 // indirect github.com/fsnotify/fsnotify v1.5.1 // indirect github.com/ghodss/yaml v1.0.0 // indirect - github.com/go-logr/logr v0.4.0 // indirect + github.com/go-logr/logr v1.2.0 // indirect github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect github.com/gobwas/glob v0.2.3 // indirect github.com/gogo/protobuf v1.3.2 // indirect - github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect + github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.2 // indirect github.com/golang/snappy v0.0.3 // indirect + github.com/google/gnostic v0.5.7-v3refs // indirect github.com/google/go-cmp v0.5.5 // indirect github.com/google/go-intervals v0.0.2 // indirect github.com/google/gofuzz v1.2.0 // indirect @@ -56,7 +57,7 @@ require ( github.com/hashicorp/hcl v1.0.0 // indirect github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d // indirect github.com/imdario/mergo v0.3.12 // indirect - github.com/json-iterator/go v1.1.11 // indirect + github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/compress v1.13.1 // indirect github.com/klauspost/pgzip v1.2.5 // indirect github.com/magiconair/properties v1.8.5 // indirect @@ -70,7 +71,7 @@ require ( github.com/moby/spdystream v0.2.0 // indirect github.com/moby/sys/mountinfo v0.4.1 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect - github.com/modern-go/reflect2 v1.0.1 // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect github.com/oklog/run v1.0.0 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.0.2-0.20190823105129-775207bd45b6 // indirect @@ -81,17 +82,17 @@ require ( github.com/pelletier/go-toml v1.9.3 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/prometheus/client_golang v1.11.0 // indirect + github.com/prometheus/client_golang v1.12.1 // indirect github.com/prometheus/client_model v0.2.0 // indirect - github.com/prometheus/common v0.26.0 // indirect - github.com/prometheus/procfs v0.6.0 // indirect + github.com/prometheus/common v0.32.1 // indirect + github.com/prometheus/procfs v0.7.3 // indirect github.com/sirupsen/logrus v1.8.1 // indirect github.com/spf13/afero v1.6.0 // indirect github.com/spf13/cast v1.3.1 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/spf13/viper v1.8.1 // indirect - github.com/stretchr/testify v1.7.0 // indirect + github.com/stretchr/testify v1.7.1 // indirect github.com/subosito/gotenv v1.2.0 // indirect github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635 // indirect github.com/tchap/go-patricia v2.3.0+incompatible // indirect @@ -99,17 +100,18 @@ require ( github.com/vbatts/tar-split v0.11.1 // indirect go.opencensus.io v0.23.0 // indirect go.uber.org/atomic v1.7.0 // indirect + go.uber.org/goleak v1.1.12 // indirect go.uber.org/multierr v1.6.0 // indirect - go.uber.org/zap v1.19.0 // indirect - golang.org/x/net v0.0.0-20210504132125-bbd867fde50d // indirect - golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602 // indirect + go.uber.org/zap v1.19.1 // indirect + golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd // indirect + golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 // indirect golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect - golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c // indirect - golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d // indirect - golang.org/x/text v0.3.6 // indirect - golang.org/x/time v0.0.0-20210611083556-38a9dc6acbc6 // indirect + golang.org/x/sys v0.0.0-20220209214540-3681064d5158 // indirect + golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect + golang.org/x/text v0.3.7 // indirect + golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c // indirect + google.golang.org/genproto v0.0.0-20220107163113-42d7afdf6368 // indirect google.golang.org/grpc v1.40.0 // indirect google.golang.org/protobuf v1.27.1 // indirect gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b // indirect @@ -117,15 +119,24 @@ require ( gopkg.in/ini.v1 v1.62.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect - k8s.io/api v0.21.3 // indirect - k8s.io/apiextensions-apiserver v0.21.3 // indirect - k8s.io/client-go v0.21.3 // indirect - k8s.io/klog/v2 v2.8.0 // indirect - k8s.io/kube-aggregator v0.21.3 // indirect - k8s.io/kube-openapi v0.0.0-20210305164622-f622666832c1 // indirect - k8s.io/utils v0.0.0-20210527160623-6fdb442a123b // indirect - sigs.k8s.io/structured-merge-diff/v4 v4.1.2 // indirect - sigs.k8s.io/yaml v1.2.0 // indirect + k8s.io/api v0.24.0 // indirect + k8s.io/apiextensions-apiserver v0.24.0 // indirect + k8s.io/client-go v0.24.0 // indirect + k8s.io/klog/v2 v2.60.1 // indirect + k8s.io/kube-aggregator v0.24.0 // indirect + k8s.io/kube-openapi v0.0.0-20220328201542-3ee0da9b0b42 // indirect + k8s.io/metrics v0.24.0 // indirect + k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9 // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.2.1 // indirect + sigs.k8s.io/yaml v1.3.0 // indirect ) replace antrea.io/antrea => ../../ + +replace ( + // The current version of Octant does not build with version v0.24.0 of + // the K8s libraries. + k8s.io/api => k8s.io/api v0.21.3 + k8s.io/apimachinery => k8s.io/apimachinery v0.21.3 + k8s.io/client-go => k8s.io/client-go v0.21.3 +) diff --git a/plugins/octant/go.sum b/plugins/octant/go.sum index ad7eab5135b..e23f4b8d721 100644 --- a/plugins/octant/go.sum +++ b/plugins/octant/go.sum @@ -1,5 +1,5 @@ antrea.io/libOpenflow v0.6.2/go.mod h1:CzEJZxDNAupiGxeL5VOw92PsxfyvehEAvE3PiC6gr8o= -antrea.io/ofnet v0.5.5/go.mod h1:8TJVF6MLe9/gZ/KbhGUvULs9/TxssepEaYEe+o1SEgs= +antrea.io/ofnet v0.5.7/go.mod h1:8TJVF6MLe9/gZ/KbhGUvULs9/TxssepEaYEe+o1SEgs= bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= @@ -44,25 +44,20 @@ dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7 github.com/14rcole/gopopulate v0.0.0-20180821133914-b175b219e774 h1:SCbEWT58NSt7d2mcFdvxC9uyrdcTfvBbPLThhkDmXzg= github.com/14rcole/gopopulate v0.0.0-20180821133914-b175b219e774/go.mod h1:6/0dYRLLXyJjbkIPeeGyoJ/eKOSI0eU6eTlCBYibgd0= github.com/Azure/azure-sdk-for-go v16.2.1+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= -github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= +github.com/Azure/go-ansiterm v0.0.0-20210608223527-2377c96fe795/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= +github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= +github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/Azure/go-autorest v10.8.1+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= -github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= -github.com/Azure/go-autorest/autorest v0.11.1/go.mod h1:JFgpikqFJ/MleTTxwepExTKnFUKKszPS8UavbQYUMuw= github.com/Azure/go-autorest/autorest v0.11.12/go.mod h1:eipySxLmqSyC5s5k1CLupqet0PSENBEDP93LQ9a8QYw= -github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= -github.com/Azure/go-autorest/autorest/adal v0.9.0/go.mod h1:/c022QCutn2P7uY+/oQWWNcK9YU+MH96NgK+jErpbcg= +github.com/Azure/go-autorest/autorest v0.11.18/go.mod h1:dSiJPy22c3u0OtOKDNttNgqpNFY/GeWa7GH/Pz56QRA= github.com/Azure/go-autorest/autorest/adal v0.9.5/go.mod h1:B7KF7jKIeC9Mct5spmyCB/A8CG/sEz1vwIRGv/bbw7A= -github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= +github.com/Azure/go-autorest/autorest/adal v0.9.13/go.mod h1:W/MM4U6nLxnIskrw4UwWzlHfGjwUS50aOsc/I3yuU8M= github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= -github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= -github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= -github.com/Azure/go-autorest/autorest/mocks v0.4.0/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= -github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= -github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= +github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= @@ -117,6 +112,7 @@ github.com/alessio/shellescape v1.2.2/go.mod h1:PZAiSCk0LJaZkiCSkPv8qIobYglO3FPp github.com/alexflint/go-filemutex v0.0.0-20171022225611-72bdc8eae2ae/go.mod h1:CgnQgUtFrFz9mxFNtED3jI5tLDjKlOM+oUF/sTk6ps0= github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/antlr/antlr4/runtime/Go/antlr v0.0.0-20210826220005-b48c857c3a0e/go.mod h1:F7bn7fEU90QkQ3tnmaTx3LTKLEDqnwWODIYppRQ5hnY= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= @@ -126,6 +122,7 @@ github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:l github.com/awalterschulze/gographviz v2.0.1+incompatible h1:XIECBRq9VPEQqkQL5pw2OtjCAdrtIgFKoJU8eT98AS8= github.com/awalterschulze/gographviz v2.0.1+incompatible/go.mod h1:GEV5wmg4YquNw7v1kkyoX9etIk8yVmXj+AkDHuuETHs= github.com/aws/aws-sdk-go v1.15.11/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0= +github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM= github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20160804104726-4c0e84591b9a/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= @@ -143,6 +140,7 @@ github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqO github.com/blang/semver v3.1.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= +github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= github.com/bshuster-repo/logrus-logstash-hook v0.4.1/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk= github.com/buger/jsonparser v0.0.0-20180808090653-f4dd9f5a6b44/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= @@ -155,10 +153,13 @@ github.com/cenkalti/hub v1.0.1/go.mod h1:tcYwtS3a2d9NO/0xDXVJWx3IedurUjYCqFCmpi0 github.com/cenkalti/rpc2 v0.0.0-20140912135055-44d0d95e4f52/go.mod h1:v2npkhrXyk5BCnkNIiPdRI23Uq6uWPUQGL2hnRcRr/M= github.com/cenkalti/rpc2 v0.0.0-20180727162946-9642ea02d0aa/go.mod h1:v2npkhrXyk5BCnkNIiPdRI23Uq6uWPUQGL2hnRcRr/M= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/certifi/gocertifi v0.0.0-20191021191039-0944d244cd40/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA= +github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA= github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= -github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= +github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5/go.mod h1:/iP1qXHoty45bqomnu2LM+VVyAEdWN+vtSHGlQgyxbw= github.com/checkpoint-restore/go-criu/v4 v4.1.0/go.mod h1:xUQBLp4RLc5zJtWY++yjOoMoB5lihDt7fai+75m+rGw= github.com/checkpoint-restore/go-criu/v5 v5.0.0/go.mod h1:cfwC0EG7HMUenopBsUf9d89JlCLQIfgVcNsNN0t6T2M= @@ -178,6 +179,9 @@ github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnht github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= +github.com/cockroachdb/datadriven v0.0.0-20200714090401-bf6692d28da5/go.mod h1:h6jFvWxBdQXxjopDMZyH2UVceIRfR84bdzbkoKrsWNo= +github.com/cockroachdb/errors v1.2.4/go.mod h1:rQD95gz6FARkaKkQXUksEje/d9a6wBJoCr5oaCLELYA= +github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI= github.com/confluentinc/bincover v0.1.0/go.mod h1:qeI1wx0RxdGTZtrJY0HVlgJ4NqC/X2Z+fHbvy87tgHE= github.com/containerd/aufs v0.0.0-20200908144142-dab0cbea06f4/go.mod h1:nukgQABAEopAHvB6j7cnP5zJ+/3aVcE7hCYqvIwAHyE= github.com/containerd/aufs v0.0.0-20201003224125-76a6863f2989/go.mod h1:AkGGQs9NM2vtYHaUen+NljV0/baGCAPELGm2q9ZXpWU= @@ -317,8 +321,9 @@ github.com/dlclark/regexp2 v1.2.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55k github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= github.com/docker/distribution v0.0.0-20190905152932-14b96e55d84c/go.mod h1:0+TTO4EOBfRPhZXAeF1Vu+W3hHZ8eLp8PgKVZlcvtFY= github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= -github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug= github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/distribution v2.8.1+incompatible h1:Q50tZOPR6T/hjNsyc9g8/syEs6bk8XXApsHjKukMl68= +github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/docker v0.7.3-0.20190327010347-be7ac8be2ae0/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker v1.4.2-0.20191219165747-a9416c67da9f h1:Sm8iD2lifO31DwXfkGzq8VgA7rwxPjRsYmeo0K/dF9Y= github.com/docker/docker v1.4.2-0.20191219165747-a9416c67da9f/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= @@ -337,7 +342,6 @@ github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDD github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE= github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 h1:UhxFibDNY/bfvqU5CAUmr9zpesgbU6SWc8/B4mflAE4= github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE= -github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= github.com/dop251/goja v0.0.0-20200629185240-bfd59704b500 h1:QthjkRYZQj+FcH5GZXltnlBiyW19WLb+l7R0TrZChNw= github.com/dop251/goja v0.0.0-20200629185240-bfd59704b500/go.mod h1:Mw6PkjjMXWbTj+nnj4s3QPXq1jaT0s5pC0iFD4+BOAA= @@ -368,8 +372,9 @@ github.com/evanphx/json-patch v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMi github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch v4.5.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/evanphx/json-patch v4.11.0+incompatible h1:glyUF9yIYtMHzn8xaKw5rMhdWcwsYV8dZHIq5567/xs= github.com/evanphx/json-patch v4.11.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch v4.12.0+incompatible h1:4onqiflcdA9EOZ4RxV643DvftH5pOlLGNtQ5lPWQu84= +github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch/v5 v5.0.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d/go.mod h1:ZZMPRZwes7CROmyNKgQzC3XPs6L/G2EJLHddWejkmf4= github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc= @@ -378,6 +383,7 @@ github.com/fatih/color v1.10.0 h1:s36xzo75JdqLaaWoiEHk767eHiwo0598uUxyfiPkDsg= github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= +github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= github.com/frankban/quicktest v1.10.2/go.mod h1:K+q6oSqb0W0Ininfk863uOk1lMy69l/P6txr3mVT54s= github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= @@ -389,6 +395,8 @@ github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa/go.mod h1:KnogPXt github.com/fvbommel/sortorder v1.0.1/go.mod h1:uk88iVf1ovNn1iLfgUVU2F9o5eO30ui720w+kxuqRs0= github.com/gammazero/deque v0.1.0/go.mod h1:KQw7vFau1hHuM8xmI9RbgKFbAsQFWmBpqQ2KenFLk6M= github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY= +github.com/getkin/kin-openapi v0.76.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSyhcnluiMv+Xg= +github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ= github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= @@ -407,10 +415,11 @@ github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= -github.com/go-logr/logr v0.4.0 h1:K7/B1jt6fIBQVd4Owv2MqGQClcgf0R266+7C/QjRcLc= github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= +github.com/go-logr/logr v1.2.0 h1:QK40JKJyMdUDz+h+xvCsru/bJhvG0UxvePV0ufL/AcE= +github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/zapr v0.1.0/go.mod h1:tabnROwaDl0UNxkVeFRbY8bwB37GwRv0P8lg6aAiEnk= -github.com/go-logr/zapr v0.4.0/go.mod h1:tabnROwaDl0UNxkVeFRbY8bwB37GwRv0P8lg6aAiEnk= +github.com/go-logr/zapr v1.2.0/go.mod h1:Qa4Bsj2Vb+FAVeAKsLD8RLQ+YRJB8YDmOAKxaBQf7Ro= github.com/go-openapi/analysis v0.0.0-20180825180245-b006789cd277/go.mod h1:k70tL6pCuVxPJOHXQ+wIac1FUrvNkHolPie/cLEU6hI= github.com/go-openapi/analysis v0.17.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= github.com/go-openapi/analysis v0.18.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= @@ -424,11 +433,13 @@ github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwds github.com/go-openapi/jsonpointer v0.18.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= github.com/go-openapi/jsonreference v0.18.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= +github.com/go-openapi/jsonreference v0.19.5/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg= github.com/go-openapi/loads v0.17.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= github.com/go-openapi/loads v0.18.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= github.com/go-openapi/loads v0.19.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= @@ -447,23 +458,21 @@ github.com/go-openapi/strfmt v0.17.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pL github.com/go-openapi/strfmt v0.18.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= github.com/go-openapi/strfmt v0.19.0/go.mod h1:+uW+93UVvGGq2qGaZxdDeJqSAqBqBdl+ZPMF/cC8nDY= github.com/go-openapi/strfmt v0.19.3/go.mod h1:0yX7dbo8mKIvc3XSKp7MNfxw4JytCfCD6+bY1AVL9LU= -github.com/go-openapi/strfmt v0.19.5/go.mod h1:eftuHTlB/dI8Uq8JJOyRlieZf+WkkxUuk0dgdHXr2Qk= github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= github.com/go-openapi/swag v0.18.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= github.com/go-openapi/validate v0.18.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4= github.com/go-openapi/validate v0.19.2/go.mod h1:1tRCw7m3jtI8eNWEEliiAqUIcBztB2KDnRCRMUi7GTA= github.com/go-openapi/validate v0.19.5/go.mod h1:8DJv2CVJQ6kGNpFW6eV9N3JviE1C85nY1c2z52x1Gk4= -github.com/go-openapi/validate v0.19.8/go.mod h1:8DJv2CVJQ6kGNpFW6eV9N3JviE1C85nY1c2z52x1Gk4= github.com/go-sourcemap/sourcemap v2.1.3+incompatible h1:W1iEw64niKVGogNgBN3ePyLFfuisuzeidWPMPWmECqU= github.com/go-sourcemap/sourcemap v2.1.3+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/gobuffalo/flect v0.2.0/go.mod h1:W3K3X9ksuZfir8f/LrfVtWmCDQFfayuylOJ7sz/Fj80= -github.com/gobuffalo/here v0.6.0/go.mod h1:wAG085dHOYqUpf+Ap+WOdrPTp5IYcDAs/x7PLa8Y5fM= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= github.com/godbus/dbus v0.0.0-20151105175453-c7fdd8b5cd55/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw= @@ -481,12 +490,14 @@ github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXP github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= @@ -523,6 +534,11 @@ github.com/golangplus/testing v0.0.0-20180327235837-af21d9c3145e/go.mod h1:0AA// github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= +github.com/google/cel-go v0.9.0/go.mod h1:U7ayypeSkw23szu4GaQTPJGx66c20mx8JklMSxrmI1w= +github.com/google/cel-go v0.10.1/go.mod h1:U7ayypeSkw23szu4GaQTPJGx66c20mx8JklMSxrmI1w= +github.com/google/cel-spec v0.6.0/go.mod h1:Nwjgxy5CbjlPrtCWjeDjUyKMl8w41YBYGjsyDdqk0xA= +github.com/google/gnostic v0.5.7-v3refs h1:FhTMOKj2VhjpouxvWJAV1TL304uMlb9zcDqkl6cEI54= +github.com/google/gnostic v0.5.7-v3refs/go.mod h1:73MKFl6jIHelAJNaBGFzt3SPtZULs9dYrGFt8OiIsHQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= @@ -570,9 +586,9 @@ github.com/googleapis/gnostic v0.1.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTV github.com/googleapis/gnostic v0.2.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= github.com/googleapis/gnostic v0.3.1/go.mod h1:on+2t9HRStVgn95RSsFWFz+6Q0Snyqv1awfrALZdbtU= github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= +github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU= github.com/googleapis/gnostic v0.5.5 h1:9fHAtK0uDfpveeqqo1hkEZJcFvYXAiCN3UutL8F9xHw= github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA= -github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/handlers v0.0.0-20150720190736-60c7bfde3e33/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= @@ -588,6 +604,7 @@ github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:Fecb github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= @@ -651,6 +668,8 @@ github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht github.com/jmespath/go-jmespath v0.0.0-20160803190731-bd40a432e4c7/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/josharian/native v0.0.0-20200817173448-b6b71def0850/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/jsimonetti/rtnetlink v0.0.0-20190606172950-9527aa82566a/go.mod h1:Oz+70psSo5OFh8DBl0Zv2ACw7Esh6pPUphlvZG9x7uw= @@ -664,8 +683,9 @@ github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCV github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.11 h1:uVUAXhF2To8cbw/3xN3pxj6kk7TYKs98NIrTqPlMWAQ= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= @@ -714,8 +734,8 @@ github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= +github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/manifoldco/promptui v0.8.0/go.mod h1:n4zTdgP0vr0S3w7/O/g98U+e0gwLScEXGwov2nIKuGQ= -github.com/markbates/pkger v0.17.1/go.mod h1:0JoVlrol20BSywW79rN3kdFFsE5xYM+rSCQDXbLhiuI= github.com/marstr/guid v1.1.0/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHefzho= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= @@ -788,12 +808,15 @@ github.com/moby/sys/mountinfo v0.4.1/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2J github.com/moby/sys/symlink v0.1.0/go.mod h1:GGDODQmbFOjFsXvfLVn3+ZRxkch54RkSiGqsZeMYowQ= github.com/moby/term v0.0.0-20200312100748-672ec06f55cd/go.mod h1:DdlQx2hp0Ss5/fLikoLlEeIYiATotOjgB//nb973jeo= github.com/moby/term v0.0.0-20201216013528-df9cb8a40635/go.mod h1:FBS0z0QWA44HXygs7VXDUOGoN/1TV3RuWkLO04am3wc= +github.com/moby/term v0.0.0-20210610120745-9d4ed1856297/go.mod h1:vgPCkQMyxTZ7IDy8SXRufE172gr8+K/JE/7hHFxHW3A= +github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6/go.mod h1:E2VnQOmVuvZB6UYnnDB0qG5Nq/1tD9acaOpo6xmt0Kw= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4= github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= @@ -823,9 +846,9 @@ github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+ github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= -github.com/onsi/ginkgo v1.16.2/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvwxz1E= -github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= +github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= +github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= github.com/onsi/gomega v0.0.0-20151007035656-2152b45fa28a/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= @@ -833,8 +856,8 @@ github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7J github.com/onsi/gomega v1.8.1/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc= -github.com/onsi/gomega v1.13.0 h1:7lLHu94wT9Ij0o6EWWclhu0aOh32VxhkwEJvzuWPeak= -github.com/onsi/gomega v1.13.0/go.mod h1:lRk9szgn8TxENtWd0Tp4c3wjlRfMTMH27I+3Je41yGY= +github.com/onsi/gomega v1.17.0 h1:9Luw4uT5HTjHTN8+aNcSThgH1vdXnmdJ8xIfZ4wyTRE= +github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= @@ -864,6 +887,7 @@ github.com/opencontainers/selinux v1.6.0/go.mod h1:VVGKuOLlE7v4PJyT6h7mNWvq1rzqi github.com/opencontainers/selinux v1.8.0/go.mod h1:RScLhm78qiWa2gbVCcGkC7tCGdgk3ogry1nUQF8Evvo= github.com/opencontainers/selinux v1.8.2 h1:c4ca10UMgRcvZ6h0K4HtS15UaVSBEaE+iln2LVpAuGc= github.com/opencontainers/selinux v1.8.2/go.mod h1:MUIHuUEvKB1wtJjQdOyYRgOnLD2xAPP8dBsCoU0KuF8= +github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/ostreedev/ostree-go v0.0.0-20190702140239-759a8c1ac913 h1:TnbXhKzrTOyuvWrjI8W6pcoI9XPbLHFXCdN2dtUw7Rw= github.com/ostreedev/ostree-go v0.0.0-20190702140239-759a8c1ac913/go.mod h1:J6OG6YJVEWopen4avK3VNQSnALmmjvniMmni/YFYAwc= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= @@ -897,8 +921,9 @@ github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDf github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= -github.com/prometheus/client_golang v1.11.0 h1:HNkLOAEQMIDv/K+04rukrLx6ch7msSRwf3/SASFAGtQ= github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= +github.com/prometheus/client_golang v1.12.1 h1:ZiaPsmm9uiBeaSMRznKsCDNtPCS0T3JVDGF+06gjBzk= +github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= github.com/prometheus/client_model v0.0.0-20171117100541-99fa1f4be8e5/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= @@ -911,8 +936,10 @@ github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y8 github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= -github.com/prometheus/common v0.26.0 h1:iMAkS2TDoNWnKM+Kopnx/8tnEStIfpYA0ur0xQzzhMQ= github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= +github.com/prometheus/common v0.28.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= +github.com/prometheus/common v0.32.1 h1:hWIdL3N2HoUx3B8j3YN9mWor0qhY/NlEKZEaXxuIRh4= +github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= @@ -924,8 +951,9 @@ github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+Gx github.com/prometheus/procfs v0.0.11/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= -github.com/prometheus/procfs v0.6.0 h1:mxy4L2jP6qMonqmq+aTtOx1ifVWUgG/TAmntgbh3xv4= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU= +github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= @@ -976,6 +1004,7 @@ github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3 github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI= +github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo= github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk= github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= @@ -1006,8 +1035,9 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= @@ -1022,6 +1052,7 @@ github.com/ti-mo/netfilter v0.3.1/go.mod h1:t/5HvCCHA1LAYj/AZF2fWcJ23BQTA7lzTPCu github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/uber/jaeger-client-go v2.25.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= @@ -1062,6 +1093,8 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs= github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA= github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg= @@ -1073,8 +1106,15 @@ go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4= go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= go.etcd.io/etcd v0.5.0-alpha.5.0.20200910180754-dd1b699fc489/go.mod h1:yVHk9ub3CSBatqGNg7GRmsnfLWtoW60w4eDYfh7vHDg= go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= +go.etcd.io/etcd/api/v3 v3.5.1/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= +go.etcd.io/etcd/client/pkg/v3 v3.5.1/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ= +go.etcd.io/etcd/client/v3 v3.5.0/go.mod h1:AIKXXVX/DQXtfTEqBryiLTUXwON+GuvO6Z7lLS/oTh0= +go.etcd.io/etcd/client/v3 v3.5.1/go.mod h1:OnjH4M8OnAotwaB2l9bVgZzRFKru7/ZMoS46OtKyd3Q= +go.etcd.io/etcd/pkg/v3 v3.5.0/go.mod h1:UzJGatBQ1lXChBkQF0AuAtkRQMYnHubxAEYIrC3MSsE= +go.etcd.io/etcd/raft/v3 v3.5.0/go.mod h1:UFOHSIvO/nKwd4lhkwabrTD3cqW5yVyYYf/KlD00Szc= +go.etcd.io/etcd/server/v3 v3.5.0/go.mod h1:3Ah5ruV+M+7RZr0+Y/5mNLwC+eQlni+mQmOVdCRJoS4= go.mongodb.org/mongo-driver v1.0.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= go.mongodb.org/mongo-driver v1.1.1/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= go.mongodb.org/mongo-driver v1.1.2/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= @@ -1087,27 +1127,40 @@ go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= +go.opentelemetry.io/contrib v0.20.0/go.mod h1:G/EtFaa6qaN7+LxqfIAT3GiZa7Wv5DTBUzl5H4LY0Kc= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.20.0/go.mod h1:oVGt1LRbBOBq1A5BQLlUg9UaU/54aiHw8cgjV3aWZ/E= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.20.0/go.mod h1:2AboqHi0CiIZU0qwhtUfCYD1GeUzvvIXWNkhDt7ZMG4= +go.opentelemetry.io/otel v0.20.0/go.mod h1:Y3ugLH2oa81t5QO+Lty+zXf8zC9L26ax4Nzoxm/dooo= +go.opentelemetry.io/otel/exporters/otlp v0.20.0/go.mod h1:YIieizyaN77rtLJra0buKiNBOm9XQfkPEKBeuhoMwAM= +go.opentelemetry.io/otel/metric v0.20.0/go.mod h1:598I5tYlH1vzBjn+BTuhzTCSb/9debfNp6R3s7Pr1eU= +go.opentelemetry.io/otel/oteltest v0.20.0/go.mod h1:L7bgKf9ZB7qCwT9Up7i9/pn0PWIa9FqQ2IQ8LoxiGnw= +go.opentelemetry.io/otel/sdk v0.20.0/go.mod h1:g/IcepuwNsoiX5Byy2nNV0ySUF1em498m7hBWC279Yc= +go.opentelemetry.io/otel/sdk/export/metric v0.20.0/go.mod h1:h7RBNMsDJ5pmI1zExLi+bJK+Dr8NQCh0qGhm1KDnNlE= +go.opentelemetry.io/otel/sdk/metric v0.20.0/go.mod h1:knxiS8Xd4E/N+ZqKmUPf3gTTZ4/0TjTXukfxjzSTpHE= +go.opentelemetry.io/otel/trace v0.20.0/go.mod h1:6GjCW8zgDjwGHGa6GkyeB8+/5vjT16gUEi0Nf1iBdgw= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5/go.mod h1:nmDLcffg48OtT/PSW0Hg7FvpRQsQh5OSqIylirxKC7o= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/goleak v1.1.10 h1:z+mqJhf6ss6BSfSM671tgKyZBFPTTJM+HLxnhPC3wu0= go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= +go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= +go.uber.org/goleak v1.1.12 h1:gZAh5/EyT/HQwlpkCy6wTpqfH9H8Lz8zbm3dZh+OyzA= +go.uber.org/goleak v1.1.12/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= -go.uber.org/zap v1.19.0 h1:mZQZefskPPCMIBCSEH0v2/iUqqLrYtaeqwD6FUGUnFE= go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= +go.uber.org/zap v1.19.1 h1:ue41HOKd1vGURxrmeKIgELGb3jPW9DMUDGtsinblHwI= +go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= golang.org/x/crypto v0.0.0-20171113213409-9f005a07e0d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181009213950-7c1a557ab941/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190320223903-b7391e95e576/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -1126,6 +1179,9 @@ golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= +golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -1149,7 +1205,6 @@ golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRu golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 h1:VLliZ0d+/avPrXXH+OakdXhpJuEoBZuwh1m2j7U6Iug= golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= @@ -1163,6 +1218,7 @@ golang.org/x/mod v0.3.1-0.20200828183125-ce943fd02449/go.mod h1:s0Qsj1ACt9ePp/hM golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180530234432-1e491301e022/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1228,8 +1284,15 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= -golang.org/x/net v0.0.0-20210504132125-bbd867fde50d h1:nTDGCTeAu2LhcsHTRzjyIUbZHCJ4QePArsm27Hka0UM= golang.org/x/net v0.0.0-20210504132125-bbd867fde50d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210825183410-e898025ed96a/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd h1:O7DYs+zxREGLKzKoMQrtrEacpb0ZVXA5rIwylE2Xchk= +golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1241,8 +1304,11 @@ golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602 h1:0Ja1LBD+yisY6RWM/BH7TJVXWsSjs2VwBSmvSX4HdBc= golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 h1:RerP+noqYHUQ8CMRcPlC2nvTa4dcBIjegkuWdcUDuqg= +golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1265,7 +1331,6 @@ golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1366,13 +1431,23 @@ golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210503173754-0981d6026fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211029165221-6e7872819dc8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220209214540-3681064d5158 h1:rm+CHSpPEEW2IsXUib1ThaHIjuBVZjxNgSKmBLFfD4c= +golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d h1:SZxvLBoTP5yHO3Frd4z4vrF+DBX9vMVanchswa69toE= golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1381,16 +1456,17 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20210611083556-38a9dc6acbc6 h1:Vv0JUPWTyeqUq42B2WJ1FeIDjjvGKoA2Ss+Ts0lAVbs= -golang.org/x/time v0.0.0-20210611083556-38a9dc6acbc6/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 h1:vVKdlvoWBphwdxWKrFZEuM0kGgGLxUOYcY4U/2Vjg44= +golang.org/x/time v0.0.0-20220210224613-90d013bbcef8/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -1456,8 +1532,9 @@ golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.6-0.20210820212750-d4cc65f0b2ff/go.mod h1:YD9qOF0M9xpSpdWTBbzEl5e/RnCefISl8E5Noe10jFM= +golang.org/x/tools v0.1.10-0.20220218145154-897bd77cd717/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -1523,6 +1600,7 @@ google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfG google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= @@ -1534,6 +1612,7 @@ google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201102152239-715cce707fb0/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= @@ -1544,8 +1623,10 @@ google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= -google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c h1:wtujag7C+4D6KMoulW9YauvK2lgdvCMS260jsqqBXr0= google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20220107163113-42d7afdf6368 h1:Et6SkiuvnBn+SgrSYXs/BrUpGB4mbdwt4R3vaPIlicA= +google.golang.org/genproto v0.0.0-20220107163113-42d7afdf6368/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.8.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= @@ -1570,6 +1651,7 @@ google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA5 google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc v1.40.0 h1:AGJ0Ih4mHjSeibYkFGh1dD9KJ/eOtZ93I6hoHhukQ5Q= google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= @@ -1646,29 +1728,14 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -k8s.io/api v0.18.2/go.mod h1:SJCWI7OLzhZSvbY7U8zwNl9UA4o1fizoug34OV/2r78= -k8s.io/api v0.18.3/go.mod h1:UOaMwERbqJMfeeeHc8XJKawj4P9TgDRnViIqqBeH2QA= -k8s.io/api v0.18.4/go.mod h1:lOIQAKYgai1+vz9J7YcDZwC26Z0zQewYOGWdyIPUUQ4= -k8s.io/api v0.20.1/go.mod h1:KqwcCVogGxQY3nBlRpwt+wpAMF/KjaCc7RpywacvqUo= -k8s.io/api v0.20.4/go.mod h1:++lNL1AJMkDymriNniQsWRkMDzRaX2Y/POTUi8yvqYQ= -k8s.io/api v0.20.6/go.mod h1:X9e8Qag6JV/bL5G6bU8sdVRltWKmdHsFUGS3eVndqE8= -k8s.io/api v0.21.0/go.mod h1:+YbrhBBGgsxbF6o6Kj4KJPJnBmAKuXDeS3E18bgHNVU= -k8s.io/api v0.21.2/go.mod h1:Lv6UGJZ1rlMI1qusN8ruAp9PUBFyBwpEHAdG24vIsiU= k8s.io/api v0.21.3 h1:cblWILbLO8ar+Fj6xdDGr603HRsf8Wu9E9rngJeprZQ= k8s.io/api v0.21.3/go.mod h1:hUgeYHUbBp23Ue4qdX9tR8/ANi/g3ehylAqDn9NWVOg= k8s.io/apiextensions-apiserver v0.18.2/go.mod h1:q3faSnRGmYimiocj6cHQ1I3WpLqmDgJFlKL37fC4ZvY= k8s.io/apiextensions-apiserver v0.18.4/go.mod h1:NYeyeYq4SIpFlPxSAB6jHPIdvu3hL0pc36wuRChybio= -k8s.io/apiextensions-apiserver v0.21.2/go.mod h1:+Axoz5/l3AYpGLlhJDfcVQzCerVYq3K3CvDMvw6X1RA= -k8s.io/apiextensions-apiserver v0.21.3 h1:+B6biyUWpqt41kz5x6peIsljlsuwvNAp/oFax/j2/aY= k8s.io/apiextensions-apiserver v0.21.3/go.mod h1:kl6dap3Gd45+21Jnh6utCx8Z2xxLm8LGDkprcd+KbsE= -k8s.io/apimachinery v0.18.2/go.mod h1:9SnR/e11v5IbyPCGbvJViimtJ0SwHG4nfZFjU77ftcA= -k8s.io/apimachinery v0.18.3/go.mod h1:OaXp26zu/5J7p0f92ASynJa1pZo06YlV9fG7BoWbCko= -k8s.io/apimachinery v0.18.4/go.mod h1:OaXp26zu/5J7p0f92ASynJa1pZo06YlV9fG7BoWbCko= -k8s.io/apimachinery v0.20.1/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= -k8s.io/apimachinery v0.20.4/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= -k8s.io/apimachinery v0.20.6/go.mod h1:ejZXtW1Ra6V1O5H8xPBGz+T3+4gfkTCeExAHKU57MAc= -k8s.io/apimachinery v0.21.0/go.mod h1:jbreFvJo3ov9rj7eWT7+sYiRx+qZuCYXwWT1bcDswPY= -k8s.io/apimachinery v0.21.2/go.mod h1:CdTY8fU/BlvAbJ2z/8kBwimGki5Zp8/fbVuLY8gJumM= +k8s.io/apiextensions-apiserver v0.23.5/go.mod h1:ntcPWNXS8ZPKN+zTXuzYMeg731CP0heCTl6gYBxLcuQ= +k8s.io/apiextensions-apiserver v0.24.0 h1:JfgFqbA8gKJ/uDT++feAqk9jBIwNnL9YGdQvaI9DLtY= +k8s.io/apiextensions-apiserver v0.24.0/go.mod h1:iuVe4aEpe6827lvO6yWQVxiPSpPoSKVjkq+MIdg84cM= k8s.io/apimachinery v0.21.3 h1:3Ju4nvjCngxxMYby0BimUk+pQHPOQp3eCGChk5kfVII= k8s.io/apimachinery v0.21.3/go.mod h1:H/IM+5vH9kZRNJ4l3x/fXP/5bOPJaVP/guptnZPeCFI= k8s.io/apiserver v0.18.2/go.mod h1:Xbh066NqrZO8cbsoenCwyDJ1OSi8Ag8I2lezeHxzwzw= @@ -1676,35 +1743,28 @@ k8s.io/apiserver v0.18.4/go.mod h1:q+zoFct5ABNnYkGIaGQ3bcbUNdmPyOCoEBcg51LChY8= k8s.io/apiserver v0.20.1/go.mod h1:ro5QHeQkgMS7ZGpvf4tSMx6bBOgPfE+f52KwvXfScaU= k8s.io/apiserver v0.20.4/go.mod h1:Mc80thBKOyy7tbvFtB4kJv1kbdD0eIH8k8vianJcbFM= k8s.io/apiserver v0.20.6/go.mod h1:QIJXNt6i6JB+0YQRNcS0hdRHJlMhflFmsBDeSgT1r8Q= -k8s.io/apiserver v0.21.0/go.mod h1:w2YSn4/WIwYuxG5zJmcqtRdtqgW/J2JRgFAqps3bBpg= -k8s.io/apiserver v0.21.2/go.mod h1:lN4yBoGyiNT7SC1dmNk0ue6a5Wi6O3SWOIw91TsucQw= k8s.io/apiserver v0.21.3/go.mod h1:eDPWlZG6/cCCMj/JBcEpDoK+I+6i3r9GsChYBHSbAzU= -k8s.io/cli-runtime v0.21.0/go.mod h1:XoaHP93mGPF37MkLbjGVYqg3S1MnsFdKtiA/RZzzxOo= -k8s.io/client-go v0.18.2/go.mod h1:Xcm5wVGXX9HAA2JJ2sSBUn3tCJ+4SVlCbl2MNNv+CIU= -k8s.io/client-go v0.18.3/go.mod h1:4a/dpQEvzAhT1BbuWW09qvIaGw6Gbu1gZYiQZIi1DMw= -k8s.io/client-go v0.18.4/go.mod h1:f5sXwL4yAZRkAtzOxRWUhA/N8XzGCb+nPZI8PfobZ9g= -k8s.io/client-go v0.20.1/go.mod h1:/zcHdt1TeWSd5HoUe6elJmHSQ6uLLgp4bIJHVEuy+/Y= -k8s.io/client-go v0.20.4/go.mod h1:LiMv25ND1gLUdBeYxBIwKpkSC5IsozMMmOOeSJboP+k= -k8s.io/client-go v0.20.6/go.mod h1:nNQMnOvEUEsOzRRFIIkdmYOjAZrC8bgq0ExboWSU1I0= -k8s.io/client-go v0.21.0/go.mod h1:nNBytTF9qPFDEhoqgEPaarobC8QPae13bElIVHzIglA= -k8s.io/client-go v0.21.2/go.mod h1:HdJ9iknWpbl3vMGtib6T2PyI/VYxiZfq936WNVHBRrA= +k8s.io/apiserver v0.23.5/go.mod h1:7wvMtGJ42VRxzgVI7jkbKvMbuCbVbgsWFT7RyXiRNTw= +k8s.io/apiserver v0.24.0/go.mod h1:WFx2yiOMawnogNToVvUYT9nn1jaIkMKj41ZYCVycsBA= +k8s.io/cli-runtime v0.24.0/go.mod h1:9XxoZDsEkRFUThnwqNviqzljtT/LdHtNWvcNFrAXl0A= k8s.io/client-go v0.21.3 h1:J9nxZTOmvkInRDCzcSNQmPJbDYN/PjlxXT9Mos3HcLg= k8s.io/client-go v0.21.3/go.mod h1:+VPhCgTsaFmGILxR/7E1N0S+ryO010QBeNCv5JwRGYU= k8s.io/code-generator v0.18.2/go.mod h1:+UHX5rSbxmR8kzS+FAv7um6dtYrZokQvjHpDSYRVkTc= k8s.io/code-generator v0.18.3/go.mod h1:TgNEVx9hCyPGpdtCWA34olQYLkh3ok9ar7XfSsr8b6c= k8s.io/code-generator v0.18.4/go.mod h1:TgNEVx9hCyPGpdtCWA34olQYLkh3ok9ar7XfSsr8b6c= -k8s.io/code-generator v0.21.0/go.mod h1:hUlps5+9QaTrKx+jiM4rmq7YmH8wPOIko64uZCHDh6Q= -k8s.io/code-generator v0.21.2/go.mod h1:8mXJDCB7HcRo1xiEQstcguZkbxZaqeUOrO9SsicWs3U= k8s.io/code-generator v0.21.3/go.mod h1:K3y0Bv9Cz2cOW2vXUrNZlFbflhuPvuadW6JdnN6gGKo= +k8s.io/code-generator v0.23.5/go.mod h1:S0Q1JVA+kSzTI1oUvbKAxZY/DYbA/ZUb4Uknog12ETk= +k8s.io/code-generator v0.24.0/go.mod h1:dpVhs00hTuTdTY6jvVxvTFCk6gSMrtfRydbhZwHI15w= k8s.io/component-base v0.18.2/go.mod h1:kqLlMuhJNHQ9lz8Z7V5bxUUtjFZnrypArGl58gmDfUM= k8s.io/component-base v0.18.4/go.mod h1:7jr/Ef5PGmKwQhyAz/pjByxJbC58mhKAhiaDu0vXfPk= k8s.io/component-base v0.20.1/go.mod h1:guxkoJnNoh8LNrbtiQOlyp2Y2XFCZQmrcg2n/DeYNLk= k8s.io/component-base v0.20.4/go.mod h1:t4p9EdiagbVCJKrQ1RsA5/V4rFQNDfRlevJajlGwgjI= k8s.io/component-base v0.20.6/go.mod h1:6f1MPBAeI+mvuts3sIdtpjljHWBQ2cIy38oBIWMYnrM= k8s.io/component-base v0.21.0/go.mod h1:qvtjz6X0USWXbgmbfXR+Agik4RZ3jv2Bgr5QnZzdPYw= -k8s.io/component-base v0.21.2/go.mod h1:9lvmIThzdlrJj5Hp8Z/TOgIkdfsNARQ1pT+3PByuiuc= k8s.io/component-base v0.21.3/go.mod h1:kkuhtfEHeZM6LkX0saqSK8PbdO7A0HigUngmhhrwfGQ= -k8s.io/component-helpers v0.21.0/go.mod h1:tezqefP7lxfvJyR+0a+6QtVrkZ/wIkyMLK4WcQ3Cj8U= +k8s.io/component-base v0.23.5/go.mod h1:c5Nq44KZyt1aLl0IpHX82fhsn84Sb0jjzwjpcA42bY0= +k8s.io/component-base v0.24.0/go.mod h1:Dgazgon0i7KYUsS8krG8muGiMVtUZxG037l1MKyXgrA= +k8s.io/component-helpers v0.24.0/go.mod h1:Q2SlLm4h6g6lPTC9GMMfzdywfLSvJT2f1hOnnjaWD8c= k8s.io/cri-api v0.17.3/go.mod h1:X1sbHmuXhwaHs9xxYffLqJogVsnI+f6cPRcgPel7ywM= k8s.io/cri-api v0.20.1/go.mod h1:2JRbKt+BFLTjtrILYVqQK5jqhI+XNdF6UiGMgczeBCI= k8s.io/cri-api v0.20.4/go.mod h1:2JRbKt+BFLTjtrILYVqQK5jqhI+XNdF6UiGMgczeBCI= @@ -1713,6 +1773,8 @@ k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8 k8s.io/gengo v0.0.0-20200114144118-36b2048a9120/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/gengo v0.0.0-20201214224949-b6c5ce23f027/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= +k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= +k8s.io/gengo v0.0.0-20211129171323-c02415ce4185/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8= @@ -1720,28 +1782,34 @@ k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= k8s.io/klog/v2 v2.4.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= -k8s.io/klog/v2 v2.8.0 h1:Q3gmuM9hKEjefWFFYF0Mat+YyFJvsUyYuwyNNJ5C9Ts= k8s.io/klog/v2 v2.8.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec= -k8s.io/kube-aggregator v0.21.0/go.mod h1:sIaa9L4QCBo9gjPyoGJns4cBjYVLq3s49FxF7m/1A0A= -k8s.io/kube-aggregator v0.21.3 h1:jS/6ZZGPCkBQhzGGusAd2St+KP/FtQBCXOCOo3H7/U4= +k8s.io/klog/v2 v2.30.0/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= +k8s.io/klog/v2 v2.60.1 h1:VW25q3bZx9uE3vvdL6M8ezOX79vA2Aq1nEWLqNQclHc= +k8s.io/klog/v2 v2.60.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= k8s.io/kube-aggregator v0.21.3/go.mod h1:9OIUuR5KIsNZYP/Xsh4HBsaqbS7ICJpRz3XSKtKajRc= +k8s.io/kube-aggregator v0.24.0 h1:ax2B6v5y+sLISgal5COnlDRKOSr97uXpwif6nnK3a/M= +k8s.io/kube-aggregator v0.24.0/go.mod h1:ftfs6Fi46z3cKzeF2kvNBPLbMlSKuqZbesJGNp/cQnw= k8s.io/kube-openapi v0.0.0-20200121204235-bf4fb3bd569c/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E= k8s.io/kube-openapi v0.0.0-20200410145947-61e04a5be9a6/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E= k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd/go.mod h1:WOJ3KddDSol4tAGcJo0Tvi+dK12EcqSLqcWsryKMpfM= k8s.io/kube-openapi v0.0.0-20210305001622-591a79e4bda7/go.mod h1:wXW5VT87nVfh/iLV8FpR2uDvrFyomxbtb1KivDbvPTE= -k8s.io/kube-openapi v0.0.0-20210305164622-f622666832c1 h1:bKbnE878105Y2291CtM1YO9XIQJe/QsG2SRx6vxQmDI= -k8s.io/kube-openapi v0.0.0-20210305164622-f622666832c1/go.mod h1:wXW5VT87nVfh/iLV8FpR2uDvrFyomxbtb1KivDbvPTE= -k8s.io/kubectl v0.21.0/go.mod h1:EU37NukZRXn1TpAkMUoy8Z/B2u6wjHDS4aInsDzVvks= -k8s.io/kubelet v0.21.0/go.mod h1:G5ZxMTVev9t4bhmsSxDAWhH6wXDYEVHVVFyYsw4laR4= +k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw= +k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65/go.mod h1:sX9MT8g7NVZM5lVL/j8QyCCJe8YSMW30QvGZWaCIDIk= +k8s.io/kube-openapi v0.0.0-20220328201542-3ee0da9b0b42 h1:Gii5eqf+GmIEwGNKQYQClCayuJCe2/4fZUvF7VG99sU= +k8s.io/kube-openapi v0.0.0-20220328201542-3ee0da9b0b42/go.mod h1:Z/45zLw8lUo4wdiUkI+v/ImEGAvu3WatcZl3lPMR4Rk= +k8s.io/kubectl v0.24.0/go.mod h1:pdXkmCyHiRTqjYfyUJiXtbVNURhv0/Q1TyRhy2d5ic0= +k8s.io/kubelet v0.24.0/go.mod h1:p3BBacmHTCMpUf+nluhlyzuGHmONKAspqCvpu9oPAyA= k8s.io/kubernetes v1.13.0/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk= -k8s.io/metrics v0.21.0/go.mod h1:L3Ji9EGPP1YBbfm9sPfEXSpnj8i24bfQbAFAsW0NueQ= -k8s.io/metrics v0.21.3 h1:BXLcDFR/2XUNOcFDyNI6//9pK+WIDCbQ0+uEkIjcHEc= k8s.io/metrics v0.21.3/go.mod h1:mN3Klf203Lw1hOsfg1MG7DR/kKUhwiyu8GSFCXZdz+o= +k8s.io/metrics v0.24.0 h1:nsFLJBDgj+B8mXvVBWFxTZBRRDJ8uTdf4C/Gedjy9BA= +k8s.io/metrics v0.24.0/go.mod h1:jrLlFGdKl3X+szubOXPG0Lf2aVxuV3QJcbsgVRAM6fI= k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= k8s.io/utils v0.0.0-20200603063816-c1c6865ac451/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= -k8s.io/utils v0.0.0-20210527160623-6fdb442a123b h1:MSqsVQ3pZvPGTqCjptfimO2WjG7A9un2zcpiHkA6M/s= -k8s.io/utils v0.0.0-20210527160623-6fdb442a123b/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/utils v0.0.0-20211116205334-6203023598ed/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9 h1:HNSDgDCrr/6Ly3WEGKZftiE7IY19Vz2GdbOCyI4qqhc= +k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= @@ -1749,22 +1817,26 @@ sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.7/go.mod h1:PHgbrJT sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.14/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.15/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.19/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.30/go.mod h1:fEO7lRTdivWO2qYVCVG7dEADOMo/MLDCVr8So2g88Uw= sigs.k8s.io/controller-runtime v0.6.1/go.mod h1:XRYBPdbf5XJu9kpS84VJiZ7h/u1hF3gEORz0efEja7A= -sigs.k8s.io/controller-runtime v0.9.1/go.mod h1:cTqsgnwSOsYS03XwySYZj8k6vf0+eC4FJRcCgQ9elb4= +sigs.k8s.io/controller-runtime v0.11.2/go.mod h1:P6QCzrEjLaZGqHsfd+os7JQ+WFZhvB8MRFsn4dWF7O4= sigs.k8s.io/controller-tools v0.3.0/go.mod h1:enhtKGfxZD1GFEoMgP8Fdbu+uKQ/cq1/WGJhdVChfvI= +sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6/go.mod h1:p4QtZmO4uMYipTQNzagwnNoseA6OxSUutVw05NhYDRs= +sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2/go.mod h1:B+TnT182UBxE84DiCz4CVE26eOSDAeYCpfDnC2kdKMY= sigs.k8s.io/kind v0.8.1/go.mod h1:oNKTxUVPYkV9lWzY6CVMNluVq8cBsyq+UgPJdvA3uu4= -sigs.k8s.io/kustomize/api v0.8.5/go.mod h1:M377apnKT5ZHJS++6H4rQoCHmWtt6qTpp3mbe7p6OLY= -sigs.k8s.io/kustomize/cmd/config v0.9.7/go.mod h1:MvXCpHs77cfyxRmCNUQjIqCmZyYsbn5PyQpWiq44nW0= -sigs.k8s.io/kustomize/kustomize/v4 v4.0.5/go.mod h1:C7rYla7sI8EnxHE/xEhRBSHMNfcL91fx0uKmUlUhrBk= -sigs.k8s.io/kustomize/kyaml v0.10.15/go.mod h1:mlQFagmkm1P+W4lZJbJ/yaxMd8PqMRSC4cPcfUVt5Hg= +sigs.k8s.io/kustomize/api v0.11.4/go.mod h1:k+8RsqYbgpkIrJ4p9jcdPqe8DprLxFUUO0yNOq8C+xI= +sigs.k8s.io/kustomize/cmd/config v0.10.6/go.mod h1:/S4A4nUANUa4bZJ/Edt7ZQTyKOY9WCER0uBS1SW2Rco= +sigs.k8s.io/kustomize/kustomize/v4 v4.5.4/go.mod h1:Zo/Xc5FKD6sHl0lilbrieeGeZHVYCA4BzxeAaLI05Bg= +sigs.k8s.io/kustomize/kyaml v0.13.6/go.mod h1:yHP031rn1QX1lr/Xd934Ri/xdVNG8BE2ECa78Ht/kEg= sigs.k8s.io/mcs-api v0.1.0/go.mod h1:gGiAryeFNB4GBsq2LBmVqSgKoobLxt+p7ii/WG5QYYw= sigs.k8s.io/structured-merge-diff/v3 v3.0.0-20200116222232-67a7b8c61874/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= sigs.k8s.io/structured-merge-diff/v3 v3.0.0/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= sigs.k8s.io/structured-merge-diff/v4 v4.0.3/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= -sigs.k8s.io/structured-merge-diff/v4 v4.1.0/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= -sigs.k8s.io/structured-merge-diff/v4 v4.1.2 h1:Hr/htKFmJEbtMgS/UD0N+gtgctAqz81t3nu+sPzynno= sigs.k8s.io/structured-merge-diff/v4 v4.1.2/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= +sigs.k8s.io/structured-merge-diff/v4 v4.2.1 h1:bKCqE9GvQ5tiVHn5rfn1r+yao3aLQEaLzkkmAkf+A6Y= +sigs.k8s.io/structured-merge-diff/v4 v4.2.1/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= -sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= +sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= +sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= diff --git a/test/e2e/README.md b/test/e2e/README.md index 656592845f8..eae5d3e72b0 100644 --- a/test/e2e/README.md +++ b/test/e2e/README.md @@ -184,9 +184,13 @@ manifest to the control-plane Docker container: ```bash ./hack/generate-manifest.sh | docker exec -i kind-control-plane dd of=/root/antrea.yml -go test -v antrea.io/antrea/test/e2e -provider=kind +go test -timeout=75 -v antrea.io/antrea/test/e2e -provider=kind ``` +The default timeout of `go test` is [10 minutes](https://pkg.go.dev/cmd/go#hdr-Testing_flags). +If you encounter any timeout issue during e2e, you can try to increase timeout first. Some cases +take more than 10 minutes. eg: `go test -v -timeout=20m antrea.io/antrea/test/e2e -run=TestAntreaPolicy -provider=kind`. + `generate-manifest.sh` supports generating the Antrea manifest with different Antrea configurations. Run `./hack/generate-manifest.sh --help` to see the supported config options. diff --git a/test/e2e/antctl_test.go b/test/e2e/antctl_test.go index 0529ff2dad1..7b1b24faad8 100644 --- a/test/e2e/antctl_test.go +++ b/test/e2e/antctl_test.go @@ -36,7 +36,6 @@ type cmdAndReturnCode struct { // TestAntctl is the top-level test which contains all subtests for // Antctl related test cases as they can share setup, teardown. func TestAntctl(t *testing.T) { - skipIfHasWindowsNodes(t) skipIfNotRequired(t, "mode-irrelevant") data, err := setupTest(t) @@ -114,7 +113,7 @@ func testAntctlAgentLocalAccess(t *testing.T, data *TestData) { cmd := strings.Join(args, " ") t.Run(cmd, func(t *testing.T) { stdout, stderr, err := runAntctl(podName, args, data) - if err != nil { + if err != nil && !strings.HasSuffix(stderr, "not enabled\n") { t.Fatalf("Error when running `antctl %s` from %s: %v\n%s", c, podName, err, antctlOutput(stdout, stderr)) } }) diff --git a/test/e2e/antreaipam_service_test.go b/test/e2e/antreaipam_service_test.go index cee0c1fc0d4..2ccc3cc5ba8 100644 --- a/test/e2e/antreaipam_service_test.go +++ b/test/e2e/antreaipam_service_test.go @@ -54,12 +54,12 @@ func TestAntreaIPAMService(t *testing.T) { }) t.Run("testAntreaIPAMClusterIPv4", func(t *testing.T) { skipIfNotIPv4Cluster(t) - data.testClusterIP(t, false, testNamespace, testAntreaIPAMNamespace) + data.testClusterIP(t, false, data.testNamespace, testAntreaIPAMNamespace) checkIPPoolsEmpty(t, data, ipPools) }) t.Run("testAntreaIPAMPodToClusterIPv4", func(t *testing.T) { skipIfNotIPv4Cluster(t) - data.testClusterIP(t, false, testAntreaIPAMNamespace, testNamespace) + data.testClusterIP(t, false, testAntreaIPAMNamespace, data.testNamespace) checkIPPoolsEmpty(t, data, ipPools) }) t.Run("testAntreaIPAMVLAN11PodToAntreaIPAMVLAN11ClusterIPv4", func(t *testing.T) { @@ -84,12 +84,12 @@ func TestAntreaIPAMService(t *testing.T) { }) t.Run("testAntreaIPAMVLAN11ClusterIPv4", func(t *testing.T) { skipIfNotIPv4Cluster(t) - data.testClusterIP(t, false, testNamespace, testAntreaIPAMNamespace11) + data.testClusterIP(t, false, data.testNamespace, testAntreaIPAMNamespace11) checkIPPoolsEmpty(t, data, ipPools) }) t.Run("testAntreaIPAMVLAN11PodToClusterIPv4", func(t *testing.T) { skipIfNotIPv4Cluster(t) - data.testClusterIP(t, false, testAntreaIPAMNamespace11, testNamespace) + data.testClusterIP(t, false, testAntreaIPAMNamespace11, data.testNamespace) checkIPPoolsEmpty(t, data, ipPools) }) @@ -100,12 +100,12 @@ func TestAntreaIPAMService(t *testing.T) { }) t.Run("testAntreaIPAMNodePort", func(t *testing.T) { skipIfHasWindowsNodes(t) - data.testNodePort(t, false, testNamespace, testAntreaIPAMNamespace) + data.testNodePort(t, false, data.testNamespace, testAntreaIPAMNamespace) checkIPPoolsEmpty(t, data, ipPools) }) t.Run("testAntreaIPAMPodToNodePort", func(t *testing.T) { skipIfHasWindowsNodes(t) - data.testNodePort(t, false, testAntreaIPAMNamespace, testNamespace) + data.testNodePort(t, false, testAntreaIPAMNamespace, data.testNamespace) checkIPPoolsEmpty(t, data, ipPools) }) t.Run("testAntreaIPAMVLAN11PodToAntreaIPAMVLAN11NodePort", func(t *testing.T) { @@ -130,12 +130,12 @@ func TestAntreaIPAMService(t *testing.T) { }) t.Run("testAntreaIPAMVLAN11NodePort", func(t *testing.T) { skipIfHasWindowsNodes(t) - data.testNodePort(t, false, testNamespace, testAntreaIPAMNamespace11) + data.testNodePort(t, false, data.testNamespace, testAntreaIPAMNamespace11) checkIPPoolsEmpty(t, data, ipPools) }) t.Run("testAntreaIPAMVLAN11PodToNodePort", func(t *testing.T) { skipIfHasWindowsNodes(t) - data.testNodePort(t, false, testAntreaIPAMNamespace11, testNamespace) + data.testNodePort(t, false, testAntreaIPAMNamespace11, data.testNamespace) checkIPPoolsEmpty(t, data, ipPools) }) } diff --git a/test/e2e/antreaipam_test.go b/test/e2e/antreaipam_test.go index 8d8eaf551ac..0a1780a9ac5 100644 --- a/test/e2e/antreaipam_test.go +++ b/test/e2e/antreaipam_test.go @@ -44,7 +44,7 @@ var ( Name: "test-ippool-ipv4-0", }, Spec: crdv1alpha2.IPPoolSpec{ - IPVersion: 4, + IPVersion: crdv1alpha2.IPv4, IPRanges: []crdv1alpha2.SubnetIPRange{{IPRange: crdv1alpha2.IPRange{ CIDR: "", Start: "192.168.240.100", @@ -61,7 +61,7 @@ var ( Name: "test-ippool-ipv4-1", }, Spec: crdv1alpha2.IPPoolSpec{ - IPVersion: 4, + IPVersion: crdv1alpha2.IPv4, IPRanges: []crdv1alpha2.SubnetIPRange{{IPRange: crdv1alpha2.IPRange{ CIDR: "", Start: "192.168.240.130", @@ -186,12 +186,12 @@ func TestAntreaIPAM(t *testing.T) { }) t.Run("testAntreaIPAMHostPortPodConnectivity", func(t *testing.T) { skipIfHasWindowsNodes(t) - data.testHostPortPodConnectivity(t, testNamespace, testAntreaIPAMNamespace) + data.testHostPortPodConnectivity(t, data.testNamespace, testAntreaIPAMNamespace) checkIPPoolsEmpty(t, data, ipPools) }) t.Run("testAntreaIPAMPodToHostPortPodConnectivity", func(t *testing.T) { skipIfHasWindowsNodes(t) - data.testHostPortPodConnectivity(t, testAntreaIPAMNamespace, testNamespace) + data.testHostPortPodConnectivity(t, testAntreaIPAMNamespace, data.testNamespace) checkIPPoolsEmpty(t, data, ipPools) }) t.Run("testAntreaIPAMVLAN11PodToAntreaIPAMVLAN11HostPortPodConnectivity", func(t *testing.T) { @@ -216,12 +216,12 @@ func TestAntreaIPAM(t *testing.T) { }) t.Run("testAntreaIPAMVLAN11HostPortPodConnectivity", func(t *testing.T) { skipIfHasWindowsNodes(t) - data.testHostPortPodConnectivity(t, testNamespace, testAntreaIPAMNamespace11) + data.testHostPortPodConnectivity(t, data.testNamespace, testAntreaIPAMNamespace11) checkIPPoolsEmpty(t, data, ipPools) }) t.Run("testAntreaIPAMVLAN11PodToHostPortPodConnectivity", func(t *testing.T) { skipIfHasWindowsNodes(t) - data.testHostPortPodConnectivity(t, testAntreaIPAMNamespace11, testNamespace) + data.testHostPortPodConnectivity(t, testAntreaIPAMNamespace11, data.testNamespace) checkIPPoolsEmpty(t, data, ipPools) }) t.Run("testAntreaIPAMOVSRestartSameNode", func(t *testing.T) { @@ -260,7 +260,7 @@ func testAntreaIPAMPodConnectivitySameNode(t *testing.T, data *TestData) { // One Per-Node IPAM Pod podInfos = append(podInfos, podInfo{ name: randName("test-pod-0-"), - namespace: testNamespace, + namespace: data.testNamespace, }) workerNode := workerNodeName(1) @@ -279,7 +279,7 @@ func testAntreaIPAMPodConnectivitySameNode(t *testing.T, data *TestData) { func testAntreaIPAMPodConnectivityDifferentNodes(t *testing.T, data *TestData) { maxNodes := 3 var podInfos []podInfo - for _, namespace := range []string{testNamespace, testAntreaIPAMNamespace, testAntreaIPAMNamespace11, testAntreaIPAMNamespace12} { + for _, namespace := range []string{data.testNamespace, testAntreaIPAMNamespace, testAntreaIPAMNamespace11, testAntreaIPAMNamespace12} { createdPodInfos, deletePods := createPodsOnDifferentNodes(t, data, namespace, "differentnodes") defer deletePods() if len(createdPodInfos) > maxNodes { diff --git a/test/e2e/antreapolicy_test.go b/test/e2e/antreapolicy_test.go index 6f94a78b841..d4b7bfc5784 100644 --- a/test/e2e/antreapolicy_test.go +++ b/test/e2e/antreapolicy_test.go @@ -48,7 +48,8 @@ var ( podsByNamespace map[string][]Pod k8sUtils *KubernetesUtils allTestList []*TestCase - pods, namespaces []string + pods []string + namespaces map[string]string podIPs map[string][]string p80, p81, p8080, p8081, p8082, p8085, p6443 int32 ) @@ -121,7 +122,11 @@ func initialize(t *testing.T, data *TestData) { p8082 = 8082 p8085 = 8085 pods = []string{"a", "b", "c"} - namespaces = []string{"x", "y", "z"} + namespaces = make(map[string]string) + suffix := randName("") + namespaces["x"] = "x-" + suffix + namespaces["y"] = "y-" + suffix + namespaces["z"] = "z-" + suffix // This function "initialize" will be used more than once, and variable "allPods" is global. // It should be empty every time when "initialize" is performed, otherwise there will be unexpected // results. @@ -149,7 +154,7 @@ func skipIfAntreaPolicyDisabled(tb testing.TB) { skipIfFeatureDisabled(tb, features.AntreaPolicy, true, true) } -func applyDefaultDenyToAllNamespaces(k8s *KubernetesUtils, namespaces []string) error { +func applyDefaultDenyToAllNamespaces(k8s *KubernetesUtils, namespaces map[string]string) error { if err := k8s.CleanNetworkPolicies(namespaces); err != nil { return err } @@ -163,7 +168,7 @@ func applyDefaultDenyToAllNamespaces(k8s *KubernetesUtils, namespaces []string) } time.Sleep(networkPolicyDelay) r := NewReachability(allPods, Dropped) - k8s.Validate(allPods, r, []int32{p80}, v1.ProtocolTCP) + k8s.Validate(allPods, r, []int32{p80}, ProtocolTCP) _, wrong, _ := r.Summary() if wrong != 0 { return fmt.Errorf("error when creating default deny k8s NetworkPolicies") @@ -171,13 +176,13 @@ func applyDefaultDenyToAllNamespaces(k8s *KubernetesUtils, namespaces []string) return nil } -func cleanupDefaultDenyNPs(k8s *KubernetesUtils, namespaces []string) error { +func cleanupDefaultDenyNPs(k8s *KubernetesUtils, namespaces map[string]string) error { if err := k8s.CleanNetworkPolicies(namespaces); err != nil { return err } time.Sleep(networkPolicyDelay * 2) r := NewReachability(allPods, Connected) - k8s.Validate(allPods, r, []int32{p80}, v1.ProtocolTCP) + k8s.Validate(allPods, r, []int32{p80}, ProtocolTCP) _, wrong, _ := r.Summary() if wrong != 0 { return fmt.Errorf("error when cleaning default deny k8s NetworkPolicies") @@ -206,7 +211,7 @@ func testMutateACNPNoTier(t *testing.T) { func testMutateANPNoTier(t *testing.T) { invalidNpErr := fmt.Errorf("ANP tier not mutated to default tier") builder := &AntreaNetworkPolicySpecBuilder{} - builder = builder.SetName("x", "anp-no-tier"). + builder = builder.SetName(namespaces["x"], "anp-no-tier"). SetAppliedToGroup([]ANPAppliedToSpec{{PodSelector: map[string]string{"pod": "a"}}}). SetPriority(10.0) anp := builder.Get() @@ -227,7 +232,7 @@ func testMutateACNPNoRuleName(t *testing.T) { builder = builder.SetName("acnp-no-rule-name"). SetAppliedToGroup([]ACNPAppliedToSpec{{PodSelector: map[string]string{"pod": "a"}}}). SetPriority(10.0). - AddIngress(v1.ProtocolTCP, &p80, nil, nil, nil, map[string]string{"pod": "b"}, map[string]string{"ns": "x"}, + AddIngress(ProtocolTCP, &p80, nil, nil, nil, nil, nil, map[string]string{"pod": "b"}, map[string]string{"ns": namespaces["x"]}, nil, nil, false, nil, crdv1alpha1.RuleActionAllow, "", "", nil) acnp := builder.Get() log.Debugf("creating ACNP %v", acnp.Name) @@ -249,10 +254,10 @@ func testMutateACNPNoRuleName(t *testing.T) { func testMutateANPNoRuleName(t *testing.T) { mutateErr := fmt.Errorf("ANP Rule name not mutated automatically") builder := &AntreaNetworkPolicySpecBuilder{} - builder = builder.SetName("x", "anp-no-rule-name"). + builder = builder.SetName(namespaces["x"], "anp-no-rule-name"). SetAppliedToGroup([]ANPAppliedToSpec{{PodSelector: map[string]string{"pod": "a"}}}). SetPriority(10.0). - AddIngress(v1.ProtocolTCP, &p80, nil, nil, nil, map[string]string{"pod": "b"}, map[string]string{"ns": "x"}, + AddIngress(ProtocolTCP, &p80, nil, nil, nil, nil, nil, map[string]string{"pod": "b"}, map[string]string{"ns": namespaces["x"]}, nil, nil, nil, crdv1alpha1.RuleActionAllow, "") anp := builder.Get() log.Debugf("creating ANP %v", anp.Name) @@ -287,7 +292,7 @@ func testInvalidACNPNoPriority(t *testing.T) { func testInvalidANPNoPriority(t *testing.T) { invalidNpErr := fmt.Errorf("invalid Antrea NetworkPolicy without a priority accepted") builder := &AntreaNetworkPolicySpecBuilder{} - builder = builder.SetName("x", "anp-no-priority"). + builder = builder.SetName(namespaces["x"], "anp-no-priority"). SetAppliedToGroup([]ANPAppliedToSpec{{PodSelector: map[string]string{"pod": "a"}}}) anp := builder.Get() log.Debugf("creating ANP %v", anp.Name) @@ -300,11 +305,11 @@ func testInvalidANPNoPriority(t *testing.T) { func testInvalidANPRuleNameNotUnique(t *testing.T) { invalidNpErr := fmt.Errorf("invalid Antrea NetworkPolicy without unique rule names accepted") builder := &AntreaNetworkPolicySpecBuilder{} - builder = builder.SetName("x", "anp-rule-name-not-unique"). + builder = builder.SetName(namespaces["x"], "anp-rule-name-not-unique"). SetAppliedToGroup([]ANPAppliedToSpec{{PodSelector: map[string]string{"pod": "a"}}}). - AddIngress(v1.ProtocolTCP, &p80, nil, nil, nil, map[string]string{"pod": "b"}, map[string]string{"ns": "x"}, + AddIngress(ProtocolTCP, &p80, nil, nil, nil, nil, nil, map[string]string{"pod": "b"}, map[string]string{"ns": namespaces["x"]}, nil, nil, nil, crdv1alpha1.RuleActionAllow, "not-unique"). - AddIngress(v1.ProtocolTCP, &p81, nil, nil, nil, map[string]string{"pod": "c"}, map[string]string{"ns": "x"}, + AddIngress(ProtocolTCP, &p81, nil, nil, nil, nil, nil, map[string]string{"pod": "c"}, map[string]string{"ns": namespaces["x"]}, nil, nil, nil, crdv1alpha1.RuleActionAllow, "not-unique") anp := builder.Get() log.Debugf("creating ANP %v", anp.Name) @@ -317,7 +322,7 @@ func testInvalidANPRuleNameNotUnique(t *testing.T) { func testInvalidANPTierDoesNotExist(t *testing.T) { invalidNpErr := fmt.Errorf("invalid Antrea NetworkPolicy without existing Tier accepted") builder := &AntreaNetworkPolicySpecBuilder{} - builder = builder.SetName("x", "anp-tier-not-exist"). + builder = builder.SetName(namespaces["x"], "anp-tier-not-exist"). SetAppliedToGroup([]ANPAppliedToSpec{{PodSelector: map[string]string{"pod": "a"}}}). SetTier("i-dont-exist") anp := builder.Get() @@ -331,10 +336,10 @@ func testInvalidANPTierDoesNotExist(t *testing.T) { func testInvalidANPPortRangePortUnset(t *testing.T) { invalidNpErr := fmt.Errorf("invalid Antrea NetworkPolicy egress rule with endPort but no port accepted") builder := &AntreaNetworkPolicySpecBuilder{} - builder = builder.SetName("y", "anp-egress-port-range-port-unset"). + builder = builder.SetName(namespaces["y"], "anp-egress-port-range-port-unset"). SetPriority(1.0). SetAppliedToGroup([]ANPAppliedToSpec{{PodSelector: map[string]string{"pod": "b"}}}) - builder.AddEgress(v1.ProtocolTCP, nil, nil, &p8085, nil, map[string]string{"pod": "c"}, map[string]string{"ns": "x"}, + builder.AddEgress(ProtocolTCP, nil, nil, &p8085, nil, nil, nil, map[string]string{"pod": "c"}, map[string]string{"ns": namespaces["x"]}, nil, nil, nil, crdv1alpha1.RuleActionDrop, "anp-port-range") anp := builder.Get() @@ -348,10 +353,10 @@ func testInvalidANPPortRangePortUnset(t *testing.T) { func testInvalidANPPortRangeEndPortSmall(t *testing.T) { invalidNpErr := fmt.Errorf("invalid Antrea NetworkPolicy egress rule with endPort smaller than port accepted") builder := &AntreaNetworkPolicySpecBuilder{} - builder = builder.SetName("y", "anp-egress-port-range-endport-small"). + builder = builder.SetName(namespaces["y"], "anp-egress-port-range-endport-small"). SetPriority(1.0). SetAppliedToGroup([]ANPAppliedToSpec{{PodSelector: map[string]string{"pod": "b"}}}) - builder.AddEgress(v1.ProtocolTCP, &p8082, nil, &p8081, nil, map[string]string{"pod": "c"}, map[string]string{"ns": "x"}, + builder.AddEgress(ProtocolTCP, &p8082, nil, &p8081, nil, nil, nil, map[string]string{"pod": "c"}, map[string]string{"ns": namespaces["x"]}, nil, nil, nil, crdv1alpha1.RuleActionDrop, "anp-port-range") anp := builder.Get() @@ -443,7 +448,7 @@ func testInvalidTierANPRefDelete(t *testing.T) { failOnError(fmt.Errorf("create Tier failed for tier tier-anp: %v", err), t) } builder := &AntreaNetworkPolicySpecBuilder{} - builder = builder.SetName("x", "anp-for-tier"). + builder = builder.SetName(namespaces["x"], "anp-for-tier"). SetAppliedToGroup([]ANPAppliedToSpec{{PodSelector: map[string]string{"pod": "a"}}}). SetTier("tier-anp"). SetPriority(13.0) @@ -461,7 +466,7 @@ func testInvalidTierANPRefDelete(t *testing.T) { } // testInvalidACNPPodSelectorNsSelectorMatchExpressions tests creating a ClusterNetworkPolicy with invalid LabelSelector(MatchExpressions) -func testInvalidACNPPodSelectorNsSelectorMatchExpressions(t *testing.T) { +func testInvalidACNPPodSelectorNsSelectorMatchExpressions(t *testing.T, data *TestData) { invalidLSErr := fmt.Errorf("create Antrea NetworkPolicy with namespaceSelector but matchExpressions invalid") allowAction := crdv1alpha1.RuleActionAllow @@ -470,7 +475,7 @@ func testInvalidACNPPodSelectorNsSelectorMatchExpressions(t *testing.T) { var acnp = &crdv1alpha1.ClusterNetworkPolicy{ ObjectMeta: metav1.ObjectMeta{ - Namespace: testNamespace, Name: "cnptest", Labels: map[string]string{"antrea-e2e": "cnp1"}}, + Namespace: data.testNamespace, Name: "cnptest", Labels: map[string]string{"antrea-e2e": "cnp1"}}, Spec: crdv1alpha1.ClusterNetworkPolicySpec{ AppliedTo: []crdv1alpha1.NetworkPolicyPeer{ {PodSelector: &selectorA}, @@ -497,13 +502,13 @@ func testACNPAllowXBtoA(t *testing.T) { builder = builder.SetName("acnp-allow-xb-to-a"). SetPriority(1.0). SetAppliedToGroup([]ACNPAppliedToSpec{{PodSelector: map[string]string{"pod": "a"}}}) - builder.AddIngress(v1.ProtocolTCP, &p80, nil, nil, nil, map[string]string{"pod": "b"}, map[string]string{"ns": "x"}, + builder.AddIngress(ProtocolTCP, &p80, nil, nil, nil, nil, nil, map[string]string{"pod": "b"}, map[string]string{"ns": namespaces["x"]}, nil, nil, false, nil, crdv1alpha1.RuleActionAllow, "", "", nil) reachability := NewReachability(allPods, Dropped) - reachability.Expect(Pod("x/b"), Pod("x/a"), Connected) - reachability.Expect(Pod("x/b"), Pod("y/a"), Connected) - reachability.Expect(Pod("x/b"), Pod("z/a"), Connected) + reachability.Expect(Pod(namespaces["x"]+"/b"), Pod(namespaces["x"]+"/a"), Connected) + reachability.Expect(Pod(namespaces["x"]+"/b"), Pod(namespaces["y"]+"/a"), Connected) + reachability.Expect(Pod(namespaces["x"]+"/b"), Pod(namespaces["z"]+"/a"), Connected) reachability.ExpectSelf(allPods, Connected) testStep := []*TestStep{ @@ -512,7 +517,7 @@ func testACNPAllowXBtoA(t *testing.T) { reachability, []metav1.Object{builder.Get()}, []int32{80}, - v1.ProtocolTCP, + ProtocolTCP, 0, nil, }, @@ -530,12 +535,12 @@ func testACNPAllowXBtoYA(t *testing.T) { builder := &ClusterNetworkPolicySpecBuilder{} builder = builder.SetName("acnp-allow-xb-to-ya"). SetPriority(2.0). - SetAppliedToGroup([]ACNPAppliedToSpec{{PodSelector: map[string]string{"pod": "a"}, NSSelector: map[string]string{"ns": "y"}}}) - builder.AddIngress(v1.ProtocolTCP, nil, &port81Name, nil, nil, map[string]string{"pod": "b"}, map[string]string{"ns": "x"}, + SetAppliedToGroup([]ACNPAppliedToSpec{{PodSelector: map[string]string{"pod": "a"}, NSSelector: map[string]string{"ns": namespaces["y"]}}}) + builder.AddIngress(ProtocolTCP, nil, &port81Name, nil, nil, nil, nil, map[string]string{"pod": "b"}, map[string]string{"ns": namespaces["x"]}, nil, nil, false, nil, crdv1alpha1.RuleActionAllow, "", "", nil) reachability := NewReachability(allPods, Dropped) - reachability.Expect(Pod("x/b"), Pod("y/a"), Connected) + reachability.Expect(Pod(namespaces["x"]+"/b"), Pod(namespaces["y"]+"/a"), Connected) reachability.ExpectSelf(allPods, Connected) testStep := []*TestStep{ @@ -544,7 +549,7 @@ func testACNPAllowXBtoYA(t *testing.T) { reachability, []metav1.Object{builder.Get()}, []int32{81}, - v1.ProtocolTCP, + ProtocolTCP, 0, nil, }, @@ -562,25 +567,25 @@ func testACNPPriorityOverrideDefaultDeny(t *testing.T) { builder1 := &ClusterNetworkPolicySpecBuilder{} builder1 = builder1.SetName("acnp-priority2"). SetPriority(2). - SetAppliedToGroup([]ACNPAppliedToSpec{{NSSelector: map[string]string{"ns": "x"}}}) - builder1.AddIngress(v1.ProtocolTCP, &p80, nil, nil, nil, nil, map[string]string{"ns": "z"}, + SetAppliedToGroup([]ACNPAppliedToSpec{{NSSelector: map[string]string{"ns": namespaces["x"]}}}) + builder1.AddIngress(ProtocolTCP, &p80, nil, nil, nil, nil, nil, nil, map[string]string{"ns": namespaces["z"]}, nil, nil, false, nil, crdv1alpha1.RuleActionAllow, "", "", nil) builder2 := &ClusterNetworkPolicySpecBuilder{} builder2 = builder2.SetName("acnp-priority1"). SetPriority(1). - SetAppliedToGroup([]ACNPAppliedToSpec{{PodSelector: map[string]string{"pod": "a"}, NSSelector: map[string]string{"ns": "x"}}}) - builder2.AddIngress(v1.ProtocolTCP, &p80, nil, nil, nil, nil, map[string]string{"ns": "z"}, + SetAppliedToGroup([]ACNPAppliedToSpec{{PodSelector: map[string]string{"pod": "a"}, NSSelector: map[string]string{"ns": namespaces["x"]}}}) + builder2.AddIngress(ProtocolTCP, &p80, nil, nil, nil, nil, nil, nil, map[string]string{"ns": namespaces["z"]}, nil, nil, false, nil, crdv1alpha1.RuleActionDrop, "", "", nil) // Ingress from ns:z to x/a will be dropped since acnp-priority1 has higher precedence. reachabilityBothACNP := NewReachability(allPods, Dropped) - reachabilityBothACNP.Expect(Pod("z/a"), Pod("x/b"), Connected) - reachabilityBothACNP.Expect(Pod("z/a"), Pod("x/c"), Connected) - reachabilityBothACNP.Expect(Pod("z/b"), Pod("x/b"), Connected) - reachabilityBothACNP.Expect(Pod("z/b"), Pod("x/c"), Connected) - reachabilityBothACNP.Expect(Pod("z/c"), Pod("x/b"), Connected) - reachabilityBothACNP.Expect(Pod("z/c"), Pod("x/c"), Connected) + reachabilityBothACNP.Expect(Pod(namespaces["z"]+"/a"), Pod(namespaces["x"]+"/b"), Connected) + reachabilityBothACNP.Expect(Pod(namespaces["z"]+"/a"), Pod(namespaces["x"]+"/c"), Connected) + reachabilityBothACNP.Expect(Pod(namespaces["z"]+"/b"), Pod(namespaces["x"]+"/b"), Connected) + reachabilityBothACNP.Expect(Pod(namespaces["z"]+"/b"), Pod(namespaces["x"]+"/c"), Connected) + reachabilityBothACNP.Expect(Pod(namespaces["z"]+"/c"), Pod(namespaces["x"]+"/b"), Connected) + reachabilityBothACNP.Expect(Pod(namespaces["z"]+"/c"), Pod(namespaces["x"]+"/c"), Connected) reachabilityBothACNP.ExpectSelf(allPods, Connected) testStep := []*TestStep{ @@ -589,7 +594,7 @@ func testACNPPriorityOverrideDefaultDeny(t *testing.T) { reachabilityBothACNP, []metav1.Object{builder1.Get(), builder2.Get()}, []int32{80}, - v1.ProtocolTCP, + ProtocolTCP, 0, nil, }, @@ -601,8 +606,8 @@ func testACNPPriorityOverrideDefaultDeny(t *testing.T) { } // testACNPAllowNoDefaultIsolation tests that no default isolation rules are created for Policies. -func testACNPAllowNoDefaultIsolation(t *testing.T, protocol v1.Protocol) { - if protocol == v1.ProtocolSCTP { +func testACNPAllowNoDefaultIsolation(t *testing.T, protocol AntreaPolicyProtocol) { + if protocol == ProtocolSCTP { // SCTP testing is failing on our IPv6 CI testbeds at the moment. This seems to be // related to an issue with ESX networking for SCTPv6 traffic when the Pods are on // different Node VMs which are themselves on different ESX hosts. We are @@ -613,10 +618,10 @@ func testACNPAllowNoDefaultIsolation(t *testing.T, protocol v1.Protocol) { builder := &ClusterNetworkPolicySpecBuilder{} builder = builder.SetName("acnp-allow-x-ingress-y-egress-z"). SetPriority(1.1). - SetAppliedToGroup([]ACNPAppliedToSpec{{NSSelector: map[string]string{"ns": "x"}}}) - builder.AddIngress(protocol, &p81, nil, nil, nil, nil, map[string]string{"ns": "y"}, + SetAppliedToGroup([]ACNPAppliedToSpec{{NSSelector: map[string]string{"ns": namespaces["x"]}}}) + builder.AddIngress(protocol, &p81, nil, nil, nil, nil, nil, nil, map[string]string{"ns": namespaces["y"]}, nil, nil, false, nil, crdv1alpha1.RuleActionAllow, "", "", nil) - builder.AddEgress(protocol, &p81, nil, nil, nil, nil, map[string]string{"ns": "z"}, + builder.AddEgress(protocol, &p81, nil, nil, nil, nil, nil, nil, map[string]string{"ns": namespaces["z"]}, nil, nil, false, nil, crdv1alpha1.RuleActionAllow, "", "", nil) reachability := NewReachability(allPods, Connected) @@ -638,8 +643,8 @@ func testACNPAllowNoDefaultIsolation(t *testing.T, protocol v1.Protocol) { } // testACNPDropEgress tests that an ACNP is able to drop egress traffic from pods labelled A to namespace Z. -func testACNPDropEgress(t *testing.T, protocol v1.Protocol) { - if protocol == v1.ProtocolSCTP { +func testACNPDropEgress(t *testing.T, protocol AntreaPolicyProtocol) { + if protocol == ProtocolSCTP { // SCTP testing is failing on our IPv6 CI testbeds at the moment. This seems to be // related to an issue with ESX networking for SCTPv6 traffic when the Pods are on // different Node VMs which are themselves on different ESX hosts. We are @@ -651,14 +656,14 @@ func testACNPDropEgress(t *testing.T, protocol v1.Protocol) { builder = builder.SetName("acnp-deny-a-to-z-egress"). SetPriority(1.0). SetAppliedToGroup([]ACNPAppliedToSpec{{PodSelector: map[string]string{"pod": "a"}}}) - builder.AddEgress(protocol, &p80, nil, nil, nil, nil, map[string]string{"ns": "z"}, + builder.AddEgress(protocol, &p80, nil, nil, nil, nil, nil, nil, map[string]string{"ns": namespaces["z"]}, nil, nil, false, nil, crdv1alpha1.RuleActionDrop, "", "", nil) reachability := NewReachability(allPods, Connected) - reachability.ExpectEgressToNamespace(Pod("x/a"), "z", Dropped) - reachability.ExpectEgressToNamespace(Pod("y/a"), "z", Dropped) - reachability.Expect(Pod("z/a"), Pod("z/b"), Dropped) - reachability.Expect(Pod("z/a"), Pod("z/c"), Dropped) + reachability.ExpectEgressToNamespace(Pod(namespaces["x"]+"/a"), namespaces["z"], Dropped) + reachability.ExpectEgressToNamespace(Pod(namespaces["y"]+"/a"), namespaces["z"], Dropped) + reachability.Expect(Pod(namespaces["z"]+"/a"), Pod(namespaces["z"]+"/b"), Dropped) + reachability.Expect(Pod(namespaces["z"]+"/a"), Pod(namespaces["z"]+"/c"), Dropped) testStep := []*TestStep{ { "Port 80", @@ -683,14 +688,14 @@ func testACNPDropIngressInSelectedNamespace(t *testing.T) { builder := &ClusterNetworkPolicySpecBuilder{} builder = builder.SetName("acnp-deny-ingress-to-x"). SetPriority(1.0). - SetAppliedToGroup([]ACNPAppliedToSpec{{NSSelector: map[string]string{"ns": "x"}}}) - builder.AddIngress(v1.ProtocolTCP, &p80, nil, nil, nil, nil, nil, nil, nil, false, nil, + SetAppliedToGroup([]ACNPAppliedToSpec{{NSSelector: map[string]string{"ns": namespaces["x"]}}}) + builder.AddIngress(ProtocolTCP, &p80, nil, nil, nil, nil, nil, nil, nil, nil, nil, false, nil, crdv1alpha1.RuleActionDrop, "", "drop-all-ingress", nil) reachability := NewReachability(allPods, Connected) - reachability.ExpectAllIngress("x/a", Dropped) - reachability.ExpectAllIngress("x/b", Dropped) - reachability.ExpectAllIngress("x/c", Dropped) + reachability.ExpectAllIngress(Pod(namespaces["x"]+"/a"), Dropped) + reachability.ExpectAllIngress(Pod(namespaces["x"]+"/b"), Dropped) + reachability.ExpectAllIngress(Pod(namespaces["x"]+"/c"), Dropped) reachability.ExpectSelf(allPods, Connected) testStep := []*TestStep{ { @@ -698,7 +703,7 @@ func testACNPDropIngressInSelectedNamespace(t *testing.T) { reachability, []metav1.Object{builder.Get()}, []int32{80}, - v1.ProtocolTCP, + ProtocolTCP, 0, nil, }, @@ -715,18 +720,18 @@ func testACNPNoEffectOnOtherProtocols(t *testing.T) { builder = builder.SetName("acnp-deny-a-to-z-ingress"). SetPriority(1.0). SetAppliedToGroup([]ACNPAppliedToSpec{{PodSelector: map[string]string{"pod": "a"}}}) - builder.AddIngress(v1.ProtocolTCP, &p80, nil, nil, nil, nil, map[string]string{"ns": "z"}, + builder.AddIngress(ProtocolTCP, &p80, nil, nil, nil, nil, nil, nil, map[string]string{"ns": namespaces["z"]}, nil, nil, false, nil, crdv1alpha1.RuleActionDrop, "", "", nil) reachability1 := NewReachability(allPods, Connected) - reachability1.Expect(Pod("z/a"), Pod("x/a"), Dropped) - reachability1.Expect(Pod("z/b"), Pod("x/a"), Dropped) - reachability1.Expect(Pod("z/c"), Pod("x/a"), Dropped) - reachability1.Expect(Pod("z/a"), Pod("y/a"), Dropped) - reachability1.Expect(Pod("z/b"), Pod("y/a"), Dropped) - reachability1.Expect(Pod("z/c"), Pod("y/a"), Dropped) - reachability1.Expect(Pod("z/b"), Pod("z/a"), Dropped) - reachability1.Expect(Pod("z/c"), Pod("z/a"), Dropped) + reachability1.Expect(Pod(namespaces["z"]+"/a"), Pod(namespaces["x"]+"/a"), Dropped) + reachability1.Expect(Pod(namespaces["z"]+"/b"), Pod(namespaces["x"]+"/a"), Dropped) + reachability1.Expect(Pod(namespaces["z"]+"/c"), Pod(namespaces["x"]+"/a"), Dropped) + reachability1.Expect(Pod(namespaces["z"]+"/a"), Pod(namespaces["y"]+"/a"), Dropped) + reachability1.Expect(Pod(namespaces["z"]+"/b"), Pod(namespaces["y"]+"/a"), Dropped) + reachability1.Expect(Pod(namespaces["z"]+"/c"), Pod(namespaces["y"]+"/a"), Dropped) + reachability1.Expect(Pod(namespaces["z"]+"/b"), Pod(namespaces["z"]+"/a"), Dropped) + reachability1.Expect(Pod(namespaces["z"]+"/c"), Pod(namespaces["z"]+"/a"), Dropped) reachability2 := NewReachability(allPods, Connected) @@ -736,7 +741,7 @@ func testACNPNoEffectOnOtherProtocols(t *testing.T) { reachability1, []metav1.Object{builder.Get()}, []int32{80}, - v1.ProtocolTCP, + ProtocolTCP, 0, nil, }, @@ -745,7 +750,7 @@ func testACNPNoEffectOnOtherProtocols(t *testing.T) { reachability2, []metav1.Object{builder.Get()}, []int32{80}, - v1.ProtocolUDP, + ProtocolUDP, 0, nil, }, @@ -761,18 +766,18 @@ func testACNPAppliedToDenyXBtoCGWithYA(t *testing.T) { cgName := "cg-pods-ya" cgBuilder := &ClusterGroupV1Alpha2SpecBuilder{} cgBuilder = cgBuilder.SetName(cgName). - SetNamespaceSelector(map[string]string{"ns": "y"}, nil). + SetNamespaceSelector(map[string]string{"ns": namespaces["y"]}, nil). SetPodSelector(map[string]string{"pod": "a"}, nil) port81Name := "serve-81" builder := &ClusterNetworkPolicySpecBuilder{} builder = builder.SetName("acnp-deny-cg-with-ya-from-xb"). SetPriority(2.0). SetAppliedToGroup([]ACNPAppliedToSpec{{Group: cgName}}) - builder.AddIngress(v1.ProtocolTCP, nil, &port81Name, nil, nil, map[string]string{"pod": "b"}, map[string]string{"ns": "x"}, + builder.AddIngress(ProtocolTCP, nil, &port81Name, nil, nil, nil, nil, map[string]string{"pod": "b"}, map[string]string{"ns": namespaces["x"]}, nil, nil, false, nil, crdv1alpha1.RuleActionDrop, "", "", nil) reachability := NewReachability(allPods, Connected) - reachability.Expect(Pod("x/b"), Pod("y/a"), Dropped) + reachability.Expect(Pod(namespaces["x"]+"/b"), Pod(namespaces["y"]+"/a"), Dropped) reachability.ExpectSelf(allPods, Connected) testStep := []*TestStep{ @@ -782,7 +787,7 @@ func testACNPAppliedToDenyXBtoCGWithYA(t *testing.T) { // Note in this testcase the ClusterGroup is created after the ACNP []metav1.Object{builder.Get(), cgBuilder.Get()}, []int32{81}, - v1.ProtocolTCP, + ProtocolTCP, 0, nil, }, @@ -798,18 +803,18 @@ func testACNPIngressRuleDenyCGWithXBtoYA(t *testing.T) { cgName := "cg-pods-xb" cgBuilder := &ClusterGroupV1Alpha2SpecBuilder{} cgBuilder = cgBuilder.SetName(cgName). - SetNamespaceSelector(map[string]string{"ns": "x"}, nil). + SetNamespaceSelector(map[string]string{"ns": namespaces["x"]}, nil). SetPodSelector(map[string]string{"pod": "b"}, nil) port81Name := "serve-81" builder := &ClusterNetworkPolicySpecBuilder{} builder = builder.SetName("acnp-deny-cg-with-xb-to-ya"). SetPriority(2.0). - SetAppliedToGroup([]ACNPAppliedToSpec{{PodSelector: map[string]string{"pod": "a"}, NSSelector: map[string]string{"ns": "y"}}}) - builder.AddIngress(v1.ProtocolTCP, nil, &port81Name, nil, nil, nil, nil, + SetAppliedToGroup([]ACNPAppliedToSpec{{PodSelector: map[string]string{"pod": "a"}, NSSelector: map[string]string{"ns": namespaces["y"]}}}) + builder.AddIngress(ProtocolTCP, nil, &port81Name, nil, nil, nil, nil, nil, nil, nil, nil, false, nil, crdv1alpha1.RuleActionDrop, cgName, "", nil) reachability := NewReachability(allPods, Connected) - reachability.Expect(Pod("x/b"), Pod("y/a"), Dropped) + reachability.Expect(Pod(namespaces["x"]+"/b"), Pod(namespaces["y"]+"/a"), Dropped) reachability.ExpectSelf(allPods, Connected) testStep := []*TestStep{ @@ -818,7 +823,7 @@ func testACNPIngressRuleDenyCGWithXBtoYA(t *testing.T) { reachability, []metav1.Object{cgBuilder.Get(), builder.Get()}, []int32{81}, - v1.ProtocolTCP, + ProtocolTCP, 0, nil, }, @@ -837,14 +842,14 @@ func testACNPAppliedToRuleCGWithPodsAToNsZ(t *testing.T) { builder := &ClusterNetworkPolicySpecBuilder{} builder = builder.SetName("acnp-deny-cg-with-a-to-z"). SetPriority(1.0) - builder.AddEgress(v1.ProtocolTCP, &p80, nil, nil, nil, nil, map[string]string{"ns": "z"}, + builder.AddEgress(ProtocolTCP, &p80, nil, nil, nil, nil, nil, nil, map[string]string{"ns": namespaces["z"]}, nil, nil, false, []ACNPAppliedToSpec{{Group: cgName}}, crdv1alpha1.RuleActionDrop, "", "", nil) reachability := NewReachability(allPods, Connected) - reachability.ExpectEgressToNamespace(Pod("x/a"), "z", Dropped) - reachability.ExpectEgressToNamespace(Pod("y/a"), "z", Dropped) - reachability.Expect(Pod("z/a"), Pod("z/b"), Dropped) - reachability.Expect(Pod("z/a"), Pod("z/c"), Dropped) + reachability.ExpectEgressToNamespace(Pod(namespaces["x"]+"/a"), namespaces["z"], Dropped) + reachability.ExpectEgressToNamespace(Pod(namespaces["y"]+"/a"), namespaces["z"], Dropped) + reachability.Expect(Pod(namespaces["z"]+"/a"), Pod(namespaces["z"]+"/b"), Dropped) + reachability.Expect(Pod(namespaces["z"]+"/a"), Pod(namespaces["z"]+"/c"), Dropped) testStep := []*TestStep{ { "Port 80", @@ -852,7 +857,7 @@ func testACNPAppliedToRuleCGWithPodsAToNsZ(t *testing.T) { // Note in this testcase the ClusterGroup is created after the ACNP []metav1.Object{builder.Get(), cgBuilder.Get()}, []int32{80}, - v1.ProtocolTCP, + ProtocolTCP, 0, nil, }, @@ -867,19 +872,19 @@ func testACNPAppliedToRuleCGWithPodsAToNsZ(t *testing.T) { func testACNPEgressRulePodsAToCGWithNsZ(t *testing.T) { cgName := "cg-ns-z" cgBuilder := &ClusterGroupV1Alpha3SpecBuilder{} - cgBuilder = cgBuilder.SetName(cgName).SetNamespaceSelector(map[string]string{"ns": "z"}, nil) + cgBuilder = cgBuilder.SetName(cgName).SetNamespaceSelector(map[string]string{"ns": namespaces["z"]}, nil) builder := &ClusterNetworkPolicySpecBuilder{} builder = builder.SetName("acnp-deny-a-to-cg-with-z-egress"). SetPriority(1.0). SetAppliedToGroup([]ACNPAppliedToSpec{{PodSelector: map[string]string{"pod": "a"}}}) - builder.AddEgress(v1.ProtocolTCP, &p80, nil, nil, nil, nil, nil, + builder.AddEgress(ProtocolTCP, &p80, nil, nil, nil, nil, nil, nil, nil, nil, nil, false, nil, crdv1alpha1.RuleActionDrop, cgName, "", nil) reachability := NewReachability(allPods, Connected) - reachability.ExpectEgressToNamespace(Pod("x/a"), "z", Dropped) - reachability.ExpectEgressToNamespace(Pod("y/a"), "z", Dropped) - reachability.Expect(Pod("z/a"), Pod("z/b"), Dropped) - reachability.Expect(Pod("z/a"), Pod("z/c"), Dropped) + reachability.ExpectEgressToNamespace(Pod(namespaces["x"]+"/a"), namespaces["z"], Dropped) + reachability.ExpectEgressToNamespace(Pod(namespaces["y"]+"/a"), namespaces["z"], Dropped) + reachability.Expect(Pod(namespaces["z"]+"/a"), Pod(namespaces["z"]+"/b"), Dropped) + reachability.Expect(Pod(namespaces["z"]+"/a"), Pod(namespaces["z"]+"/c"), Dropped) testStep := []*TestStep{ { "Port 80", @@ -887,7 +892,7 @@ func testACNPEgressRulePodsAToCGWithNsZ(t *testing.T) { // Note in this testcase the ClusterGroup is created after the ACNP []metav1.Object{builder.Get(), cgBuilder.Get()}, []int32{80}, - v1.ProtocolTCP, + ProtocolTCP, 0, nil, }, @@ -909,27 +914,27 @@ func testACNPClusterGroupUpdateAppliedTo(t *testing.T) { builder = builder.SetName("acnp-deny-cg-with-a-to-z-egress"). SetPriority(1.0). SetAppliedToGroup([]ACNPAppliedToSpec{{Group: cgName}}) - builder.AddEgress(v1.ProtocolTCP, &p80, nil, nil, nil, nil, map[string]string{"ns": "z"}, + builder.AddEgress(ProtocolTCP, &p80, nil, nil, nil, nil, nil, nil, map[string]string{"ns": namespaces["z"]}, nil, nil, false, nil, crdv1alpha1.RuleActionDrop, "", "", nil) reachability := NewReachability(allPods, Connected) - reachability.ExpectEgressToNamespace(Pod("x/a"), "z", Dropped) - reachability.ExpectEgressToNamespace(Pod("y/a"), "z", Dropped) - reachability.Expect(Pod("z/a"), Pod("z/b"), Dropped) - reachability.Expect(Pod("z/a"), Pod("z/c"), Dropped) + reachability.ExpectEgressToNamespace(Pod(namespaces["x"]+"/a"), namespaces["z"], Dropped) + reachability.ExpectEgressToNamespace(Pod(namespaces["y"]+"/a"), namespaces["z"], Dropped) + reachability.Expect(Pod(namespaces["z"]+"/a"), Pod(namespaces["z"]+"/b"), Dropped) + reachability.Expect(Pod(namespaces["z"]+"/a"), Pod(namespaces["z"]+"/c"), Dropped) updatedReachability := NewReachability(allPods, Connected) - updatedReachability.ExpectEgressToNamespace(Pod("x/c"), "z", Dropped) - updatedReachability.ExpectEgressToNamespace(Pod("y/c"), "z", Dropped) - updatedReachability.Expect(Pod("z/c"), Pod("z/a"), Dropped) - updatedReachability.Expect(Pod("z/c"), Pod("z/b"), Dropped) + updatedReachability.ExpectEgressToNamespace(Pod(namespaces["x"]+"/c"), namespaces["z"], Dropped) + updatedReachability.ExpectEgressToNamespace(Pod(namespaces["y"]+"/c"), namespaces["z"], Dropped) + updatedReachability.Expect(Pod(namespaces["z"]+"/c"), Pod(namespaces["z"]+"/a"), Dropped) + updatedReachability.Expect(Pod(namespaces["z"]+"/c"), Pod(namespaces["z"]+"/b"), Dropped) testStep := []*TestStep{ { "CG Pods A", reachability, []metav1.Object{cgBuilder.Get(), builder.Get()}, []int32{80}, - v1.ProtocolTCP, + ProtocolTCP, 0, nil, }, @@ -938,7 +943,7 @@ func testACNPClusterGroupUpdateAppliedTo(t *testing.T) { updatedReachability, []metav1.Object{updatedCgBuilder.Get()}, []int32{80}, - v1.ProtocolTCP, + ProtocolTCP, 0, nil, }, @@ -952,35 +957,35 @@ func testACNPClusterGroupUpdateAppliedTo(t *testing.T) { func testACNPClusterGroupUpdate(t *testing.T) { cgName := "cg-ns-z-then-y" cgBuilder := &ClusterGroupV1Alpha3SpecBuilder{} - cgBuilder = cgBuilder.SetName(cgName).SetNamespaceSelector(map[string]string{"ns": "z"}, nil) + cgBuilder = cgBuilder.SetName(cgName).SetNamespaceSelector(map[string]string{"ns": namespaces["z"]}, nil) // Update CG NS selector to group Pods from Namespace Y updatedCgBuilder := &ClusterGroupV1Alpha3SpecBuilder{} - updatedCgBuilder = updatedCgBuilder.SetName(cgName).SetNamespaceSelector(map[string]string{"ns": "y"}, nil) + updatedCgBuilder = updatedCgBuilder.SetName(cgName).SetNamespaceSelector(map[string]string{"ns": namespaces["y"]}, nil) builder := &ClusterNetworkPolicySpecBuilder{} builder = builder.SetName("acnp-deny-a-to-cg-with-z-egress"). SetPriority(1.0). SetAppliedToGroup([]ACNPAppliedToSpec{{PodSelector: map[string]string{"pod": "a"}}}) - builder.AddEgress(v1.ProtocolTCP, &p80, nil, nil, nil, nil, nil, + builder.AddEgress(ProtocolTCP, &p80, nil, nil, nil, nil, nil, nil, nil, nil, nil, false, nil, crdv1alpha1.RuleActionDrop, cgName, "", nil) reachability := NewReachability(allPods, Connected) - reachability.ExpectEgressToNamespace(Pod("x/a"), "z", Dropped) - reachability.ExpectEgressToNamespace(Pod("y/a"), "z", Dropped) - reachability.Expect(Pod("z/a"), Pod("z/b"), Dropped) - reachability.Expect(Pod("z/a"), Pod("z/c"), Dropped) + reachability.ExpectEgressToNamespace(Pod(namespaces["x"]+"/a"), namespaces["z"], Dropped) + reachability.ExpectEgressToNamespace(Pod(namespaces["y"]+"/a"), namespaces["z"], Dropped) + reachability.Expect(Pod(namespaces["z"]+"/a"), Pod(namespaces["z"]+"/b"), Dropped) + reachability.Expect(Pod(namespaces["z"]+"/a"), Pod(namespaces["z"]+"/c"), Dropped) updatedReachability := NewReachability(allPods, Connected) - updatedReachability.ExpectEgressToNamespace(Pod("x/a"), "y", Dropped) - updatedReachability.ExpectEgressToNamespace(Pod("z/a"), "y", Dropped) - updatedReachability.Expect(Pod("y/a"), Pod("y/b"), Dropped) - updatedReachability.Expect(Pod("y/a"), Pod("y/c"), Dropped) + updatedReachability.ExpectEgressToNamespace(Pod(namespaces["x"]+"/a"), namespaces["y"], Dropped) + updatedReachability.ExpectEgressToNamespace(Pod(namespaces["z"]+"/a"), namespaces["y"], Dropped) + updatedReachability.Expect(Pod(namespaces["y"]+"/a"), Pod(namespaces["y"]+"/b"), Dropped) + updatedReachability.Expect(Pod(namespaces["y"]+"/a"), Pod(namespaces["y"]+"/c"), Dropped) testStep := []*TestStep{ { "Port 80", reachability, []metav1.Object{cgBuilder.Get(), builder.Get()}, []int32{80}, - v1.ProtocolTCP, + ProtocolTCP, 0, nil, }, @@ -989,7 +994,7 @@ func testACNPClusterGroupUpdate(t *testing.T) { updatedReachability, []metav1.Object{updatedCgBuilder.Get()}, []int32{80}, - v1.ProtocolTCP, + ProtocolTCP, 0, nil, }, @@ -1004,22 +1009,22 @@ func testACNPClusterGroupAppliedToPodAdd(t *testing.T, data *TestData) { cgName := "cg-pod-custom-pod-zj" cgBuilder := &ClusterGroupV1Alpha3SpecBuilder{} cgBuilder = cgBuilder.SetName(cgName). - SetNamespaceSelector(map[string]string{"ns": "z"}, nil). + SetNamespaceSelector(map[string]string{"ns": namespaces["z"]}, nil). SetPodSelector(map[string]string{"pod": "j"}, nil) builder := &ClusterNetworkPolicySpecBuilder{} builder = builder.SetName("acnp-deny-cg-with-zj-to-xj-egress"). SetPriority(1.0). SetAppliedToGroup([]ACNPAppliedToSpec{{Group: cgName}}) - builder.AddEgress(v1.ProtocolTCP, &p80, nil, nil, nil, map[string]string{"pod": "j"}, map[string]string{"ns": "x"}, + builder.AddEgress(ProtocolTCP, &p80, nil, nil, nil, nil, nil, map[string]string{"pod": "j"}, map[string]string{"ns": namespaces["x"]}, nil, nil, false, nil, crdv1alpha1.RuleActionDrop, "", "", nil) cp := []*CustomProbe{ { SourcePod: CustomPod{ - Pod: NewPod("z", "j"), + Pod: NewPod(namespaces["z"], "j"), Labels: map[string]string{"pod": "j"}, }, DestPod: CustomPod{ - Pod: NewPod("x", "j"), + Pod: NewPod(namespaces["x"], "j"), Labels: map[string]string{"pod": "j"}, }, ExpectConnectivity: Dropped, @@ -1032,7 +1037,7 @@ func testACNPClusterGroupAppliedToPodAdd(t *testing.T, data *TestData) { nil, []metav1.Object{cgBuilder.Get(), builder.Get()}, []int32{80}, - v1.ProtocolTCP, + ProtocolTCP, 0, cp, }, @@ -1047,7 +1052,7 @@ func testACNPClusterGroupRefRulePodAdd(t *testing.T, data *TestData) { cgName := "cg-pod-custom-pod-zk" cgBuilder := &ClusterGroupV1Alpha3SpecBuilder{} cgBuilder = cgBuilder.SetName(cgName). - SetNamespaceSelector(map[string]string{"ns": "z"}, nil). + SetNamespaceSelector(map[string]string{"ns": namespaces["z"]}, nil). SetPodSelector(map[string]string{"pod": "k"}, nil) builder := &ClusterNetworkPolicySpecBuilder{} builder = builder.SetName("acnp-deny-xk-to-cg-with-zk-egress"). @@ -1055,19 +1060,19 @@ func testACNPClusterGroupRefRulePodAdd(t *testing.T, data *TestData) { SetAppliedToGroup([]ACNPAppliedToSpec{ { PodSelector: map[string]string{"pod": "k"}, - NSSelector: map[string]string{"ns": "x"}, + NSSelector: map[string]string{"ns": namespaces["x"]}, }, }) - builder.AddEgress(v1.ProtocolTCP, &p80, nil, nil, nil, nil, nil, + builder.AddEgress(ProtocolTCP, &p80, nil, nil, nil, nil, nil, nil, nil, nil, nil, false, nil, crdv1alpha1.RuleActionDrop, cgName, "", nil) cp := []*CustomProbe{ { SourcePod: CustomPod{ - Pod: NewPod("x", "k"), + Pod: NewPod(namespaces["x"], "k"), Labels: map[string]string{"pod": "k"}, }, DestPod: CustomPod{ - Pod: NewPod("z", "k"), + Pod: NewPod(namespaces["z"], "k"), Labels: map[string]string{"pod": "k"}, }, ExpectConnectivity: Dropped, @@ -1081,7 +1086,7 @@ func testACNPClusterGroupRefRulePodAdd(t *testing.T, data *TestData) { // Note in this testcase the ClusterGroup is created after the ACNP []metav1.Object{builder.Get(), cgBuilder.Get()}, []int32{80}, - v1.ProtocolTCP, + ProtocolTCP, 0, cp, }, @@ -1093,10 +1098,10 @@ func testACNPClusterGroupRefRulePodAdd(t *testing.T, data *TestData) { } func testACNPClusterGroupRefRuleIPBlocks(t *testing.T) { - podXAIP, _ := podIPs["x/a"] - podXBIP, _ := podIPs["x/b"] - podXCIP, _ := podIPs["x/c"] - podZAIP, _ := podIPs["z/a"] + podXAIP, _ := podIPs[namespaces["x"]+"/a"] + podXBIP, _ := podIPs[namespaces["x"]+"/b"] + podXCIP, _ := podIPs[namespaces["x"]+"/c"] + podZAIP, _ := podIPs[namespaces["z"]+"/a"] // There are three situations of a Pod's IP(s): // 1. Only one IPv4 address. // 2. Only one IPv6 address. @@ -1132,26 +1137,26 @@ func testACNPClusterGroupRefRuleIPBlocks(t *testing.T) { SetAppliedToGroup([]ACNPAppliedToSpec{ { PodSelector: map[string]string{"pod": "a"}, - NSSelector: map[string]string{"ns": "y"}, + NSSelector: map[string]string{"ns": namespaces["y"]}, }, }) - builder.AddIngress(v1.ProtocolTCP, &p80, nil, nil, nil, nil, nil, + builder.AddIngress(ProtocolTCP, &p80, nil, nil, nil, nil, nil, nil, nil, nil, nil, false, nil, crdv1alpha1.RuleActionDrop, cgv1a3Name, "", nil) - builder.AddIngress(v1.ProtocolTCP, &p80, nil, nil, nil, nil, nil, + builder.AddIngress(ProtocolTCP, &p80, nil, nil, nil, nil, nil, nil, nil, nil, nil, false, nil, crdv1alpha1.RuleActionDrop, cgv1a2Name, "", nil) reachability := NewReachability(allPods, Connected) - reachability.Expect(Pod("x/a"), Pod("y/a"), Dropped) - reachability.Expect(Pod("x/b"), Pod("y/a"), Dropped) - reachability.Expect(Pod("x/c"), Pod("y/a"), Dropped) - reachability.Expect(Pod("z/a"), Pod("y/a"), Dropped) + reachability.Expect(Pod(namespaces["x"]+"/a"), Pod(namespaces["y"]+"/a"), Dropped) + reachability.Expect(Pod(namespaces["x"]+"/b"), Pod(namespaces["y"]+"/a"), Dropped) + reachability.Expect(Pod(namespaces["x"]+"/c"), Pod(namespaces["y"]+"/a"), Dropped) + reachability.Expect(Pod(namespaces["z"]+"/a"), Pod(namespaces["y"]+"/a"), Dropped) testStep := []*TestStep{ { "Port 80", reachability, []metav1.Object{builder.Get(), cgBuilder.Get(), cgBuilder2.Get()}, []int32{80}, - v1.ProtocolTCP, + ProtocolTCP, 0, nil, }, @@ -1169,43 +1174,43 @@ func testBaselineNamespaceIsolation(t *testing.T) { nsExpOtherThanX := metav1.LabelSelectorRequirement{ Key: "ns", Operator: metav1.LabelSelectorOpNotIn, - Values: []string{"x"}, + Values: []string{namespaces["x"]}, } builder = builder.SetName("acnp-baseline-isolate-ns-x"). SetTier("baseline"). SetPriority(1.0). - SetAppliedToGroup([]ACNPAppliedToSpec{{NSSelector: map[string]string{"ns": "x"}}}) - builder.AddIngress(v1.ProtocolTCP, &p80, nil, nil, nil, nil, nil, + SetAppliedToGroup([]ACNPAppliedToSpec{{NSSelector: map[string]string{"ns": namespaces["x"]}}}) + builder.AddIngress(ProtocolTCP, &p80, nil, nil, nil, nil, nil, nil, nil, nil, []metav1.LabelSelectorRequirement{nsExpOtherThanX}, false, nil, crdv1alpha1.RuleActionDrop, "", "", nil) // create a K8s NetworkPolicy for Pods in namespace x to allow ingress traffic from Pods in the same namespace, // as well as from the y/a Pod. It should open up ingress from y/a since it's evaluated before the baseline tier. k8sNPBuilder := &NetworkPolicySpecBuilder{} - k8sNPBuilder = k8sNPBuilder.SetName("x", "allow-ns-x-and-y-a"). + k8sNPBuilder = k8sNPBuilder.SetName(namespaces["x"], "allow-ns-x-and-y-a"). SetTypeIngress(). AddIngress(v1.ProtocolTCP, &p80, nil, nil, nil, - nil, map[string]string{"ns": "x"}, nil, nil). + nil, map[string]string{"ns": namespaces["x"]}, nil, nil). AddIngress(v1.ProtocolTCP, &p80, nil, nil, nil, - map[string]string{"pod": "a"}, map[string]string{"ns": "y"}, nil, nil) + map[string]string{"pod": "a"}, map[string]string{"ns": namespaces["y"]}, nil, nil) reachability := NewReachability(allPods, Connected) - reachability.Expect(Pod("y/b"), Pod("x/a"), Dropped) - reachability.Expect(Pod("y/c"), Pod("x/a"), Dropped) - reachability.ExpectIngressFromNamespace(Pod("x/a"), "z", Dropped) - reachability.Expect(Pod("y/b"), Pod("x/b"), Dropped) - reachability.Expect(Pod("y/c"), Pod("x/b"), Dropped) - reachability.ExpectIngressFromNamespace(Pod("x/b"), "z", Dropped) - reachability.Expect(Pod("y/b"), Pod("x/c"), Dropped) - reachability.Expect(Pod("y/c"), Pod("x/c"), Dropped) - reachability.ExpectIngressFromNamespace(Pod("x/c"), "z", Dropped) + reachability.Expect(Pod(namespaces["y"]+"/b"), Pod(namespaces["x"]+"/a"), Dropped) + reachability.Expect(Pod(namespaces["y"]+"/c"), Pod(namespaces["x"]+"/a"), Dropped) + reachability.ExpectIngressFromNamespace(Pod(namespaces["x"]+"/a"), namespaces["z"], Dropped) + reachability.Expect(Pod(namespaces["y"]+"/b"), Pod(namespaces["x"]+"/b"), Dropped) + reachability.Expect(Pod(namespaces["y"]+"/c"), Pod(namespaces["x"]+"/b"), Dropped) + reachability.ExpectIngressFromNamespace(Pod(namespaces["x"]+"/b"), namespaces["z"], Dropped) + reachability.Expect(Pod(namespaces["y"]+"/b"), Pod(namespaces["x"]+"/c"), Dropped) + reachability.Expect(Pod(namespaces["y"]+"/c"), Pod(namespaces["x"]+"/c"), Dropped) + reachability.ExpectIngressFromNamespace(Pod(namespaces["x"]+"/c"), namespaces["z"], Dropped) testStep := []*TestStep{ { "Port 80", reachability, []metav1.Object{builder.Get(), k8sNPBuilder.Get()}, []int32{80}, - v1.ProtocolTCP, + ProtocolTCP, 0, nil, }, @@ -1215,7 +1220,7 @@ func testBaselineNamespaceIsolation(t *testing.T) { } executeTests(t, testCase) // Cleanup the K8s NetworkPolicy created for this test. - failOnError(k8sUtils.CleanNetworkPolicies([]string{"x"}), t) + failOnError(k8sUtils.CleanNetworkPolicies(map[string]string{"x": namespaces["x"]}), t) time.Sleep(networkPolicyDelay) } @@ -1225,43 +1230,43 @@ func testACNPPriorityOverride(t *testing.T) { builder1 := &ClusterNetworkPolicySpecBuilder{} builder1 = builder1.SetName("acnp-priority1"). SetPriority(1.001). - SetAppliedToGroup([]ACNPAppliedToSpec{{PodSelector: map[string]string{"pod": "a"}, NSSelector: map[string]string{"ns": "x"}}}) + SetAppliedToGroup([]ACNPAppliedToSpec{{PodSelector: map[string]string{"pod": "a"}, NSSelector: map[string]string{"ns": namespaces["x"]}}}) // Highest priority. Drops traffic from z/b to x/a. - builder1.AddIngress(v1.ProtocolTCP, &p80, nil, nil, nil, map[string]string{"pod": "b"}, map[string]string{"ns": "z"}, + builder1.AddIngress(ProtocolTCP, &p80, nil, nil, nil, nil, nil, map[string]string{"pod": "b"}, map[string]string{"ns": namespaces["z"]}, nil, nil, false, nil, crdv1alpha1.RuleActionDrop, "", "", nil) builder2 := &ClusterNetworkPolicySpecBuilder{} builder2 = builder2.SetName("acnp-priority2"). SetPriority(1.002). - SetAppliedToGroup([]ACNPAppliedToSpec{{PodSelector: map[string]string{"pod": "a"}, NSSelector: map[string]string{"ns": "x"}}}) + SetAppliedToGroup([]ACNPAppliedToSpec{{PodSelector: map[string]string{"pod": "a"}, NSSelector: map[string]string{"ns": namespaces["x"]}}}) // Medium priority. Allows traffic from z to x/a. - builder2.AddIngress(v1.ProtocolTCP, &p80, nil, nil, nil, nil, map[string]string{"ns": "z"}, + builder2.AddIngress(ProtocolTCP, &p80, nil, nil, nil, nil, nil, nil, map[string]string{"ns": namespaces["z"]}, nil, nil, false, nil, crdv1alpha1.RuleActionAllow, "", "", nil) builder3 := &ClusterNetworkPolicySpecBuilder{} builder3 = builder3.SetName("acnp-priority3"). SetPriority(1.003). - SetAppliedToGroup([]ACNPAppliedToSpec{{NSSelector: map[string]string{"ns": "x"}}}) + SetAppliedToGroup([]ACNPAppliedToSpec{{NSSelector: map[string]string{"ns": namespaces["x"]}}}) // Lowest priority. Drops traffic from z to x. - builder3.AddIngress(v1.ProtocolTCP, &p80, nil, nil, nil, nil, map[string]string{"ns": "z"}, + builder3.AddIngress(ProtocolTCP, &p80, nil, nil, nil, nil, nil, nil, map[string]string{"ns": namespaces["z"]}, nil, nil, false, nil, crdv1alpha1.RuleActionDrop, "", "", nil) reachabilityTwoACNPs := NewReachability(allPods, Connected) - reachabilityTwoACNPs.Expect(Pod("z/a"), Pod("x/b"), Dropped) - reachabilityTwoACNPs.Expect(Pod("z/a"), Pod("x/c"), Dropped) - reachabilityTwoACNPs.Expect(Pod("z/b"), Pod("x/b"), Dropped) - reachabilityTwoACNPs.Expect(Pod("z/b"), Pod("x/c"), Dropped) - reachabilityTwoACNPs.Expect(Pod("z/c"), Pod("x/b"), Dropped) - reachabilityTwoACNPs.Expect(Pod("z/c"), Pod("x/c"), Dropped) + reachabilityTwoACNPs.Expect(Pod(namespaces["z"]+"/a"), Pod(namespaces["x"]+"/b"), Dropped) + reachabilityTwoACNPs.Expect(Pod(namespaces["z"]+"/a"), Pod(namespaces["x"]+"/c"), Dropped) + reachabilityTwoACNPs.Expect(Pod(namespaces["z"]+"/b"), Pod(namespaces["x"]+"/b"), Dropped) + reachabilityTwoACNPs.Expect(Pod(namespaces["z"]+"/b"), Pod(namespaces["x"]+"/c"), Dropped) + reachabilityTwoACNPs.Expect(Pod(namespaces["z"]+"/c"), Pod(namespaces["x"]+"/b"), Dropped) + reachabilityTwoACNPs.Expect(Pod(namespaces["z"]+"/c"), Pod(namespaces["x"]+"/c"), Dropped) reachabilityAllACNPs := NewReachability(allPods, Connected) - reachabilityAllACNPs.Expect(Pod("z/a"), Pod("x/b"), Dropped) - reachabilityAllACNPs.Expect(Pod("z/a"), Pod("x/c"), Dropped) - reachabilityAllACNPs.Expect(Pod("z/b"), Pod("x/a"), Dropped) - reachabilityAllACNPs.Expect(Pod("z/b"), Pod("x/b"), Dropped) - reachabilityAllACNPs.Expect(Pod("z/b"), Pod("x/c"), Dropped) - reachabilityAllACNPs.Expect(Pod("z/c"), Pod("x/b"), Dropped) - reachabilityAllACNPs.Expect(Pod("z/c"), Pod("x/c"), Dropped) + reachabilityAllACNPs.Expect(Pod(namespaces["z"]+"/a"), Pod(namespaces["x"]+"/b"), Dropped) + reachabilityAllACNPs.Expect(Pod(namespaces["z"]+"/a"), Pod(namespaces["x"]+"/c"), Dropped) + reachabilityAllACNPs.Expect(Pod(namespaces["z"]+"/b"), Pod(namespaces["x"]+"/a"), Dropped) + reachabilityAllACNPs.Expect(Pod(namespaces["z"]+"/b"), Pod(namespaces["x"]+"/b"), Dropped) + reachabilityAllACNPs.Expect(Pod(namespaces["z"]+"/b"), Pod(namespaces["x"]+"/c"), Dropped) + reachabilityAllACNPs.Expect(Pod(namespaces["z"]+"/c"), Pod(namespaces["x"]+"/b"), Dropped) + reachabilityAllACNPs.Expect(Pod(namespaces["z"]+"/c"), Pod(namespaces["x"]+"/c"), Dropped) testStepTwoACNP := []*TestStep{ { @@ -1269,7 +1274,7 @@ func testACNPPriorityOverride(t *testing.T) { reachabilityTwoACNPs, []metav1.Object{builder3.Get(), builder2.Get()}, []int32{80}, - v1.ProtocolTCP, + ProtocolTCP, 0, nil, }, @@ -1281,7 +1286,7 @@ func testACNPPriorityOverride(t *testing.T) { reachabilityAllACNPs, []metav1.Object{builder3.Get(), builder1.Get(), builder2.Get()}, []int32{80}, - v1.ProtocolTCP, + ProtocolTCP, 0, nil, }, @@ -1300,45 +1305,45 @@ func testACNPTierOverride(t *testing.T) { builder1 = builder1.SetName("acnp-tier-emergency"). SetTier("emergency"). SetPriority(100). - SetAppliedToGroup([]ACNPAppliedToSpec{{PodSelector: map[string]string{"pod": "a"}, NSSelector: map[string]string{"ns": "x"}}}) + SetAppliedToGroup([]ACNPAppliedToSpec{{PodSelector: map[string]string{"pod": "a"}, NSSelector: map[string]string{"ns": namespaces["x"]}}}) // Highest priority tier. Drops traffic from z/b to x/a. - builder1.AddIngress(v1.ProtocolTCP, &p80, nil, nil, nil, map[string]string{"pod": "b"}, map[string]string{"ns": "z"}, + builder1.AddIngress(ProtocolTCP, &p80, nil, nil, nil, nil, nil, map[string]string{"pod": "b"}, map[string]string{"ns": namespaces["z"]}, nil, nil, false, nil, crdv1alpha1.RuleActionDrop, "", "", nil) builder2 := &ClusterNetworkPolicySpecBuilder{} builder2 = builder2.SetName("acnp-tier-securityops"). SetTier("securityops"). SetPriority(10). - SetAppliedToGroup([]ACNPAppliedToSpec{{PodSelector: map[string]string{"pod": "a"}, NSSelector: map[string]string{"ns": "x"}}}) + SetAppliedToGroup([]ACNPAppliedToSpec{{PodSelector: map[string]string{"pod": "a"}, NSSelector: map[string]string{"ns": namespaces["x"]}}}) // Medium priority tier. Allows traffic from z to x/a. - builder2.AddIngress(v1.ProtocolTCP, &p80, nil, nil, nil, nil, map[string]string{"ns": "z"}, + builder2.AddIngress(ProtocolTCP, &p80, nil, nil, nil, nil, nil, nil, map[string]string{"ns": namespaces["z"]}, nil, nil, false, nil, crdv1alpha1.RuleActionAllow, "", "", nil) builder3 := &ClusterNetworkPolicySpecBuilder{} builder3 = builder3.SetName("acnp-tier-application"). SetTier("application"). SetPriority(1). - SetAppliedToGroup([]ACNPAppliedToSpec{{NSSelector: map[string]string{"ns": "x"}}}) + SetAppliedToGroup([]ACNPAppliedToSpec{{NSSelector: map[string]string{"ns": namespaces["x"]}}}) // Lowest priority tier. Drops traffic from z to x. - builder3.AddIngress(v1.ProtocolTCP, &p80, nil, nil, nil, nil, map[string]string{"ns": "z"}, + builder3.AddIngress(ProtocolTCP, &p80, nil, nil, nil, nil, nil, nil, map[string]string{"ns": namespaces["z"]}, nil, nil, false, nil, crdv1alpha1.RuleActionDrop, "", "", nil) reachabilityTwoACNPs := NewReachability(allPods, Connected) - reachabilityTwoACNPs.Expect(Pod("z/a"), Pod("x/b"), Dropped) - reachabilityTwoACNPs.Expect(Pod("z/a"), Pod("x/c"), Dropped) - reachabilityTwoACNPs.Expect(Pod("z/b"), Pod("x/b"), Dropped) - reachabilityTwoACNPs.Expect(Pod("z/b"), Pod("x/c"), Dropped) - reachabilityTwoACNPs.Expect(Pod("z/c"), Pod("x/b"), Dropped) - reachabilityTwoACNPs.Expect(Pod("z/c"), Pod("x/c"), Dropped) + reachabilityTwoACNPs.Expect(Pod(namespaces["z"]+"/a"), Pod(namespaces["x"]+"/b"), Dropped) + reachabilityTwoACNPs.Expect(Pod(namespaces["z"]+"/a"), Pod(namespaces["x"]+"/c"), Dropped) + reachabilityTwoACNPs.Expect(Pod(namespaces["z"]+"/b"), Pod(namespaces["x"]+"/b"), Dropped) + reachabilityTwoACNPs.Expect(Pod(namespaces["z"]+"/b"), Pod(namespaces["x"]+"/c"), Dropped) + reachabilityTwoACNPs.Expect(Pod(namespaces["z"]+"/c"), Pod(namespaces["x"]+"/b"), Dropped) + reachabilityTwoACNPs.Expect(Pod(namespaces["z"]+"/c"), Pod(namespaces["x"]+"/c"), Dropped) reachabilityAllACNPs := NewReachability(allPods, Connected) - reachabilityAllACNPs.Expect(Pod("z/a"), Pod("x/b"), Dropped) - reachabilityAllACNPs.Expect(Pod("z/a"), Pod("x/c"), Dropped) - reachabilityAllACNPs.Expect(Pod("z/b"), Pod("x/a"), Dropped) - reachabilityAllACNPs.Expect(Pod("z/b"), Pod("x/b"), Dropped) - reachabilityAllACNPs.Expect(Pod("z/b"), Pod("x/c"), Dropped) - reachabilityAllACNPs.Expect(Pod("z/c"), Pod("x/b"), Dropped) - reachabilityAllACNPs.Expect(Pod("z/c"), Pod("x/c"), Dropped) + reachabilityAllACNPs.Expect(Pod(namespaces["z"]+"/a"), Pod(namespaces["x"]+"/b"), Dropped) + reachabilityAllACNPs.Expect(Pod(namespaces["z"]+"/a"), Pod(namespaces["x"]+"/c"), Dropped) + reachabilityAllACNPs.Expect(Pod(namespaces["z"]+"/b"), Pod(namespaces["x"]+"/a"), Dropped) + reachabilityAllACNPs.Expect(Pod(namespaces["z"]+"/b"), Pod(namespaces["x"]+"/b"), Dropped) + reachabilityAllACNPs.Expect(Pod(namespaces["z"]+"/b"), Pod(namespaces["x"]+"/c"), Dropped) + reachabilityAllACNPs.Expect(Pod(namespaces["z"]+"/c"), Pod(namespaces["x"]+"/b"), Dropped) + reachabilityAllACNPs.Expect(Pod(namespaces["z"]+"/c"), Pod(namespaces["x"]+"/c"), Dropped) testStepTwoACNP := []*TestStep{ { @@ -1346,7 +1351,7 @@ func testACNPTierOverride(t *testing.T) { reachabilityTwoACNPs, []metav1.Object{builder3.Get(), builder2.Get()}, []int32{80}, - v1.ProtocolTCP, + ProtocolTCP, 0, nil, }, @@ -1357,7 +1362,7 @@ func testACNPTierOverride(t *testing.T) { reachabilityAllACNPs, []metav1.Object{builder3.Get(), builder1.Get(), builder2.Get()}, []int32{80}, - v1.ProtocolTCP, + ProtocolTCP, 0, nil, }, @@ -1384,34 +1389,34 @@ func testACNPCustomTiers(t *testing.T) { builder1 = builder1.SetName("acnp-tier-high"). SetTier("high-priority"). SetPriority(100). - SetAppliedToGroup([]ACNPAppliedToSpec{{PodSelector: map[string]string{"pod": "a"}, NSSelector: map[string]string{"ns": "x"}}}) + SetAppliedToGroup([]ACNPAppliedToSpec{{PodSelector: map[string]string{"pod": "a"}, NSSelector: map[string]string{"ns": namespaces["x"]}}}) // Medium priority tier. Allows traffic from z to x/a. - builder1.AddIngress(v1.ProtocolTCP, &p80, nil, nil, nil, nil, map[string]string{"ns": "z"}, + builder1.AddIngress(ProtocolTCP, &p80, nil, nil, nil, nil, nil, nil, map[string]string{"ns": namespaces["z"]}, nil, nil, false, nil, crdv1alpha1.RuleActionAllow, "", "", nil) builder2 := &ClusterNetworkPolicySpecBuilder{} builder2 = builder2.SetName("acnp-tier-low"). SetTier("low-priority"). SetPriority(1). - SetAppliedToGroup([]ACNPAppliedToSpec{{NSSelector: map[string]string{"ns": "x"}}}) + SetAppliedToGroup([]ACNPAppliedToSpec{{NSSelector: map[string]string{"ns": namespaces["x"]}}}) // Lowest priority tier. Drops traffic from z to x. - builder2.AddIngress(v1.ProtocolTCP, &p80, nil, nil, nil, nil, map[string]string{"ns": "z"}, + builder2.AddIngress(ProtocolTCP, &p80, nil, nil, nil, nil, nil, nil, map[string]string{"ns": namespaces["z"]}, nil, nil, false, nil, crdv1alpha1.RuleActionDrop, "", "", nil) reachabilityTwoACNPs := NewReachability(allPods, Connected) - reachabilityTwoACNPs.Expect(Pod("z/a"), Pod("x/b"), Dropped) - reachabilityTwoACNPs.Expect(Pod("z/a"), Pod("x/c"), Dropped) - reachabilityTwoACNPs.Expect(Pod("z/b"), Pod("x/b"), Dropped) - reachabilityTwoACNPs.Expect(Pod("z/b"), Pod("x/c"), Dropped) - reachabilityTwoACNPs.Expect(Pod("z/c"), Pod("x/b"), Dropped) - reachabilityTwoACNPs.Expect(Pod("z/c"), Pod("x/c"), Dropped) + reachabilityTwoACNPs.Expect(Pod(namespaces["z"]+"/a"), Pod(namespaces["x"]+"/b"), Dropped) + reachabilityTwoACNPs.Expect(Pod(namespaces["z"]+"/a"), Pod(namespaces["x"]+"/c"), Dropped) + reachabilityTwoACNPs.Expect(Pod(namespaces["z"]+"/b"), Pod(namespaces["x"]+"/b"), Dropped) + reachabilityTwoACNPs.Expect(Pod(namespaces["z"]+"/b"), Pod(namespaces["x"]+"/c"), Dropped) + reachabilityTwoACNPs.Expect(Pod(namespaces["z"]+"/c"), Pod(namespaces["x"]+"/b"), Dropped) + reachabilityTwoACNPs.Expect(Pod(namespaces["z"]+"/c"), Pod(namespaces["x"]+"/c"), Dropped) testStepTwoACNP := []*TestStep{ { "Two Policies in different tiers", reachabilityTwoACNPs, []metav1.Object{builder2.Get(), builder1.Get()}, []int32{80}, - v1.ProtocolTCP, + ProtocolTCP, 0, nil, }, @@ -1433,30 +1438,30 @@ func testACNPPriorityConflictingRule(t *testing.T) { builder1 := &ClusterNetworkPolicySpecBuilder{} builder1 = builder1.SetName("acnp-drop"). SetPriority(1). - SetAppliedToGroup([]ACNPAppliedToSpec{{NSSelector: map[string]string{"ns": "x"}}}) - builder1.AddIngress(v1.ProtocolTCP, &p80, nil, nil, nil, nil, map[string]string{"ns": "z"}, + SetAppliedToGroup([]ACNPAppliedToSpec{{NSSelector: map[string]string{"ns": namespaces["x"]}}}) + builder1.AddIngress(ProtocolTCP, &p80, nil, nil, nil, nil, nil, nil, map[string]string{"ns": namespaces["z"]}, nil, nil, false, nil, crdv1alpha1.RuleActionDrop, "", "", nil) builder2 := &ClusterNetworkPolicySpecBuilder{} builder2 = builder2.SetName("acnp-allow"). SetPriority(2). - SetAppliedToGroup([]ACNPAppliedToSpec{{NSSelector: map[string]string{"ns": "x"}}}) + SetAppliedToGroup([]ACNPAppliedToSpec{{NSSelector: map[string]string{"ns": namespaces["x"]}}}) // The following ingress rule will take no effect as it is exactly the same as ingress rule of cnp-drop, // but cnp-allow has lower priority. - builder2.AddIngress(v1.ProtocolTCP, &p80, nil, nil, nil, nil, map[string]string{"ns": "z"}, + builder2.AddIngress(ProtocolTCP, &p80, nil, nil, nil, nil, nil, nil, map[string]string{"ns": namespaces["z"]}, nil, nil, false, nil, crdv1alpha1.RuleActionAllow, "", "", nil) reachabilityBothACNP := NewReachability(allPods, Connected) - reachabilityBothACNP.ExpectEgressToNamespace(Pod("z/a"), "x", Dropped) - reachabilityBothACNP.ExpectEgressToNamespace(Pod("z/b"), "x", Dropped) - reachabilityBothACNP.ExpectEgressToNamespace(Pod("z/c"), "x", Dropped) + reachabilityBothACNP.ExpectEgressToNamespace(Pod(namespaces["z"]+"/a"), namespaces["x"], Dropped) + reachabilityBothACNP.ExpectEgressToNamespace(Pod(namespaces["z"]+"/b"), namespaces["x"], Dropped) + reachabilityBothACNP.ExpectEgressToNamespace(Pod(namespaces["z"]+"/c"), namespaces["x"], Dropped) testStep := []*TestStep{ { "Both ACNP", reachabilityBothACNP, []metav1.Object{builder1.Get(), builder2.Get()}, []int32{80}, - v1.ProtocolTCP, + ProtocolTCP, 0, nil, }, @@ -1474,36 +1479,36 @@ func testACNPRulePriority(t *testing.T) { // acnp-deny will apply to all pods in namespace x builder1 = builder1.SetName("acnp-deny"). SetPriority(5). - SetAppliedToGroup([]ACNPAppliedToSpec{{NSSelector: map[string]string{"ns": "x"}}}) - builder1.AddEgress(v1.ProtocolTCP, &p80, nil, nil, nil, nil, map[string]string{"ns": "y"}, + SetAppliedToGroup([]ACNPAppliedToSpec{{NSSelector: map[string]string{"ns": namespaces["x"]}}}) + builder1.AddEgress(ProtocolTCP, &p80, nil, nil, nil, nil, nil, nil, map[string]string{"ns": namespaces["y"]}, nil, nil, false, nil, crdv1alpha1.RuleActionDrop, "", "", nil) // This rule should take no effect as it will be overridden by the first rule of cnp-allow - builder1.AddEgress(v1.ProtocolTCP, &p80, nil, nil, nil, nil, map[string]string{"ns": "z"}, + builder1.AddEgress(ProtocolTCP, &p80, nil, nil, nil, nil, nil, nil, map[string]string{"ns": namespaces["z"]}, nil, nil, false, nil, crdv1alpha1.RuleActionDrop, "", "", nil) builder2 := &ClusterNetworkPolicySpecBuilder{} // acnp-allow will also apply to all pods in namespace x builder2 = builder2.SetName("acnp-allow"). SetPriority(5). - SetAppliedToGroup([]ACNPAppliedToSpec{{NSSelector: map[string]string{"ns": "x"}}}) - builder2.AddEgress(v1.ProtocolTCP, &p80, nil, nil, nil, nil, map[string]string{"ns": "z"}, + SetAppliedToGroup([]ACNPAppliedToSpec{{NSSelector: map[string]string{"ns": namespaces["x"]}}}) + builder2.AddEgress(ProtocolTCP, &p80, nil, nil, nil, nil, nil, nil, map[string]string{"ns": namespaces["z"]}, nil, nil, false, nil, crdv1alpha1.RuleActionAllow, "", "", nil) // This rule should take no effect as it will be overridden by the first rule of cnp-drop - builder2.AddEgress(v1.ProtocolTCP, &p80, nil, nil, nil, nil, map[string]string{"ns": "y"}, + builder2.AddEgress(ProtocolTCP, &p80, nil, nil, nil, nil, nil, nil, map[string]string{"ns": namespaces["y"]}, nil, nil, false, nil, crdv1alpha1.RuleActionAllow, "", "", nil) // Only egress from pods in namespace x to namespace y should be denied reachabilityBothACNP := NewReachability(allPods, Connected) - reachabilityBothACNP.ExpectIngressFromNamespace("y/a", "x", Dropped) - reachabilityBothACNP.ExpectIngressFromNamespace("y/b", "x", Dropped) - reachabilityBothACNP.ExpectIngressFromNamespace("y/c", "x", Dropped) + reachabilityBothACNP.ExpectIngressFromNamespace(Pod(namespaces["y"]+"/a"), namespaces["x"], Dropped) + reachabilityBothACNP.ExpectIngressFromNamespace(Pod(namespaces["y"]+"/b"), namespaces["x"], Dropped) + reachabilityBothACNP.ExpectIngressFromNamespace(Pod(namespaces["y"]+"/c"), namespaces["x"], Dropped) testStep := []*TestStep{ { "Both ACNP", reachabilityBothACNP, []metav1.Object{builder2.Get(), builder1.Get()}, []int32{80}, - v1.ProtocolTCP, + ProtocolTCP, 0, nil, }, @@ -1520,21 +1525,21 @@ func testACNPPortRange(t *testing.T) { builder = builder.SetName("acnp-deny-a-to-z-egress-port-range"). SetPriority(1.0). SetAppliedToGroup([]ACNPAppliedToSpec{{PodSelector: map[string]string{"pod": "a"}}}) - builder.AddEgress(v1.ProtocolTCP, &p8080, nil, &p8085, nil, nil, map[string]string{"ns": "z"}, + builder.AddEgress(ProtocolTCP, &p8080, nil, &p8085, nil, nil, nil, nil, map[string]string{"ns": namespaces["z"]}, nil, nil, false, nil, crdv1alpha1.RuleActionDrop, "", "acnp-port-range", nil) reachability := NewReachability(allPods, Connected) - reachability.ExpectEgressToNamespace(Pod("x/a"), "z", Dropped) - reachability.ExpectEgressToNamespace(Pod("y/a"), "z", Dropped) - reachability.Expect(Pod("z/a"), Pod("z/b"), Dropped) - reachability.Expect(Pod("z/a"), Pod("z/c"), Dropped) + reachability.ExpectEgressToNamespace(Pod(namespaces["x"]+"/a"), namespaces["z"], Dropped) + reachability.ExpectEgressToNamespace(Pod(namespaces["y"]+"/a"), namespaces["z"], Dropped) + reachability.Expect(Pod(namespaces["z"]+"/a"), Pod(namespaces["z"]+"/b"), Dropped) + reachability.Expect(Pod(namespaces["z"]+"/a"), Pod(namespaces["z"]+"/c"), Dropped) testSteps := []*TestStep{ { fmt.Sprintf("ACNP Drop Ports 8080:8085"), reachability, []metav1.Object{builder.Get()}, []int32{8080, 8081, 8082, 8083, 8084, 8085}, - v1.ProtocolTCP, + ProtocolTCP, 0, nil, }, @@ -1552,21 +1557,21 @@ func testACNPRejectEgress(t *testing.T) { builder = builder.SetName("acnp-reject-a-to-z-egress"). SetPriority(1.0). SetAppliedToGroup([]ACNPAppliedToSpec{{PodSelector: map[string]string{"pod": "a"}}}) - builder.AddEgress(v1.ProtocolTCP, &p80, nil, nil, nil, nil, map[string]string{"ns": "z"}, + builder.AddEgress(ProtocolTCP, &p80, nil, nil, nil, nil, nil, nil, map[string]string{"ns": namespaces["z"]}, nil, nil, false, nil, crdv1alpha1.RuleActionReject, "", "", nil) reachability := NewReachability(allPods, Connected) - reachability.ExpectEgressToNamespace(Pod("x/a"), "z", Rejected) - reachability.ExpectEgressToNamespace(Pod("y/a"), "z", Rejected) - reachability.Expect(Pod("z/a"), Pod("z/b"), Rejected) - reachability.Expect(Pod("z/a"), Pod("z/c"), Rejected) + reachability.ExpectEgressToNamespace(Pod(namespaces["x"]+"/a"), namespaces["z"], Rejected) + reachability.ExpectEgressToNamespace(Pod(namespaces["y"]+"/a"), namespaces["z"], Rejected) + reachability.Expect(Pod(namespaces["z"]+"/a"), Pod(namespaces["z"]+"/b"), Rejected) + reachability.Expect(Pod(namespaces["z"]+"/a"), Pod(namespaces["z"]+"/c"), Rejected) testStep := []*TestStep{ { "Port 80", reachability, []metav1.Object{builder.Get()}, []int32{80}, - v1.ProtocolTCP, + ProtocolTCP, 0, nil, }, @@ -1578,19 +1583,19 @@ func testACNPRejectEgress(t *testing.T) { } // testACNPRejectIngress tests that an ACNP is able to reject egress traffic from pods labelled A to namespace Z. -func testACNPRejectIngress(t *testing.T, protocol v1.Protocol) { +func testACNPRejectIngress(t *testing.T, protocol AntreaPolicyProtocol) { builder := &ClusterNetworkPolicySpecBuilder{} builder = builder.SetName("acnp-reject-a-from-z-ingress"). SetPriority(1.0). SetAppliedToGroup([]ACNPAppliedToSpec{{PodSelector: map[string]string{"pod": "a"}}}) - builder.AddIngress(protocol, &p80, nil, nil, nil, nil, map[string]string{"ns": "z"}, + builder.AddIngress(protocol, &p80, nil, nil, nil, nil, nil, nil, map[string]string{"ns": namespaces["z"]}, nil, nil, false, nil, crdv1alpha1.RuleActionReject, "", "", nil) reachability := NewReachability(allPods, Connected) - reachability.ExpectIngressFromNamespace(Pod("x/a"), "z", Rejected) - reachability.ExpectIngressFromNamespace(Pod("y/a"), "z", Rejected) - reachability.Expect(Pod("z/b"), Pod("z/a"), Rejected) - reachability.Expect(Pod("z/c"), Pod("z/a"), Rejected) + reachability.ExpectIngressFromNamespace(Pod(namespaces["x"]+"/a"), namespaces["z"], Rejected) + reachability.ExpectIngressFromNamespace(Pod(namespaces["y"]+"/a"), namespaces["z"], Rejected) + reachability.Expect(Pod(namespaces["z"]+"/b"), Pod(namespaces["z"]+"/a"), Rejected) + reachability.Expect(Pod(namespaces["z"]+"/c"), Pod(namespaces["z"]+"/a"), Rejected) testStep := []*TestStep{ { "Port 80", @@ -1610,26 +1615,26 @@ func testACNPRejectIngress(t *testing.T, protocol v1.Protocol) { func testRejectServiceTraffic(t *testing.T, data *TestData) { clientName := "agnhost-client" - require.NoError(t, data.createAgnhostPodOnNode(clientName, testNamespace, nodeName(0), false)) - defer data.deletePodAndWait(defaultTimeout, clientName, testNamespace) - _, err := data.podWaitForIPs(defaultTimeout, clientName, testNamespace) + require.NoError(t, data.createAgnhostPodOnNode(clientName, data.testNamespace, nodeName(0), false)) + defer data.deletePodAndWait(defaultTimeout, clientName, data.testNamespace) + _, err := data.podWaitForIPs(defaultTimeout, clientName, data.testNamespace) require.NoError(t, err) - svc1, cleanup1 := data.createAgnhostServiceAndBackendPods(t, "s1", testNamespace, nodeName(0), v1.ServiceTypeClusterIP) + svc1, cleanup1 := data.createAgnhostServiceAndBackendPods(t, "s1", data.testNamespace, nodeName(0), v1.ServiceTypeClusterIP) defer cleanup1() - svc2, cleanup2 := data.createAgnhostServiceAndBackendPods(t, "s2", testNamespace, nodeName(1), v1.ServiceTypeClusterIP) + svc2, cleanup2 := data.createAgnhostServiceAndBackendPods(t, "s2", data.testNamespace, nodeName(1), v1.ServiceTypeClusterIP) defer cleanup2() testcases := []podToAddrTestStep{ { - "antrea-test/agnhost-client", + Pod(data.testNamespace + "/agnhost-client"), svc1.Spec.ClusterIP, 80, Rejected, }, { - "antrea-test/agnhost-client", + Pod(data.testNamespace + "/agnhost-client"), svc2.Spec.ClusterIP, 80, Rejected, @@ -1641,9 +1646,9 @@ func testRejectServiceTraffic(t *testing.T, data *TestData) { builder1 = builder1.SetName("acnp-reject-egress-svc-traffic"). SetPriority(1.0). SetAppliedToGroup([]ACNPAppliedToSpec{{PodSelector: map[string]string{"antrea-e2e": "agnhost-client"}}}) - builder1.AddEgress(v1.ProtocolTCP, &p80, nil, nil, nil, map[string]string{"antrea-e2e": "s1"}, nil, + builder1.AddEgress(ProtocolTCP, &p80, nil, nil, nil, nil, nil, map[string]string{"antrea-e2e": "s1"}, nil, nil, nil, false, nil, crdv1alpha1.RuleActionReject, "", "", nil) - builder1.AddEgress(v1.ProtocolTCP, &p80, nil, nil, nil, map[string]string{"antrea-e2e": "s2"}, nil, + builder1.AddEgress(ProtocolTCP, &p80, nil, nil, nil, nil, nil, map[string]string{"antrea-e2e": "s2"}, nil, nil, nil, false, nil, crdv1alpha1.RuleActionReject, "", "", nil) acnpEgress := builder1.Get() @@ -1653,7 +1658,7 @@ func testRejectServiceTraffic(t *testing.T, data *TestData) { for _, tc := range testcases { log.Tracef("Probing: %s -> %s:%d", tc.clientPod.PodName(), tc.destAddr, tc.destPort) - connectivity, err := k8sUtils.ProbeAddr(tc.clientPod.Namespace(), "antrea-e2e", tc.clientPod.PodName(), tc.destAddr, tc.destPort, v1.ProtocolTCP) + connectivity, err := k8sUtils.ProbeAddr(tc.clientPod.Namespace(), "antrea-e2e", tc.clientPod.PodName(), tc.destAddr, tc.destPort, ProtocolTCP) if err != nil { t.Errorf("failure -- could not complete probe: %v", err) } @@ -1671,7 +1676,7 @@ func testRejectServiceTraffic(t *testing.T, data *TestData) { builder2 = builder2.SetName("acnp-reject-ingress-svc-traffic"). SetPriority(1.0). SetAppliedToGroup([]ACNPAppliedToSpec{{PodSelector: map[string]string{"antrea-e2e": "s1"}}, {PodSelector: map[string]string{"antrea-e2e": "s2"}}}) - builder2.AddIngress(v1.ProtocolTCP, &p80, nil, nil, nil, map[string]string{"antrea-e2e": "agnhost-client"}, nil, + builder2.AddIngress(ProtocolTCP, &p80, nil, nil, nil, nil, nil, map[string]string{"antrea-e2e": "agnhost-client"}, nil, nil, nil, false, nil, crdv1alpha1.RuleActionReject, "", "", nil) acnpIngress := builder2.Get() @@ -1681,7 +1686,7 @@ func testRejectServiceTraffic(t *testing.T, data *TestData) { for _, tc := range testcases { log.Tracef("Probing: %s -> %s:%d", tc.clientPod.PodName(), tc.destAddr, tc.destPort) - connectivity, err := k8sUtils.ProbeAddr(tc.clientPod.Namespace(), "antrea-e2e", tc.clientPod.PodName(), tc.destAddr, tc.destPort, v1.ProtocolTCP) + connectivity, err := k8sUtils.ProbeAddr(tc.clientPod.Namespace(), "antrea-e2e", tc.clientPod.PodName(), tc.destAddr, tc.destPort, ProtocolTCP) if err != nil { t.Errorf("failure -- could not complete probe: %v", err) } @@ -1695,17 +1700,133 @@ func testRejectServiceTraffic(t *testing.T, data *TestData) { time.Sleep(networkPolicyDelay) } +// RejectNoInfiniteLoop tests that a reject action in both traffic directions won't cause an infinite rejection loop. +func testRejectNoInfiniteLoop(t *testing.T, data *TestData) { + clientName := "agnhost-client" + require.NoError(t, data.createAgnhostPodOnNode(clientName, data.testNamespace, nodeName(0), false)) + defer data.deletePodAndWait(defaultTimeout, clientName, data.testNamespace) + _, err := data.podWaitForIPs(defaultTimeout, clientName, data.testNamespace) + require.NoError(t, err) + + _, server0IP, cleanupFunc := createAndWaitForPod(t, data, data.createNginxPodOnNode, "server", nodeName(0), data.testNamespace, false) + defer cleanupFunc() + + _, server1IP, cleanupFunc := createAndWaitForPod(t, data, data.createNginxPodOnNode, "server", nodeName(1), data.testNamespace, false) + defer cleanupFunc() + + var testcases []podToAddrTestStep + if clusterInfo.podV4NetworkCIDR != "" { + testcases = append(testcases, []podToAddrTestStep{ + { + Pod(data.testNamespace + "/agnhost-client"), + server0IP.ipv4.String(), + 80, + Rejected, + }, + { + Pod(data.testNamespace + "/agnhost-client"), + server1IP.ipv4.String(), + 80, + Rejected, + }, + }...) + } + if clusterInfo.podV6NetworkCIDR != "" { + testcases = append(testcases, []podToAddrTestStep{ + { + Pod(data.testNamespace + "/agnhost-client"), + server0IP.ipv6.String(), + 80, + Rejected, + }, + { + Pod(data.testNamespace + "/agnhost-client"), + server1IP.ipv6.String(), + 80, + Rejected, + }, + }...) + } + + runTestsWithACNP := func(acnp *crdv1alpha1.ClusterNetworkPolicy, testcases []podToAddrTestStep) { + k8sUtils.CreateOrUpdateACNP(acnp) + failOnError(waitForResourceReady(acnp, timeout), t) + time.Sleep(networkPolicyDelay) + + for _, tc := range testcases { + log.Tracef("Probing: %s -> %s:%d", tc.clientPod.PodName(), tc.destAddr, tc.destPort) + connectivity, err := k8sUtils.ProbeAddr(tc.clientPod.Namespace(), "antrea-e2e", tc.clientPod.PodName(), tc.destAddr, tc.destPort, ProtocolTCP) + if err != nil { + t.Errorf("failure -- could not complete probe: %v", err) + } + if connectivity != tc.expectedConnectivity { + t.Errorf("failure -- wrong results for probe: Source %s/%s --> Dest %s:%d connectivity: %v, expected: %v", + tc.clientPod.Namespace(), tc.clientPod.PodName(), tc.destAddr, tc.destPort, connectivity, tc.expectedConnectivity) + } + } + failOnError(k8sUtils.DeleteACNP(acnp.Name), t) + failOnError(waitForResourceDelete("", acnp.Name, resourceACNP, timeout), t) + time.Sleep(networkPolicyDelay) + } + + // Test client and server reject traffic that ingress from each other. + builder1 := &ClusterNetworkPolicySpecBuilder{} + builder1 = builder1.SetName("acnp-reject-ingress-double-dir"). + SetPriority(1.0) + builder1.AddIngress(ProtocolTCP, nil, nil, nil, nil, nil, nil, map[string]string{"app": "nginx"}, nil, + nil, nil, false, []ACNPAppliedToSpec{{PodSelector: map[string]string{"antrea-e2e": clientName}}}, crdv1alpha1.RuleActionReject, "", "", nil) + builder1.AddIngress(ProtocolTCP, nil, nil, nil, nil, nil, nil, map[string]string{"antrea-e2e": clientName}, nil, + nil, nil, false, []ACNPAppliedToSpec{{PodSelector: map[string]string{"app": "nginx"}}}, crdv1alpha1.RuleActionReject, "", "", nil) + + runTestsWithACNP(builder1.Get(), testcases) + + // Test client and server reject traffic that egress to each other. + builder2 := &ClusterNetworkPolicySpecBuilder{} + builder2 = builder2.SetName("acnp-reject-egress-double-dir"). + SetPriority(1.0) + builder2.AddEgress(ProtocolTCP, nil, nil, nil, nil, nil, nil, map[string]string{"app": "nginx"}, nil, + nil, nil, false, []ACNPAppliedToSpec{{PodSelector: map[string]string{"antrea-e2e": clientName}}}, crdv1alpha1.RuleActionReject, "", "", nil) + builder2.AddEgress(ProtocolTCP, nil, nil, nil, nil, nil, nil, map[string]string{"antrea-e2e": clientName}, nil, + nil, nil, false, []ACNPAppliedToSpec{{PodSelector: map[string]string{"app": "nginx"}}}, crdv1alpha1.RuleActionReject, "", "", nil) + + runTestsWithACNP(builder2.Get(), testcases) + + // Test server reject traffic that egress to client and ingress from client. + builder3 := &ClusterNetworkPolicySpecBuilder{} + builder3 = builder3.SetName("acnp-reject-server-double-dir"). + SetPriority(1.0). + SetAppliedToGroup([]ACNPAppliedToSpec{{PodSelector: map[string]string{"app": "nginx"}}}) + builder3.AddIngress(ProtocolTCP, nil, nil, nil, nil, nil, nil, map[string]string{"antrea-e2e": clientName}, nil, + nil, nil, false, nil, crdv1alpha1.RuleActionReject, "", "", nil) + builder3.AddEgress(ProtocolTCP, nil, nil, nil, nil, nil, nil, map[string]string{"antrea-e2e": clientName}, nil, + nil, nil, false, nil, crdv1alpha1.RuleActionReject, "", "", nil) + + runTestsWithACNP(builder3.Get(), testcases) + + // Test client reject traffic that egress to server and ingress from server. + builder4 := &ClusterNetworkPolicySpecBuilder{} + builder4 = builder4.SetName("acnp-reject-client-double-dir"). + SetPriority(1.0). + SetAppliedToGroup([]ACNPAppliedToSpec{{PodSelector: map[string]string{"antrea-e2e": clientName}}}) + builder4.AddIngress(ProtocolTCP, nil, nil, nil, nil, nil, nil, map[string]string{"app": "nginx"}, nil, + nil, nil, false, nil, crdv1alpha1.RuleActionReject, "", "", nil) + builder4.AddEgress(ProtocolTCP, nil, nil, nil, nil, nil, nil, map[string]string{"app": "nginx"}, nil, + nil, nil, false, nil, crdv1alpha1.RuleActionReject, "", "", nil) + + runTestsWithACNP(builder4.Get(), testcases) +} + // testANPPortRange tests the port range in a ANP can work. func testANPPortRange(t *testing.T) { builder := &AntreaNetworkPolicySpecBuilder{} - builder = builder.SetName("y", "anp-deny-yb-to-xc-egress-port-range"). + builder = builder.SetName(namespaces["y"], "anp-deny-yb-to-xc-egress-port-range"). SetPriority(1.0). SetAppliedToGroup([]ANPAppliedToSpec{{PodSelector: map[string]string{"pod": "b"}}}) - builder.AddEgress(v1.ProtocolTCP, &p8080, nil, &p8085, nil, map[string]string{"pod": "c"}, map[string]string{"ns": "x"}, + builder.AddEgress(ProtocolTCP, &p8080, nil, &p8085, nil, nil, nil, map[string]string{"pod": "c"}, map[string]string{"ns": namespaces["x"]}, nil, nil, nil, crdv1alpha1.RuleActionDrop, "anp-port-range") reachability := NewReachability(allPods, Connected) - reachability.Expect(Pod("y/b"), Pod("x/c"), Dropped) + reachability.Expect(Pod(namespaces["y"]+"/b"), Pod(namespaces["x"]+"/c"), Dropped) var testSteps []*TestStep testSteps = append(testSteps, &TestStep{ @@ -1713,7 +1834,7 @@ func testANPPortRange(t *testing.T) { reachability, []metav1.Object{builder.Get()}, []int32{8080, 8081, 8082, 8083, 8084, 8085}, - v1.ProtocolTCP, + ProtocolTCP, 0, nil, }) @@ -1728,28 +1849,28 @@ func testANPPortRange(t *testing.T) { // that specifies that. Also it tests that a K8s NetworkPolicy with same appliedTo will not affect its behavior. func testANPBasic(t *testing.T) { builder := &AntreaNetworkPolicySpecBuilder{} - builder = builder.SetName("y", "np-same-name"). + builder = builder.SetName(namespaces["y"], "np-same-name"). SetPriority(1.0). SetAppliedToGroup([]ANPAppliedToSpec{{PodSelector: map[string]string{"pod": "a"}}}) - builder.AddIngress(v1.ProtocolTCP, &p80, nil, nil, nil, map[string]string{"pod": "b"}, map[string]string{"ns": "x"}, + builder.AddIngress(ProtocolTCP, &p80, nil, nil, nil, nil, nil, map[string]string{"pod": "b"}, map[string]string{"ns": namespaces["x"]}, nil, nil, nil, crdv1alpha1.RuleActionDrop, "") reachability := NewReachability(allPods, Connected) - reachability.Expect(Pod("x/b"), Pod("y/a"), Dropped) + reachability.Expect(Pod(namespaces["x"]+"/b"), Pod(namespaces["y"]+"/a"), Dropped) testStep := []*TestStep{ { "Port 80", reachability, []metav1.Object{builder.Get()}, []int32{80}, - v1.ProtocolTCP, + ProtocolTCP, 0, nil, }, } // build a K8s NetworkPolicy that has the same appliedTo but allows all traffic. k8sNPBuilder := &NetworkPolicySpecBuilder{} - k8sNPBuilder = k8sNPBuilder.SetName("y", "np-same-name"). + k8sNPBuilder = k8sNPBuilder.SetName(namespaces["y"], "np-same-name"). SetPodSelector(map[string]string{"pod": "a"}) k8sNPBuilder.AddIngress(v1.ProtocolTCP, &p80, nil, nil, nil, nil, nil, nil, nil) @@ -1759,7 +1880,7 @@ func testANPBasic(t *testing.T) { reachability, []metav1.Object{builder.Get(), k8sNPBuilder.Get()}, []int32{80}, - v1.ProtocolTCP, + ProtocolTCP, 0, nil, }, @@ -1777,27 +1898,27 @@ func testANPBasic(t *testing.T) { func testANPMultipleAppliedTo(t *testing.T, data *TestData, singleRule bool) { tempLabel := randName("temp-") builder := &AntreaNetworkPolicySpecBuilder{} - builder = builder.SetName("y", "np-multiple-appliedto").SetPriority(1.0) + builder = builder.SetName(namespaces["y"], "np-multiple-appliedto").SetPriority(1.0) // Make it apply to an extra dummy AppliedTo to ensure it handles multiple AppliedToGroups correctly. // See https://github.com/antrea-io/antrea/issues/2083. if singleRule { builder.SetAppliedToGroup([]ANPAppliedToSpec{{PodSelector: map[string]string{"pod": "a"}}, {PodSelector: map[string]string{tempLabel: ""}}}) - builder.AddIngress(v1.ProtocolTCP, &p80, nil, nil, nil, map[string]string{"pod": "b"}, map[string]string{"ns": "x"}, + builder.AddIngress(ProtocolTCP, &p80, nil, nil, nil, nil, nil, map[string]string{"pod": "b"}, map[string]string{"ns": namespaces["x"]}, nil, nil, nil, crdv1alpha1.RuleActionDrop, "") } else { - builder.AddIngress(v1.ProtocolTCP, &p80, nil, nil, nil, map[string]string{"pod": "b"}, map[string]string{"ns": "x"}, + builder.AddIngress(ProtocolTCP, &p80, nil, nil, nil, nil, nil, map[string]string{"pod": "b"}, map[string]string{"ns": namespaces["x"]}, nil, nil, []ANPAppliedToSpec{{PodSelector: map[string]string{"pod": "a"}}}, crdv1alpha1.RuleActionDrop, "") - builder.AddIngress(v1.ProtocolTCP, &p80, nil, nil, nil, map[string]string{"pod": "b"}, map[string]string{"ns": "x"}, + builder.AddIngress(ProtocolTCP, &p80, nil, nil, nil, nil, nil, map[string]string{"pod": "b"}, map[string]string{"ns": namespaces["x"]}, nil, nil, []ANPAppliedToSpec{{PodSelector: map[string]string{tempLabel: ""}}}, crdv1alpha1.RuleActionDrop, "") } reachability := NewReachability(allPods, Connected) - reachability.Expect(Pod("x/b"), Pod("y/a"), Dropped) + reachability.Expect(Pod(namespaces["x"]+"/b"), Pod(namespaces["y"]+"/a"), Dropped) anp, err := k8sUtils.CreateOrUpdateANP(builder.Get()) failOnError(err, t) failOnError(data.waitForANPRealized(t, anp.Namespace, anp.Name), t) - k8sUtils.Validate(allPods, reachability, []int32{80}, v1.ProtocolTCP) + k8sUtils.Validate(allPods, reachability, []int32{80}, ProtocolTCP) _, wrong, _ := reachability.Summary() if wrong != 0 { t.Errorf("failure -- %d wrong results", wrong) @@ -1805,7 +1926,7 @@ func testANPMultipleAppliedTo(t *testing.T, data *TestData, singleRule bool) { } t.Logf("Making the Policy apply to y/c by labeling it with the temporary label that matches the dummy AppliedTo") - podYC, err := k8sUtils.GetPodByLabel("y", "c") + podYC, err := k8sUtils.GetPodByLabel(namespaces["y"], "c") if err != nil { t.Errorf("Failed to get Pod in Namespace y with label 'pod=c': %v", err) } @@ -1813,10 +1934,10 @@ func testANPMultipleAppliedTo(t *testing.T, data *TestData, singleRule bool) { podYC, err = k8sUtils.clientset.CoreV1().Pods(podYC.Namespace).Update(context.TODO(), podYC, metav1.UpdateOptions{}) assert.NoError(t, err) reachability = NewReachability(allPods, Connected) - reachability.Expect(Pod("x/b"), Pod("y/a"), Dropped) - reachability.Expect(Pod("x/b"), Pod("y/c"), Dropped) + reachability.Expect(Pod(namespaces["x"]+"/b"), Pod(namespaces["y"]+"/a"), Dropped) + reachability.Expect(Pod(namespaces["x"]+"/b"), Pod(namespaces["y"]+"/c"), Dropped) time.Sleep(networkPolicyDelay) - k8sUtils.Validate(allPods, reachability, []int32{80}, v1.ProtocolTCP) + k8sUtils.Validate(allPods, reachability, []int32{80}, ProtocolTCP) _, wrong, _ = reachability.Summary() if wrong != 0 { t.Errorf("failure -- %d wrong results", wrong) @@ -1828,9 +1949,9 @@ func testANPMultipleAppliedTo(t *testing.T, data *TestData, singleRule bool) { _, err = k8sUtils.clientset.CoreV1().Pods(podYC.Namespace).Update(context.TODO(), podYC, metav1.UpdateOptions{}) assert.NoError(t, err) reachability = NewReachability(allPods, Connected) - reachability.Expect(Pod("x/b"), Pod("y/a"), Dropped) + reachability.Expect(Pod(namespaces["x"]+"/b"), Pod(namespaces["y"]+"/a"), Dropped) time.Sleep(networkPolicyDelay) - k8sUtils.Validate(allPods, reachability, []int32{80}, v1.ProtocolTCP) + k8sUtils.Validate(allPods, reachability, []int32{80}, ProtocolTCP) _, wrong, _ = reachability.Summary() if wrong != 0 { t.Errorf("failure -- %d wrong results", wrong) @@ -1845,8 +1966,8 @@ func testAuditLoggingBasic(t *testing.T, data *TestData) { builder := &ClusterNetworkPolicySpecBuilder{} builder = builder.SetName("test-log-acnp-deny"). SetPriority(1.0). - SetAppliedToGroup([]ACNPAppliedToSpec{{PodSelector: map[string]string{"pod": "a"}, NSSelector: map[string]string{"ns": "x"}}}) - builder.AddEgress(v1.ProtocolTCP, &p80, nil, nil, nil, nil, map[string]string{"ns": "z"}, + SetAppliedToGroup([]ACNPAppliedToSpec{{PodSelector: map[string]string{"pod": "a"}, NSSelector: map[string]string{"ns": namespaces["x"]}}}) + builder.AddEgress(ProtocolTCP, &p80, nil, nil, nil, nil, nil, nil, map[string]string{"ns": namespaces["z"]}, nil, nil, false, nil, crdv1alpha1.RuleActionDrop, "", "", nil) builder.AddEgressLogging() @@ -1860,15 +1981,15 @@ func testAuditLoggingBasic(t *testing.T, data *TestData) { wg.Add(1) go func() { defer wg.Done() - k8sUtils.Probe(ns1, pod1, ns2, pod2, p80, v1.ProtocolTCP) + k8sUtils.Probe(ns1, pod1, ns2, pod2, p80, ProtocolTCP) }() } - oneProbe("x", "a", "z", "a") - oneProbe("x", "a", "z", "b") - oneProbe("x", "a", "z", "c") + oneProbe(namespaces["x"], "a", namespaces["z"], "a") + oneProbe(namespaces["x"], "a", namespaces["z"], "b") + oneProbe(namespaces["x"], "a", namespaces["z"], "c") wg.Wait() - podXA, err := k8sUtils.GetPodByLabel("x", "a") + podXA, err := k8sUtils.GetPodByLabel(namespaces["x"], "a") if err != nil { t.Errorf("Failed to get Pod in Namespace x with label 'pod=a': %v", err) } @@ -1892,8 +2013,8 @@ func testAuditLoggingBasic(t *testing.T, data *TestData) { return false, nil } - destinations := []string{"z/a", "z/b", "z/c"} - srcIPs, _ := podIPs["x/a"] + destinations := []string{namespaces["z"] + "/a", namespaces["z"] + "/b", namespaces["z"] + "/c"} + srcIPs, _ := podIPs[namespaces["x"]+"/a"] var expectedNumEntries, actualNumEntries int for _, d := range destinations { dstIPs, _ := podIPs[d] @@ -1930,24 +2051,24 @@ func testAuditLoggingBasic(t *testing.T, data *TestData) { func testAppliedToPerRule(t *testing.T) { builder := &AntreaNetworkPolicySpecBuilder{} - builder = builder.SetName("y", "np1").SetPriority(1.0) + builder = builder.SetName(namespaces["y"], "np1").SetPriority(1.0) anpATGrp1 := ANPAppliedToSpec{PodSelector: map[string]string{"pod": "a"}, PodSelectorMatchExp: nil} anpATGrp2 := ANPAppliedToSpec{PodSelector: map[string]string{"pod": "b"}, PodSelectorMatchExp: nil} - builder.AddIngress(v1.ProtocolTCP, &p80, nil, nil, nil, map[string]string{"pod": "b"}, map[string]string{"ns": "x"}, + builder.AddIngress(ProtocolTCP, &p80, nil, nil, nil, nil, nil, map[string]string{"pod": "b"}, map[string]string{"ns": namespaces["x"]}, nil, nil, []ANPAppliedToSpec{anpATGrp1}, crdv1alpha1.RuleActionDrop, "") - builder.AddIngress(v1.ProtocolTCP, &p80, nil, nil, nil, map[string]string{"pod": "b"}, map[string]string{"ns": "z"}, + builder.AddIngress(ProtocolTCP, &p80, nil, nil, nil, nil, nil, map[string]string{"pod": "b"}, map[string]string{"ns": namespaces["z"]}, nil, nil, []ANPAppliedToSpec{anpATGrp2}, crdv1alpha1.RuleActionDrop, "") reachability := NewReachability(allPods, Connected) - reachability.Expect(Pod("x/b"), Pod("y/a"), Dropped) - reachability.Expect(Pod("z/b"), Pod("y/b"), Dropped) + reachability.Expect(Pod(namespaces["x"]+"/b"), Pod(namespaces["y"]+"/a"), Dropped) + reachability.Expect(Pod(namespaces["z"]+"/b"), Pod(namespaces["y"]+"/b"), Dropped) testStep := []*TestStep{ { "Port 80", reachability, []metav1.Object{builder.Get()}, []int32{80}, - v1.ProtocolTCP, + ProtocolTCP, 0, nil, }, @@ -1957,25 +2078,25 @@ func testAppliedToPerRule(t *testing.T) { builder2 = builder2.SetName("cnp1").SetPriority(1.0) cnpATGrp1 := ACNPAppliedToSpec{PodSelector: map[string]string{"pod": "a"}, PodSelectorMatchExp: nil} cnpATGrp2 := ACNPAppliedToSpec{ - PodSelector: map[string]string{"pod": "b"}, NSSelector: map[string]string{"ns": "y"}, + PodSelector: map[string]string{"pod": "b"}, NSSelector: map[string]string{"ns": namespaces["y"]}, PodSelectorMatchExp: nil, NSSelectorMatchExp: nil} - builder2.AddIngress(v1.ProtocolTCP, &p80, nil, nil, nil, map[string]string{"pod": "b"}, map[string]string{"ns": "x"}, + builder2.AddIngress(ProtocolTCP, &p80, nil, nil, nil, nil, nil, map[string]string{"pod": "b"}, map[string]string{"ns": namespaces["x"]}, nil, nil, false, []ACNPAppliedToSpec{cnpATGrp1}, crdv1alpha1.RuleActionDrop, "", "", nil) - builder2.AddIngress(v1.ProtocolTCP, &p80, nil, nil, nil, map[string]string{"pod": "b"}, map[string]string{"ns": "z"}, + builder2.AddIngress(ProtocolTCP, &p80, nil, nil, nil, nil, nil, map[string]string{"pod": "b"}, map[string]string{"ns": namespaces["z"]}, nil, nil, false, []ACNPAppliedToSpec{cnpATGrp2}, crdv1alpha1.RuleActionDrop, "", "", nil) reachability2 := NewReachability(allPods, Connected) - reachability2.Expect(Pod("x/b"), Pod("x/a"), Dropped) - reachability2.Expect(Pod("x/b"), Pod("y/a"), Dropped) - reachability2.Expect(Pod("x/b"), Pod("z/a"), Dropped) - reachability2.Expect(Pod("z/b"), Pod("y/b"), Dropped) + reachability2.Expect(Pod(namespaces["x"]+"/b"), Pod(namespaces["x"]+"/a"), Dropped) + reachability2.Expect(Pod(namespaces["x"]+"/b"), Pod(namespaces["y"]+"/a"), Dropped) + reachability2.Expect(Pod(namespaces["x"]+"/b"), Pod(namespaces["z"]+"/a"), Dropped) + reachability2.Expect(Pod(namespaces["z"]+"/b"), Pod(namespaces["y"]+"/b"), Dropped) testStep2 := []*TestStep{ { "Port 80", reachability2, []metav1.Object{builder2.Get()}, []int32{80}, - v1.ProtocolTCP, + ProtocolTCP, 0, nil, }, @@ -1989,45 +2110,45 @@ func testAppliedToPerRule(t *testing.T) { } func testACNPClusterGroupServiceRefCreateAndUpdate(t *testing.T, data *TestData) { - svc1 := k8sUtils.BuildService("svc1", "x", 80, 80, map[string]string{"app": "a"}, nil) - svc2 := k8sUtils.BuildService("svc2", "y", 80, 80, map[string]string{"app": "b"}, nil) + svc1 := k8sUtils.BuildService("svc1", namespaces["x"], 80, 80, map[string]string{"app": "a"}, nil) + svc2 := k8sUtils.BuildService("svc2", namespaces["y"], 80, 80, map[string]string{"app": "b"}, nil) cg1Name, cg2Name := "cg-svc1", "cg-svc2" cgBuilder1 := &ClusterGroupV1Alpha3SpecBuilder{} - cgBuilder1 = cgBuilder1.SetName(cg1Name).SetServiceReference("x", "svc1") + cgBuilder1 = cgBuilder1.SetName(cg1Name).SetServiceReference(namespaces["x"], "svc1") cgBuilder2 := &ClusterGroupV1Alpha3SpecBuilder{} - cgBuilder2 = cgBuilder2.SetName(cg2Name).SetServiceReference("y", "svc2") + cgBuilder2 = cgBuilder2.SetName(cg2Name).SetServiceReference(namespaces["y"], "svc2") builder := &ClusterNetworkPolicySpecBuilder{} builder = builder.SetName("cnp-cg-svc-ref").SetPriority(1.0).SetAppliedToGroup([]ACNPAppliedToSpec{{Group: cg1Name}}) - builder.AddIngress(v1.ProtocolTCP, &p80, nil, nil, nil, nil, nil, nil, nil, + builder.AddIngress(ProtocolTCP, &p80, nil, nil, nil, nil, nil, nil, nil, nil, nil, false, nil, crdv1alpha1.RuleActionDrop, cg2Name, "", nil) // Pods backing svc1 (label pod=a) in Namespace x should not allow ingress from Pods backing svc2 (label pod=b) in Namespace y. reachability := NewReachability(allPods, Connected) - reachability.Expect(Pod("y/b"), Pod("x/a"), Dropped) + reachability.Expect(Pod(namespaces["y"]+"/b"), Pod(namespaces["x"]+"/a"), Dropped) testStep1 := &TestStep{ "Port 80", reachability, []metav1.Object{svc1, svc2, cgBuilder1.Get(), cgBuilder2.Get(), builder.Get()}, []int32{80}, - v1.ProtocolTCP, + ProtocolTCP, 0, nil, } // Test update selector of Service referred in cg-svc1, and update serviceReference of cg-svc2. - svc1Updated := k8sUtils.BuildService("svc1", "x", 80, 80, map[string]string{"app": "b"}, nil) - svc3 := k8sUtils.BuildService("svc3", "y", 80, 80, map[string]string{"app": "a"}, nil) - cgBuilder2Updated := cgBuilder2.SetServiceReference("y", "svc3") + svc1Updated := k8sUtils.BuildService("svc1", namespaces["x"], 80, 80, map[string]string{"app": "b"}, nil) + svc3 := k8sUtils.BuildService("svc3", namespaces["y"], 80, 80, map[string]string{"app": "a"}, nil) + cgBuilder2Updated := cgBuilder2.SetServiceReference(namespaces["y"], "svc3") cp := []*CustomProbe{ { SourcePod: CustomPod{ - Pod: NewPod("y", "test-add-pod-svc3"), + Pod: NewPod(namespaces["y"], "test-add-pod-svc3"), Labels: map[string]string{"pod": "test-add-pod-svc3", "app": "a"}, }, DestPod: CustomPod{ - Pod: NewPod("x", "test-add-pod-svc1"), + Pod: NewPod(namespaces["x"], "test-add-pod-svc1"), Labels: map[string]string{"pod": "test-add-pod-svc1", "app": "b"}, }, ExpectConnectivity: Dropped, @@ -2037,21 +2158,21 @@ func testACNPClusterGroupServiceRefCreateAndUpdate(t *testing.T, data *TestData) // Pods backing svc1 (label pod=b) in namespace x should not allow ingress from Pods backing svc3 (label pod=a) in namespace y. reachability2 := NewReachability(allPods, Connected) - reachability2.Expect(Pod("y/a"), Pod("x/b"), Dropped) + reachability2.Expect(Pod(namespaces["y"]+"/a"), Pod(namespaces["x"]+"/b"), Dropped) testStep2 := &TestStep{ "Port 80 updated", reachability2, []metav1.Object{svc1Updated, svc3, cgBuilder1.Get(), cgBuilder2Updated.Get()}, []int32{80}, - v1.ProtocolTCP, + ProtocolTCP, 0, cp, } builderUpdated := &ClusterNetworkPolicySpecBuilder{} builderUpdated = builderUpdated.SetName("cnp-cg-svc-ref").SetPriority(1.0) - builderUpdated.SetAppliedToGroup([]ACNPAppliedToSpec{{PodSelector: map[string]string{"pod": "a"}, NSSelector: map[string]string{"ns": "x"}}}) - builderUpdated.AddIngress(v1.ProtocolTCP, &p80, nil, nil, nil, map[string]string{"pod": "b"}, map[string]string{"ns": "y"}, + builderUpdated.SetAppliedToGroup([]ACNPAppliedToSpec{{PodSelector: map[string]string{"pod": "a"}, NSSelector: map[string]string{"ns": namespaces["x"]}}}) + builderUpdated.AddIngress(ProtocolTCP, &p80, nil, nil, nil, nil, nil, map[string]string{"pod": "b"}, map[string]string{"ns": namespaces["y"]}, nil, nil, false, nil, crdv1alpha1.RuleActionDrop, "", "", nil) // Pod x/a should not allow ingress from y/b per the updated ACNP spec. @@ -2060,7 +2181,7 @@ func testACNPClusterGroupServiceRefCreateAndUpdate(t *testing.T, data *TestData) reachability, []metav1.Object{builderUpdated.Get()}, []int32{80}, - v1.ProtocolTCP, + ProtocolTCP, 0, nil, } @@ -2073,17 +2194,17 @@ func testACNPClusterGroupServiceRefCreateAndUpdate(t *testing.T, data *TestData) } func testACNPNestedClusterGroupCreateAndUpdate(t *testing.T, data *TestData) { - svc1 := k8sUtils.BuildService("svc1", "x", 80, 80, map[string]string{"app": "a"}, nil) + svc1 := k8sUtils.BuildService("svc1", namespaces["x"], 80, 80, map[string]string{"app": "a"}, nil) cg1Name, cg2Name, cg3Name := "cg-svc-x-a", "cg-select-y-b", "cg-select-y-c" cgBuilder1 := &ClusterGroupV1Alpha3SpecBuilder{} - cgBuilder1 = cgBuilder1.SetName(cg1Name).SetServiceReference("x", "svc1") + cgBuilder1 = cgBuilder1.SetName(cg1Name).SetServiceReference(namespaces["x"], "svc1") cgBuilder2 := &ClusterGroupV1Alpha3SpecBuilder{} cgBuilder2 = cgBuilder2.SetName(cg2Name). - SetNamespaceSelector(map[string]string{"ns": "y"}, nil). + SetNamespaceSelector(map[string]string{"ns": namespaces["y"]}, nil). SetPodSelector(map[string]string{"pod": "b"}, nil) cgBuilder3 := &ClusterGroupV1Alpha3SpecBuilder{} cgBuilder3 = cgBuilder3.SetName(cg3Name). - SetNamespaceSelector(map[string]string{"ns": "y"}, nil). + SetNamespaceSelector(map[string]string{"ns": namespaces["y"]}, nil). SetPodSelector(map[string]string{"pod": "c"}, nil) cgNestedName := "cg-nested" cgBuilderNested := &ClusterGroupV1Alpha3SpecBuilder{} @@ -2091,15 +2212,15 @@ func testACNPNestedClusterGroupCreateAndUpdate(t *testing.T, data *TestData) { builder := &ClusterNetworkPolicySpecBuilder{} builder = builder.SetName("cnp-nested-cg").SetPriority(1.0). - SetAppliedToGroup([]ACNPAppliedToSpec{{NSSelector: map[string]string{"ns": "z"}}}). - AddIngress(v1.ProtocolTCP, &p80, nil, nil, nil, nil, nil, nil, nil, + SetAppliedToGroup([]ACNPAppliedToSpec{{NSSelector: map[string]string{"ns": namespaces["z"]}}}). + AddIngress(ProtocolTCP, &p80, nil, nil, nil, nil, nil, nil, nil, nil, nil, false, nil, crdv1alpha1.RuleActionDrop, cgNestedName, "", nil) // Pods in Namespace z should not allow traffic from Pods backing svc1 (label pod=a) in Namespace x. // Note that in this testStep cg3 will not be created yet, so even though cg-nested selects cg1 and // cg3 as childGroups, only members of cg1 will be included as this time. reachability := NewReachability(allPods, Connected) - reachability.ExpectEgressToNamespace("x/a", "z", Dropped) + reachability.ExpectEgressToNamespace(Pod(namespaces["x"]+"/a"), namespaces["z"], Dropped) testStep1 := &TestStep{ "Port 80", @@ -2107,7 +2228,7 @@ func testACNPNestedClusterGroupCreateAndUpdate(t *testing.T, data *TestData) { // Note in this testcase the ClusterGroup is created after the ACNP []metav1.Object{builder.Get(), svc1, cgBuilder1.Get(), cgBuilderNested.Get()}, []int32{80}, - v1.ProtocolTCP, + ProtocolTCP, 0, nil, } @@ -2116,17 +2237,17 @@ func testACNPNestedClusterGroupCreateAndUpdate(t *testing.T, data *TestData) { cgBuilderNested = cgBuilderNested.SetChildGroups([]string{cg1Name, cg2Name, cg3Name}) // In addition to x/a, all traffic from y/b to Namespace z should also be denied. reachability2 := NewReachability(allPods, Connected) - reachability2.ExpectEgressToNamespace("x/a", "z", Dropped) - reachability2.ExpectEgressToNamespace("y/b", "z", Dropped) + reachability2.ExpectEgressToNamespace(Pod(namespaces["x"]+"/a"), namespaces["z"], Dropped) + reachability2.ExpectEgressToNamespace(Pod(namespaces["y"]+"/b"), namespaces["z"], Dropped) // New member in cg-svc-x-a should be reflected in cg-nested as well. cp := []*CustomProbe{ { SourcePod: CustomPod{ - Pod: NewPod("x", "test-add-pod-svc1"), + Pod: NewPod(namespaces["x"], "test-add-pod-svc1"), Labels: map[string]string{"pod": "test-add-pod-svc1", "app": "a"}, }, DestPod: CustomPod{ - Pod: NewPod("z", "test-add-pod-ns-z"), + Pod: NewPod(namespaces["z"], "test-add-pod-ns-z"), Labels: map[string]string{"pod": "test-add-pod-ns-z"}, }, ExpectConnectivity: Dropped, @@ -2138,7 +2259,7 @@ func testACNPNestedClusterGroupCreateAndUpdate(t *testing.T, data *TestData) { reachability2, []metav1.Object{cgBuilder2.Get(), cgBuilderNested.Get()}, []int32{80}, - v1.ProtocolTCP, + ProtocolTCP, 0, cp, } @@ -2146,15 +2267,15 @@ func testACNPNestedClusterGroupCreateAndUpdate(t *testing.T, data *TestData) { // In this testStep cg3 is created. It's members should reflect in cg-nested // and as a result, all traffic from y/c to Namespace z should be denied as well. reachability3 := NewReachability(allPods, Connected) - reachability3.ExpectEgressToNamespace("x/a", "z", Dropped) - reachability3.ExpectEgressToNamespace("y/b", "z", Dropped) - reachability3.ExpectEgressToNamespace("y/c", "z", Dropped) + reachability3.ExpectEgressToNamespace(Pod(namespaces["x"]+"/a"), namespaces["z"], Dropped) + reachability3.ExpectEgressToNamespace(Pod(namespaces["y"]+"/b"), namespaces["z"], Dropped) + reachability3.ExpectEgressToNamespace(Pod(namespaces["y"]+"/c"), namespaces["z"], Dropped) testStep3 := &TestStep{ "Port 80 updated", reachability3, []metav1.Object{cgBuilder3.Get()}, []int32{80}, - v1.ProtocolTCP, + ProtocolTCP, 0, nil, } @@ -2167,8 +2288,8 @@ func testACNPNestedClusterGroupCreateAndUpdate(t *testing.T, data *TestData) { } func testACNPNestedIPBlockClusterGroupCreateAndUpdate(t *testing.T) { - podXAIP, _ := podIPs["x/a"] - podXBIP, _ := podIPs["x/b"] + podXAIP, _ := podIPs[namespaces["x"]+"/a"] + podXBIP, _ := podIPs[namespaces["x"]+"/b"] genCIDR := func(ip string) string { if strings.Contains(ip, ".") { return ip + "/32" @@ -2195,41 +2316,41 @@ func testACNPNestedIPBlockClusterGroupCreateAndUpdate(t *testing.T) { SetAppliedToGroup([]ACNPAppliedToSpec{ { PodSelector: map[string]string{"pod": "a"}, - NSSelector: map[string]string{"ns": "y"}, + NSSelector: map[string]string{"ns": namespaces["y"]}, }, }) - builder.AddIngress(v1.ProtocolTCP, &p80, nil, nil, nil, nil, nil, + builder.AddIngress(ProtocolTCP, &p80, nil, nil, nil, nil, nil, nil, nil, nil, nil, false, nil, crdv1alpha1.RuleActionDrop, cgParentName, "", nil) reachability := NewReachability(allPods, Connected) - reachability.Expect("x/a", "y/a", Dropped) - reachability.Expect("x/b", "y/a", Dropped) + reachability.Expect(Pod(namespaces["x"]+"/a"), Pod(namespaces["y"]+"/a"), Dropped) + reachability.Expect(Pod(namespaces["x"]+"/b"), Pod(namespaces["y"]+"/a"), Dropped) testStep := &TestStep{ "Port 80", reachability, []metav1.Object{builder.Get(), cgBuilder1.Get(), cgBuilder2.Get(), cgParent.Get()}, []int32{80}, - v1.ProtocolTCP, + ProtocolTCP, 0, nil, } cgBuilder3 := &ClusterGroupV1Alpha3SpecBuilder{} cgBuilder3 = cgBuilder3.SetName(cg3Name). - SetNamespaceSelector(map[string]string{"ns": "x"}, nil). + SetNamespaceSelector(map[string]string{"ns": namespaces["x"]}, nil). SetPodSelector(map[string]string{"pod": "c"}, nil) updatedCGParent := &ClusterGroupV1Alpha3SpecBuilder{} updatedCGParent = updatedCGParent.SetName(cgParentName).SetChildGroups([]string{cg1Name, cg3Name}) reachability2 := NewReachability(allPods, Connected) - reachability2.Expect("x/a", "y/a", Dropped) - reachability2.Expect("x/c", "y/a", Dropped) + reachability2.Expect(Pod(namespaces["x"]+"/a"), Pod(namespaces["y"]+"/a"), Dropped) + reachability2.Expect(Pod(namespaces["x"]+"/c"), Pod(namespaces["y"]+"/a"), Dropped) testStep2 := &TestStep{ "Port 80, updated", reachability2, []metav1.Object{cgBuilder3.Get(), updatedCGParent.Get()}, []int32{80}, - v1.ProtocolTCP, + ProtocolTCP, 0, nil, } @@ -2247,9 +2368,9 @@ func testACNPNamespaceIsolation(t *testing.T) { SetPriority(1.0). SetAppliedToGroup([]ACNPAppliedToSpec{{NSSelector: map[string]string{}}}) // deny ingress traffic except from own namespace, which is always allowed. - builder.AddIngress(v1.ProtocolTCP, nil, nil, nil, nil, nil, nil, nil, nil, + builder.AddIngress(ProtocolTCP, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, true, nil, crdv1alpha1.RuleActionAllow, "", "", nil) - builder.AddIngress(v1.ProtocolTCP, nil, nil, nil, nil, nil, map[string]string{}, nil, nil, + builder.AddIngress(ProtocolTCP, nil, nil, nil, nil, nil, nil, nil, map[string]string{}, nil, nil, false, nil, crdv1alpha1.RuleActionDrop, "", "", nil) reachability := NewReachability(allPods, Dropped) @@ -2259,7 +2380,7 @@ func testACNPNamespaceIsolation(t *testing.T) { reachability, []metav1.Object{builder.Get()}, []int32{80}, - v1.ProtocolTCP, + ProtocolTCP, 0, nil, } @@ -2268,24 +2389,24 @@ func testACNPNamespaceIsolation(t *testing.T) { builder2 = builder2.SetName("test-acnp-ns-isolation-applied-to-per-rule"). SetTier("baseline"). SetPriority(1.0) - builder2.AddEgress(v1.ProtocolTCP, nil, nil, nil, nil, nil, nil, nil, nil, - true, []ACNPAppliedToSpec{{NSSelector: map[string]string{"ns": "x"}}}, crdv1alpha1.RuleActionAllow, "", "", nil) - builder2.AddEgress(v1.ProtocolTCP, nil, nil, nil, nil, nil, map[string]string{}, nil, nil, - false, []ACNPAppliedToSpec{{NSSelector: map[string]string{"ns": "x"}}}, crdv1alpha1.RuleActionDrop, "", "", nil) + builder2.AddEgress(ProtocolTCP, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, + true, []ACNPAppliedToSpec{{NSSelector: map[string]string{"ns": namespaces["x"]}}}, crdv1alpha1.RuleActionAllow, "", "", nil) + builder2.AddEgress(ProtocolTCP, nil, nil, nil, nil, nil, nil, nil, map[string]string{}, nil, nil, + false, []ACNPAppliedToSpec{{NSSelector: map[string]string{"ns": namespaces["x"]}}}, crdv1alpha1.RuleActionDrop, "", "", nil) reachability2 := NewReachability(allPods, Connected) - reachability2.ExpectEgressToNamespace(Pod("x/a"), "y", Dropped) - reachability2.ExpectEgressToNamespace(Pod("x/a"), "z", Dropped) - reachability2.ExpectEgressToNamespace(Pod("x/b"), "y", Dropped) - reachability2.ExpectEgressToNamespace(Pod("x/b"), "z", Dropped) - reachability2.ExpectEgressToNamespace(Pod("x/c"), "y", Dropped) - reachability2.ExpectEgressToNamespace(Pod("x/c"), "z", Dropped) + reachability2.ExpectEgressToNamespace(Pod(namespaces["x"]+"/a"), namespaces["y"], Dropped) + reachability2.ExpectEgressToNamespace(Pod(namespaces["x"]+"/a"), namespaces["z"], Dropped) + reachability2.ExpectEgressToNamespace(Pod(namespaces["x"]+"/b"), namespaces["y"], Dropped) + reachability2.ExpectEgressToNamespace(Pod(namespaces["x"]+"/b"), namespaces["z"], Dropped) + reachability2.ExpectEgressToNamespace(Pod(namespaces["x"]+"/c"), namespaces["y"], Dropped) + reachability2.ExpectEgressToNamespace(Pod(namespaces["x"]+"/c"), namespaces["z"], Dropped) testStep2 := &TestStep{ "Port 80", reachability2, []metav1.Object{builder2.Get()}, []int32{80}, - v1.ProtocolTCP, + ProtocolTCP, 0, nil, } @@ -2303,9 +2424,9 @@ func testACNPStrictNamespacesIsolation(t *testing.T) { SetTier("securityops"). SetPriority(1.0). SetAppliedToGroup([]ACNPAppliedToSpec{{NSSelector: map[string]string{}}}) - builder.AddIngress(v1.ProtocolTCP, nil, nil, nil, nil, nil, nil, nil, nil, + builder.AddIngress(ProtocolTCP, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, true, nil, crdv1alpha1.RuleActionPass, "", "", nil) - builder.AddIngress(v1.ProtocolTCP, nil, nil, nil, nil, nil, map[string]string{}, nil, nil, + builder.AddIngress(ProtocolTCP, nil, nil, nil, nil, nil, nil, nil, map[string]string{}, nil, nil, false, nil, crdv1alpha1.RuleActionDrop, "", "", nil) // deny ingress traffic except from own namespace, which is delegated to Namespace owners (who can create K8s // NetworkPolicies to regulate intra-Namespace traffic) @@ -2316,25 +2437,25 @@ func testACNPStrictNamespacesIsolation(t *testing.T) { reachability, []metav1.Object{builder.Get()}, []int32{80}, - v1.ProtocolTCP, + ProtocolTCP, 0, nil, } // Add a K8s namespaced NetworkPolicy in ns x that isolates all Pods in that namespace. builder2 := &NetworkPolicySpecBuilder{} - builder2 = builder2.SetName("x", "default-deny-in-namespace-x") + builder2 = builder2.SetName(namespaces["x"], "default-deny-in-namespace-x") builder2.SetTypeIngress() reachability2 := NewReachability(allPods, Dropped) reachability2.ExpectAllSelfNamespace(Connected) - reachability2.ExpectSelfNamespace("x", Dropped) + reachability2.ExpectSelfNamespace(namespaces["x"], Dropped) reachability2.ExpectSelf(allPods, Connected) testStep2 := &TestStep{ "Namespace isolation with K8s NP, Port 80", reachability2, []metav1.Object{builder2.Get()}, []int32{80}, - v1.ProtocolTCP, + ProtocolTCP, 0, nil, } @@ -2357,30 +2478,30 @@ func testFQDNPolicy(t *testing.T) { SetTier("application"). SetPriority(1.0). SetAppliedToGroup([]ACNPAppliedToSpec{{NSSelector: map[string]string{}}}) - builder.AddFQDNRule("*google.com", v1.ProtocolTCP, nil, nil, nil, "r1", nil, crdv1alpha1.RuleActionReject) - builder.AddFQDNRule("wayfair.com", v1.ProtocolTCP, nil, nil, nil, "r2", nil, crdv1alpha1.RuleActionDrop) + builder.AddFQDNRule("*google.com", ProtocolTCP, nil, nil, nil, "r1", nil, crdv1alpha1.RuleActionReject) + builder.AddFQDNRule("wayfair.com", ProtocolTCP, nil, nil, nil, "r2", nil, crdv1alpha1.RuleActionDrop) testcases := []podToAddrTestStep{ { - "x/a", + Pod(namespaces["x"] + "/a"), "drive.google.com", 80, Rejected, }, { - "x/b", + Pod(namespaces["x"] + "/b"), "maps.google.com", 80, Rejected, }, { - "y/a", + Pod(namespaces["y"] + "/a"), "wayfair.com", 80, Dropped, }, { - "y/b", + Pod(namespaces["y"] + "/b"), "facebook.com", 80, Connected, @@ -2391,7 +2512,7 @@ func testFQDNPolicy(t *testing.T) { time.Sleep(networkPolicyDelay) for _, tc := range testcases { log.Tracef("Probing: %s -> %s", tc.clientPod.PodName(), tc.destAddr) - connectivity, err := k8sUtils.ProbeAddr(tc.clientPod.Namespace(), "pod", tc.clientPod.PodName(), tc.destAddr, tc.destPort, v1.ProtocolTCP) + connectivity, err := k8sUtils.ProbeAddr(tc.clientPod.Namespace(), "pod", tc.clientPod.PodName(), tc.destAddr, tc.destPort, ProtocolTCP) if err != nil { t.Errorf("failure -- could not complete probe: %v", err) } @@ -2421,13 +2542,13 @@ func testFQDNPolicyInClusterService(t *testing.T) { defer log.SetLevel(logLevel) var services []*v1.Service if clusterInfo.podV4NetworkCIDR != "" { - ipv4Svc := k8sUtils.BuildService("ipv4-svc", "x", 80, 80, map[string]string{"pod": "a"}, nil) + ipv4Svc := k8sUtils.BuildService("ipv4-svc", namespaces["x"], 80, 80, map[string]string{"pod": "a"}, nil) ipv4Svc.Spec.ClusterIP = "None" ipv4Svc.Spec.IPFamilies = []v1.IPFamily{v1.IPv4Protocol} services = append(services, ipv4Svc) } if clusterInfo.podV6NetworkCIDR != "" { - ipv6Svc := k8sUtils.BuildService("ipv6-svc", "x", 80, 80, map[string]string{"pod": "b"}, nil) + ipv6Svc := k8sUtils.BuildService("ipv6-svc", namespaces["x"], 80, 80, map[string]string{"pod": "b"}, nil) ipv6Svc.Spec.ClusterIP = "None" ipv6Svc.Spec.IPFamilies = []v1.IPFamily{v1.IPv6Protocol} services = append(services, ipv6Svc) @@ -2447,8 +2568,8 @@ func testFQDNPolicyInClusterService(t *testing.T) { SetTier("application"). SetPriority(1.0) for idx, service := range services { - builder.AddFQDNRule(svcDNSName(service), v1.ProtocolTCP, nil, nil, nil, fmt.Sprintf("r%d", idx*2), []ACNPAppliedToSpec{{NSSelector: map[string]string{"ns": "y"}, PodSelector: map[string]string{"pod": "b"}}}, crdv1alpha1.RuleActionReject) - builder.AddFQDNRule(svcDNSName(service), v1.ProtocolTCP, nil, nil, nil, fmt.Sprintf("r%d", idx*2+1), []ACNPAppliedToSpec{{NSSelector: map[string]string{"ns": "z"}, PodSelector: map[string]string{"pod": "c"}}}, crdv1alpha1.RuleActionDrop) + builder.AddFQDNRule(svcDNSName(service), ProtocolTCP, nil, nil, nil, fmt.Sprintf("r%d", idx*2), []ACNPAppliedToSpec{{NSSelector: map[string]string{"ns": namespaces["y"]}, PodSelector: map[string]string{"pod": "b"}}}, crdv1alpha1.RuleActionReject) + builder.AddFQDNRule(svcDNSName(service), ProtocolTCP, nil, nil, nil, fmt.Sprintf("r%d", idx*2+1), []ACNPAppliedToSpec{{NSSelector: map[string]string{"ns": namespaces["z"]}, PodSelector: map[string]string{"pod": "c"}}}, crdv1alpha1.RuleActionDrop) } acnp := builder.Get() k8sUtils.CreateOrUpdateACNP(acnp) @@ -2458,19 +2579,19 @@ func testFQDNPolicyInClusterService(t *testing.T) { for _, service := range services { eachServiceCases := []podToAddrTestStep{ { - "y/b", + Pod(namespaces["y"] + "/b"), svcDNSName(service), 80, Rejected, }, { - "z/c", + Pod(namespaces["z"] + "/c"), svcDNSName(service), 80, Dropped, }, { - "x/c", + Pod(namespaces["x"] + "/c"), svcDNSName(service), 80, Connected, @@ -2481,7 +2602,7 @@ func testFQDNPolicyInClusterService(t *testing.T) { for _, tc := range testcases { log.Tracef("Probing: %s -> %s", tc.clientPod.PodName(), tc.destAddr) - connectivity, err := k8sUtils.ProbeAddr(tc.clientPod.Namespace(), "pod", tc.clientPod.PodName(), tc.destAddr, tc.destPort, v1.ProtocolTCP) + connectivity, err := k8sUtils.ProbeAddr(tc.clientPod.Namespace(), "pod", tc.clientPod.PodName(), tc.destAddr, tc.destPort, ProtocolTCP) if err != nil { t.Errorf("failure -- could not complete probe: %v", err) } @@ -2504,12 +2625,12 @@ func testToServices(t *testing.T) { skipIfProxyDisabled(t) var services []*v1.Service if clusterInfo.podV4NetworkCIDR != "" { - ipv4Svc := k8sUtils.BuildService("ipv4-svc", "x", 81, 81, map[string]string{"pod": "a"}, nil) + ipv4Svc := k8sUtils.BuildService("ipv4-svc", namespaces["x"], 81, 81, map[string]string{"pod": "a"}, nil) ipv4Svc.Spec.IPFamilies = []v1.IPFamily{v1.IPv4Protocol} services = append(services, ipv4Svc) } if clusterInfo.podV6NetworkCIDR != "" { - ipv6Svc := k8sUtils.BuildService("ipv6-svc", "x", 80, 80, map[string]string{"pod": "b"}, nil) + ipv6Svc := k8sUtils.BuildService("ipv6-svc", namespaces["x"], 80, 80, map[string]string{"pod": "b"}, nil) ipv6Svc.Spec.IPFamilies = []v1.IPFamily{v1.IPv6Protocol} services = append(services, ipv6Svc) } @@ -2530,7 +2651,7 @@ func testToServices(t *testing.T) { builder = builder.SetName("test-acnp-to-services"). SetTier("application"). SetPriority(1.0) - builder.AddToServicesRule(svcRefs, "svc", []ACNPAppliedToSpec{{NSSelector: map[string]string{"ns": "y"}}}, crdv1alpha1.RuleActionDrop) + builder.AddToServicesRule(svcRefs, "svc", []ACNPAppliedToSpec{{NSSelector: map[string]string{"ns": namespaces["y"]}}}, crdv1alpha1.RuleActionDrop) time.Sleep(networkPolicyDelay) acnp := builder.Get() @@ -2541,13 +2662,13 @@ func testToServices(t *testing.T) { for _, service := range builtSvcs { eachServiceCases := []podToAddrTestStep{ { - "y/b", + Pod(namespaces["y"] + "/b"), service.Spec.ClusterIP, service.Spec.Ports[0].Port, Dropped, }, { - "z/c", + Pod(namespaces["z"] + "/c"), service.Spec.ClusterIP, service.Spec.Ports[0].Port, Connected, @@ -2558,7 +2679,7 @@ func testToServices(t *testing.T) { for _, tc := range testcases { log.Tracef("Probing: %s -> %s", tc.clientPod.PodName(), tc.destAddr) - connectivity, err := k8sUtils.ProbeAddr(tc.clientPod.Namespace(), "pod", tc.clientPod.PodName(), tc.destAddr, tc.destPort, v1.ProtocolTCP) + connectivity, err := k8sUtils.ProbeAddr(tc.clientPod.Namespace(), "pod", tc.clientPod.PodName(), tc.destAddr, tc.destPort, ProtocolTCP) if err != nil { t.Errorf("failure -- could not complete probe: %v", err) } @@ -2578,28 +2699,28 @@ func testToServices(t *testing.T) { } func testServiceAccountSelector(t *testing.T, data *TestData) { - k8sUtils.CreateOrUpdateServiceAccount(k8sUtils.BuildServiceAccount("test-sa", "x", nil)) - defer k8sUtils.DeleteServiceAccount("x", "test-sa") + k8sUtils.CreateOrUpdateServiceAccount(k8sUtils.BuildServiceAccount("test-sa", namespaces["x"], nil)) + defer k8sUtils.DeleteServiceAccount(namespaces["x"], "test-sa") - serverName, serverIP, cleanupFunc := createAndWaitForPod(t, data, data.createNginxPodOnNode, "server", controlPlaneNodeName(), testNamespace, false) + serverName, serverIP, cleanupFunc := createAndWaitForPod(t, data, data.createNginxPodOnNode, "server", controlPlaneNodeName(), data.testNamespace, false) defer cleanupFunc() - client0Name, _, cleanupFunc := createAndWaitForPodWithServiceAccount(t, data, data.createAgnhostPodWithSAOnNode, "client", controlPlaneNodeName(), "x", false, "test-sa") + client0Name, _, cleanupFunc := createAndWaitForPodWithServiceAccount(t, data, data.createAgnhostPodWithSAOnNode, "client", controlPlaneNodeName(), namespaces["x"], false, "test-sa") defer cleanupFunc() - client1Name, _, cleanupFunc := createAndWaitForPodWithServiceAccount(t, data, data.createAgnhostPodWithSAOnNode, "client", controlPlaneNodeName(), "x", false, "default") + client1Name, _, cleanupFunc := createAndWaitForPodWithServiceAccount(t, data, data.createAgnhostPodWithSAOnNode, "client", controlPlaneNodeName(), namespaces["x"], false, "default") defer cleanupFunc() sa := &crdv1alpha1.NamespacedName{ Name: "test-sa", - Namespace: "x", + Namespace: namespaces["x"], } builder := &ClusterNetworkPolicySpecBuilder{} builder = builder.SetName("acnp-service-account"). SetPriority(1.0). SetAppliedToGroup([]ACNPAppliedToSpec{{PodSelector: map[string]string{"antrea-e2e": serverName}}}) - builder.AddIngress(v1.ProtocolTCP, &p80, nil, nil, nil, nil, nil, + builder.AddIngress(ProtocolTCP, &p80, nil, nil, nil, nil, nil, nil, nil, nil, nil, false, nil, crdv1alpha1.RuleActionDrop, "", "", sa) acnp := builder.Get() @@ -2614,13 +2735,13 @@ func testServiceAccountSelector(t *testing.T, data *TestData) { if clusterInfo.podV4NetworkCIDR != "" { ipv4Testcases := []podToAddrTestStep{ { - Pod("x/" + client0Name), + Pod(namespaces["x"] + "/" + client0Name), serverIP.ipv4.String(), 80, Dropped, }, { - Pod("x/" + client1Name), + Pod(namespaces["x"] + "/" + client1Name), serverIP.ipv4.String(), 80, Connected, @@ -2632,13 +2753,13 @@ func testServiceAccountSelector(t *testing.T, data *TestData) { if clusterInfo.podV6NetworkCIDR != "" { ipv6Testcases := []podToAddrTestStep{ { - Pod("x/" + client0Name), + Pod(namespaces["x"] + "/" + client0Name), serverIP.ipv6.String(), 80, Dropped, }, { - Pod("x/" + client1Name), + Pod(namespaces["x"] + "/" + client1Name), serverIP.ipv6.String(), 80, Connected, @@ -2649,7 +2770,7 @@ func testServiceAccountSelector(t *testing.T, data *TestData) { for _, tc := range testcases { log.Tracef("Probing: %s -> %s:%d", tc.clientPod.PodName(), tc.destAddr, tc.destPort) - connectivity, err := k8sUtils.ProbeAddr(tc.clientPod.Namespace(), "antrea-e2e", tc.clientPod.PodName(), tc.destAddr, tc.destPort, v1.ProtocolTCP) + connectivity, err := k8sUtils.ProbeAddr(tc.clientPod.Namespace(), "antrea-e2e", tc.clientPod.PodName(), tc.destAddr, tc.destPort, ProtocolTCP) if err != nil { t.Errorf("failure -- could not complete probe: %v", err) } @@ -2668,21 +2789,21 @@ func testACNPNodeSelectorEgress(t *testing.T) { builder = builder.SetName("test-acnp-drop-egress-control-plane"). SetPriority(1.0) nodeSelector := metav1.LabelSelector{MatchLabels: map[string]string{"kubernetes.io/hostname": controlPlaneNodeName()}} - builder.AddNodeSelectorRule(&nodeSelector, v1.ProtocolTCP, &p6443, "egress-control-plane-drop", - []ACNPAppliedToSpec{{NSSelector: map[string]string{"ns": "x"}, PodSelector: map[string]string{"pod": "a"}}}, + builder.AddNodeSelectorRule(&nodeSelector, ProtocolTCP, &p6443, "egress-control-plane-drop", + []ACNPAppliedToSpec{{NSSelector: map[string]string{"ns": namespaces["x"]}, PodSelector: map[string]string{"pod": "a"}}}, crdv1alpha1.RuleActionDrop, true) var testcases []podToAddrTestStep if clusterInfo.podV4NetworkCIDR != "" { ipv4Testcases := []podToAddrTestStep{ { - "x/a", + Pod(namespaces["x"] + "/a"), controlPlaneNodeIPv4(), 6443, Dropped, }, { - "x/b", + Pod(namespaces["x"] + "/b"), controlPlaneNodeIPv4(), 6443, Connected, @@ -2694,13 +2815,13 @@ func testACNPNodeSelectorEgress(t *testing.T) { if clusterInfo.podV6NetworkCIDR != "" { ipv6Testcases := []podToAddrTestStep{ { - "x/a", + Pod(namespaces["x"] + "/a"), controlPlaneNodeIPv6(), 6443, Dropped, }, { - "x/b", + Pod(namespaces["x"] + "/b"), controlPlaneNodeIPv6(), 6443, Connected, @@ -2713,7 +2834,7 @@ func testACNPNodeSelectorEgress(t *testing.T) { time.Sleep(networkPolicyDelay) for _, tc := range testcases { log.Tracef("Probing: %s -> %s", tc.clientPod.PodName(), tc.destAddr) - connectivity, err := k8sUtils.ProbeAddr(tc.clientPod.Namespace(), "pod", tc.clientPod.PodName(), tc.destAddr, tc.destPort, v1.ProtocolTCP) + connectivity, err := k8sUtils.ProbeAddr(tc.clientPod.Namespace(), "pod", tc.clientPod.PodName(), tc.destAddr, tc.destPort, ProtocolTCP) if err != nil { t.Errorf("failure -- could not complete probe: %v", err) } @@ -2729,37 +2850,37 @@ func testACNPNodeSelectorEgress(t *testing.T) { } func testACNPNodeSelectorIngress(t *testing.T, data *TestData) { - _, serverIP0, cleanupFunc := createAndWaitForPod(t, data, data.createNginxPodOnNode, "server0", nodeName(1), "x", false) + _, serverIP0, cleanupFunc := createAndWaitForPod(t, data, data.createNginxPodOnNode, "server0", nodeName(1), namespaces["x"], false) defer cleanupFunc() - _, serverIP1, cleanupFunc := createAndWaitForPod(t, data, data.createNginxPodOnNode, "server1", nodeName(1), "y", false) + _, serverIP1, cleanupFunc := createAndWaitForPod(t, data, data.createNginxPodOnNode, "server1", nodeName(1), namespaces["y"], false) defer cleanupFunc() clientName := "agnhost-client" - require.NoError(t, data.createAgnhostPodOnNode(clientName, "z", controlPlaneNodeName(), true)) - defer data.deletePodAndWait(defaultTimeout, clientName, "z") - _, err := data.podWaitForIPs(defaultTimeout, clientName, "z") + require.NoError(t, data.createAgnhostPodOnNode(clientName, namespaces["z"], controlPlaneNodeName(), true)) + defer data.deletePodAndWait(defaultTimeout, clientName, namespaces["z"]) + _, err := data.podWaitForIPs(defaultTimeout, clientName, namespaces["z"]) require.NoError(t, err) builder := &ClusterNetworkPolicySpecBuilder{} builder = builder.SetName("test-acnp-drop-ingress-from-control-plane"). SetPriority(1.0) nodeSelector := metav1.LabelSelector{MatchLabels: map[string]string{"kubernetes.io/hostname": controlPlaneNodeName()}} - builder.AddNodeSelectorRule(&nodeSelector, v1.ProtocolTCP, &p80, "ingress-control-plane-drop", - []ACNPAppliedToSpec{{NSSelector: map[string]string{"ns": "x"}}}, + builder.AddNodeSelectorRule(&nodeSelector, ProtocolTCP, &p80, "ingress-control-plane-drop", + []ACNPAppliedToSpec{{NSSelector: map[string]string{"ns": namespaces["x"]}}}, crdv1alpha1.RuleActionDrop, false) testcases := []podToAddrTestStep{} if clusterInfo.podV4NetworkCIDR != "" { ipv4TestCases := []podToAddrTestStep{ { - Pod("z/" + clientName), + Pod(namespaces["z"] + "/" + clientName), serverIP0.ipv4.String(), 80, Dropped, }, { - Pod("z/" + clientName), + Pod(namespaces["z"] + "/" + clientName), serverIP1.ipv4.String(), 80, Connected, @@ -2770,13 +2891,13 @@ func testACNPNodeSelectorIngress(t *testing.T, data *TestData) { if clusterInfo.podV6NetworkCIDR != "" { ipv6TestCases := []podToAddrTestStep{ { - Pod("z/" + clientName), + Pod(namespaces["z"] + "/" + clientName), serverIP0.ipv6.String(), 80, Dropped, }, { - Pod("z/" + clientName), + Pod(namespaces["z"] + "/" + clientName), serverIP1.ipv6.String(), 80, Connected, @@ -2790,7 +2911,81 @@ func testACNPNodeSelectorIngress(t *testing.T, data *TestData) { time.Sleep(networkPolicyDelay) for _, tc := range testcases { log.Tracef("Probing: %s -> %s", tc.clientPod.PodName(), tc.destAddr) - connectivity, err := k8sUtils.ProbeAddr(tc.clientPod.Namespace(), "antrea-e2e", tc.clientPod.PodName(), tc.destAddr, tc.destPort, v1.ProtocolTCP) + connectivity, err := k8sUtils.ProbeAddr(tc.clientPod.Namespace(), "antrea-e2e", tc.clientPod.PodName(), tc.destAddr, tc.destPort, ProtocolTCP) + if err != nil { + t.Errorf("failure -- could not complete probe: %v", err) + } + if connectivity != tc.expectedConnectivity { + t.Errorf("failure -- wrong results for probe: Source %s/%s --> Dest %s:%d connectivity: %v, expected: %v", + tc.clientPod.Namespace(), tc.clientPod.PodName(), tc.destAddr, tc.destPort, connectivity, tc.expectedConnectivity) + } + } + // cleanup test resources + failOnError(k8sUtils.DeleteACNP(builder.Name), t) + failOnError(waitForResourceDelete("", builder.Name, resourceACNP, timeout), t) + time.Sleep(networkPolicyDelay) +} + +func testACNPICMPSupport(t *testing.T, data *TestData) { + clientName, _, cleanupFunc := createAndWaitForPod(t, data, data.createNetshootPodOnNode, "client", nodeName(1), data.testNamespace, false) + defer cleanupFunc() + + server0Name, server0IP, cleanupFunc := createAndWaitForPod(t, data, data.createNginxPodOnNode, "server0", nodeName(0), data.testNamespace, false) + defer cleanupFunc() + + server1Name, server1IP, cleanupFunc := createAndWaitForPod(t, data, data.createNginxPodOnNode, "server1", nodeName(1), data.testNamespace, false) + defer cleanupFunc() + + icmpType := int32(8) + icmpCode := int32(0) + builder := &ClusterNetworkPolicySpecBuilder{} + builder = builder.SetName("test-acnp-icmp"). + SetPriority(1.0).SetAppliedToGroup([]ACNPAppliedToSpec{{PodSelector: map[string]string{"antrea-e2e": clientName}}}) + builder.AddEgress(ProtocolICMP, nil, nil, nil, &icmpType, &icmpCode, nil, map[string]string{"antrea-e2e": server0Name}, nil, + nil, nil, false, nil, crdv1alpha1.RuleActionReject, "", "", nil) + builder.AddEgress(ProtocolICMP, nil, nil, nil, nil, nil, nil, map[string]string{"antrea-e2e": server1Name}, nil, + nil, nil, false, nil, crdv1alpha1.RuleActionDrop, "", "", nil) + + testcases := []podToAddrTestStep{} + if clusterInfo.podV4NetworkCIDR != "" { + testcases = append(testcases, []podToAddrTestStep{ + { + Pod(fmt.Sprintf("%s/%s", data.testNamespace, clientName)), + server0IP.ipv4.String(), + -1, + Rejected, + }, + { + Pod(fmt.Sprintf("%s/%s", data.testNamespace, clientName)), + server1IP.ipv4.String(), + -1, + Dropped, + }, + }...) + } + if clusterInfo.podV6NetworkCIDR != "" { + testcases = append(testcases, []podToAddrTestStep{ + { + Pod(fmt.Sprintf("%s/%s", data.testNamespace, clientName)), + server0IP.ipv6.String(), + -1, + Rejected, + }, + { + Pod(fmt.Sprintf("%s/%s", data.testNamespace, clientName)), + server1IP.ipv6.String(), + -1, + Dropped, + }, + }...) + } + + _, err := k8sUtils.CreateOrUpdateACNP(builder.Get()) + failOnError(err, t) + time.Sleep(networkPolicyDelay) + for _, tc := range testcases { + log.Tracef("Probing: %s -> %s", tc.clientPod.PodName(), tc.destAddr) + connectivity, err := k8sUtils.ProbeAddr(tc.clientPod.Namespace(), "antrea-e2e", tc.clientPod.PodName(), tc.destAddr, tc.destPort, ProtocolICMP) if err != nil { t.Errorf("failure -- could not complete probe: %v", err) } @@ -2845,7 +3040,7 @@ func executeTestsWithData(t *testing.T, testList []*TestCase, data *TestData) { allTestList = append(allTestList, testList...) } -func doProbe(t *testing.T, data *TestData, p *CustomProbe, protocol v1.Protocol) { +func doProbe(t *testing.T, data *TestData, p *CustomProbe, protocol AntreaPolicyProtocol) { // Bootstrap Pods _, _, srcPodCleanupFunc := createAndWaitForPodWithLabels(t, data, data.createServerPodWithLabels, p.SourcePod.Pod.PodName(), p.SourcePod.Pod.Namespace(), p.Port, p.SourcePod.Labels) defer srcPodCleanupFunc() @@ -3064,7 +3259,7 @@ func TestAntreaPolicy(t *testing.T) { t.Run("Case=ANPTierDoesNotExistDenied", func(t *testing.T) { testInvalidANPTierDoesNotExist(t) }) t.Run("Case=ANPPortRangePortUnsetDenied", func(t *testing.T) { testInvalidANPPortRangePortUnset(t) }) t.Run("Case=ANPPortRangePortEndPortSmallDenied", func(t *testing.T) { testInvalidANPPortRangeEndPortSmall(t) }) - t.Run("Case=ACNPInvalidPodSelectorNsSelectorMatchExpressions", func(t *testing.T) { testInvalidACNPPodSelectorNsSelectorMatchExpressions(t) }) + t.Run("Case=ACNPInvalidPodSelectorNsSelectorMatchExpressions", func(t *testing.T) { testInvalidACNPPodSelectorNsSelectorMatchExpressions(t, data) }) }) t.Run("TestGroupValidateTiers", func(t *testing.T) { @@ -3094,18 +3289,19 @@ func TestAntreaPolicy(t *testing.T) { t.Run("TestGroupNoK8sNP", func(t *testing.T) { // testcases below do not depend on underlying default-deny K8s NetworkPolicies. - t.Run("Case=ACNPAllowNoDefaultIsolationTCP", func(t *testing.T) { testACNPAllowNoDefaultIsolation(t, v1.ProtocolTCP) }) - t.Run("Case=ACNPAllowNoDefaultIsolationUDP", func(t *testing.T) { testACNPAllowNoDefaultIsolation(t, v1.ProtocolUDP) }) - t.Run("Case=ACNPAllowNoDefaultIsolationSCTP", func(t *testing.T) { testACNPAllowNoDefaultIsolation(t, v1.ProtocolSCTP) }) - t.Run("Case=ACNPDropEgress", func(t *testing.T) { testACNPDropEgress(t, v1.ProtocolTCP) }) - t.Run("Case=ACNPDropEgressUDP", func(t *testing.T) { testACNPDropEgress(t, v1.ProtocolUDP) }) - t.Run("Case=ACNPDropEgressSCTP", func(t *testing.T) { testACNPDropEgress(t, v1.ProtocolSCTP) }) + t.Run("Case=ACNPAllowNoDefaultIsolationTCP", func(t *testing.T) { testACNPAllowNoDefaultIsolation(t, ProtocolTCP) }) + t.Run("Case=ACNPAllowNoDefaultIsolationUDP", func(t *testing.T) { testACNPAllowNoDefaultIsolation(t, ProtocolUDP) }) + t.Run("Case=ACNPAllowNoDefaultIsolationSCTP", func(t *testing.T) { testACNPAllowNoDefaultIsolation(t, ProtocolSCTP) }) + t.Run("Case=ACNPDropEgress", func(t *testing.T) { testACNPDropEgress(t, ProtocolTCP) }) + t.Run("Case=ACNPDropEgressUDP", func(t *testing.T) { testACNPDropEgress(t, ProtocolUDP) }) + t.Run("Case=ACNPDropEgressSCTP", func(t *testing.T) { testACNPDropEgress(t, ProtocolSCTP) }) t.Run("Case=ACNPDropIngressInNamespace", func(t *testing.T) { testACNPDropIngressInSelectedNamespace(t) }) t.Run("Case=ACNPPortRange", func(t *testing.T) { testACNPPortRange(t) }) t.Run("Case=ACNPRejectEgress", func(t *testing.T) { testACNPRejectEgress(t) }) - t.Run("Case=ACNPRejectIngress", func(t *testing.T) { testACNPRejectIngress(t, v1.ProtocolTCP) }) - t.Run("Case=ACNPRejectIngressUDP", func(t *testing.T) { testACNPRejectIngress(t, v1.ProtocolUDP) }) + t.Run("Case=ACNPRejectIngress", func(t *testing.T) { testACNPRejectIngress(t, ProtocolTCP) }) + t.Run("Case=ACNPRejectIngressUDP", func(t *testing.T) { testACNPRejectIngress(t, ProtocolUDP) }) t.Run("Case=RejectServiceTraffic", func(t *testing.T) { testRejectServiceTraffic(t, data) }) + t.Run("Case=RejectNoInfiniteLoop", func(t *testing.T) { testRejectNoInfiniteLoop(t, data) }) t.Run("Case=ACNPNoEffectOnOtherProtocols", func(t *testing.T) { testACNPNoEffectOnOtherProtocols(t) }) t.Run("Case=ACNPBaselinePolicy", func(t *testing.T) { testBaselineNamespaceIsolation(t) }) t.Run("Case=ACNPPriorityOverride", func(t *testing.T) { testACNPPriorityOverride(t) }) @@ -3138,6 +3334,7 @@ func TestAntreaPolicy(t *testing.T) { t.Run("Case=ACNPServiceAccountSelector", func(t *testing.T) { testServiceAccountSelector(t, data) }) t.Run("Case=ACNPNodeSelectorEgress", func(t *testing.T) { testACNPNodeSelectorEgress(t) }) t.Run("Case=ACNPNodeSelectorIngress", func(t *testing.T) { testACNPNodeSelectorIngress(t, data) }) + t.Run("Case=ACNPICMPSupport", func(t *testing.T) { testACNPICMPSupport(t, data) }) }) // print results for reachability tests printResults() @@ -3158,16 +3355,16 @@ func TestAntreaPolicyStatus(t *testing.T) { } defer teardownTest(t, data) - _, _, cleanupFunc := createAndWaitForPod(t, data, data.createNginxPodOnNode, "server-0", controlPlaneNodeName(), testNamespace, false) + _, _, cleanupFunc := createAndWaitForPod(t, data, data.createNginxPodOnNode, "server-0", controlPlaneNodeName(), data.testNamespace, false) defer cleanupFunc() - _, _, cleanupFunc = createAndWaitForPod(t, data, data.createNginxPodOnNode, "server-1", workerNodeName(1), testNamespace, false) + _, _, cleanupFunc = createAndWaitForPod(t, data, data.createNginxPodOnNode, "server-1", workerNodeName(1), data.testNamespace, false) defer cleanupFunc() anpBuilder := &AntreaNetworkPolicySpecBuilder{} - anpBuilder = anpBuilder.SetName(testNamespace, "anp-applied-to-two-nodes"). + anpBuilder = anpBuilder.SetName(data.testNamespace, "anp-applied-to-two-nodes"). SetPriority(1.0). SetAppliedToGroup([]ANPAppliedToSpec{{PodSelector: map[string]string{"app": "nginx"}}}) - anpBuilder.AddIngress(v1.ProtocolTCP, &p80, nil, nil, nil, map[string]string{"pod": "b"}, map[string]string{"ns": "x"}, + anpBuilder.AddIngress(ProtocolTCP, &p80, nil, nil, nil, nil, nil, map[string]string{"pod": "b"}, map[string]string{"ns": namespaces["x"]}, nil, nil, nil, crdv1alpha1.RuleActionAllow, "") anp := anpBuilder.Get() log.Debugf("creating ANP %v", anp.Name) @@ -3179,7 +3376,7 @@ func TestAntreaPolicyStatus(t *testing.T) { acnpBuilder = acnpBuilder.SetName("acnp-applied-to-two-nodes"). SetPriority(1.0). SetAppliedToGroup([]ACNPAppliedToSpec{{PodSelector: map[string]string{"app": "nginx"}}}) - acnpBuilder.AddIngress(v1.ProtocolTCP, &p80, nil, nil, nil, map[string]string{"pod": "b"}, map[string]string{"ns": "x"}, + acnpBuilder.AddIngress(ProtocolTCP, &p80, nil, nil, nil, nil, nil, map[string]string{"pod": "b"}, map[string]string{"ns": namespaces["x"]}, nil, nil, false, nil, crdv1alpha1.RuleActionAllow, "", "", nil) acnp := acnpBuilder.Get() log.Debugf("creating ACNP %v", acnp.Name) @@ -3207,17 +3404,17 @@ func TestAntreaPolicyStatusWithAppliedToPerRule(t *testing.T) { } defer teardownTest(t, data) - server0Name, _, cleanupFunc := createAndWaitForPod(t, data, data.createNginxPodOnNode, "server-0", controlPlaneNodeName(), testNamespace, false) + server0Name, _, cleanupFunc := createAndWaitForPod(t, data, data.createNginxPodOnNode, "server-0", controlPlaneNodeName(), data.testNamespace, false) defer cleanupFunc() - server1Name, _, cleanupFunc := createAndWaitForPod(t, data, data.createNginxPodOnNode, "server-1", workerNodeName(1), testNamespace, false) + server1Name, _, cleanupFunc := createAndWaitForPod(t, data, data.createNginxPodOnNode, "server-1", workerNodeName(1), data.testNamespace, false) defer cleanupFunc() anpBuilder := &AntreaNetworkPolicySpecBuilder{} - anpBuilder = anpBuilder.SetName(testNamespace, "anp-applied-to-per-rule"). + anpBuilder = anpBuilder.SetName(data.testNamespace, "anp-applied-to-per-rule"). SetPriority(1.0) - anpBuilder.AddIngress(v1.ProtocolTCP, &p80, nil, nil, nil, map[string]string{"pod": "b"}, map[string]string{"ns": "x"}, + anpBuilder.AddIngress(ProtocolTCP, &p80, nil, nil, nil, nil, nil, map[string]string{"pod": "b"}, map[string]string{"ns": namespaces["x"]}, nil, nil, []ANPAppliedToSpec{{PodSelector: map[string]string{"antrea-e2e": server0Name}}}, crdv1alpha1.RuleActionAllow, "") - anpBuilder.AddIngress(v1.ProtocolTCP, &p80, nil, nil, nil, map[string]string{"pod": "b"}, map[string]string{"ns": "x"}, + anpBuilder.AddIngress(ProtocolTCP, &p80, nil, nil, nil, nil, nil, map[string]string{"pod": "b"}, map[string]string{"ns": namespaces["x"]}, nil, nil, []ANPAppliedToSpec{{PodSelector: map[string]string{"antrea-e2e": server1Name}}}, crdv1alpha1.RuleActionAllow, "") anp := anpBuilder.Get() log.Debugf("creating ANP %v", anp.Name) @@ -3307,10 +3504,10 @@ func (data *TestData) waitForACNPRealized(t *testing.T, name string) error { // testANPNetworkPolicyStatsWithDropAction tests antreanetworkpolicystats can correctly collect dropped packets stats from ANP if // networkpolicystats feature is enabled func testANPNetworkPolicyStatsWithDropAction(t *testing.T, data *TestData) { - serverName, serverIPs, cleanupFunc := createAndWaitForPod(t, data, data.createNginxPodOnNode, "test-server-", "", testNamespace, false) + serverName, serverIPs, cleanupFunc := createAndWaitForPod(t, data, data.createNginxPodOnNode, "test-server-", "", data.testNamespace, false) defer cleanupFunc() - clientName, _, cleanupFunc := createAndWaitForPod(t, data, data.createBusyboxPodOnNode, "test-client-", "", testNamespace, false) + clientName, _, cleanupFunc := createAndWaitForPod(t, data, data.createBusyboxPodOnNode, "test-client-", "", data.testNamespace, false) defer cleanupFunc() var err error k8sUtils, err = NewKubernetesUtils(data) @@ -3322,21 +3519,21 @@ func testANPNetworkPolicyStatsWithDropAction(t *testing.T, data *TestData) { allowAction := crdv1alpha1.RuleActionAllow selectorB := metav1.LabelSelector{MatchLabels: map[string]string{"antrea-e2e": clientName}} selectorC := metav1.LabelSelector{MatchLabels: map[string]string{"antrea-e2e": serverName}} - protocol := v1.ProtocolUDP + protocol, _ := AntreaPolicyProtocolToK8sProtocol(ProtocolUDP) // When using the userspace OVS datapath and tunneling, // the first IP packet sent on a tunnel is always dropped because of a missing ARP entry. // So we need to "warm-up" the tunnel. if clusterInfo.podV4NetworkCIDR != "" { cmd := []string{"/bin/sh", "-c", fmt.Sprintf("nc -vz -w 4 %s 80", serverIPs.ipv4.String())} - data.RunCommandFromPod(testNamespace, clientName, busyboxContainerName, cmd) + data.RunCommandFromPod(data.testNamespace, clientName, busyboxContainerName, cmd) } if clusterInfo.podV6NetworkCIDR != "" { cmd := []string{"/bin/sh", "-c", fmt.Sprintf("nc -vz -w 4 %s 80", serverIPs.ipv6.String())} - data.RunCommandFromPod(testNamespace, clientName, busyboxContainerName, cmd) + data.RunCommandFromPod(data.testNamespace, clientName, busyboxContainerName, cmd) } var anp = &crdv1alpha1.NetworkPolicy{ - ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: "np1", Labels: map[string]string{"antrea-e2e": "np1"}}, + ObjectMeta: metav1.ObjectMeta{Namespace: data.testNamespace, Name: "np1", Labels: map[string]string{"antrea-e2e": "np1"}}, Spec: crdv1alpha1.NetworkPolicySpec{ AppliedTo: []crdv1alpha1.NetworkPolicyPeer{ {PodSelector: &selectorC}, @@ -3391,14 +3588,14 @@ func testANPNetworkPolicyStatsWithDropAction(t *testing.T, data *TestData) { if clusterInfo.podV4NetworkCIDR != "" { cmd := []string{"/bin/sh", "-c", fmt.Sprintf("echo test | nc -w 4 -u %s 80", serverIPs.ipv4.String())} cmd2 := []string{"/bin/sh", "-c", fmt.Sprintf("echo test | nc -w 4 -u %s 443", serverIPs.ipv4.String())} - data.RunCommandFromPod(testNamespace, clientName, busyboxContainerName, cmd) - data.RunCommandFromPod(testNamespace, clientName, busyboxContainerName, cmd2) + data.RunCommandFromPod(data.testNamespace, clientName, busyboxContainerName, cmd) + data.RunCommandFromPod(data.testNamespace, clientName, busyboxContainerName, cmd2) } if clusterInfo.podV6NetworkCIDR != "" { cmd := []string{"/bin/sh", "-c", fmt.Sprintf("echo test | nc -w 4 -u %s 80", serverIPs.ipv6.String())} cmd2 := []string{"/bin/sh", "-c", fmt.Sprintf("echo test | nc -w 4 -u %s 443", serverIPs.ipv6.String())} - data.RunCommandFromPod(testNamespace, clientName, busyboxContainerName, cmd) - data.RunCommandFromPod(testNamespace, clientName, busyboxContainerName, cmd2) + data.RunCommandFromPod(data.testNamespace, clientName, busyboxContainerName, cmd) + data.RunCommandFromPod(data.testNamespace, clientName, busyboxContainerName, cmd2) } wg.Done() }() @@ -3414,7 +3611,7 @@ func testANPNetworkPolicyStatsWithDropAction(t *testing.T, data *TestData) { } if err := wait.Poll(5*time.Second, defaultTimeout, func() (bool, error) { - stats, err := data.crdClient.StatsV1alpha1().AntreaNetworkPolicyStats(testNamespace).Get(context.TODO(), "np1", metav1.GetOptions{}) + stats, err := data.crdClient.StatsV1alpha1().AntreaNetworkPolicyStats(data.testNamespace).Get(context.TODO(), "np1", metav1.GetOptions{}) if err != nil { return false, err } @@ -3442,10 +3639,10 @@ func testANPNetworkPolicyStatsWithDropAction(t *testing.T, data *TestData) { } func testAntreaClusterNetworkPolicyStats(t *testing.T, data *TestData) { - serverName, serverIPs, cleanupFunc := createAndWaitForPod(t, data, data.createNginxPodOnNode, "test-server-", "", testNamespace, false) + serverName, serverIPs, cleanupFunc := createAndWaitForPod(t, data, data.createNginxPodOnNode, "test-server-", "", data.testNamespace, false) defer cleanupFunc() - clientName, _, cleanupFunc := createAndWaitForPod(t, data, data.createBusyboxPodOnNode, "test-client-", "", testNamespace, false) + clientName, _, cleanupFunc := createAndWaitForPod(t, data, data.createBusyboxPodOnNode, "test-client-", "", data.testNamespace, false) defer cleanupFunc() var err error k8sUtils, err = NewKubernetesUtils(data) @@ -3457,21 +3654,21 @@ func testAntreaClusterNetworkPolicyStats(t *testing.T, data *TestData) { allowAction := crdv1alpha1.RuleActionAllow selectorB := metav1.LabelSelector{MatchLabels: map[string]string{"antrea-e2e": clientName}} selectorC := metav1.LabelSelector{MatchLabels: map[string]string{"antrea-e2e": serverName}} - protocol := v1.ProtocolUDP + protocol, _ := AntreaPolicyProtocolToK8sProtocol(ProtocolUDP) // When using the userspace OVS datapath and tunneling, // the first IP packet sent on a tunnel is always dropped because of a missing ARP entry. // So we need to "warm-up" the tunnel. if clusterInfo.podV4NetworkCIDR != "" { cmd := []string{"/bin/sh", "-c", fmt.Sprintf("nc -vz -w 4 %s 80", serverIPs.ipv4.String())} - data.RunCommandFromPod(testNamespace, clientName, busyboxContainerName, cmd) + data.RunCommandFromPod(data.testNamespace, clientName, busyboxContainerName, cmd) } if clusterInfo.podV6NetworkCIDR != "" { cmd := []string{"/bin/sh", "-c", fmt.Sprintf("nc -vz -w 4 %s 80", serverIPs.ipv6.String())} - data.RunCommandFromPod(testNamespace, clientName, busyboxContainerName, cmd) + data.RunCommandFromPod(data.testNamespace, clientName, busyboxContainerName, cmd) } var acnp = &crdv1alpha1.ClusterNetworkPolicy{ - ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: "cnp1", Labels: map[string]string{"antrea-e2e": "cnp1"}}, + ObjectMeta: metav1.ObjectMeta{Namespace: data.testNamespace, Name: "cnp1", Labels: map[string]string{"antrea-e2e": "cnp1"}}, Spec: crdv1alpha1.ClusterNetworkPolicySpec{ AppliedTo: []crdv1alpha1.NetworkPolicyPeer{ {PodSelector: &selectorC}, @@ -3526,14 +3723,14 @@ func testAntreaClusterNetworkPolicyStats(t *testing.T, data *TestData) { if clusterInfo.podV4NetworkCIDR != "" { cmd := []string{"/bin/sh", "-c", fmt.Sprintf("echo test | nc -w 4 -u %s 800", serverIPs.ipv4.String())} cmd2 := []string{"/bin/sh", "-c", fmt.Sprintf("echo test | nc -w 4 -u %s 4430", serverIPs.ipv4.String())} - data.RunCommandFromPod(testNamespace, clientName, busyboxContainerName, cmd) - data.RunCommandFromPod(testNamespace, clientName, busyboxContainerName, cmd2) + data.RunCommandFromPod(data.testNamespace, clientName, busyboxContainerName, cmd) + data.RunCommandFromPod(data.testNamespace, clientName, busyboxContainerName, cmd2) } if clusterInfo.podV6NetworkCIDR != "" { cmd := []string{"/bin/sh", "-c", fmt.Sprintf("echo test | nc -w 4 -u %s 800", serverIPs.ipv6.String())} cmd2 := []string{"/bin/sh", "-c", fmt.Sprintf("echo test | nc -w 4 -u %s 4430", serverIPs.ipv6.String())} - data.RunCommandFromPod(testNamespace, clientName, busyboxContainerName, cmd) - data.RunCommandFromPod(testNamespace, clientName, busyboxContainerName, cmd2) + data.RunCommandFromPod(data.testNamespace, clientName, busyboxContainerName, cmd) + data.RunCommandFromPod(data.testNamespace, clientName, busyboxContainerName, cmd2) } wg.Done() }() diff --git a/test/e2e/bandwidth_test.go b/test/e2e/bandwidth_test.go index 9ea79dd4704..a48aa867caa 100644 --- a/test/e2e/bandwidth_test.go +++ b/test/e2e/bandwidth_test.go @@ -46,6 +46,7 @@ func TestBandwidth(t *testing.T) { func TestBenchmarkBandwidth(t *testing.T) { skipIfNotBenchmarkTest(t) skipIfHasWindowsNodes(t) + data, err := setupTest(t) if err != nil { t.Fatalf("Error when setting up test: %v", err) @@ -68,21 +69,21 @@ func TestBenchmarkBandwidth(t *testing.T) { // testBenchmarkBandwidthIntraNode runs the bandwidth benchmark between Pods on same node. func testBenchmarkBandwidthIntraNode(t *testing.T, data *TestData) { - if err := data.createPodOnNode("perftest-a", testNamespace, controlPlaneNodeName(), perftoolImage, nil, nil, nil, nil, false, nil); err != nil { + if err := data.createPodOnNode("perftest-a", data.testNamespace, controlPlaneNodeName(), perftoolImage, nil, nil, nil, nil, false, nil); err != nil { t.Fatalf("Error when creating the perftest client Pod: %v", err) } - if err := data.podWaitForRunning(defaultTimeout, "perftest-a", testNamespace); err != nil { + if err := data.podWaitForRunning(defaultTimeout, "perftest-a", data.testNamespace); err != nil { t.Fatalf("Error when waiting for the perftest client Pod: %v", err) } - if err := data.createPodOnNode("perftest-b", testNamespace, controlPlaneNodeName(), perftoolImage, nil, nil, nil, []v1.ContainerPort{{Protocol: v1.ProtocolTCP, ContainerPort: iperfPort}}, false, nil); err != nil { + if err := data.createPodOnNode("perftest-b", data.testNamespace, controlPlaneNodeName(), perftoolImage, nil, nil, nil, []v1.ContainerPort{{Protocol: v1.ProtocolTCP, ContainerPort: iperfPort}}, false, nil); err != nil { t.Fatalf("Error when creating the perftest server Pod: %v", err) } - podBIPs, err := data.podWaitForIPs(defaultTimeout, "perftest-b", testNamespace) + podBIPs, err := data.podWaitForIPs(defaultTimeout, "perftest-b", data.testNamespace) if err != nil { t.Fatalf("Error when getting the perftest server Pod's IP: %v", err) } podBIP := podBIPs.ipv4.String() - stdout, _, err := data.RunCommandFromPod(testNamespace, "perftest-a", "perftool", []string{"bash", "-c", fmt.Sprintf("iperf3 -c %s|grep sender|awk '{print $7,$8}'", podBIP)}) + stdout, _, err := data.RunCommandFromPod(data.testNamespace, "perftest-a", "perftool", []string{"bash", "-c", fmt.Sprintf("iperf3 -c %s|grep sender|awk '{print $7,$8}'", podBIP)}) if err != nil { t.Fatalf("Error when running iperf3 client: %v", err) } @@ -91,23 +92,23 @@ func testBenchmarkBandwidthIntraNode(t *testing.T, data *TestData) { } func benchmarkBandwidthService(t *testing.T, endpointNode, clientNode string, data *TestData) { - svc, err := data.CreateService("perftest-b", testNamespace, iperfPort, iperfPort, map[string]string{"antrea-e2e": "perftest-b"}, false, false, v1.ServiceTypeClusterIP, nil) + svc, err := data.CreateService("perftest-b", data.testNamespace, iperfPort, iperfPort, map[string]string{"antrea-e2e": "perftest-b"}, false, false, v1.ServiceTypeClusterIP, nil) if err != nil { t.Fatalf("Error when creating perftest service: %v", err) } - if err := data.createPodOnNode("perftest-a", testNamespace, clientNode, perftoolImage, nil, nil, nil, nil, false, nil); err != nil { + if err := data.createPodOnNode("perftest-a", data.testNamespace, clientNode, perftoolImage, nil, nil, nil, nil, false, nil); err != nil { t.Fatalf("Error when creating the perftest client Pod: %v", err) } - if err := data.podWaitForRunning(defaultTimeout, "perftest-a", testNamespace); err != nil { + if err := data.podWaitForRunning(defaultTimeout, "perftest-a", data.testNamespace); err != nil { t.Fatalf("Error when waiting for the perftest client Pod: %v", err) } - if err := data.createPodOnNode("perftest-b", testNamespace, endpointNode, perftoolImage, nil, nil, nil, []v1.ContainerPort{{Protocol: v1.ProtocolTCP, ContainerPort: iperfPort}}, false, nil); err != nil { + if err := data.createPodOnNode("perftest-b", data.testNamespace, endpointNode, perftoolImage, nil, nil, nil, []v1.ContainerPort{{Protocol: v1.ProtocolTCP, ContainerPort: iperfPort}}, false, nil); err != nil { t.Fatalf("Error when creating the perftest server Pod: %v", err) } - if err := data.podWaitForRunning(defaultTimeout, "perftest-b", testNamespace); err != nil { + if err := data.podWaitForRunning(defaultTimeout, "perftest-b", data.testNamespace); err != nil { t.Fatalf("Error when getting the perftest server Pod's IP: %v", err) } - stdout, stderr, err := data.RunCommandFromPod(testNamespace, "perftest-a", perftoolContainerName, []string{"bash", "-c", fmt.Sprintf("iperf3 -c %s|grep sender|awk '{print $7,$8}'", svc.Spec.ClusterIP)}) + stdout, stderr, err := data.RunCommandFromPod(data.testNamespace, "perftest-a", perftoolContainerName, []string{"bash", "-c", fmt.Sprintf("iperf3 -c %s|grep sender|awk '{print $7,$8}'", svc.Spec.ClusterIP)}) if err != nil { t.Fatalf("Error when running iperf3 client: %v, stderr: %s", err, stderr) } @@ -158,32 +159,32 @@ func testPodTrafficShaping(t *testing.T, data *TestData) { t.Run(tt.name, func(t *testing.T) { clientPodName := fmt.Sprintf("client-a-%d", i) serverPodName := fmt.Sprintf("server-a-%d", i) - if err := data.createPodOnNode(clientPodName, testNamespace, nodeName, perftoolImage, nil, nil, nil, nil, false, func(pod *v1.Pod) { + if err := data.createPodOnNode(clientPodName, data.testNamespace, nodeName, perftoolImage, nil, nil, nil, nil, false, func(pod *v1.Pod) { pod.Annotations = map[string]string{ "kubernetes.io/egress-bandwidth": fmt.Sprintf("%dM", tt.clientEgressBandwidth), } }); err != nil { t.Fatalf("Error when creating the perftest client Pod: %v", err) } - defer deletePodWrapper(t, data, testNamespace, clientPodName) - if err := data.podWaitForRunning(defaultTimeout, clientPodName, testNamespace); err != nil { + defer deletePodWrapper(t, data, data.testNamespace, clientPodName) + if err := data.podWaitForRunning(defaultTimeout, clientPodName, data.testNamespace); err != nil { t.Fatalf("Error when waiting for the perftest client Pod: %v", err) } - if err := data.createPodOnNode(serverPodName, testNamespace, nodeName, perftoolImage, nil, nil, nil, []v1.ContainerPort{{Protocol: v1.ProtocolTCP, ContainerPort: iperfPort}}, false, func(pod *v1.Pod) { + if err := data.createPodOnNode(serverPodName, data.testNamespace, nodeName, perftoolImage, nil, nil, nil, []v1.ContainerPort{{Protocol: v1.ProtocolTCP, ContainerPort: iperfPort}}, false, func(pod *v1.Pod) { pod.Annotations = map[string]string{ "kubernetes.io/ingress-bandwidth": fmt.Sprintf("%dM", tt.serverIngressBandwidth), } }); err != nil { t.Fatalf("Error when creating the perftest server Pod: %v", err) } - defer deletePodWrapper(t, data, testNamespace, serverPodName) - podIPs, err := data.podWaitForIPs(defaultTimeout, serverPodName, testNamespace) + defer deletePodWrapper(t, data, data.testNamespace, serverPodName) + podIPs, err := data.podWaitForIPs(defaultTimeout, serverPodName, data.testNamespace) if err != nil { t.Fatalf("Error when getting the perftest server Pod's IP: %v", err) } runIperf := func(cmd []string) { - stdout, _, err := data.RunCommandFromPod(testNamespace, clientPodName, "perftool", cmd) + stdout, _, err := data.RunCommandFromPod(data.testNamespace, clientPodName, "perftool", cmd) if err != nil { t.Fatalf("Error when running iperf3 client: %v", err) } diff --git a/test/e2e/basic_test.go b/test/e2e/basic_test.go index ba2657bfd46..99e20da54b4 100644 --- a/test/e2e/basic_test.go +++ b/test/e2e/basic_test.go @@ -26,6 +26,8 @@ import ( "github.com/google/uuid" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/util/wait" "antrea.io/antrea/pkg/agent/apiserver/handlers/podinterface" @@ -47,12 +49,12 @@ func TestBasic(t *testing.T) { } defer teardownTest(t, data) - t.Run("testPodAssignIP", func(t *testing.T) { testPodAssignIP(t, data, testNamespace, "", "") }) - t.Run("testDeletePod", func(t *testing.T) { testDeletePod(t, data, testNamespace) }) + t.Run("testPodAssignIP", func(t *testing.T) { testPodAssignIP(t, data, data.testNamespace, "", "") }) + t.Run("testDeletePod", func(t *testing.T) { testDeletePod(t, data, data.testNamespace) }) t.Run("testAntreaGracefulExit", func(t *testing.T) { testAntreaGracefulExit(t, data) }) - t.Run("testIPAMRestart", func(t *testing.T) { testIPAMRestart(t, data, testNamespace) }) + t.Run("testIPAMRestart", func(t *testing.T) { testIPAMRestart(t, data, data.testNamespace) }) t.Run("testDeletePreviousRoundFlowsOnStartup", func(t *testing.T) { testDeletePreviousRoundFlowsOnStartup(t, data) }) - t.Run("testGratuitousARP", func(t *testing.T) { testGratuitousARP(t, data, testNamespace) }) + t.Run("testGratuitousARP", func(t *testing.T) { testGratuitousARP(t, data, data.testNamespace) }) t.Run("testClusterIdentity", func(t *testing.T) { testClusterIdentity(t, data) }) } @@ -360,67 +362,13 @@ func testReconcileGatewayRoutesOnStartup(t *testing.T, data *TestData, isIPv6 bo t.Fatalf(" failed to get encap mode, err %v", err) } - type Route struct { - peerPodCIDR *net.IPNet - peerPodGW net.IP - } - nodeName := nodeName(0) - antreaPodName := func() string { - antreaPodName, err := data.getAntreaPodOnNode(nodeName) - if err != nil { - t.Fatalf("Error when retrieving the name of the Antrea Pod running on Node '%s': %v", nodeName, err) - } - t.Logf("The Antrea Pod for Node '%s' is '%s'", nodeName, antreaPodName) - return antreaPodName - } - + podName := getAntreaPodName(t, data, nodeName) antreaGWName, err := data.GetGatewayInterfaceName(antreaNamespace) if err != nil { t.Fatalf("Failed to detect gateway interface name from ConfigMap: %v", err) } - getGatewayRoutes := func() (routes []Route, err error) { - var cmd []string - if !isIPv6 { - cmd = []string{"ip", "route", "list", "dev", antreaGWName} - } else { - cmd = []string{"ip", "-6", "route", "list", "dev", antreaGWName} - } - podName := antreaPodName() - stdout, stderr, err := data.RunCommandFromPod(antreaNamespace, podName, agentContainerName, cmd) - if err != nil { - return nil, fmt.Errorf("error when running ip command in Pod '%s': %v - stdout: %s - stderr: %s", podName, err, stdout, stderr) - } - re := regexp.MustCompile(`([^\s]+) via ([^\s]+)`) - for _, line := range strings.Split(stdout, "\n") { - var err error - matches := re.FindStringSubmatch(line) - if len(matches) == 0 { - continue - } - route := Route{} - if _, route.peerPodCIDR, err = net.ParseCIDR(matches[1]); err != nil { - return nil, fmt.Errorf("%s is not a valid net CIDR", matches[1]) - } - if route.peerPodGW = net.ParseIP(matches[2]); route.peerPodGW == nil { - return nil, fmt.Errorf("%s is not a valid IP", matches[2]) - } - // For gateway routes, the Antrea Node controller will not clean the route whose gateway is virtual Service IP. - // When running all e2e tests together, AntreaProxy could be installed and uninstalled several times. - // After uninstalling AntreaProxy, the route which is used to route ClusterIP to gateway still exists. - // When installing AntreaProxy again, a new route which used to route ClusterIP to gateway will be installed. - // The old route will be an orphan route, but Antrea Node controller cannot clean it because the func `Reconcile` - // of Antrea Node controller will not clean the route whose gateway is virtual Service IP. In short, the number - // of gateway routes is uncertain because there may be orphan routes, so it should not be counted. - if route.peerPodGW.Equal(config.VirtualServiceIPv4) || route.peerPodGW.Equal(config.VirtualServiceIPv6) { - continue - } - routes = append(routes, route) - } - return routes, nil - } - expectedRtNumMin, expectedRtNumMax := clusterInfo.numNodes-1, clusterInfo.numNodes-1 if encapMode == config.TrafficEncapModeNoEncap { expectedRtNumMin, expectedRtNumMax = 0, 0 @@ -432,7 +380,7 @@ func testReconcileGatewayRoutesOnStartup(t *testing.T, data *TestData, isIPv6 bo t.Logf("Retrieving gateway routes on Node '%s'", nodeName) var routes []Route if err := wait.PollImmediate(defaultInterval, defaultTimeout, func() (found bool, err error) { - routes, err = getGatewayRoutes() + routes, _, err = getGatewayRoutes(t, data, antreaGWName, nodeName, isIPv6) if err != nil { return false, err } @@ -459,11 +407,11 @@ func testReconcileGatewayRoutesOnStartup(t *testing.T, data *TestData, isIPv6 bo // A dummy route routeToAdd := &Route{} if !isIPv6 { - _, routeToAdd.peerPodCIDR, _ = net.ParseCIDR("99.99.99.0/24") - routeToAdd.peerPodGW = net.ParseIP("99.99.99.1") + _, routeToAdd.routeCIDR, _ = net.ParseCIDR("99.99.99.0/24") + routeToAdd.routeGW = net.ParseIP("99.99.99.1") } else { - _, routeToAdd.peerPodCIDR, _ = net.ParseCIDR("fe80::0/112") - routeToAdd.peerPodGW = net.ParseIP("fe80::1") + _, routeToAdd.routeCIDR, _ = net.ParseCIDR("fe80::0/112") + routeToAdd.routeGW = net.ParseIP("fe80::1") } // We run the ip command from the antrea-agent container for delete / add since they need to @@ -472,11 +420,11 @@ func testReconcileGatewayRoutesOnStartup(t *testing.T, data *TestData, isIPv6 bo deleteGatewayRoute := func(route *Route) error { var cmd []string if !isIPv6 { - cmd = []string{"ip", "route", "del", route.peerPodCIDR.String()} + cmd = []string{"ip", "route", "del", route.routeCIDR.String()} } else { - cmd = []string{"ip", "-6", "route", "del", route.peerPodCIDR.String()} + cmd = []string{"ip", "-6", "route", "del", route.routeCIDR.String()} } - _, _, err := data.RunCommandFromPod(antreaNamespace, antreaPodName(), agentContainerName, cmd) + _, _, err := data.RunCommandFromPod(antreaNamespace, podName, agentContainerName, cmd) if err != nil { return fmt.Errorf("error when running ip command on Node '%s': %v", nodeName, err) } @@ -486,11 +434,11 @@ func testReconcileGatewayRoutesOnStartup(t *testing.T, data *TestData, isIPv6 bo addGatewayRoute := func(route *Route) error { var cmd []string if !isIPv6 { - cmd = []string{"ip", "route", "add", route.peerPodCIDR.String(), "via", route.peerPodGW.String(), "dev", antreaGWName, "onlink"} + cmd = []string{"ip", "route", "add", route.routeCIDR.String(), "via", route.routeGW.String(), "dev", antreaGWName, "onlink"} } else { - cmd = []string{"ip", "-6", "route", "add", route.peerPodCIDR.String(), "via", route.peerPodGW.String(), "dev", antreaGWName, "onlink"} + cmd = []string{"ip", "-6", "route", "add", route.routeCIDR.String(), "via", route.routeGW.String(), "dev", antreaGWName, "onlink"} } - _, _, err := data.RunCommandFromPod(antreaNamespace, antreaPodName(), agentContainerName, cmd) + _, _, err := data.RunCommandFromPod(antreaNamespace, podName, agentContainerName, cmd) if err != nil { return fmt.Errorf("error when running ip command on Node '%s': %v", nodeName, err) } @@ -526,7 +474,7 @@ func testReconcileGatewayRoutesOnStartup(t *testing.T, data *TestData, isIPv6 bo // We expect the agent to delete the extra route we added and add back the route we deleted t.Logf("Waiting for gateway routes to converge") if err := wait.Poll(defaultInterval, defaultTimeout, func() (bool, error) { - newRoutes, err := getGatewayRoutes() + newRoutes, _, err := getGatewayRoutes(t, data, antreaGWName, nodeName, isIPv6) if err != nil { return false, err } @@ -534,7 +482,7 @@ func testReconcileGatewayRoutesOnStartup(t *testing.T, data *TestData, isIPv6 bo return false, nil } for _, route := range newRoutes { - if route.peerPodGW.Equal(routeToAdd.peerPodGW) { + if route.routeGW.Equal(routeToAdd.routeGW) { // The dummy route hasn't been deleted yet, keep trying return false, nil } @@ -542,7 +490,7 @@ func testReconcileGatewayRoutesOnStartup(t *testing.T, data *TestData, isIPv6 bo if routeToDelete != nil { // At this stage we have confirmed that the dummy route has been deleted for _, route := range newRoutes { - if route.peerPodGW.Equal(routeToDelete.peerPodGW) { + if route.routeGW.Equal(routeToDelete.routeGW) { // The deleted route was added back, success! return true, nil } @@ -561,6 +509,80 @@ func testReconcileGatewayRoutesOnStartup(t *testing.T, data *TestData, isIPv6 bo } } +func TestCleanStaleClusterIPRoutes(t *testing.T) { + skipIfNumNodesLessThan(t, 2) + skipIfHasWindowsNodes(t) + skipIfProxyDisabled(t) + + data, err := setupTest(t) + if err != nil { + t.Fatalf("Error when setting up test: %v", err) + } + defer teardownTest(t, data) + skipIfProxyAllDisabled(t, data) + + // Create a backend Pod for test Service: if a Service has no backend Pod, no ClusterIP route will be installed. + createAndWaitForPod(t, data, data.createNginxPodOnNode, "test-clean-stale-route-pod", nodeName(0), data.testNamespace, false) + + if len(clusterInfo.podV4NetworkCIDR) != 0 { + t.Logf("Running IPv4 test") + testCleanStaleClusterIPRoutes(t, data, false) + } + if len(clusterInfo.podV6NetworkCIDR) != 0 { + t.Logf("Running IPv6 test") + testCleanStaleClusterIPRoutes(t, data, true) + } +} + +func testCleanStaleClusterIPRoutes(t *testing.T, data *TestData, isIPv6 bool) { + ipProtocol := corev1.IPv4Protocol + if isIPv6 { + ipProtocol = corev1.IPv6Protocol + } + // Create two test ClusterIPs. + svc, err := data.createNginxClusterIPService(fmt.Sprintf("test-clean-stale-route-svc1-%v", isIPv6), data.testNamespace, false, &ipProtocol) + require.NoError(t, err) + require.NotEqual(t, "", svc.Spec.ClusterIP, "ClusterIP should not be empty") + svc, err = data.createNginxClusterIPService(fmt.Sprintf("test-clean-stale-route-svc2-%v", isIPv6), data.testNamespace, false, &ipProtocol) + require.NoError(t, err) + require.NotEqual(t, "", svc.Spec.ClusterIP, "ClusterIP should not be empty") + time.Sleep(time.Second) + + nodeName := nodeName(0) + if _, err := data.deleteAntreaAgentOnNode(nodeName, 30 /* grace period in seconds */, defaultTimeout); err != nil { + t.Logf("Error when restarting antrea-agent on Node '%s': %v", nodeName, err) + } + + antreaGWName, err := data.GetGatewayInterfaceName(antreaNamespace) + if err != nil { + t.Fatalf("Failed to detect gateway interface name from ConfigMap: %v", err) + } + var routes []Route + if err := wait.PollImmediate(defaultInterval, defaultTimeout, func() (bool, error) { + _, routes, err = getGatewayRoutes(t, data, antreaGWName, nodeName, isIPv6) + if err != nil { + t.Logf("Failed to get Service gateway routes: %v", err) + return false, nil + } + if len(routes) < 1 { + t.Logf("Failed to get enough Service gateway routes") + return false, nil + } + return true, nil + }); err != nil { + t.Errorf("Failed to get enough Service gateway routes after timeout") + } + + clusterIP := net.ParseIP(svc.Spec.ClusterIP) + routeCounter := 0 + for _, rt := range routes { + if rt.routeCIDR.Contains(clusterIP) { + routeCounter++ + } + } + require.Equal(t, 1, routeCounter, "There should be only one route whose destination CIDR can container the ClusterIP %v", clusterIP.String()) +} + func getRoundNumber(data *TestData, podName string) (uint64, error) { type transaction struct { Op string `json:"op"` @@ -614,22 +636,73 @@ func getRoundNumber(data *TestData, podName string) (uint64, error) { return 0, fmt.Errorf("did not find roundNum in OVSDB result") } +func getAntreaPodName(t *testing.T, data *TestData, nodeName string) string { + antreaPodName, err := data.getAntreaPodOnNode(nodeName) + if err != nil { + t.Fatalf("Error when retrieving the name of the Antrea Pod running on Node '%s': %v", nodeName, err) + } + t.Logf("The Antrea Pod for Node '%s' is '%s'", nodeName, antreaPodName) + return antreaPodName +} + +type Route struct { + routeCIDR *net.IPNet + routeGW net.IP +} + +func getGatewayRoutes(t *testing.T, data *TestData, antreaGWName, nodeName string, isIPv6 bool) ([]Route, []Route, error) { + var cmd []string + virtualIP := config.VirtualServiceIPv4 + mask := 32 + if !isIPv6 { + cmd = []string{"ip", "route", "list", "dev", antreaGWName} + } else { + cmd = []string{"ip", "-6", "route", "list", "dev", antreaGWName} + virtualIP = config.VirtualServiceIPv6 + mask = 128 + } + podName := getAntreaPodName(t, data, nodeName) + stdout, stderr, err := data.RunCommandFromPod(antreaNamespace, podName, agentContainerName, cmd) + if err != nil { + return nil, nil, fmt.Errorf("error when running ip command in Pod '%s': %v - stdout: %s - stderr: %s", podName, err, stdout, stderr) + } + + var nodeRoutes, serviceRoutes []Route + re := regexp.MustCompile(`([^\s]+) via ([^\s]+)`) + for _, line := range strings.Split(stdout, "\n") { + var err error + matches := re.FindStringSubmatch(line) + if len(matches) == 0 { + continue + } + if net.ParseIP(matches[1]) != nil { + matches[1] = fmt.Sprintf("%s/%d", matches[1], mask) + } + route := Route{} + if _, route.routeCIDR, err = net.ParseCIDR(matches[1]); err != nil { + return nil, nil, fmt.Errorf("%s is not a valid net CIDR", matches[1]) + } + if route.routeGW = net.ParseIP(matches[2]); route.routeGW == nil { + return nil, nil, fmt.Errorf("%s is not a valid IP", matches[2]) + } + if route.routeGW.Equal(virtualIP) { + // If the route is added by AntreaProxy, append it to slice serviceRoutes. + serviceRoutes = append(serviceRoutes, route) + } else { + // If the route is added by Node controller, append it to slice nodeRoutes. + nodeRoutes = append(nodeRoutes, route) + } + } + return nodeRoutes, serviceRoutes, nil +} + // testDeletePreviousRoundFlowsOnStartup checks that when the Antrea agent is restarted, flows from // the previous "round" which are no longer needed (e.g. in case of changes to the cluster / to // Network Policies) are removed correctly. func testDeletePreviousRoundFlowsOnStartup(t *testing.T, data *TestData) { skipIfRunCoverage(t, "Stopping Agent does not work with Coverage") nodeName := nodeName(0) - antreaPodName := func() string { - antreaPodName, err := data.getAntreaPodOnNode(nodeName) - if err != nil { - t.Fatalf("Error when retrieving the name of the Antrea Pod running on Node '%s': %v", nodeName, err) - } - t.Logf("The Antrea Pod for Node '%s' is '%s'", nodeName, antreaPodName) - return antreaPodName - } - - podName := antreaPodName() + podName := getAntreaPodName(t, data, nodeName) roundNumber := func(podName string) uint64 { roundNum, err := getRoundNumber(data, podName) @@ -648,7 +721,7 @@ func testDeletePreviousRoundFlowsOnStartup(t *testing.T, data *TestData) { t.Fatalf("Error when restarting antrea-agent on Node '%s': %v", nodeName, err) } - podName = antreaPodName() // pod name has changed + podName = getAntreaPodName(t, data, nodeName) // pod name has changed waitForNextRoundNum := func(roundNum uint64) uint64 { var nextRoundNum uint64 diff --git a/test/e2e/batch_test.go b/test/e2e/batch_test.go index f66121f5e87..1ddac2e2090 100644 --- a/test/e2e/batch_test.go +++ b/test/e2e/batch_test.go @@ -54,7 +54,7 @@ func TestBatchCreatePods(t *testing.T) { oldFDs := getFDs() - _, _, cleanupFn := createTestBusyboxPods(t, data, batchNum, testNamespace, node1) + _, _, cleanupFn := createTestBusyboxPods(t, data, batchNum, data.testNamespace, node1) defer cleanupFn() newFDs := getFDs() diff --git a/test/e2e/clustergroup_test.go b/test/e2e/clustergroup_test.go index 723fb3c8755..ab37691c789 100644 --- a/test/e2e/clustergroup_test.go +++ b/test/e2e/clustergroup_test.go @@ -52,7 +52,7 @@ func testInvalidCGIPBlockWithPodSelector(t *testing.T) { func testInvalidCGIPBlockWithNSSelector(t *testing.T) { invalidErr := fmt.Errorf("clustergroup created with ipblock and namespaceSelector") cgName := "ipb-ns" - nSel := &metav1.LabelSelector{MatchLabels: map[string]string{"ns": "y"}} + nSel := &metav1.LabelSelector{MatchLabels: map[string]string{"ns": namespaces["y"]}} cidr := "10.0.0.10/32" ipb := []crdv1alpha1.IPBlock{{CIDR: cidr}} cg := &crdv1alpha3.ClusterGroup{ @@ -97,7 +97,7 @@ func testInvalidCGServiceRefWithPodSelector(t *testing.T) { cgName := "svcref-pod-selector" pSel := &metav1.LabelSelector{MatchLabels: map[string]string{"pod": "x"}} svcRef := &crdv1alpha1.NamespacedName{ - Namespace: "y", + Namespace: namespaces["y"], Name: "test-svc", } cg := &crdv1alpha3.ClusterGroup{ @@ -118,9 +118,9 @@ func testInvalidCGServiceRefWithPodSelector(t *testing.T) { func testInvalidCGServiceRefWithNSSelector(t *testing.T) { invalidErr := fmt.Errorf("clustergroup created with serviceReference and namespaceSelector") cgName := "svcref-ns-selector" - nSel := &metav1.LabelSelector{MatchLabels: map[string]string{"ns": "y"}} + nSel := &metav1.LabelSelector{MatchLabels: map[string]string{"ns": namespaces["y"]}} svcRef := &crdv1alpha1.NamespacedName{ - Namespace: "y", + Namespace: namespaces["y"], Name: "test-svc", } cg := &crdv1alpha3.ClusterGroup{ @@ -144,7 +144,7 @@ func testInvalidCGServiceRefWithIPBlock(t *testing.T) { cidr := "10.0.0.10/32" ipb := []crdv1alpha1.IPBlock{{CIDR: cidr}} svcRef := &crdv1alpha1.NamespacedName{ - Namespace: "y", + Namespace: namespaces["y"], Name: "test-svc", } cg := &crdv1alpha3.ClusterGroup{ @@ -207,7 +207,7 @@ func testInvalidCGChildGroupWithServiceReference(t *testing.T) { invalidErr := fmt.Errorf("clustergroup created with childGroups and ServiceReference") cgName := "child-group-svcref" svcRef := &crdv1alpha1.NamespacedName{ - Namespace: "y", + Namespace: namespaces["y"], Name: "test-svc", } cg := &crdv1alpha3.ClusterGroup{ @@ -389,6 +389,7 @@ func TestClusterGroup(t *testing.T) { t.Fatalf("Error when setting up test: %v", err) } defer teardownTest(t, data) + initialize(t, data) t.Run("TestGroupClusterGroupValidate", func(t *testing.T) { diff --git a/test/e2e/connectivity_test.go b/test/e2e/connectivity_test.go index 13c75b71726..6210cfabc56 100644 --- a/test/e2e/connectivity_test.go +++ b/test/e2e/connectivity_test.go @@ -54,16 +54,16 @@ func TestConnectivity(t *testing.T) { }) t.Run("testPodConnectivityAfterAntreaRestart", func(t *testing.T) { skipIfHasWindowsNodes(t) - testPodConnectivityAfterAntreaRestart(t, data, testNamespace) + testPodConnectivityAfterAntreaRestart(t, data, data.testNamespace) }) t.Run("testOVSRestartSameNode", func(t *testing.T) { skipIfNotIPv4Cluster(t) skipIfHasWindowsNodes(t) - testOVSRestartSameNode(t, data, testNamespace) + testOVSRestartSameNode(t, data, data.testNamespace) }) t.Run("testOVSFlowReplay", func(t *testing.T) { skipIfHasWindowsNodes(t) - testOVSFlowReplay(t, data, testNamespace) + testOVSFlowReplay(t, data, data.testNamespace) }) t.Run("testPingLargeMTU", func(t *testing.T) { skipIfNumNodesLessThan(t, 2) @@ -76,7 +76,7 @@ func waitForPodIPs(t *testing.T, data *TestData, podInfos []podInfo) map[string] podIPs := make(map[string]*PodIPs) for _, pi := range podInfos { podName := pi.name - podNamespace := testNamespace + podNamespace := data.testNamespace if pi.namespace != "" { podNamespace = pi.namespace } @@ -101,11 +101,11 @@ func (data *TestData) runPingMesh(t *testing.T, podInfos []podInfo, ctrname stri if pi1.name == pi2.name { continue } - podNamespace := testNamespace + podNamespace := data.testNamespace if pi1.namespace != "" { podNamespace = pi1.namespace } - pod2Namespace := testNamespace + pod2Namespace := data.testNamespace if pi2.namespace != "" { pod2Namespace = pi2.namespace } @@ -133,10 +133,10 @@ func (data *TestData) testPodConnectivitySameNode(t *testing.T) { t.Logf("Creating %d agnhost Pods on '%s'", numPods, workerNode) for i := range podInfos { podInfos[i].os = clusterInfo.nodesOS[workerNode] - if err := data.createAgnhostPodOnNode(podInfos[i].name, testNamespace, workerNode, false); err != nil { + if err := data.createAgnhostPodOnNode(podInfos[i].name, data.testNamespace, workerNode, false); err != nil { t.Fatalf("Error when creating agnhost test Pod '%s': %v", podInfos[i], err) } - defer deletePodWrapper(t, data, testNamespace, podInfos[i].name) + defer deletePodWrapper(t, data, data.testNamespace, podInfos[i].name) } data.runPingMesh(t, podInfos, agnhostContainerName) @@ -181,7 +181,7 @@ func (data *TestData) testHostPortPodConnectivity(t *testing.T, clientNamespace, // testHostPortPodConnectivity checks that a Pod with hostPort set is reachable. func testHostPortPodConnectivity(t *testing.T, data *TestData) { - data.testHostPortPodConnectivity(t, testNamespace, testNamespace) + data.testHostPortPodConnectivity(t, data.testNamespace, data.testNamespace) } // createPodsOnDifferentNodes creates agnhost Pods through a DaemonSet. This function returns information of the created @@ -238,7 +238,7 @@ func (data *TestData) testPodConnectivityDifferentNodes(t *testing.T) { // subnet, all Nodes should have a Pod. numPods = maxPods } - podInfos, deletePods := createPodsOnDifferentNodes(t, data, testNamespace, "differentnodes") + podInfos, deletePods := createPodsOnDifferentNodes(t, data, data.testNamespace, "differentnodes") defer deletePods() if len(podInfos) > maxPods { @@ -394,28 +394,46 @@ func testOVSFlowReplay(t *testing.T, data *TestData, namespace string) { } t.Logf("The Antrea Pod for Node '%s' is '%s'", workerNode, antreaPodName) - countFlows := func() int { - cmd := []string{"ovs-ofctl", "dump-flows", defaultBridgeName} + dumpFlows := func() []string { + cmd := []string{"ovs-ofctl", "dump-flows", defaultBridgeName, "--names"} stdout, stderr, err := data.RunCommandFromPod(antreaNamespace, antreaPodName, ovsContainerName, cmd) if err != nil { t.Fatalf("error when dumping flows: <%v>, err: <%v>", stderr, err) } - count := strings.Count(stdout, "\n") + flows := make([]string, 0) + for _, flow := range strings.Split(stdout, "\n") { + flow = strings.TrimSpace(flow) + if flow == "" { + continue + } + flows = append(flows, flow) + } + count := len(flows) t.Logf("Counted %d flow in OVS bridge '%s' for Node '%s'", count, defaultBridgeName, workerNode) - return count + return flows } - countGroups := func() int { + dumpGroups := func() []string { cmd := []string{"ovs-ofctl", "dump-groups", defaultBridgeName} stdout, stderr, err := data.RunCommandFromPod(antreaNamespace, antreaPodName, ovsContainerName, cmd) if err != nil { t.Fatalf("error when dumping groups: <%v>, err: <%v>", stderr, err) } - count := strings.Count(stdout, "\n") + groups := make([]string, 0) + // remove first line ("NXST_GROUP_DESC reply (xid=0x2):") + for _, group := range strings.Split(stdout, "\n")[1:] { + group = strings.TrimSpace(group) + if group == "" { + continue + } + groups = append(groups, group) + } + count := len(groups) t.Logf("Counted %d group in OVS bridge '%s' for Node '%s'", count, defaultBridgeName, workerNode) - return count + return groups } - numFlows1, numGroups1 := countFlows(), countGroups() + flows1, groups1 := dumpFlows(), dumpGroups() + numFlows1, numGroups1 := len(flows1), len(groups1) // This is necessary because "ovs-ctl restart" saves and restores OpenFlow flows for the // bridge. An alternative may be to kill the antrea-ovs container running on that Node. @@ -451,22 +469,33 @@ func testOVSFlowReplay(t *testing.T, data *TestData, namespace string) { t.Logf("Running second ping mesh to check that flows have been restored") data.runPingMesh(t, podInfos, busyboxContainerName) - numFlows2, numGroups2 := countFlows(), countGroups() - assert.Equal(t, numFlows1, numFlows2, "Mismatch in OVS flow count after flow replay") - assert.Equal(t, numGroups1, numGroups2, "Mismatch in OVS group count after flow replay") + flows2, groups2 := dumpFlows(), dumpGroups() + numFlows2, numGroups2 := len(flows2), len(groups2) + if !assert.Equal(t, numFlows1, numFlows2, "Mismatch in OVS flow count after flow replay") { + fmt.Println("Flows before replay:") + fmt.Println(strings.Join(flows1, "\n")) + fmt.Println("Flows after replay:") + fmt.Println(strings.Join(flows2, "\n")) + } + if !assert.Equal(t, numGroups1, numGroups2, "Mismatch in OVS group count after flow replay") { + fmt.Println("Groups before replay:") + fmt.Println(strings.Join(groups1, "\n")) + fmt.Println("Groups after replay:") + fmt.Println(strings.Join(groups2, "\n")) + } } // testPingLargeMTU verifies that fragmented ICMP packets are handled correctly. func testPingLargeMTU(t *testing.T, data *TestData) { skipIfNumNodesLessThan(t, 2) - podInfos, deletePods := createPodsOnDifferentNodes(t, data, testNamespace, "largemtu") + podInfos, deletePods := createPodsOnDifferentNodes(t, data, data.testNamespace, "largemtu") defer deletePods() podIPs := waitForPodIPs(t, data, podInfos) pingSize := 2000 t.Logf("Running ping with size %d between Pods %s and %s", pingSize, podInfos[0].name, podInfos[1].name) - if err := data.runPingCommandFromTestPod(podInfos[0], testNamespace, podIPs[podInfos[1].name], agnhostContainerName, pingCount, pingSize); err != nil { + if err := data.runPingCommandFromTestPod(podInfos[0], data.testNamespace, podIPs[podInfos[1].name], agnhostContainerName, pingCount, pingSize); err != nil { t.Error(err) } } diff --git a/test/e2e/egress_test.go b/test/e2e/egress_test.go index 72eb7c7a096..70f9ed86f5b 100644 --- a/test/e2e/egress_test.go +++ b/test/e2e/egress_test.go @@ -34,14 +34,20 @@ import ( "antrea.io/antrea/pkg/agent/config" "antrea.io/antrea/pkg/apis/crd/v1alpha2" + "antrea.io/antrea/pkg/features" ) const waitEgressRealizedTimeout = 3 * time.Second +func skipIfEgressDisabled(tb testing.TB) { + skipIfFeatureDisabled(tb, features.Egress, true, true) +} + func TestEgress(t *testing.T) { skipIfHasWindowsNodes(t) skipIfNumNodesLessThan(t, 2) skipIfAntreaIPAMTest(t) + skipIfEgressDisabled(t) data, err := setupTest(t) if err != nil { @@ -119,31 +125,31 @@ ip netns exec %[1]s ip link set dev %[1]s-a up && \ ip netns exec %[1]s ip route replace default via %[3]s && \ ip netns exec %[1]s /agnhost netexec `, tt.fakeServer, tt.serverIP, tt.localIP0, tt.localIP1, tt.ipMaskLen) - if err := data.createPodOnNode(tt.fakeServer, testNamespace, egressNode, agnhostImage, []string{"sh", "-c", cmd}, nil, nil, nil, true, func(pod *v1.Pod) { + if err := data.createPodOnNode(tt.fakeServer, data.testNamespace, egressNode, agnhostImage, []string{"sh", "-c", cmd}, nil, nil, nil, true, func(pod *v1.Pod) { privileged := true pod.Spec.Containers[0].SecurityContext = &v1.SecurityContext{Privileged: &privileged} }); err != nil { t.Fatalf("Failed to create server Pod: %v", err) } - defer deletePodWrapper(t, data, testNamespace, tt.fakeServer) - if err := data.podWaitForRunning(defaultTimeout, tt.fakeServer, testNamespace); err != nil { + defer deletePodWrapper(t, data, data.testNamespace, tt.fakeServer) + if err := data.podWaitForRunning(defaultTimeout, tt.fakeServer, data.testNamespace); err != nil { t.Fatalf("Error when waiting for Pod '%s' to be in the Running state", tt.fakeServer) } localPod := fmt.Sprintf("localpod%s", tt.name) remotePod := fmt.Sprintf("remotepod%s", tt.name) - if err := data.createBusyboxPodOnNode(localPod, testNamespace, egressNode, false); err != nil { + if err := data.createBusyboxPodOnNode(localPod, data.testNamespace, egressNode, false); err != nil { t.Fatalf("Failed to create local Pod: %v", err) } - defer deletePodWrapper(t, data, testNamespace, localPod) - if err := data.podWaitForRunning(defaultTimeout, localPod, testNamespace); err != nil { + defer deletePodWrapper(t, data, data.testNamespace, localPod) + if err := data.podWaitForRunning(defaultTimeout, localPod, data.testNamespace); err != nil { t.Fatalf("Error when waiting for Pod '%s' to be in the Running state", localPod) } - if err := data.createBusyboxPodOnNode(remotePod, testNamespace, workerNodeName(1), false); err != nil { + if err := data.createBusyboxPodOnNode(remotePod, data.testNamespace, workerNodeName(1), false); err != nil { t.Fatalf("Failed to create remote Pod: %v", err) } - defer deletePodWrapper(t, data, testNamespace, remotePod) - if err := data.podWaitForRunning(defaultTimeout, remotePod, testNamespace); err != nil { + defer deletePodWrapper(t, data, data.testNamespace, remotePod) + if err := data.podWaitForRunning(defaultTimeout, remotePod, data.testNamespace); err != nil { t.Fatalf("Error when waiting for Pod '%s' to be in the Running state", remotePod) } @@ -155,7 +161,7 @@ ip netns exec %[1]s /agnhost netexec // getClientIP gets the translated client IP by accessing the API that replies the request's client IP. getClientIP := func(pod string) (string, string, error) { url := fmt.Sprintf("%s:8080/clientip", serverIPStr) - return data.runWgetCommandOnBusyboxWithRetry(pod, testNamespace, url, 5) + return data.runWgetCommandOnBusyboxWithRetry(pod, data.testNamespace, url, 5) } // assertClientIP asserts the Pod is translated to the provided client IP. @@ -233,13 +239,13 @@ ip netns exec %[1]s /agnhost netexec clientIPStr = fmt.Sprintf("[%s]", clientIPStr) } cmd = fmt.Sprintf("wget -T 3 -O - %s:8080/clientip | grep %s:", serverIPStr, clientIPStr) - if err := data.createPodOnNode(initialIPChecker, testNamespace, egressNode, busyboxImage, []string{"sh", "-c", cmd}, nil, nil, nil, false, func(pod *v1.Pod) { + if err := data.createPodOnNode(initialIPChecker, data.testNamespace, egressNode, busyboxImage, []string{"sh", "-c", cmd}, nil, nil, nil, false, func(pod *v1.Pod) { pod.Spec.RestartPolicy = v1.RestartPolicyNever }); err != nil { t.Fatalf("Failed to create Pod initial-ip-checker: %v", err) } - defer data.DeletePod(testNamespace, initialIPChecker) - _, err = data.PodWaitFor(timeout, initialIPChecker, testNamespace, func(pod *v1.Pod) (bool, error) { + defer data.DeletePod(data.testNamespace, initialIPChecker) + _, err = data.PodWaitFor(timeout, initialIPChecker, data.testNamespace, func(pod *v1.Pod) (bool, error) { if pod.Status.Phase == v1.PodFailed { return false, fmt.Errorf("Pod terminated with failure") } diff --git a/test/e2e/fixtures.go b/test/e2e/fixtures.go index fda353c0afb..a8596f1eec3 100644 --- a/test/e2e/fixtures.go +++ b/test/e2e/fixtures.go @@ -49,6 +49,12 @@ func skipIfAntreaIPAMTest(tb testing.TB) { } } +func skipIfNotFlowVisibilityTest(tb testing.TB) { + if !testOptions.flowVisibility { + tb.Skipf("Skipping when not running flow visibility test") + } +} + func skipIfNamespaceIsNotEqual(tb testing.TB, actualNamespace, expectNamespace string) { if actualNamespace != expectNamespace { tb.Skipf("Skipping test when namespace is not: %s", expectNamespace) @@ -202,18 +208,19 @@ func setupTest(tb testing.TB) (*TestData, error) { exportLogs(tb, testData, "afterSetupTest", true) } }() - tb.Logf("Creating '%s' K8s Namespace", testNamespace) + testData.testNamespace = randName(strings.ToLower(tb.Name()) + "-") + tb.Logf("Creating '%s' K8s Namespace", testData.testNamespace) if err := ensureAntreaRunning(testData); err != nil { return nil, err } - if err := testData.createTestNamespace(); err != nil { + if err := testData.CreateNamespace(testData.testNamespace, nil); err != nil { return nil, err } success = true return testData, nil } -func setupTestWithIPFIXCollector(tb testing.TB) (*TestData, bool, bool, error) { +func setupTestForFlowAggregator(tb testing.TB) (*TestData, bool, bool, error) { v4Enabled := clusterInfo.podV4NetworkCIDR != "" v6Enabled := clusterInfo.podV6NetworkCIDR != "" testData, err := setupTest(tb) @@ -221,10 +228,10 @@ func setupTestWithIPFIXCollector(tb testing.TB) (*TestData, bool, bool, error) { return testData, v4Enabled, v6Enabled, err } // Create pod using ipfix collector image - if err = testData.createPodOnNode("ipfix-collector", testNamespace, "", ipfixCollectorImage, nil, nil, nil, nil, true, nil); err != nil { + if err = testData.createPodOnNode("ipfix-collector", testData.testNamespace, "", ipfixCollectorImage, nil, nil, nil, nil, true, nil); err != nil { tb.Errorf("Error when creating the ipfix collector Pod: %v", err) } - ipfixCollectorIP, err := testData.podWaitForIPs(defaultTimeout, "ipfix-collector", testNamespace) + ipfixCollectorIP, err := testData.podWaitForIPs(defaultTimeout, "ipfix-collector", testData.testNamespace) if err != nil || len(ipfixCollectorIP.ipStrings) == 0 { tb.Errorf("Error when waiting to get ipfix collector Pod IP: %v", err) return nil, v4Enabled, v6Enabled, err @@ -237,17 +244,15 @@ func setupTestWithIPFIXCollector(tb testing.TB) (*TestData, bool, bool, error) { } ipfixCollectorAddr := fmt.Sprintf("%s:tcp", net.JoinHostPort(ipStr, ipfixCollectorPort)) - tb.Logf("Applying flow aggregator YAML with ipfix collector address: %s", ipfixCollectorAddr) - if err := testData.deployFlowAggregator(ipfixCollectorAddr); err != nil { - return testData, v4Enabled, v6Enabled, err - } - tb.Logf("Enabling flow exporter in Antrea Agent") - if err = testData.enableAntreaFlowExporter(""); err != nil { + tb.Logf("Deploying ClickHouse") + chSvcIP, err := testData.deployFlowVisibilityClickHouse() + if err != nil { return testData, v4Enabled, v6Enabled, err } - - tb.Logf("Checking CoreDNS deployment") - if err = testData.checkCoreDNSPods(defaultTimeout); err != nil { + tb.Logf("ClickHouse Service created with ClusterIP: %v", chSvcIP) + tb.Logf("Applying flow aggregator YAML with ipfix collector: %s and clickHouse enabled", + ipfixCollectorAddr) + if err := testData.deployFlowAggregator(ipfixCollectorAddr); err != nil { return testData, v4Enabled, v6Enabled, err } return testData, v4Enabled, v6Enabled, nil @@ -323,6 +328,12 @@ func exportLogs(tb testing.TB, data *TestData, logsSubDir string, writeNodeLogs // dump the logs for flow-aggregator Pods to disk. data.forAllMatchingPodsInNamespace("", flowAggregatorNamespace, writePodLogs) + // dump the logs for flow-visibility Pods to disk. + data.forAllMatchingPodsInNamespace("", flowVisibilityNamespace, writePodLogs) + + // dump the logs for clickhouse operator Pods to disk. + data.forAllMatchingPodsInNamespace("app=clickhouse-operator", kubeNamespace, writePodLogs) + // dump the output of "kubectl describe" for Antrea pods to disk. data.forAllMatchingPodsInNamespace("app=antrea", antreaNamespace, func(nodeName, podName, nsName string) error { w := getPodWriter(nodeName, podName, "describe") @@ -390,6 +401,14 @@ func teardownFlowAggregator(tb testing.TB, data *TestData) { if err := data.DeleteNamespace(flowAggregatorNamespace, defaultTimeout); err != nil { tb.Logf("Error when tearing down flow aggregator: %v", err) } + + tb.Logf("Deleting '%s' K8s Namespace and ClickHouse Operator", flowVisibilityNamespace) + if err := data.DeleteNamespace(flowVisibilityNamespace, defaultTimeout); err != nil { + tb.Logf("Error when tearing down flow visibility: %v", err) + } + if err := data.deleteClickHouseOperator(); err != nil { + tb.Logf("Error when removing ClickHouse Operator: %v", err) + } } func teardownTest(tb testing.TB, data *TestData) { @@ -397,8 +416,8 @@ func teardownTest(tb testing.TB, data *TestData) { if empty, _ := IsDirEmpty(data.logsDirForTestCase); empty { _ = os.Remove(data.logsDirForTestCase) } - tb.Logf("Deleting '%s' K8s Namespace", testNamespace) - if err := data.deleteTestNamespace(defaultTimeout); err != nil { + tb.Logf("Deleting '%s' K8s Namespace", testData.testNamespace) + if err := data.DeleteNamespace(testData.testNamespace, defaultTimeout); err != nil { tb.Logf("Error when tearing down test: %v", err) } } @@ -419,6 +438,18 @@ func deletePodWrapper(tb testing.TB, data *TestData, namespace, name string) { // created Pods. Pods are created in parallel to reduce the time required to run the tests. func createTestBusyboxPods(tb testing.TB, data *TestData, num int, ns string, nodeName string) ( podNames []string, podIPs []*PodIPs, cleanupFn func(), +) { + return createTestPods(tb, data, num, ns, nodeName, data.createBusyboxPodOnNode) +} + +func createTestAgnhostPods(tb testing.TB, data *TestData, num int, ns string, nodeName string) ( + podNames []string, podIPs []*PodIPs, cleanupFn func(), +) { + return createTestPods(tb, data, num, ns, nodeName, data.createAgnhostPodOnNode) +} + +func createTestPods(tb testing.TB, data *TestData, num int, ns string, nodeName string, createFunc func(string, string, string, bool) error) ( + podNames []string, podIPs []*PodIPs, cleanupFn func(), ) { cleanupFn = func() { var wg sync.WaitGroup @@ -440,9 +471,9 @@ func createTestBusyboxPods(tb testing.TB, data *TestData, num int, ns string, no createPodAndGetIP := func() (string, *PodIPs, error) { podName := randName("test-pod-") - tb.Logf("Creating a busybox test Pod '%s' and waiting for IP", podName) - if err := data.createBusyboxPodOnNode(podName, ns, nodeName, false); err != nil { - tb.Errorf("Error when creating busybox test Pod '%s': %v", podName, err) + tb.Logf("Creating a test Pod '%s' and waiting for IP", podName) + if err := createFunc(podName, ns, nodeName, false); err != nil { + tb.Errorf("Error when creating test Pod '%s': %v", podName, err) return "", nil, err } podIP, err := data.podWaitForIPs(defaultTimeout, podName, ns) diff --git a/test/e2e/flowaggregator_test.go b/test/e2e/flowaggregator_test.go index 950015c6d66..dc1e5abfe9c 100644 --- a/test/e2e/flowaggregator_test.go +++ b/test/e2e/flowaggregator_test.go @@ -127,6 +127,7 @@ const ( egressAntreaNetworkPolicyName = "test-flow-aggregator-antrea-networkpolicy-egress" testIngressRuleName = "test-ingress-rule-name" testEgressRuleName = "test-egress-rule-name" + clickHousePodName = "chi-clickhouse-clickhouse-0-0-0" iperfTimeSec = 12 protocolIdentifierTCP = 6 // Set target bandwidth(bits/sec) of iPerf traffic to a relatively small value @@ -152,17 +153,15 @@ type testFlow struct { } func TestFlowAggregator(t *testing.T) { + skipIfNotFlowVisibilityTest(t) skipIfHasWindowsNodes(t) - data, v4Enabled, v6Enabled, err := setupTestWithIPFIXCollector(t) + data, v4Enabled, v6Enabled, err := setupTestForFlowAggregator(t) if err != nil { t.Fatalf("Error when setting up test: %v", err) } defer func() { teardownTest(t, data) - if err := data.disableAntreaFlowExporter(); err != nil { - t.Errorf("Failed to disable flow exporter in Antrea Agent: %v", err) - } // Execute teardownFlowAggregator later than teardownTest to ensure that the log // of Flow Aggregator has been exported. teardownFlowAggregator(t, data) @@ -334,10 +333,10 @@ func testHelper(t *testing.T, data *TestData, podAIPs, podBIPs, podCIPs, podDIPs anp1, anp2 := deployAntreaNetworkPolicies(t, data, "perftest-a", "perftest-c") defer func() { if anp1 != nil { - k8sUtils.DeleteANP(testNamespace, anp1.Name) + k8sUtils.DeleteANP(data.testNamespace, anp1.Name) } if anp2 != nil { - k8sUtils.DeleteANP(testNamespace, anp2.Name) + k8sUtils.DeleteANP(data.testNamespace, anp2.Name) } }() if !isIPv6 { @@ -458,11 +457,11 @@ func testHelper(t *testing.T, data *TestData, podAIPs, podBIPs, podCIPs, podDIPs // Creating an agnhost server as a host network Pod serverPodPort := int32(80) _, serverIPs, cleanupFunc := createAndWaitForPod(t, data, func(name string, ns string, nodeName string, hostNetwork bool) error { - return data.createServerPod(name, testNamespace, "", serverPodPort, false, true) - }, "test-server-", "", testNamespace, false) + return data.createServerPod(name, data.testNamespace, "", serverPodPort, false, true) + }, "test-server-", "", data.testNamespace, false) defer cleanupFunc() - clientName, clientIPs, cleanupFunc := createAndWaitForPod(t, data, data.createBusyboxPodOnNode, "test-client-", nodeName(0), testNamespace, false) + clientName, clientIPs, cleanupFunc := createAndWaitForPod(t, data, data.createBusyboxPodOnNode, "test-client-", nodeName(0), data.testNamespace, false) defer cleanupFunc() if !isIPv6 { @@ -548,7 +547,7 @@ func checkAntctlGetFlowRecordsJson(t *testing.T, data *TestData, podName string, dstIP = podBIPs.ipv6.String() cmdStr = fmt.Sprintf("iperf3 -6 -c %s -t %d", dstIP, iperfTimeSecShort) } - stdout, _, err := data.RunCommandFromPod(testNamespace, "perftest-a", "perftool", []string{"bash", "-c", cmdStr}) + stdout, _, err := data.RunCommandFromPod(data.testNamespace, "perftest-a", "perftool", []string{"bash", "-c", cmdStr}) require.NoErrorf(t, err, "Error when running iperf3 client: %v", err) _, srcPort, dstPort := getBandwidthAndPorts(stdout) @@ -570,10 +569,10 @@ func checkAntctlGetFlowRecordsJson(t *testing.T, data *TestData, podName string, require.NoErrorf(t, err, "Error when parsing flow records from antctl: %v", err) require.Len(t, records, 1) - checkAntctlRecord(t, records[0], srcIP, dstIP, srcPort, dstPort, isIPv6) + checkAntctlRecord(t, records[0], srcIP, dstIP, srcPort, dstPort, isIPv6, data.testNamespace) } -func checkAntctlRecord(t *testing.T, record map[string]interface{}, srcIP, dstIP, srcPort, dstPort string, isIPv6 bool) { +func checkAntctlRecord(t *testing.T, record map[string]interface{}, srcIP, dstIP, srcPort, dstPort string, isIPv6 bool, namespace string) { assert := assert.New(t) if isIPv6 { assert.Equal(srcIP, record["sourceIPv6Address"], "The record from antctl does not have correct sourceIPv6Address") @@ -586,14 +585,14 @@ func checkAntctlRecord(t *testing.T, record map[string]interface{}, srcIP, dstIP require.NoErrorf(t, err, "error when converting the iperf srcPort to int type: %s", srcPort) assert.EqualValues(srcPortNum, record["sourceTransportPort"], "The record from antctl does not have correct sourceTransportPort") assert.Equal("perftest-a", record["sourcePodName"], "The record from antctl does not have correct sourcePodName") - assert.Equal("antrea-test", record["sourcePodNamespace"], "The record from antctl does not have correct sourcePodNamespace") + assert.Equal(namespace, record["sourcePodNamespace"], "The record from antctl does not have correct sourcePodNamespace") assert.Equal(controlPlaneNodeName(), record["sourceNodeName"], "The record from antctl does not have correct sourceNodeName") dstPortNum, err := strconv.Atoi(dstPort) require.NoErrorf(t, err, "error when converting the iperf dstPort to int type: %s", dstPort) assert.EqualValues(dstPortNum, record["destinationTransportPort"], "The record from antctl does not have correct destinationTransportPort") assert.Equal("perftest-b", record["destinationPodName"], "The record from antctl does not have correct destinationPodName") - assert.Equal("antrea-test", record["destinationPodNamespace"], "The record from antctl does not have correct destinationPodNamespace") + assert.Equal(namespace, record["destinationPodNamespace"], "The record from antctl does not have correct destinationPodNamespace") assert.Equal(controlPlaneNodeName(), record["destinationNodeName"], "The record from antctl does not have correct destinationNodeName") assert.EqualValues(ipfixregistry.FlowTypeIntraNode, record["flowType"], "The record from antctl does not have correct flowType") @@ -607,7 +606,7 @@ func checkRecordsForFlows(t *testing.T, data *TestData, srcIP string, dstIP stri } else { cmdStr = fmt.Sprintf("iperf3 -6 -c %s -t %d -b %s", dstIP, iperfTimeSec, iperfBandwidth) } - stdout, _, err := data.RunCommandFromPod(testNamespace, "perftest-a", "perftool", []string{"bash", "-c", cmdStr}) + stdout, _, err := data.RunCommandFromPod(data.testNamespace, "perftest-a", "perftool", []string{"bash", "-c", cmdStr}) require.NoErrorf(t, err, "Error when running iperf3 client: %v", err) bwSlice, srcPort, _ := getBandwidthAndPorts(stdout) require.Equal(t, 2, len(bwSlice), "bandwidth value and / or bandwidth unit are not available") @@ -621,50 +620,55 @@ func checkRecordsForFlows(t *testing.T, data *TestData, srcIP string, dstIP stri t.Fatalf("Unit of the traffic bandwidth reported by iperf should be Mbits.") } + checkRecordsForFlowsCollector(t, data, srcIP, dstIP, srcPort, isIPv6, isIntraNode, checkService, checkK8sNetworkPolicy, checkAntreaNetworkPolicy, bandwidthInMbps) + checkRecordsForFlowsClickHouse(t, data, srcIP, dstIP, srcPort, isIntraNode, checkService, checkK8sNetworkPolicy, checkAntreaNetworkPolicy, bandwidthInMbps) +} + +func checkRecordsForFlowsCollector(t *testing.T, data *TestData, srcIP, dstIP, srcPort string, isIPv6, isIntraNode, checkService, checkK8sNetworkPolicy, checkAntreaNetworkPolicy bool, bandwidthInMbps float64) { collectorOutput, recordSlices := getCollectorOutput(t, srcIP, dstIP, srcPort, checkService, true, isIPv6, data) // Iterate over recordSlices and build some results to test with expected results dataRecordsCount := 0 src, dst := matchSrcAndDstAddress(srcIP, dstIP, checkService, isIPv6) for _, record := range recordSlices { // Check the source port along with source and destination IPs as there - // are flow records for control flows during the iperf with same IPs + // are flow records for control flows during the iperf with same IPs // and destination port. if strings.Contains(record, src) && strings.Contains(record, dst) && strings.Contains(record, srcPort) { dataRecordsCount = dataRecordsCount + 1 // Check if record has both Pod name of source and destination Pod. if isIntraNode { - checkPodAndNodeData(t, record, "perftest-a", controlPlaneNodeName(), "perftest-b", controlPlaneNodeName()) + checkPodAndNodeData(t, record, "perftest-a", controlPlaneNodeName(), "perftest-b", controlPlaneNodeName(), data.testNamespace) checkFlowType(t, record, ipfixregistry.FlowTypeIntraNode) } else { - checkPodAndNodeData(t, record, "perftest-a", controlPlaneNodeName(), "perftest-c", workerNodeName(1)) + checkPodAndNodeData(t, record, "perftest-a", controlPlaneNodeName(), "perftest-c", workerNodeName(1), data.testNamespace) checkFlowType(t, record, ipfixregistry.FlowTypeInterNode) } assert := assert.New(t) if checkService { if isIntraNode { - assert.Contains(record, "antrea-test/perftest-b", "Record with ServiceIP does not have Service name") + assert.Contains(record, data.testNamespace+"/perftest-b", "Record with ServiceIP does not have Service name") } else { - assert.Contains(record, "antrea-test/perftest-c", "Record with ServiceIP does not have Service name") + assert.Contains(record, data.testNamespace+"/perftest-c", "Record with ServiceIP does not have Service name") } } if checkK8sNetworkPolicy { // Check if records have both ingress and egress network policies. assert.Contains(record, fmt.Sprintf("ingressNetworkPolicyName: %s", ingressAllowNetworkPolicyName), "Record does not have the correct NetworkPolicy name with the ingress rule") - assert.Contains(record, fmt.Sprintf("ingressNetworkPolicyNamespace: %s", testNamespace), "Record does not have the correct NetworkPolicy Namespace with the ingress rule") + assert.Contains(record, fmt.Sprintf("ingressNetworkPolicyNamespace: %s", data.testNamespace), "Record does not have the correct NetworkPolicy Namespace with the ingress rule") assert.Contains(record, fmt.Sprintf("ingressNetworkPolicyType: %d", ipfixregistry.PolicyTypeK8sNetworkPolicy), "Record does not have the correct NetworkPolicy Type with the ingress rule") assert.Contains(record, fmt.Sprintf("egressNetworkPolicyName: %s", egressAllowNetworkPolicyName), "Record does not have the correct NetworkPolicy name with the egress rule") - assert.Contains(record, fmt.Sprintf("egressNetworkPolicyNamespace: %s", testNamespace), "Record does not have the correct NetworkPolicy Namespace with the egress rule") + assert.Contains(record, fmt.Sprintf("egressNetworkPolicyNamespace: %s", data.testNamespace), "Record does not have the correct NetworkPolicy Namespace with the egress rule") assert.Contains(record, fmt.Sprintf("egressNetworkPolicyType: %d", ipfixregistry.PolicyTypeK8sNetworkPolicy), "Record does not have the correct NetworkPolicy Type with the egress rule") } if checkAntreaNetworkPolicy { // Check if records have both ingress and egress network policies. assert.Contains(record, fmt.Sprintf("ingressNetworkPolicyName: %s", ingressAntreaNetworkPolicyName), "Record does not have the correct NetworkPolicy name with the ingress rule") - assert.Contains(record, fmt.Sprintf("ingressNetworkPolicyNamespace: %s", testNamespace), "Record does not have the correct NetworkPolicy Namespace with the ingress rule") + assert.Contains(record, fmt.Sprintf("ingressNetworkPolicyNamespace: %s", data.testNamespace), "Record does not have the correct NetworkPolicy Namespace with the ingress rule") assert.Contains(record, fmt.Sprintf("ingressNetworkPolicyType: %d", ipfixregistry.PolicyTypeAntreaNetworkPolicy), "Record does not have the correct NetworkPolicy Type with the ingress rule") assert.Contains(record, fmt.Sprintf("ingressNetworkPolicyRuleName: %s", testIngressRuleName), "Record does not have the correct NetworkPolicy RuleName with the ingress rule") assert.Contains(record, fmt.Sprintf("ingressNetworkPolicyRuleAction: %d", ipfixregistry.NetworkPolicyRuleActionAllow), "Record does not have the correct NetworkPolicy RuleAction with the ingress rule") assert.Contains(record, fmt.Sprintf("egressNetworkPolicyName: %s", egressAntreaNetworkPolicyName), "Record does not have the correct NetworkPolicy name with the egress rule") - assert.Contains(record, fmt.Sprintf("egressNetworkPolicyNamespace: %s", testNamespace), "Record does not have the correct NetworkPolicy Namespace with the egress rule") + assert.Contains(record, fmt.Sprintf("egressNetworkPolicyNamespace: %s", data.testNamespace), "Record does not have the correct NetworkPolicy Namespace with the egress rule") assert.Contains(record, fmt.Sprintf("egressNetworkPolicyType: %d", ipfixregistry.PolicyTypeAntreaNetworkPolicy), "Record does not have the correct NetworkPolicy Type with the egress rule") assert.Contains(record, fmt.Sprintf("egressNetworkPolicyRuleName: %s", testEgressRuleName), "Record does not have the correct NetworkPolicy RuleName with the egress rule") assert.Contains(record, fmt.Sprintf("egressNetworkPolicyRuleAction: %d", ipfixregistry.NetworkPolicyRuleActionAllow), "Record does not have the correct NetworkPolicy RuleAction with the egress rule") @@ -697,6 +701,76 @@ func checkRecordsForFlows(t *testing.T, data *TestData, srcIP string, dstIP stri assert.GreaterOrEqualf(t, dataRecordsCount, expectedNumDataRecords, "IPFIX collector should receive expected number of flow records. Considered records: %s \n Collector output: %s", recordSlices, collectorOutput) } +func checkRecordsForFlowsClickHouse(t *testing.T, data *TestData, srcIP, dstIP, srcPort string, isIntraNode, checkService, checkK8sNetworkPolicy, checkAntreaNetworkPolicy bool, bandwidthInMbps float64) { + // Check the source port along with source and destination IPs as there + // are flow records for control flows during the iperf with same IPs + // and destination port. + clickHouseRecords := getClickHouseOutput(t, data, srcIP, dstIP, srcPort, checkService, true) + + for _, record := range clickHouseRecords { + // Check if record has both Pod name of source and destination Pod. + if isIntraNode { + checkPodAndNodeDataClickHouse(data, t, record, "perftest-a", controlPlaneNodeName(), "perftest-b", controlPlaneNodeName()) + checkFlowTypeClickHouse(t, record, ipfixregistry.FlowTypeIntraNode) + } else { + checkPodAndNodeDataClickHouse(data, t, record, "perftest-a", controlPlaneNodeName(), "perftest-c", workerNodeName(1)) + checkFlowTypeClickHouse(t, record, ipfixregistry.FlowTypeInterNode) + } + assert := assert.New(t) + if checkService { + if isIntraNode { + assert.Contains(record.DestinationServicePortName, "antrea-test/perftest-b", "Record with ServiceIP does not have Service name") + } else { + assert.Contains(record.DestinationServicePortName, "antrea-test/perftest-c", "Record with ServiceIP does not have Service name") + } + } + if checkK8sNetworkPolicy { + // Check if records have both ingress and egress network policies. + assert.Equal(record.IngressNetworkPolicyName, ingressAllowNetworkPolicyName, "Record does not have the correct NetworkPolicy name with the ingress rule") + assert.Equal(record.IngressNetworkPolicyNamespace, data.testNamespace, "Record does not have the correct NetworkPolicy Namespace with the ingress rule") + assert.Equal(record.IngressNetworkPolicyType, ipfixregistry.PolicyTypeK8sNetworkPolicy, "Record does not have the correct NetworkPolicy Type with the ingress rule") + assert.Equal(record.EgressNetworkPolicyName, egressAllowNetworkPolicyName, "Record does not have the correct NetworkPolicy name with the egress rule") + assert.Equal(record.EgressNetworkPolicyNamespace, data.testNamespace, "Record does not have the correct NetworkPolicy Namespace with the egress rule") + assert.Equal(record.EgressNetworkPolicyType, ipfixregistry.PolicyTypeK8sNetworkPolicy, "Record does not have the correct NetworkPolicy Type with the egress rule") + } + if checkAntreaNetworkPolicy { + // Check if records have both ingress and egress network policies. + assert.Equal(record.IngressNetworkPolicyName, ingressAntreaNetworkPolicyName, "Record does not have the correct NetworkPolicy name with the ingress rule") + assert.Equal(record.IngressNetworkPolicyNamespace, data.testNamespace, "Record does not have the correct NetworkPolicy Namespace with the ingress rule") + assert.Equal(record.IngressNetworkPolicyType, ipfixregistry.PolicyTypeAntreaNetworkPolicy, "Record does not have the correct NetworkPolicy Type with the ingress rule") + assert.Equal(record.IngressNetworkPolicyRuleName, testIngressRuleName, "Record does not have the correct NetworkPolicy RuleName with the ingress rule") + assert.Equal(record.IngressNetworkPolicyRuleAction, ipfixregistry.NetworkPolicyRuleActionAllow, "Record does not have the correct NetworkPolicy RuleAction with the ingress rule") + assert.Equal(record.EgressNetworkPolicyName, egressAntreaNetworkPolicyName, "Record does not have the correct NetworkPolicy name with the egress rule") + assert.Equal(record.EgressNetworkPolicyNamespace, data.testNamespace, "Record does not have the correct NetworkPolicy Namespace with the egress rule") + assert.Equal(record.EgressNetworkPolicyType, ipfixregistry.PolicyTypeAntreaNetworkPolicy, "Record does not have the correct NetworkPolicy Type with the egress rule") + assert.Equal(record.EgressNetworkPolicyRuleName, testEgressRuleName, "Record does not have the correct NetworkPolicy RuleName with the egress rule") + assert.Equal(record.EgressNetworkPolicyRuleAction, ipfixregistry.NetworkPolicyRuleActionAllow, "Record does not have the correct NetworkPolicy RuleAction with the egress rule") + } + + // Skip the bandwidth check for the iperf control flow records which have 0 throughput. + if record.Throughput > 0 { + flowStartTime := record.FlowStartSeconds.Unix() + exportTime := record.FlowEndSeconds.Unix() + var recBandwidth float64 + // flowEndReason == 3 means the end of flow detected + if exportTime >= flowStartTime+iperfTimeSec || record.FlowEndReason == 3 { + octetTotalCount := record.OctetTotalCount + recBandwidth = float64(octetTotalCount) * 8 / float64(exportTime-flowStartTime) / 1000000 + } else { + // Check bandwidth with the field "throughput" except for the last record, + // as their throughput may be significantly lower than the average Iperf throughput. + throughput := record.Throughput + recBandwidth = float64(throughput) / 1000000 + } + t.Logf("Throughput check on record with flowEndSeconds-flowStartSeconds: %v, Iperf throughput: %.2f Mbits/s, ClickHouse record throughput: %.2f Mbits/s", exportTime-flowStartTime, bandwidthInMbps, recBandwidth) + assert.InDeltaf(recBandwidth, bandwidthInMbps, bandwidthInMbps*0.15, "Difference between Iperf bandwidth and ClickHouse record bandwidth should be lower than 15%%, record: %v", record) + } + + } + // Checking only data records as data records cannot be decoded without template record. + assert.GreaterOrEqualf(t, len(clickHouseRecords), expectedNumDataRecords, "ClickHouse should receive expected number of flow records. Considered records: %s", clickHouseRecords) +} + func checkRecordsForToExternalFlows(t *testing.T, data *TestData, srcNodeName string, srcPodName string, srcIP string, dstIP string, dstPort int32, isIPv6 bool) { var cmd string if !isIPv6 { @@ -704,20 +778,31 @@ func checkRecordsForToExternalFlows(t *testing.T, data *TestData, srcNodeName st } else { cmd = fmt.Sprintf("wget -O- [%s]:%d", dstIP, dstPort) } - stdout, stderr, err := data.RunCommandFromPod(testNamespace, srcPodName, busyboxContainerName, strings.Fields(cmd)) + stdout, stderr, err := data.RunCommandFromPod(data.testNamespace, srcPodName, busyboxContainerName, strings.Fields(cmd)) require.NoErrorf(t, err, "Error when running wget command, stdout: %s, stderr: %s", stdout, stderr) _, recordSlices := getCollectorOutput(t, srcIP, dstIP, "", false, false, isIPv6, data) for _, record := range recordSlices { if strings.Contains(record, srcIP) && strings.Contains(record, dstIP) { - checkPodAndNodeData(t, record, srcPodName, srcNodeName, "", "") + checkPodAndNodeData(t, record, srcPodName, srcNodeName, "", "", data.testNamespace) checkFlowType(t, record, ipfixregistry.FlowTypeToExternal) assert.NotContains(t, record, "octetDeltaCount: 0", "octetDeltaCount should be non-zero") } } + + clickHouseRecords := getClickHouseOutput(t, data, srcIP, dstIP, "", false, false) + for _, record := range clickHouseRecords { + checkPodAndNodeDataClickHouse(data, t, record, srcPodName, srcNodeName, "", "") + checkFlowTypeClickHouse(t, record, ipfixregistry.FlowTypeToExternal) + // Since the OVS userspace conntrack implementation doesn't maintain + // packet or byte counter statistics, skip the check for Kind clusters + if testOptions.providerName != "kind" { + assert.Greater(t, record.OctetDeltaCount, uint64(0), "octetDeltaCount should be non-zero") + } + } } -func checkRecordsForDenyFlows(t *testing.T, data *TestData, testFlow1, testFlow2 testFlow, isIPv6 bool, isIntraNode bool, isANP bool) { +func checkRecordsForDenyFlows(t *testing.T, data *TestData, testFlow1, testFlow2 testFlow, isIPv6, isIntraNode, isANP bool) { var cmdStr1, cmdStr2 string if !isIPv6 { cmdStr1 = fmt.Sprintf("iperf3 -c %s -n 1", testFlow1.dstIP) @@ -726,11 +811,16 @@ func checkRecordsForDenyFlows(t *testing.T, data *TestData, testFlow1, testFlow2 cmdStr1 = fmt.Sprintf("iperf3 -6 -c %s -n 1", testFlow1.dstIP) cmdStr2 = fmt.Sprintf("iperf3 -6 -c %s -n 1", testFlow2.dstIP) } - _, _, err := data.RunCommandFromPod(testNamespace, testFlow1.srcPodName, "", []string{"timeout", "2", "bash", "-c", cmdStr1}) + _, _, err := data.RunCommandFromPod(data.testNamespace, testFlow1.srcPodName, "", []string{"timeout", "2", "bash", "-c", cmdStr1}) assert.Error(t, err) - _, _, err = data.RunCommandFromPod(testNamespace, testFlow2.srcPodName, "", []string{"timeout", "2", "bash", "-c", cmdStr2}) + _, _, err = data.RunCommandFromPod(data.testNamespace, testFlow2.srcPodName, "", []string{"timeout", "2", "bash", "-c", cmdStr2}) assert.Error(t, err) + checkRecordsForDenyFlowsCollector(t, data, testFlow1, testFlow2, isIPv6, isIntraNode, isANP) + checkRecordsForDenyFlowsClickHouse(t, data, testFlow1, testFlow2, isIPv6, isIntraNode, isANP) +} + +func checkRecordsForDenyFlowsCollector(t *testing.T, data *TestData, testFlow1, testFlow2 testFlow, isIPv6, isIntraNode, isANP bool) { _, recordSlices1 := getCollectorOutput(t, testFlow1.srcIP, testFlow1.dstIP, "", false, false, isIPv6, data) _, recordSlices2 := getCollectorOutput(t, testFlow2.srcIP, testFlow2.dstIP, "", false, false, isIPv6, data) recordSlices := append(recordSlices1, recordSlices2...) @@ -753,10 +843,10 @@ func checkRecordsForDenyFlows(t *testing.T, data *TestData, testFlow1, testFlow2 egressDropStr := fmt.Sprintf("egressNetworkPolicyRuleAction: %d", ipfixregistry.NetworkPolicyRuleActionDrop) if isIntraNode { - checkPodAndNodeData(t, record, srcPodName, controlPlaneNodeName(), dstPodName, controlPlaneNodeName()) + checkPodAndNodeData(t, record, srcPodName, controlPlaneNodeName(), dstPodName, controlPlaneNodeName(), data.testNamespace) checkFlowType(t, record, ipfixregistry.FlowTypeIntraNode) } else { - checkPodAndNodeData(t, record, srcPodName, controlPlaneNodeName(), dstPodName, workerNodeName(1)) + checkPodAndNodeData(t, record, srcPodName, controlPlaneNodeName(), dstPodName, workerNodeName(1), data.testNamespace) checkFlowType(t, record, ipfixregistry.FlowTypeInterNode) } assert := assert.New(t) @@ -769,22 +859,22 @@ func checkRecordsForDenyFlows(t *testing.T, data *TestData, testFlow1, testFlow2 } else { // Antrea Network Policies if strings.Contains(record, ingressRejectStr) { assert.Contains(record, ingressRejectANPName, "Record does not have Antrea NetworkPolicy name with ingress reject rule") - assert.Contains(record, fmt.Sprintf("ingressNetworkPolicyNamespace: %s", testNamespace), "Record does not have correct ingressNetworkPolicyNamespace") + assert.Contains(record, fmt.Sprintf("ingressNetworkPolicyNamespace: %s", data.testNamespace), "Record does not have correct ingressNetworkPolicyNamespace") assert.Contains(record, fmt.Sprintf("ingressNetworkPolicyType: %d", ipfixregistry.PolicyTypeAntreaNetworkPolicy), "Record does not have the correct NetworkPolicy Type with the ingress reject rule") assert.Contains(record, fmt.Sprintf("ingressNetworkPolicyRuleName: %s", testIngressRuleName), "Record does not have the correct NetworkPolicy RuleName with the ingress reject rule") } else if strings.Contains(record, ingressDropStr) { assert.Contains(record, ingressDropANPName, "Record does not have Antrea NetworkPolicy name with ingress drop rule") - assert.Contains(record, fmt.Sprintf("ingressNetworkPolicyNamespace: %s", testNamespace), "Record does not have correct ingressNetworkPolicyNamespace") + assert.Contains(record, fmt.Sprintf("ingressNetworkPolicyNamespace: %s", data.testNamespace), "Record does not have correct ingressNetworkPolicyNamespace") assert.Contains(record, fmt.Sprintf("ingressNetworkPolicyType: %d", ipfixregistry.PolicyTypeAntreaNetworkPolicy), "Record does not have the correct NetworkPolicy Type with the ingress drop rule") assert.Contains(record, fmt.Sprintf("ingressNetworkPolicyRuleName: %s", testIngressRuleName), "Record does not have the correct NetworkPolicy RuleName with the ingress drop rule") } else if strings.Contains(record, egressRejectStr) { assert.Contains(record, egressRejectANPName, "Record does not have Antrea NetworkPolicy name with egress reject rule") - assert.Contains(record, fmt.Sprintf("egressNetworkPolicyNamespace: %s", testNamespace), "Record does not have correct egressNetworkPolicyNamespace") + assert.Contains(record, fmt.Sprintf("egressNetworkPolicyNamespace: %s", data.testNamespace), "Record does not have correct egressNetworkPolicyNamespace") assert.Contains(record, fmt.Sprintf("egressNetworkPolicyType: %d", ipfixregistry.PolicyTypeAntreaNetworkPolicy), "Record does not have the correct NetworkPolicy Type with the egress reject rule") assert.Contains(record, fmt.Sprintf("egressNetworkPolicyRuleName: %s", testEgressRuleName), "Record does not have the correct NetworkPolicy RuleName with the egress reject rule") } else if strings.Contains(record, egressDropStr) { assert.Contains(record, egressDropANPName, "Record does not have Antrea NetworkPolicy name with egress drop rule") - assert.Contains(record, fmt.Sprintf("egressNetworkPolicyNamespace: %s", testNamespace), "Record does not have correct egressNetworkPolicyNamespace") + assert.Contains(record, fmt.Sprintf("egressNetworkPolicyNamespace: %s", data.testNamespace), "Record does not have correct egressNetworkPolicyNamespace") assert.Contains(record, fmt.Sprintf("egressNetworkPolicyType: %d", ipfixregistry.PolicyTypeAntreaNetworkPolicy), "Record does not have the correct NetworkPolicy Type with the egress drop rule") assert.Contains(record, fmt.Sprintf("egressNetworkPolicyRuleName: %s", testEgressRuleName), "Record does not have the correct NetworkPolicy RuleName with the egress drop rule") } @@ -794,17 +884,72 @@ func checkRecordsForDenyFlows(t *testing.T, data *TestData, testFlow1, testFlow2 } } -func checkPodAndNodeData(t *testing.T, record, srcPod, srcNode, dstPod, dstNode string) { +func checkRecordsForDenyFlowsClickHouse(t *testing.T, data *TestData, testFlow1, testFlow2 testFlow, isIPv6, isIntraNode, isANP bool) { + clickHouseRecords1 := getClickHouseOutput(t, data, testFlow1.srcIP, testFlow1.dstIP, "", false, false) + clickHouseRecords2 := getClickHouseOutput(t, data, testFlow2.srcIP, testFlow2.dstIP, "", false, false) + recordSlices := append(clickHouseRecords1, clickHouseRecords2...) + // Iterate over recordSlices and build some results to test with expected results + for _, record := range recordSlices { + var srcPodName, dstPodName string + if record.SourceIP == testFlow1.srcIP && record.DestinationIP == testFlow1.dstIP { + srcPodName = testFlow1.srcPodName + dstPodName = testFlow1.dstPodName + } else if record.SourceIP == testFlow2.srcIP && record.DestinationIP == testFlow2.dstIP { + srcPodName = testFlow2.srcPodName + dstPodName = testFlow2.dstPodName + } + + if isIntraNode { + checkPodAndNodeDataClickHouse(data, t, record, srcPodName, controlPlaneNodeName(), dstPodName, controlPlaneNodeName()) + checkFlowTypeClickHouse(t, record, ipfixregistry.FlowTypeIntraNode) + } else { + checkPodAndNodeDataClickHouse(data, t, record, srcPodName, controlPlaneNodeName(), dstPodName, workerNodeName(1)) + checkFlowTypeClickHouse(t, record, ipfixregistry.FlowTypeInterNode) + } + assert := assert.New(t) + if !isANP { // K8s Network Policies + if (record.IngressNetworkPolicyRuleAction == ipfixregistry.NetworkPolicyRuleActionDrop) && (record.IngressNetworkPolicyName != ingressDropANPName) { + assert.Equal(record.DestinationIP, testFlow1.dstIP) + } else if (record.EgressNetworkPolicyRuleAction == ipfixregistry.NetworkPolicyRuleActionDrop) && (record.EgressNetworkPolicyName != egressDropANPName) { + assert.Equal(record.DestinationIP, testFlow2.dstIP) + } + } else { // Antrea Network Policies + if record.IngressNetworkPolicyRuleAction == ipfixregistry.NetworkPolicyRuleActionReject { + assert.Equal(record.IngressNetworkPolicyName, ingressRejectANPName, "Record does not have Antrea NetworkPolicy name with ingress reject rule") + assert.Equal(record.IngressNetworkPolicyNamespace, data.testNamespace, "Record does not have correct ingressNetworkPolicyNamespace") + assert.Equal(record.IngressNetworkPolicyType, ipfixregistry.PolicyTypeAntreaNetworkPolicy, "Record does not have the correct NetworkPolicy Type with the ingress reject rule") + assert.Equal(record.IngressNetworkPolicyRuleName, testIngressRuleName, "Record does not have the correct NetworkPolicy RuleName with the ingress reject rule") + } else if record.IngressNetworkPolicyRuleAction == ipfixregistry.NetworkPolicyRuleActionDrop { + assert.Equal(record.IngressNetworkPolicyName, ingressDropANPName, "Record does not have Antrea NetworkPolicy name with ingress drop rule") + assert.Equal(record.IngressNetworkPolicyNamespace, data.testNamespace, "Record does not have correct ingressNetworkPolicyNamespace") + assert.Equal(record.IngressNetworkPolicyType, ipfixregistry.PolicyTypeAntreaNetworkPolicy, "Record does not have the correct NetworkPolicy Type with the ingress drop rule") + assert.Equal(record.IngressNetworkPolicyRuleName, testIngressRuleName, "Record does not have the correct NetworkPolicy RuleName with the ingress drop rule") + } else if record.EgressNetworkPolicyRuleAction == ipfixregistry.NetworkPolicyRuleActionReject { + assert.Equal(record.EgressNetworkPolicyName, egressRejectANPName, "Record does not have Antrea NetworkPolicy name with egress reject rule") + assert.Equal(record.EgressNetworkPolicyNamespace, data.testNamespace, "Record does not have correct egressNetworkPolicyNamespace") + assert.Equal(record.EgressNetworkPolicyType, ipfixregistry.PolicyTypeAntreaNetworkPolicy, "Record does not have the correct NetworkPolicy Type with the egress reject rule") + assert.Equal(record.EgressNetworkPolicyRuleName, testEgressRuleName, "Record does not have the correct NetworkPolicy RuleName with the egress reject rule") + } else if record.EgressNetworkPolicyRuleAction == ipfixregistry.NetworkPolicyRuleActionDrop { + assert.Equal(record.EgressNetworkPolicyName, egressDropANPName, "Record does not have Antrea NetworkPolicy name with egress drop rule") + assert.Equal(record.EgressNetworkPolicyNamespace, data.testNamespace, "Record does not have correct egressNetworkPolicyNamespace") + assert.Equal(record.EgressNetworkPolicyType, ipfixregistry.PolicyTypeAntreaNetworkPolicy, "Record does not have the correct NetworkPolicy Type with the egress drop rule") + assert.Equal(record.EgressNetworkPolicyRuleName, testEgressRuleName, "Record does not have the correct NetworkPolicy RuleName with the egress drop rule") + } + } + } +} + +func checkPodAndNodeData(t *testing.T, record, srcPod, srcNode, dstPod, dstNode string, namespace string) { assert := assert.New(t) assert.Contains(record, srcPod, "Record with srcIP does not have Pod name: %s", srcPod) - assert.Contains(record, fmt.Sprintf("sourcePodNamespace: %s", testNamespace), "Record does not have correct sourcePodNamespace: %s", testNamespace) + assert.Contains(record, fmt.Sprintf("sourcePodNamespace: %s", namespace), "Record does not have correct sourcePodNamespace: %s", namespace) assert.Contains(record, fmt.Sprintf("sourceNodeName: %s", srcNode), "Record does not have correct sourceNodeName: %s", srcNode) // For Pod-To-External flow type, we send traffic to an external address, // so we skip the verification of destination Pod info. // Also, source Pod labels are different for Pod-To-External flow test. if dstPod != "" { assert.Contains(record, dstPod, "Record with dstIP does not have Pod name: %s", dstPod) - assert.Contains(record, fmt.Sprintf("destinationPodNamespace: %s", testNamespace), "Record does not have correct destinationPodNamespace: %s", testNamespace) + assert.Contains(record, fmt.Sprintf("destinationPodNamespace: %s", namespace), "Record does not have correct destinationPodNamespace: %s", namespace) assert.Contains(record, fmt.Sprintf("destinationNodeName: %s", dstNode), "Record does not have correct destinationNodeName: %s", dstNode) assert.Contains(record, fmt.Sprintf("{\"antrea-e2e\":\"%s\",\"app\":\"perftool\"}", srcPod), "Record does not have correct label for source Pod") assert.Contains(record, fmt.Sprintf("{\"antrea-e2e\":\"%s\",\"app\":\"perftool\"}", dstPod), "Record does not have correct label for destination Pod") @@ -813,10 +958,33 @@ func checkPodAndNodeData(t *testing.T, record, srcPod, srcNode, dstPod, dstNode } } +func checkPodAndNodeDataClickHouse(data *TestData, t *testing.T, record *ClickHouseFullRow, srcPod, srcNode, dstPod, dstNode string) { + assert := assert.New(t) + assert.Equal(record.SourcePodName, srcPod, "Record with srcIP does not have Pod name: %s", srcPod) + assert.Equal(record.SourcePodNamespace, data.testNamespace, "Record does not have correct sourcePodNamespace: %s", data.testNamespace) + assert.Equal(record.SourceNodeName, srcNode, "Record does not have correct sourceNodeName: %s", srcNode) + // For Pod-To-External flow type, we send traffic to an external address, + // so we skip the verification of destination Pod info. + // Also, source Pod labels are different for Pod-To-External flow test. + if dstPod != "" { + assert.Equal(record.DestinationPodName, dstPod, "Record with dstIP does not have Pod name: %s", dstPod) + assert.Equal(record.DestinationPodNamespace, data.testNamespace, "Record does not have correct destinationPodNamespace: %s", data.testNamespace) + assert.Equal(record.DestinationNodeName, dstNode, "Record does not have correct destinationNodeName: %s", dstNode) + assert.Equal(record.SourcePodLabels, fmt.Sprintf("{\"antrea-e2e\":\"%s\",\"app\":\"perftool\"}", srcPod), "Record does not have correct label for source Pod") + assert.Equal(record.DestinationPodLabels, fmt.Sprintf("{\"antrea-e2e\":\"%s\",\"app\":\"perftool\"}", dstPod), "Record does not have correct label for destination Pod") + } else { + assert.Equal(record.SourcePodLabels, fmt.Sprintf("{\"antrea-e2e\":\"%s\",\"app\":\"busybox\"}", srcPod), "Record does not have correct label for source Pod") + } +} + func checkFlowType(t *testing.T, record string, flowType uint8) { assert.Containsf(t, record, fmt.Sprintf("flowType: %d", flowType), "Record does not have correct flowType") } +func checkFlowTypeClickHouse(t *testing.T, record *ClickHouseFullRow, flowType uint8) { + assert.Equal(t, record.FlowType, flowType, "Record does not have correct flowType") +} + func getUint64FieldFromRecord(t *testing.T, record string, field string) uint64 { if strings.Contains(record, "TEMPLATE SET") { return 0 @@ -846,7 +1014,7 @@ func getCollectorOutput(t *testing.T, srcIP, dstIP, srcPort string, isDstService var rc int var err error // `pod-running-timeout` option is added to cover scenarios where ipfix flow-collector has crashed after being deployed - rc, collectorOutput, _, err = data.RunCommandOnNode(controlPlaneNodeName(), fmt.Sprintf("kubectl logs --pod-running-timeout=%v ipfix-collector -n antrea-test", aggregatorInactiveFlowRecordTimeout.String())) + rc, collectorOutput, _, err = data.RunCommandOnNode(controlPlaneNodeName(), fmt.Sprintf("kubectl logs --pod-running-timeout=%v ipfix-collector -n %s", aggregatorInactiveFlowRecordTimeout.String(), data.testNamespace)) if err != nil || rc != 0 { return false, err } @@ -873,6 +1041,67 @@ func getCollectorOutput(t *testing.T, srcIP, dstIP, srcPort string, isDstService return collectorOutput, recordSlices } +// getClickHouseOutput queries clickhouse with built-in client and checks if we have +// received all the expected records for a given flow with source IP, destination IP +// and source port. We send source port to ignore the control flows during the iperf test. +// Polling timeout is coded assuming IPFIX output has been checked first. +func getClickHouseOutput(t *testing.T, data *TestData, srcIP, dstIP, srcPort string, isDstService, checkAllRecords bool) []*ClickHouseFullRow { + var flowRecords []*ClickHouseFullRow + var queryOutput string + + query := fmt.Sprintf("SELECT * FROM flows WHERE (sourceIP = '%s') AND (destinationIP = '%s')", srcIP, dstIP) + if isDstService { + query = fmt.Sprintf("SELECT * FROM flows WHERE (sourceIP = '%s') AND (destinationClusterIP = '%s')", srcIP, dstIP) + } + if len(srcPort) > 0 { + query = fmt.Sprintf("%s AND (sourceTransportPort = %s)", query, srcPort) + } + cmd := []string{ + "clickhouse-client", + "--date_time_output_format=iso", + "--format=JSONEachRow", + fmt.Sprintf("--query=%s", query), + } + // ClickHouse output expected to be checked after IPFIX collector. + // Waiting additional 4x commit interval to be adequate for 3 commit attempts. + err := wait.PollImmediate(500*time.Millisecond, aggregatorClickHouseCommitInterval*4, func() (bool, error) { + queryOutput, _, err := data.RunCommandFromPod(flowVisibilityNamespace, clickHousePodName, "clickhouse", cmd) + if err != nil { + return false, err + } + + rows := strings.Split(queryOutput, "\n") + flowRecords = make([]*ClickHouseFullRow, 0, len(rows)) + for _, row := range rows { + row = strings.TrimSpace(row) + if len(row) == 0 { + continue + } + flowRecord := ClickHouseFullRow{} + err = json.Unmarshal([]byte(row), &flowRecord) + if err != nil { + return false, err + } + flowRecords = append(flowRecords, &flowRecord) + } + + if checkAllRecords { + for _, record := range flowRecords { + flowStartTime := record.FlowStartSeconds.Unix() + exportTime := record.FlowEndSeconds.Unix() + // flowEndReason == 3 means the end of flow detected + if exportTime >= flowStartTime+iperfTimeSec || record.FlowEndReason == 3 { + return true, nil + } + } + return false, nil + } + return len(flowRecords) > 0, nil + }) + require.NoErrorf(t, err, "ClickHouse did not receive the expected records in query output: %v; query: %s", queryOutput, query) + return flowRecords +} + func getRecordsFromOutput(output string) []string { re := regexp.MustCompile("(?m)^.*" + "#" + ".*$[\r\n]+") output = re.ReplaceAllString(output, "") @@ -927,10 +1156,10 @@ func deployK8sNetworkPolicies(t *testing.T, data *TestData, srcPod, dstPod strin func deployAntreaNetworkPolicies(t *testing.T, data *TestData, srcPod, dstPod string) (anp1 *secv1alpha1.NetworkPolicy, anp2 *secv1alpha1.NetworkPolicy) { builder1 := &utils.AntreaNetworkPolicySpecBuilder{} // apply anp to dstPod, allow ingress from srcPod - builder1 = builder1.SetName(testNamespace, ingressAntreaNetworkPolicyName). + builder1 = builder1.SetName(data.testNamespace, ingressAntreaNetworkPolicyName). SetPriority(2.0). SetAppliedToGroup([]utils.ANPAppliedToSpec{{PodSelector: map[string]string{"antrea-e2e": dstPod}}}) - builder1 = builder1.AddIngress(corev1.ProtocolTCP, nil, nil, nil, nil, map[string]string{"antrea-e2e": srcPod}, map[string]string{}, + builder1 = builder1.AddIngress(utils.ProtocolTCP, nil, nil, nil, nil, nil, nil, map[string]string{"antrea-e2e": srcPod}, map[string]string{}, nil, nil, nil, secv1alpha1.RuleActionAllow, testIngressRuleName) anp1 = builder1.Get() anp1, err1 := k8sUtils.CreateOrUpdateANP(anp1) @@ -940,10 +1169,10 @@ func deployAntreaNetworkPolicies(t *testing.T, data *TestData, srcPod, dstPod st builder2 := &utils.AntreaNetworkPolicySpecBuilder{} // apply anp to srcPod, allow egress to dstPod - builder2 = builder2.SetName(testNamespace, egressAntreaNetworkPolicyName). + builder2 = builder2.SetName(data.testNamespace, egressAntreaNetworkPolicyName). SetPriority(2.0). SetAppliedToGroup([]utils.ANPAppliedToSpec{{PodSelector: map[string]string{"antrea-e2e": srcPod}}}) - builder2 = builder2.AddEgress(corev1.ProtocolTCP, nil, nil, nil, nil, map[string]string{"antrea-e2e": dstPod}, map[string]string{}, + builder2 = builder2.AddEgress(utils.ProtocolTCP, nil, nil, nil, nil, nil, nil, map[string]string{"antrea-e2e": dstPod}, map[string]string{}, nil, nil, nil, secv1alpha1.RuleActionAllow, testEgressRuleName) anp2 = builder2.Get() anp2, err2 := k8sUtils.CreateOrUpdateANP(anp2) @@ -965,27 +1194,27 @@ func deployDenyAntreaNetworkPolicies(t *testing.T, data *TestData, srcPod, podRe builder2 := &utils.AntreaNetworkPolicySpecBuilder{} if isIngress { // apply reject and drop ingress rule to destination pods - builder1 = builder1.SetName(testNamespace, ingressRejectANPName). + builder1 = builder1.SetName(data.testNamespace, ingressRejectANPName). SetPriority(2.0). SetAppliedToGroup([]utils.ANPAppliedToSpec{{PodSelector: map[string]string{"antrea-e2e": podReject}}}) - builder1 = builder1.AddIngress(corev1.ProtocolTCP, nil, nil, nil, nil, map[string]string{"antrea-e2e": srcPod}, map[string]string{}, + builder1 = builder1.AddIngress(utils.ProtocolTCP, nil, nil, nil, nil, nil, nil, map[string]string{"antrea-e2e": srcPod}, map[string]string{}, nil, nil, nil, secv1alpha1.RuleActionReject, testIngressRuleName) - builder2 = builder2.SetName(testNamespace, ingressDropANPName). + builder2 = builder2.SetName(data.testNamespace, ingressDropANPName). SetPriority(2.0). SetAppliedToGroup([]utils.ANPAppliedToSpec{{PodSelector: map[string]string{"antrea-e2e": podDrop}}}) - builder2 = builder2.AddIngress(corev1.ProtocolTCP, nil, nil, nil, nil, map[string]string{"antrea-e2e": srcPod}, map[string]string{}, + builder2 = builder2.AddIngress(utils.ProtocolTCP, nil, nil, nil, nil, nil, nil, map[string]string{"antrea-e2e": srcPod}, map[string]string{}, nil, nil, nil, secv1alpha1.RuleActionDrop, testIngressRuleName) } else { // apply reject and drop egress rule to source pod - builder1 = builder1.SetName(testNamespace, egressRejectANPName). + builder1 = builder1.SetName(data.testNamespace, egressRejectANPName). SetPriority(2.0). SetAppliedToGroup([]utils.ANPAppliedToSpec{{PodSelector: map[string]string{"antrea-e2e": srcPod}}}) - builder1 = builder1.AddEgress(corev1.ProtocolTCP, nil, nil, nil, nil, map[string]string{"antrea-e2e": podReject}, map[string]string{}, + builder1 = builder1.AddEgress(utils.ProtocolTCP, nil, nil, nil, nil, nil, nil, map[string]string{"antrea-e2e": podReject}, map[string]string{}, nil, nil, nil, secv1alpha1.RuleActionReject, testEgressRuleName) - builder2 = builder2.SetName(testNamespace, egressDropANPName). + builder2 = builder2.SetName(data.testNamespace, egressDropANPName). SetPriority(2.0). SetAppliedToGroup([]utils.ANPAppliedToSpec{{PodSelector: map[string]string{"antrea-e2e": srcPod}}}) - builder2 = builder2.AddEgress(corev1.ProtocolTCP, nil, nil, nil, nil, map[string]string{"antrea-e2e": podDrop}, map[string]string{}, + builder2 = builder2.AddEgress(utils.ProtocolTCP, nil, nil, nil, nil, nil, nil, map[string]string{"antrea-e2e": podDrop}, map[string]string{}, nil, nil, nil, secv1alpha1.RuleActionDrop, testEgressRuleName) } anp1 = builder1.Get() @@ -1040,42 +1269,42 @@ func deployDenyNetworkPolicies(t *testing.T, data *TestData, pod1, pod2 string) } func createPerftestPods(data *TestData) (podAIPs *PodIPs, podBIPs *PodIPs, podCIPs *PodIPs, podDIPs *PodIPs, podEIPs *PodIPs, err error) { - if err := data.createPodOnNode("perftest-a", testNamespace, controlPlaneNodeName(), perftoolImage, nil, nil, nil, nil, false, nil); err != nil { + if err := data.createPodOnNode("perftest-a", data.testNamespace, controlPlaneNodeName(), perftoolImage, nil, nil, nil, nil, false, nil); err != nil { return nil, nil, nil, nil, nil, fmt.Errorf("Error when creating the perftest client Pod: %v", err) } - podAIPs, err = data.podWaitForIPs(defaultTimeout, "perftest-a", testNamespace) + podAIPs, err = data.podWaitForIPs(defaultTimeout, "perftest-a", data.testNamespace) if err != nil { return nil, nil, nil, nil, nil, fmt.Errorf("Error when waiting for the perftest client Pod: %v", err) } - if err := data.createPodOnNode("perftest-b", testNamespace, controlPlaneNodeName(), perftoolImage, nil, nil, nil, []corev1.ContainerPort{{Protocol: corev1.ProtocolTCP, ContainerPort: iperfPort}}, false, nil); err != nil { + if err := data.createPodOnNode("perftest-b", data.testNamespace, controlPlaneNodeName(), perftoolImage, nil, nil, nil, []corev1.ContainerPort{{Protocol: corev1.ProtocolTCP, ContainerPort: iperfPort}}, false, nil); err != nil { return nil, nil, nil, nil, nil, fmt.Errorf("Error when creating the perftest server Pod: %v", err) } - podBIPs, err = data.podWaitForIPs(defaultTimeout, "perftest-b", testNamespace) + podBIPs, err = data.podWaitForIPs(defaultTimeout, "perftest-b", data.testNamespace) if err != nil { return nil, nil, nil, nil, nil, fmt.Errorf("Error when getting the perftest server Pod's IPs: %v", err) } - if err := data.createPodOnNode("perftest-c", testNamespace, workerNodeName(1), perftoolImage, nil, nil, nil, []corev1.ContainerPort{{Protocol: corev1.ProtocolTCP, ContainerPort: iperfPort}}, false, nil); err != nil { + if err := data.createPodOnNode("perftest-c", data.testNamespace, workerNodeName(1), perftoolImage, nil, nil, nil, []corev1.ContainerPort{{Protocol: corev1.ProtocolTCP, ContainerPort: iperfPort}}, false, nil); err != nil { return nil, nil, nil, nil, nil, fmt.Errorf("Error when creating the perftest server Pod: %v", err) } - podCIPs, err = data.podWaitForIPs(defaultTimeout, "perftest-c", testNamespace) + podCIPs, err = data.podWaitForIPs(defaultTimeout, "perftest-c", data.testNamespace) if err != nil { return nil, nil, nil, nil, nil, fmt.Errorf("Error when getting the perftest server Pod's IPs: %v", err) } - if err := data.createPodOnNode("perftest-d", testNamespace, controlPlaneNodeName(), perftoolImage, nil, nil, nil, []corev1.ContainerPort{{Protocol: corev1.ProtocolTCP, ContainerPort: iperfPort}}, false, nil); err != nil { + if err := data.createPodOnNode("perftest-d", data.testNamespace, controlPlaneNodeName(), perftoolImage, nil, nil, nil, []corev1.ContainerPort{{Protocol: corev1.ProtocolTCP, ContainerPort: iperfPort}}, false, nil); err != nil { return nil, nil, nil, nil, nil, fmt.Errorf("Error when creating the perftest server Pod: %v", err) } - podDIPs, err = data.podWaitForIPs(defaultTimeout, "perftest-d", testNamespace) + podDIPs, err = data.podWaitForIPs(defaultTimeout, "perftest-d", data.testNamespace) if err != nil { return nil, nil, nil, nil, nil, fmt.Errorf("Error when getting the perftest server Pod's IPs: %v", err) } - if err := data.createPodOnNode("perftest-e", testNamespace, workerNodeName(1), perftoolImage, nil, nil, nil, []corev1.ContainerPort{{Protocol: corev1.ProtocolTCP, ContainerPort: iperfPort}}, false, nil); err != nil { + if err := data.createPodOnNode("perftest-e", data.testNamespace, workerNodeName(1), perftoolImage, nil, nil, nil, []corev1.ContainerPort{{Protocol: corev1.ProtocolTCP, ContainerPort: iperfPort}}, false, nil); err != nil { return nil, nil, nil, nil, nil, fmt.Errorf("Error when creating the perftest server Pod: %v", err) } - podEIPs, err = data.podWaitForIPs(defaultTimeout, "perftest-e", testNamespace) + podEIPs, err = data.podWaitForIPs(defaultTimeout, "perftest-e", data.testNamespace) if err != nil { return nil, nil, nil, nil, nil, fmt.Errorf("Error when getting the perftest server Pod's IPs: %v", err) } @@ -1089,12 +1318,12 @@ func createPerftestServices(data *TestData, isIPv6 bool) (svcB *corev1.Service, svcIPFamily = corev1.IPv6Protocol } - svcB, err = data.CreateService("perftest-b", testNamespace, iperfPort, iperfPort, map[string]string{"antrea-e2e": "perftest-b"}, false, false, corev1.ServiceTypeClusterIP, &svcIPFamily) + svcB, err = data.CreateService("perftest-b", data.testNamespace, iperfPort, iperfPort, map[string]string{"antrea-e2e": "perftest-b"}, false, false, corev1.ServiceTypeClusterIP, &svcIPFamily) if err != nil { return nil, nil, fmt.Errorf("Error when creating perftest-b Service: %v", err) } - svcC, err = data.CreateService("perftest-c", testNamespace, iperfPort, iperfPort, map[string]string{"antrea-e2e": "perftest-c"}, false, false, corev1.ServiceTypeClusterIP, &svcIPFamily) + svcC, err = data.CreateService("perftest-c", data.testNamespace, iperfPort, iperfPort, map[string]string{"antrea-e2e": "perftest-c"}, false, false, corev1.ServiceTypeClusterIP, &svcIPFamily) if err != nil { return nil, nil, fmt.Errorf("Error when creating perftest-c Service: %v", err) } @@ -1104,7 +1333,7 @@ func createPerftestServices(data *TestData, isIPv6 bool) (svcB *corev1.Service, func deletePerftestServices(t *testing.T, data *TestData) { for _, serviceName := range []string{"perftest-b", "perftest-c"} { - err := data.deleteService(testNamespace, serviceName) + err := data.deleteService(data.testNamespace, serviceName) if err != nil { t.Logf("Error when deleting %s Service: %v", serviceName, err) } @@ -1147,3 +1376,55 @@ func matchSrcAndDstAddress(srcIP string, dstIP string, isDstService bool, isIPv6 } return srcField, dstField } + +type ClickHouseFullRow struct { + TimeInserted time.Time `json:"timeInserted"` + FlowStartSeconds time.Time `json:"flowStartSeconds"` + FlowEndSeconds time.Time `json:"flowEndSeconds"` + FlowEndSecondsFromSourceNode time.Time `json:"flowEndSecondsFromSourceNode"` + FlowEndSecondsFromDestinationNode time.Time `json:"flowEndSecondsFromDestinationNode"` + FlowEndReason uint8 `json:"flowEndReason"` + SourceIP string `json:"sourceIP"` + DestinationIP string `json:"destinationIP"` + SourceTransportPort uint16 `json:"sourceTransportPort"` + DestinationTransportPort uint16 `json:"destinationTransportPort"` + ProtocolIdentifier uint8 `json:"protocolIdentifier"` + PacketTotalCount uint64 `json:"packetTotalCount,string"` + OctetTotalCount uint64 `json:"octetTotalCount,string"` + PacketDeltaCount uint64 `json:"packetDeltaCount,string"` + OctetDeltaCount uint64 `json:"octetDeltaCount,string"` + ReversePacketTotalCount uint64 `json:"reversePacketTotalCount,string"` + ReverseOctetTotalCount uint64 `json:"reverseOctetTotalCount,string"` + ReversePacketDeltaCount uint64 `json:"reversePacketDeltaCount,string"` + ReverseOctetDeltaCount uint64 `json:"reverseOctetDeltaCount,string"` + SourcePodName string `json:"sourcePodName"` + SourcePodNamespace string `json:"sourcePodNamespace"` + SourceNodeName string `json:"sourceNodeName"` + DestinationPodName string `json:"destinationPodName"` + DestinationPodNamespace string `json:"destinationPodNamespace"` + DestinationNodeName string `json:"destinationNodeName"` + DestinationClusterIP string `json:"destinationClusterIP"` + DestinationServicePort uint16 `json:"destinationServicePort"` + DestinationServicePortName string `json:"destinationServicePortName"` + IngressNetworkPolicyName string `json:"ingressNetworkPolicyName"` + IngressNetworkPolicyNamespace string `json:"ingressNetworkPolicyNamespace"` + IngressNetworkPolicyRuleName string `json:"ingressNetworkPolicyRuleName"` + IngressNetworkPolicyRuleAction uint8 `json:"ingressNetworkPolicyRuleAction"` + IngressNetworkPolicyType uint8 `json:"ingressNetworkPolicyType"` + EgressNetworkPolicyName string `json:"egressNetworkPolicyName"` + EgressNetworkPolicyNamespace string `json:"egressNetworkPolicyNamespace"` + EgressNetworkPolicyRuleName string `json:"egressNetworkPolicyRuleName"` + EgressNetworkPolicyRuleAction uint8 `json:"egressNetworkPolicyRuleAction"` + EgressNetworkPolicyType uint8 `json:"egressNetworkPolicyType"` + TcpState string `json:"tcpState"` + FlowType uint8 `json:"flowType"` + SourcePodLabels string `json:"sourcePodLabels"` + DestinationPodLabels string `json:"destinationPodLabels"` + Throughput uint64 `json:"throughput,string"` + ReverseThroughput uint64 `json:"reverseThroughput,string"` + ThroughputFromSourceNode uint64 `json:"throughputFromSourceNode,string"` + ThroughputFromDestinationNode uint64 `json:"throughputFromDestinationNode,string"` + ReverseThroughputFromSourceNode uint64 `json:"reverseThroughputFromSourceNode,string"` + ReverseThroughputFromDestinationNode uint64 `json:"reverseThroughputFromDestinationNode,string"` + Trusted uint8 `json:"trusted"` +} diff --git a/test/e2e/framework.go b/test/e2e/framework.go index 828f79b582f..f592ed82bf8 100644 --- a/test/e2e/framework.go +++ b/test/e2e/framework.go @@ -76,13 +76,13 @@ const ( kubeNamespace string = "kube-system" flowAggregatorNamespace string = "flow-aggregator" antreaConfigVolume string = "antrea-config" + antreaWindowsConfigVolume string = "antrea-windows-config" flowAggregatorConfigVolume string = "flow-aggregator-config" antreaDaemonSet string = "antrea-agent" antreaWindowsDaemonSet string = "antrea-agent-windows" antreaDeployment string = "antrea-controller" flowAggregatorDeployment string = "flow-aggregator" antreaDefaultGW string = "antrea-gw0" - testNamespace string = "antrea-test" testAntreaIPAMNamespace string = "antrea-ipam-test" testAntreaIPAMNamespace11 string = "antrea-ipam-test-11" testAntreaIPAMNamespace12 string = "antrea-ipam-test-12" @@ -99,6 +99,10 @@ const ( antreaIPSecCovYML string = "antrea-ipsec-coverage.yml" flowAggregatorYML string = "flow-aggregator.yml" flowAggregatorCovYML string = "flow-aggregator-coverage.yml" + flowVisibilityYML string = "flow-visibility.yml" + chOperatorYML string = "clickhouse-operator-install-bundle.yml" + flowVisibilityCHPodName string = "chi-clickhouse-clickhouse-0-0-0" + flowVisibilityNamespace string = "flow-visibility" defaultBridgeName string = "br-int" monitoringNamespace string = "monitoring" @@ -116,20 +120,24 @@ const ( nameSuffixLength int = 8 agnhostImage = "k8s.gcr.io/e2e-test-images/agnhost:2.29" - busyboxImage = "projects.registry.vmware.com/library/busybox" + busyboxImage = "projects.registry.vmware.com/antrea/busybox" mcjoinImage = "projects.registry.vmware.com/antrea/mcjoin:v2.9" netshootImage = "projects.registry.vmware.com/antrea/netshoot:v0.1" nginxImage = "projects.registry.vmware.com/antrea/nginx:1.21.6-alpine" + iisImage = "mcr.microsoft.com/windows/servercore/iis" perftoolImage = "projects.registry.vmware.com/antrea/perftool" ipfixCollectorImage = "projects.registry.vmware.com/antrea/ipfix-collector:v0.5.12" ipfixCollectorPort = "4739" + clickHouseHTTPPort = "8123" nginxLBService = "nginx-loadbalancer" + exporterFlowPollInterval = 1 * time.Second exporterActiveFlowExportTimeout = 2 * time.Second exporterIdleFlowExportTimeout = 1 * time.Second aggregatorActiveFlowRecordTimeout = 3500 * time.Millisecond aggregatorInactiveFlowRecordTimeout = 6 * time.Second + aggregatorClickHouseCommitInterval = 1 * time.Second statefulSetRestartAnnotationKey = "antrea-e2e/restartedAt" ) @@ -180,6 +188,7 @@ type TestOptions struct { withBench bool enableCoverage bool enableAntreaIPAM bool + flowVisibility bool coverageDir string skipCases string } @@ -202,6 +211,7 @@ type TestData struct { aggregatorClient aggregatorclientset.Interface crdClient crdclientset.Interface logsDirForTestCase string + testNamespace string } var testData *TestData @@ -371,12 +381,19 @@ func labelNodeRoleControlPlane() string { return labelNodeRoleControlPlane } -func controlPlaneNoScheduleToleration() corev1.Toleration { +func controlPlaneNoScheduleTolerations() []corev1.Toleration { // the Node taint still uses "master" in K8s v1.20 - return corev1.Toleration{ - Key: "node-role.kubernetes.io/master", - Operator: corev1.TolerationOpExists, - Effect: corev1.TaintEffectNoSchedule, + return []corev1.Toleration{ + { + Key: "node-role.kubernetes.io/master", + Operator: corev1.TolerationOpExists, + Effect: corev1.TaintEffectNoSchedule, + }, + { + Key: "node-role.kubernetes.io/control-plane", + Operator: corev1.TolerationOpExists, + Effect: corev1.TaintEffectNoSchedule, + }, } } @@ -403,7 +420,21 @@ func (data *TestData) RunCommandOnNode(nodeName string, cmd string) (code int, s return data.provider.RunCommandOnNode(nodeName, cmd) } +func (data *TestData) RunCommandOnNodeExt(nodeName, cmd string, envs map[string]string, stdin string, sudo bool) ( + code int, stdout, stderr string, err error) { + return data.provider.RunCommandOnNodeExt(nodeName, cmd, envs, stdin, sudo) +} + func (data *TestData) collectClusterInfo() error { + // retrieve K8s server version + // this needs to be done first, as there may be dependencies on the + // version later in this function (e.g., for labelNodeRoleControlPlane()). + serverVersion, err := testData.clientset.Discovery().ServerVersion() + if err != nil { + return err + } + clusterInfo.k8sServerVersion = serverVersion.String() + // retrieve Node information nodes, err := testData.clientset.CoreV1().Nodes().List(context.TODO(), metav1.ListOptions{}) if err != nil { @@ -547,14 +578,6 @@ func (data *TestData) collectClusterInfo() error { clusterInfo.svcV4NetworkCIDR = svcCIDRs[0] clusterInfo.svcV6NetworkCIDR = svcCIDRs[1] - // retrieve K8s server version - - serverVersion, err := testData.clientset.Discovery().ServerVersion() - if err != nil { - return err - } - clusterInfo.k8sServerVersion = serverVersion.String() - // Retrieve kubernetes Service host and Port svc, err := testData.clientset.CoreV1().Services("default").Get(context.TODO(), "kubernetes", metav1.GetOptions{}) if err != nil { @@ -589,11 +612,6 @@ func (data *TestData) CreateNamespace(namespace string, mutateFunc func(*corev1. return nil } -// createTestNamespace creates the namespace used for tests. -func (data *TestData) createTestNamespace() error { - return data.CreateNamespace(testNamespace, nil) -} - // createNamespaceWithAnnotations creates the namespace with Annotations. func (data *TestData) createNamespaceWithAnnotations(namespace string, annotations map[string]string) error { var mutateFunc func(*corev1.Namespace) @@ -632,26 +650,8 @@ func (data *TestData) DeleteNamespace(namespace string, timeout time.Duration) e } return fmt.Errorf("error when deleting '%s' Namespace: %v", namespace, err) } - err := wait.Poll(defaultInterval, timeout, func() (bool, error) { - if ns, err := data.clientset.CoreV1().Namespaces().Get(context.TODO(), namespace, metav1.GetOptions{}); err != nil { - if errors.IsNotFound(err) { - // Success - return true, nil - } - return false, fmt.Errorf("error when getting Namespace '%s' after delete: %v", namespace, err) - } else if ns.Status.Phase != corev1.NamespaceTerminating { - return false, fmt.Errorf("deleted Namespace '%s' should be in 'Terminating' phase", namespace) - } - - // Keep trying - return false, nil - }) - return err -} -// deleteTestNamespace deletes test namespace and waits for deletion to actually complete. -func (data *TestData) deleteTestNamespace(timeout time.Duration) error { - return data.DeleteNamespace(testNamespace, timeout) + return nil } // deployAntreaCommon deploys Antrea using kubectl on the control-plane Node. @@ -689,7 +689,7 @@ func (data *TestData) enableAntreaFlowExporter(ipfixCollector string) error { // Enable flow exporter feature and add related config params to antrea agent configmap. ac := func(config *agentconfig.AgentConfig) { config.FeatureGates["FlowExporter"] = true - config.FlowPollInterval = "1s" + config.FlowPollInterval = exporterFlowPollInterval.String() config.ActiveFlowExportTimeout = exporterActiveFlowExportTimeout.String() config.IdleFlowExportTimeout = exporterIdleFlowExportTimeout.String() if ipfixCollector != "" { @@ -699,14 +699,69 @@ func (data *TestData) enableAntreaFlowExporter(ipfixCollector string) error { return data.mutateAntreaConfigMap(nil, ac, false, true) } -func (data *TestData) disableAntreaFlowExporter() error { - ac := func(config *agentconfig.AgentConfig) { - config.FeatureGates["FlowExporter"] = false +// deployFlowVisibilityClickHouse deploys ClickHouse operator and DB. +func (data *TestData) deployFlowVisibilityClickHouse() (string, error) { + err := data.CreateNamespace(flowVisibilityNamespace, nil) + if err != nil { + return "", err } - return data.mutateAntreaConfigMap(nil, ac, false, true) + + rc, _, _, err := data.provider.RunCommandOnNode(controlPlaneNodeName(), fmt.Sprintf("kubectl apply -f %s", chOperatorYML)) + if err != nil || rc != 0 { + return "", fmt.Errorf("error when deploying the ClickHouse Operator YML; %s not available on the control-plane Node", chOperatorYML) + } + if err := wait.Poll(2*time.Second, 10*time.Second, func() (bool, error) { + rc, stdout, stderr, err := data.provider.RunCommandOnNode(controlPlaneNodeName(), fmt.Sprintf("kubectl apply -f %s", flowVisibilityYML)) + if err != nil || rc != 0 { + // ClickHouseInstallation CRD from ClickHouse Operator install bundle applied soon before + // applying CR. Sometimes apiserver validation fails to recognize resource of + // kind: ClickHouseInstallation. Retry in such scenario. + if strings.Contains(stderr, "ClickHouseInstallation") || strings.Contains(stdout, "ClickHouseInstallation") { + return false, nil + } + return false, fmt.Errorf("error when deploying the flow visibility YML %s: %s, %s, %v", flowVisibilityYML, stdout, stderr, err) + } + return true, nil + }); err != nil { + return "", err + } + + // check for clickhouse pod Ready. Wait for 2x timeout as ch operator needs to be running first to handle chi + if err = data.podWaitForReady(2*defaultTimeout, flowVisibilityCHPodName, flowVisibilityNamespace); err != nil { + return "", err + } + + // check clickhouse service http port for service connectivity + chSvc, err := data.GetService("flow-visibility", "clickhouse-clickhouse") + if err != nil { + return "", err + } + if err := wait.PollImmediate(defaultInterval, defaultTimeout, func() (bool, error) { + rc, stdout, stderr, err := testData.RunCommandOnNode(controlPlaneNodeName(), + fmt.Sprintf("curl -Ss %s:%s", chSvc.Spec.ClusterIP, clickHouseHTTPPort)) + if rc != 0 || err != nil { + log.Infof("Failed to curl clickhouse Service: %s", strings.Trim(stderr, "\n")) + return false, nil + } else { + log.Infof("Successfully curl'ed clickhouse Service: %s", strings.Trim(stdout, "\n")) + return true, nil + } + }); err != nil { + return "", fmt.Errorf("timeout checking http port connectivity of clickhouse service: %v", err) + } + + return chSvc.Spec.ClusterIP, nil +} + +func (data *TestData) deleteClickHouseOperator() error { + rc, _, _, err := data.provider.RunCommandOnNode(controlPlaneNodeName(), fmt.Sprintf("kubectl delete -f %s -n kube-system", chOperatorYML)) + if err != nil || rc != 0 { + return fmt.Errorf("error when deleting ClickHouse operator: %v", err) + } + return nil } -// deployFlowAggregator deploys the Flow Aggregator with ipfix collector address. +// deployFlowAggregator deploys the Flow Aggregator with ipfix collector and clickHouse address. func (data *TestData) deployFlowAggregator(ipfixCollector string) error { flowAggYaml := flowAggregatorYML if testOptions.enableCoverage { @@ -716,11 +771,7 @@ func (data *TestData) deployFlowAggregator(ipfixCollector string) error { if err != nil || rc != 0 { return fmt.Errorf("error when deploying the Flow Aggregator; %s not available on the control-plane Node", flowAggYaml) } - svc, err := data.clientset.CoreV1().Services(flowAggregatorNamespace).Get(context.TODO(), flowAggregatorDeployment, metav1.GetOptions{}) - if err != nil { - return fmt.Errorf("unable to get service %v: %v", flowAggregatorDeployment, err) - } - if err = data.mutateFlowAggregatorConfigMap(ipfixCollector, svc.Spec.ClusterIP); err != nil { + if err = data.mutateFlowAggregatorConfigMap(ipfixCollector); err != nil { return err } if rc, _, _, err = data.provider.RunCommandOnNode(controlPlaneNodeName(), fmt.Sprintf("kubectl -n %s rollout status deployment/%s --timeout=%v", flowAggregatorNamespace, flowAggregatorDeployment, 2*defaultTimeout)); err != nil || rc != 0 { @@ -728,10 +779,18 @@ func (data *TestData) deployFlowAggregator(ipfixCollector string) error { _, logStdout, _, _ := data.provider.RunCommandOnNode(controlPlaneNodeName(), fmt.Sprintf("kubectl -n %s logs -l app=flow-aggregator", flowAggregatorNamespace)) return fmt.Errorf("error when waiting for the Flow Aggregator rollout to complete. kubectl describe output: %s, logs: %s", stdout, logStdout) } + // Check for flow-aggregator Pod running again for db connection establishment + flowAggPod, err := data.getFlowAggregator() + if err != nil { + return fmt.Errorf("error when getting flow-aggregator Pod: %v", err) + } + if err = data.podWaitForReady(2*defaultTimeout, flowAggPod.Name, flowAggregatorNamespace); err != nil { + return err + } return nil } -func (data *TestData) mutateFlowAggregatorConfigMap(ipfixCollector string, faClusterIP string) error { +func (data *TestData) mutateFlowAggregatorConfigMap(ipfixCollectorAddr string) error { configMap, err := data.GetFlowAggregatorConfigMap() if err != nil { return err @@ -744,7 +803,11 @@ func (data *TestData) mutateFlowAggregatorConfigMap(ipfixCollector string, faClu flowAggregatorConf.FlowCollector = flowaggregatorconfig.FlowCollectorConfig{ Enable: true, - Address: ipfixCollector, + Address: ipfixCollectorAddr, + } + flowAggregatorConf.ClickHouse = flowaggregatorconfig.ClickHouseConfig{ + Enable: true, + CommitInterval: aggregatorClickHouseCommitInterval.String(), } flowAggregatorConf.ActiveFlowRecordTimeout = aggregatorActiveFlowRecordTimeout.String() flowAggregatorConf.InactiveFlowRecordTimeout = aggregatorInactiveFlowRecordTimeout.String() @@ -1042,8 +1105,7 @@ func (data *TestData) CreatePodOnNodeInNamespace(name, ns string, nodeName, ctrN } if nodeName == controlPlaneNodeName() { // tolerate NoSchedule taint if we want Pod to run on control-plane Node - noScheduleToleration := controlPlaneNoScheduleToleration() - podSpec.Tolerations = []corev1.Toleration{noScheduleToleration} + podSpec.Tolerations = controlPlaneNoScheduleTolerations() } pod := &corev1.Pod{ ObjectMeta: metav1.ObjectMeta{ @@ -1080,21 +1142,28 @@ func (data *TestData) createMcJoinPodOnNode(name string, ns string, nodeName str // createNetshootPodOnNode creates a Pod in the test namespace with a single netshoot container. The // Pod will be scheduled on the specified Node (if nodeName is not empty). -func (data *TestData) createNetshootPodOnNode(name string, ns string, nodeName string, _ bool) error { +func (data *TestData) createNetshootPodOnNode(name string, ns string, nodeName string, hostNetwork bool) error { sleepDuration := 3600 // seconds - return data.createPodOnNode(name, ns, nodeName, netshootImage, []string{"sleep", strconv.Itoa(sleepDuration)}, nil, nil, nil, true, nil) + return data.createPodOnNode(name, ns, nodeName, netshootImage, []string{"sleep", strconv.Itoa(sleepDuration)}, nil, nil, nil, hostNetwork, nil) } // createNginxPodOnNode creates a Pod in the test namespace with a single nginx container. The // Pod will be scheduled on the specified Node (if nodeName is not empty). func (data *TestData) createNginxPodOnNode(name string, ns string, nodeName string, hostNetwork bool) error { + var mutateImage func(*corev1.Pod) + mutateImage = nil + if clusterInfo.nodesOS[nodeName] == "windows" { + mutateImage = func(pod *corev1.Pod) { + pod.Spec.Containers[0].Image = iisImage + } + } return data.createPodOnNode(name, ns, nodeName, nginxImage, []string{}, nil, nil, []corev1.ContainerPort{ { Name: "http", ContainerPort: 80, Protocol: corev1.ProtocolTCP, }, - }, hostNetwork, nil) + }, hostNetwork, mutateImage) } // createServerPod creates a Pod that can listen to specified port and have named port set. @@ -1195,6 +1264,20 @@ func (data *TestData) podWaitForRunning(timeout time.Duration, name, namespace s return err } +// podWaitForReady polls the k8s apiserver until the specified Pod is in the "Ready" status (or +// until the provided timeout expires). +func (data *TestData) podWaitForReady(timeout time.Duration, name, namespace string) error { + _, err := data.PodWaitFor(timeout, name, namespace, func(p *corev1.Pod) (bool, error) { + for _, condition := range p.Status.Conditions { + if condition.Type == corev1.PodReady { + return condition.Status == corev1.ConditionTrue, nil + } + } + return false, nil + }) + return err +} + // podWaitForIPs polls the K8s apiserver until the specified Pod is in the "running" state (or until // the provided timeout expires). The function then returns the IP addresses assigned to the Pod. If the // Pod is not using "hostNetwork", the function also checks that an IP address exists in each required @@ -1508,7 +1591,7 @@ func (data *TestData) CreateServiceWithAnnotations(serviceName, namespace string // createNginxClusterIPServiceWithAnnotations creates nginx service with Annotation func (data *TestData) createNginxClusterIPServiceWithAnnotations(affinity bool, ipFamily *corev1.IPFamily, annotation map[string]string) (*corev1.Service, error) { - return data.CreateServiceWithAnnotations("nginx", testNamespace, 80, 80, corev1.ProtocolTCP, map[string]string{"app": "nginx"}, affinity, false, corev1.ServiceTypeClusterIP, ipFamily, annotation) + return data.CreateServiceWithAnnotations("nginx", data.testNamespace, 80, 80, corev1.ProtocolTCP, map[string]string{"app": "nginx"}, affinity, false, corev1.ServiceTypeClusterIP, ipFamily, annotation) } // createNginxClusterIPService creates a nginx service with the given name. @@ -1521,21 +1604,21 @@ func (data *TestData) createNginxClusterIPService(name, namespace string, affini // createAgnhostClusterIPService creates a ClusterIP agnhost service with the given name. func (data *TestData) createAgnhostClusterIPService(serviceName string, affinity bool, ipFamily *corev1.IPFamily) (*corev1.Service, error) { - return data.CreateService(serviceName, testNamespace, 8080, 8080, map[string]string{"app": "agnhost"}, affinity, false, corev1.ServiceTypeClusterIP, ipFamily) + return data.CreateService(serviceName, data.testNamespace, 8080, 8080, map[string]string{"app": "agnhost"}, affinity, false, corev1.ServiceTypeClusterIP, ipFamily) } // createAgnhostNodePortService creates a NodePort agnhost service with the given name. func (data *TestData) createAgnhostNodePortService(serviceName string, affinity, nodeLocalExternal bool, ipFamily *corev1.IPFamily) (*corev1.Service, error) { - return data.CreateService(serviceName, testNamespace, 8080, 8080, map[string]string{"app": "agnhost"}, affinity, nodeLocalExternal, corev1.ServiceTypeNodePort, ipFamily) + return data.CreateService(serviceName, data.testNamespace, 8080, 8080, map[string]string{"app": "agnhost"}, affinity, nodeLocalExternal, corev1.ServiceTypeNodePort, ipFamily) } // createNginxNodePortService creates a NodePort nginx service with the given name. func (data *TestData) createNginxNodePortService(serviceName string, affinity, nodeLocalExternal bool, ipFamily *corev1.IPFamily) (*corev1.Service, error) { - return data.CreateService(serviceName, testNamespace, 80, 80, map[string]string{"app": "nginx"}, affinity, nodeLocalExternal, corev1.ServiceTypeNodePort, ipFamily) + return data.CreateService(serviceName, data.testNamespace, 80, 80, map[string]string{"app": "nginx"}, affinity, nodeLocalExternal, corev1.ServiceTypeNodePort, ipFamily) } func (data *TestData) updateServiceExternalTrafficPolicy(serviceName string, nodeLocalExternal bool) (*corev1.Service, error) { - svc, err := data.clientset.CoreV1().Services(testNamespace).Get(context.TODO(), serviceName, metav1.GetOptions{}) + svc, err := data.clientset.CoreV1().Services(data.testNamespace).Get(context.TODO(), serviceName, metav1.GetOptions{}) if err != nil { return svc, err } @@ -1545,12 +1628,12 @@ func (data *TestData) updateServiceExternalTrafficPolicy(serviceName string, nod svc.Spec.ExternalTrafficPolicy = corev1.ServiceExternalTrafficPolicyTypeCluster } - return data.clientset.CoreV1().Services(testNamespace).Update(context.TODO(), svc, metav1.UpdateOptions{}) + return data.clientset.CoreV1().Services(data.testNamespace).Update(context.TODO(), svc, metav1.UpdateOptions{}) } // createAgnhostLoadBalancerService creates a LoadBalancer agnhost service with the given name. func (data *TestData) createAgnhostLoadBalancerService(serviceName string, affinity, nodeLocalExternal bool, ingressIPs []string, ipFamily *corev1.IPFamily) (*corev1.Service, error) { - svc, err := data.CreateService(serviceName, testNamespace, 8080, 8080, map[string]string{"app": "agnhost"}, affinity, nodeLocalExternal, corev1.ServiceTypeLoadBalancer, ipFamily) + svc, err := data.CreateService(serviceName, data.testNamespace, 8080, 8080, map[string]string{"app": "agnhost"}, affinity, nodeLocalExternal, corev1.ServiceTypeLoadBalancer, ipFamily) if err != nil { return svc, err } @@ -1569,7 +1652,7 @@ func (data *TestData) createAgnhostLoadBalancerService(serviceName string, affin } func (data *TestData) createNginxLoadBalancerService(affinity bool, ingressIPs []string, ipFamily *corev1.IPFamily) (*corev1.Service, error) { - svc, err := data.CreateService(nginxLBService, testNamespace, 80, 80, map[string]string{"app": "nginx"}, affinity, false, corev1.ServiceTypeLoadBalancer, ipFamily) + svc, err := data.CreateService(nginxLBService, data.testNamespace, 80, 80, map[string]string{"app": "nginx"}, affinity, false, corev1.ServiceTypeLoadBalancer, ipFamily) if err != nil { return svc, err } @@ -1627,7 +1710,7 @@ func (data *TestData) createNetworkPolicy(name string, spec *networkingv1.Networ }, Spec: *spec, } - return data.clientset.NetworkingV1().NetworkPolicies(testNamespace).Create(context.TODO(), policy, metav1.CreateOptions{}) + return data.clientset.NetworkingV1().NetworkPolicies(data.testNamespace).Create(context.TODO(), policy, metav1.CreateOptions{}) } // deleteNetworkpolicy deletes the network policy. @@ -1651,6 +1734,7 @@ func randSeq(n int) string { return string(b) } +// randName generates a DNS-1123 subdomain name func randName(prefix string) string { return prefix + randSeq(nameSuffixLength) } @@ -1770,10 +1854,10 @@ func (data *TestData) runPingCommandFromTestPod(podInfo podInfo, ns string, targ } func (data *TestData) runNetcatCommandFromTestPod(podName string, ns string, server string, port int32) error { - return data.runNetcatCommandFromTestPodWithProtocol(podName, ns, server, port, "tcp") + return data.runNetcatCommandFromTestPodWithProtocol(podName, ns, busyboxContainerName, server, port, "tcp") } -func (data *TestData) runNetcatCommandFromTestPodWithProtocol(podName string, ns string, server string, port int32, protocol string) error { +func (data *TestData) runNetcatCommandFromTestPodWithProtocol(podName string, ns string, containerName string, server string, port int32, protocol string) error { // No parameter required for TCP connections. protocolOption := "" if protocol == "udp" { @@ -1787,7 +1871,7 @@ func (data *TestData) runNetcatCommandFromTestPodWithProtocol(podName string, ns protocolOption, server, port), } - stdout, stderr, err := data.RunCommandFromPod(ns, podName, busyboxContainerName, cmd) + stdout, stderr, err := data.RunCommandFromPod(ns, podName, containerName, cmd) if err == nil { return nil } @@ -1833,34 +1917,37 @@ func (data *TestData) doesOVSPortExistOnWindows(nodeName, portName string) (bool return false, fmt.Errorf("error when running ovs-vsctl command on Windows Node '%s': %v", nodeName, err) } -func (data *TestData) GetEncapMode() (config.TrafficEncapModeType, error) { +func (data *TestData) GetAntreaAgentConf() (*agentconfig.AgentConfig, error) { configMap, err := data.GetAntreaConfigMap(antreaNamespace) if err != nil { - return config.TrafficEncapModeInvalid, fmt.Errorf("failed to get Antrea ConfigMap: %v", err) + return nil, err } - for _, antreaConfig := range configMap.Data { - for _, mode := range config.GetTrafficEncapModes() { - searchStr := fmt.Sprintf("trafficEncapMode: %s", mode) - if strings.Index(strings.ToLower(antreaConfig), strings.ToLower(searchStr)) != -1 { - return mode, nil - } - } + var agentConf agentconfig.AgentConfig + if err := yaml.Unmarshal([]byte(configMap.Data["antrea-agent.conf"]), &agentConf); err != nil { + return nil, fmt.Errorf("failed to unmarshal Agent config from ConfigMap: %v", err) } - return config.TrafficEncapModeEncap, nil + return &agentConf, nil } -func (data *TestData) isProxyAll() (bool, error) { - configMap, err := data.GetAntreaConfigMap(antreaNamespace) +func (data *TestData) GetEncapMode() (config.TrafficEncapModeType, error) { + agentConf, err := data.GetAntreaAgentConf() if err != nil { - return false, fmt.Errorf("failed to get Antrea ConfigMap: %v", err) + return config.TrafficEncapModeInvalid, fmt.Errorf("failed to get Antrea Agent config: %w", err) } - for _, antreaConfig := range configMap.Data { - searchStr := "proxyAll: true" - if strings.Index(strings.ToLower(antreaConfig), strings.ToLower(searchStr)) != -1 { - return true, nil - } + if agentConf.TrafficEncapMode == "" { + // default encap mode + return config.TrafficEncapModeEncap, nil } - return false, nil + _, encapMode := config.GetTrafficEncapModeFromStr(agentConf.TrafficEncapMode) + return encapMode, nil +} + +func (data *TestData) isProxyAll() (bool, error) { + agentConf, err := data.GetAntreaAgentConf() + if err != nil { + return false, fmt.Errorf("failed to get Antrea Agent config: %w", err) + } + return agentConf.AntreaProxy.ProxyAll, nil } func getFeatures(confName string) (featuregate.FeatureGate, error) { @@ -1891,6 +1978,28 @@ func GetControllerFeatures() (featuregate.FeatureGate, error) { return getFeatures(antreaControllerConfName) } +func (data *TestData) GetAntreaWindowsConfigMap(antreaNamespace string) (*corev1.ConfigMap, error) { + daemonset, err := data.clientset.AppsV1().DaemonSets(antreaNamespace).Get(context.TODO(), antreaWindowsDaemonSet, metav1.GetOptions{}) + if err != nil { + return nil, fmt.Errorf("failed to retrieve Antrea Windows DaemonSet: %v", err) + } + var configMapName string + for _, volume := range daemonset.Spec.Template.Spec.Volumes { + if volume.ConfigMap != nil && volume.Name == antreaWindowsConfigVolume { + configMapName = volume.ConfigMap.Name + break + } + } + if len(configMapName) == 0 { + return nil, fmt.Errorf("failed to locate Windows %s ConfigMap volume", antreaWindowsConfigVolume) + } + configMap, err := data.clientset.CoreV1().ConfigMaps(antreaNamespace).Get(context.TODO(), configMapName, metav1.GetOptions{}) + if err != nil { + return nil, fmt.Errorf("failed to get Windows ConfigMap %s: %v", configMapName, err) + } + return configMap, nil +} + func (data *TestData) GetAntreaConfigMap(antreaNamespace string) (*corev1.ConfigMap, error) { deployment, err := data.clientset.AppsV1().Deployments(antreaNamespace).Get(context.TODO(), antreaDeployment, metav1.GetOptions{}) if err != nil { @@ -1942,7 +2051,7 @@ func (data *TestData) GetMulticastInterfaces(antreaNamespace string) ([]string, if err != nil { return []string{}, err } - return agentConf.MulticastInterfaces, nil + return agentConf.Multicast.MulticastInterfaces, nil } func GetTransportInterface(data *TestData) (string, error) { @@ -1963,6 +2072,16 @@ func (data *TestData) mutateAntreaConfigMap( restartController bool, restartAgent bool, ) error { + includeWindowsAgent := false + var antreaWindowsConfigMap *corev1.ConfigMap + if len(clusterInfo.windowsNodes) != 0 { + var err error + includeWindowsAgent = true + antreaWindowsConfigMap, err = data.GetAntreaWindowsConfigMap(antreaNamespace) + if err != nil { + return err + } + } configMap, err := data.GetAntreaConfigMap(antreaNamespace) if err != nil { return err @@ -2004,10 +2123,10 @@ func (data *TestData) mutateAntreaConfigMap( } configMap.Data["antrea-controller.conf"] = string(b) } - - getAgentConf := func() (*agentconfig.AgentConfig, error) { + //getAgentConf should be able to process both windows and linux configmap. + getAgentConf := func(cm *corev1.ConfigMap) (*agentconfig.AgentConfig, error) { var agentConf agentconfig.AgentConfig - if err := yaml.Unmarshal([]byte(configMap.Data["antrea-agent.conf"]), &agentConf); err != nil { + if err := yaml.Unmarshal([]byte(cm.Data["antrea-agent.conf"]), &agentConf); err != nil { return nil, fmt.Errorf("failed to unmarshal Agent config from ConfigMap: %v", err) } // as a convenience, we initialize the FeatureGates map if it is nil @@ -2018,24 +2137,30 @@ func (data *TestData) mutateAntreaConfigMap( } agentConfChanged := false + agentConfigMaps := []*corev1.ConfigMap{configMap} if agentChanges != nil { - agentConfIn, err := getAgentConf() - if err != nil { - return err - } - agentConfOut, err := getAgentConf() - if err != nil { - return err + if includeWindowsAgent { + agentConfigMaps = append(agentConfigMaps, antreaWindowsConfigMap) } + for _, cm := range agentConfigMaps { + agentConfIn, err := getAgentConf(cm) + if err != nil { + return err + } + agentConfOut, err := getAgentConf(cm) + if err != nil { + return err + } - agentChanges(agentConfOut) - agentConfChanged = !reflect.DeepEqual(agentConfIn, agentConfOut) + agentChanges(agentConfOut) + agentConfChanged = !reflect.DeepEqual(agentConfIn, agentConfOut) - b, err := yaml.Marshal(agentConfOut) - if err != nil { - return fmt.Errorf("failed to marshal Agent config: %v", err) + b, err := yaml.Marshal(agentConfOut) + if err != nil { + return fmt.Errorf("failed to marshal Agent config: %v", err) + } + cm.Data["antrea-agent.conf"] = string(b) } - configMap.Data["antrea-agent.conf"] = string(b) } if !agentConfChanged && !controllerConfChanged { @@ -2043,9 +2168,12 @@ func (data *TestData) mutateAntreaConfigMap( return nil } - if _, err := data.clientset.CoreV1().ConfigMaps(antreaNamespace).Update(context.TODO(), configMap, metav1.UpdateOptions{}); err != nil { - return fmt.Errorf("failed to update ConfigMap %s: %v", configMap.Name, err) + for _, cm := range agentConfigMaps { + if _, err := data.clientset.CoreV1().ConfigMaps(antreaNamespace).Update(context.TODO(), cm, metav1.UpdateOptions{}); err != nil { + return fmt.Errorf("failed to update ConfigMap %s: %v", cm.Name, err) + } } + if restartAgent && agentConfChanged { err = data.restartAntreaAgentPods(defaultTimeout) if err != nil { @@ -2062,35 +2190,47 @@ func (data *TestData) mutateAntreaConfigMap( return nil } -// gracefulExitAntreaController copies the Antrea controller binary coverage data file out before terminating the Pod -func (data *TestData) gracefulExitAntreaController(covDir string) error { - antreaController, err := data.getAntreaController() - if err != nil { - return fmt.Errorf("error when getting antrea-controller Pod: %v", err) +func (data *TestData) killProcessAndCollectCovFiles(namespace, podName, containerName, processName, covFile, covDir string) error { + if err := data.collectAntctlCovFiles(podName, containerName, namespace, covDir); err != nil { + return fmt.Errorf("error when copying antctl coverage files out: %v", err) } - podName := antreaController.Name - - err = data.collectAntctlCovFiles(podName, "antrea-controller", antreaNamespace, covDir) + cmds := []string{"pgrep", "-f", processName, "-P", "1"} + stdout, stderr, err := data.RunCommandFromPod(namespace, podName, containerName, cmds) if err != nil { - return fmt.Errorf("error when graceful exit Antrea controller - copy antctl coverage files out: %v", err) + return fmt.Errorf("error when getting pid of '%s', stderr: <%v>, err: <%v>", processName, stderr, err) } - - cmds := []string{"pgrep", "-f", antreaControllerCovBinary, "-P", "1"} - stdout, stderr, err := data.RunCommandFromPod(antreaNamespace, podName, "antrea-controller", cmds) + cmds = []string{"kill", "-SIGINT", strings.TrimSpace(stdout)} + log.Infof("Sending SIGINT to '%s'", processName) + _, stderr, err = data.RunCommandFromPod(namespace, podName, containerName, cmds) if err != nil { - return fmt.Errorf("error when getting pid of '%s', stderr: <%v>, err: <%v>", antreaControllerCovBinary, stderr, err) + return fmt.Errorf("error when sending SIGINT signal to '%s', stderr: <%v>, err: <%v>", processName, stderr, err) } - cmds = []string{"kill", "-SIGINT", strings.TrimSpace(stdout)} - _, stderr, err = data.RunCommandFromPod(antreaNamespace, podName, "antrea-controller", cmds) - if err != nil { - return fmt.Errorf("error when sending SIGINT signal to '%s', stderr: <%v>, err: <%v>", antreaControllerCovBinary, stderr, err) + log.Infof("Copying coverage files from Pod '%s'", podName) + if err := wait.PollImmediate(1*time.Second, 5*time.Second, func() (bool, error) { + if err = data.copyPodFiles(podName, containerName, namespace, covFile, covDir); err != nil { + log.Infof("Coverage file not available yet for copy: %v", err) + return false, nil + } + return true, nil + }); err != nil { + return fmt.Errorf("timeout when waiting for coverage file") } - err = data.copyPodFiles(podName, "antrea-controller", antreaNamespace, antreaControllerCovFile, covDir) + return nil +} + +// gracefulExitAntreaController copies the Antrea controller binary coverage data file out before terminating the Pod +func (data *TestData) gracefulExitAntreaController(covDir string) error { + antreaController, err := data.getAntreaController() if err != nil { - return fmt.Errorf("error when graceful exit Antrea controller - copy antrea-controller coverage files out: %v", err) + return fmt.Errorf("error when getting antrea-controller Pod: %w", err) + } + podName := antreaController.Name + + if err := data.killProcessAndCollectCovFiles(antreaNamespace, podName, "antrea-controller", antreaControllerCovBinary, antreaControllerCovFile, covDir); err != nil { + return fmt.Errorf("error when gracefully exiting Antrea Controller: %w", err) } return nil @@ -2111,26 +2251,8 @@ func (data *TestData) gracefulExitAntreaAgent(covDir string, nodeName string) er } for _, pod := range pods.Items { podName := pod.Name - err := data.collectAntctlCovFiles(podName, "antrea-agent", antreaNamespace, covDir) - - if err != nil { - return fmt.Errorf("error when graceful exit Antrea agent - copy antctl coverage files out: %v", err) - } - - cmds := []string{"pgrep", "-f", antreaAgentCovBinary, "-P", "1"} - stdout, stderr, err := data.RunCommandFromPod(antreaNamespace, podName, "antrea-agent", cmds) - if err != nil { - return fmt.Errorf("error when getting pid of '%s', stderr: <%v>, err: <%v>", antreaAgentCovBinary, stderr, err) - } - cmds = []string{"kill", "-SIGINT", strings.TrimSpace(stdout)} - _, stderr, err = data.RunCommandFromPod(antreaNamespace, podName, "antrea-agent", cmds) - if err != nil { - return fmt.Errorf("error when sending SIGINT signal to '%s', stderr: <%v>, err: <%v>", antreaAgentCovBinary, stderr, err) - } - err = data.copyPodFiles(podName, "antrea-agent", antreaNamespace, antreaAgentCovFile, covDir) - - if err != nil { - return fmt.Errorf("error when graceful exit Antrea agent - copy antrea-agent coverage files out: %v", err) + if err := data.killProcessAndCollectCovFiles(antreaNamespace, podName, "antrea-agent", antreaAgentCovBinary, antreaAgentCovFile, covDir); err != nil { + return fmt.Errorf("error when gracefully exiting Antrea Agent: %w", err) } } return nil @@ -2144,18 +2266,8 @@ func (data *TestData) gracefulExitFlowAggregator(covDir string) error { } podName := flowAggPod.Name - cmds := []string{"pgrep", "-f", flowAggregatorCovBinary, "-P", "1"} - stdout, stderr, err := data.RunCommandFromPod(flowAggregatorNamespace, podName, "flow-aggregator", cmds) - if err != nil { - _, describeStdout, _, _ := data.RunCommandOnNode(controlPlaneNodeName(), fmt.Sprintf("kubectl -n %s describe pod", flowAggregatorNamespace)) - return fmt.Errorf("error when getting pid of '%s', stdout: <%v>, stderr: <%v>, err: <%v>, describe stdout: <%v>", flowAggregatorCovBinary, stdout, stderr, err, describeStdout) - } - cmds = []string{"kill", "-SIGINT", strings.TrimSpace(stdout)} - if _, stderr, err = data.RunCommandFromPod(flowAggregatorNamespace, podName, "flow-aggregator", cmds); err != nil { - return fmt.Errorf("error when sending SIGINT signal to '%s', stderr: <%v>, err: <%v>", flowAggregatorCovBinary, stderr, err) - } - if err = data.copyPodFiles(podName, "flow-aggregator", flowAggregatorNamespace, flowAggregatorCovFile, covDir); err != nil { - return fmt.Errorf("error when gracefully exiting Flow Aggregator - copy flow-aggregator coverage files out: %v", err) + if err := data.killProcessAndCollectCovFiles(flowAggregatorNamespace, podName, "flow-aggregator", flowAggregatorCovBinary, flowAggregatorCovFile, covDir); err != nil { + return fmt.Errorf("error when gracefully exiting Flow Aggregator: %w", err) } return nil @@ -2213,14 +2325,14 @@ func (data *TestData) collectAntctlCovFilesFromControlPlaneNode(covDir string) e } // copyPodFiles copies file from a Pod and save it to specified directory -func (data *TestData) copyPodFiles(podName string, containerName string, nsName string, fileName string, covDir string) error { +func (data *TestData) copyPodFiles(podName string, containerName string, nsName string, fileName string, destDir string) error { // getPodWriter creates the file with name podName-fileName-suffix. It returns nil if the // file cannot be created. File must be closed by the caller. getPodWriter := func(podName, fileName, suffix string) *os.File { - covFile := filepath.Join(covDir, fmt.Sprintf("%s-%s-%s", podName, fileName, suffix)) - f, err := os.Create(covFile) + destFile := filepath.Join(destDir, fmt.Sprintf("%s-%s-%s", podName, fileName, suffix)) + f, err := os.Create(destFile) if err != nil { - _ = fmt.Errorf("error when creating coverage file '%s': %v", covFile, err) + _ = fmt.Errorf("error when creating destination file '%s': %v", destFile, err) return nil } return f @@ -2312,9 +2424,7 @@ func (data *TestData) createAgnhostPodOnNodeWithAnnotations(name string, ns stri func (data *TestData) createDaemonSet(name string, ns string, ctrName string, image string, cmd []string, args []string) (*appsv1.DaemonSet, func() error, error) { podSpec := corev1.PodSpec{ - Tolerations: []corev1.Toleration{ - controlPlaneNoScheduleToleration(), - }, + Tolerations: controlPlaneNoScheduleTolerations(), Containers: []corev1.Container{ { Name: ctrName, @@ -2386,9 +2496,7 @@ func (data *TestData) waitForDaemonSetPods(timeout time.Duration, dsName string, func (data *TestData) createStatefulSet(name string, ns string, size int32, ctrName string, image string, cmd []string, args []string, mutateFunc func(*appsv1.StatefulSet)) (*appsv1.StatefulSet, func() error, error) { podSpec := corev1.PodSpec{ - Tolerations: []corev1.Toleration{ - controlPlaneNoScheduleToleration(), - }, + Tolerations: controlPlaneNoScheduleTolerations(), Containers: []corev1.Container{ { Name: ctrName, diff --git a/test/e2e/infra/vagrant/Vagrantfile b/test/e2e/infra/vagrant/Vagrantfile index db9c7b33a04..8f087ad5cd1 100644 --- a/test/e2e/infra/vagrant/Vagrantfile +++ b/test/e2e/infra/vagrant/Vagrantfile @@ -35,11 +35,7 @@ end NODE_NETWORK_V4_PREFIX = "192.168.77." NODE_NETWORK_V6_PREFIX = "fd3b:fcf5:3e92:d732::" -if ENV['K8S_NODE_LARGE'] == "true" - MEMORY = 4096 -else - MEMORY = 2048 -end +MEMORY = 2048 KUBE_PROXY_MODE = ENV['KUBE_PROXY_MODE'] || "iptables" if KUBE_PROXY_MODE == "iptables" || KUBE_PROXY_MODE == "none" diff --git a/test/e2e/infra/vagrant/playbook/roles/control-plane/tasks/main.yml b/test/e2e/infra/vagrant/playbook/roles/control-plane/tasks/main.yml index c6e22ba55ad..d96a5191b91 100644 --- a/test/e2e/infra/vagrant/playbook/roles/control-plane/tasks/main.yml +++ b/test/e2e/infra/vagrant/playbook/roles/control-plane/tasks/main.yml @@ -46,6 +46,7 @@ dest: /home/{{ test_user }}/.kube/config owner: "{{ test_user }}" group: "{{ test_user }}" + mode: '0600' # We currently copy the kube config and join command to the host so that it can # be copied to all the worker nodes when provisioning them. An alternative is to diff --git a/test/e2e/infra/vagrant/provision.sh b/test/e2e/infra/vagrant/provision.sh index cc3592dd1aa..eb8249b1c1d 100755 --- a/test/e2e/infra/vagrant/provision.sh +++ b/test/e2e/infra/vagrant/provision.sh @@ -14,11 +14,9 @@ # limitations under the License. function usage() { - echo "Usage: provision.sh [--ip-family ] [-l|--large] [-h|--help] + echo "Usage: provision.sh [--ip-family ] [-h|--help] Provisions the Vagrant VMs. --ip-family Deploy IPv4, IPv6 or dual-stack Kubernetes cluster. - --large Deploy large vagrant VMs with 2 vCPUs and 4096MB memory. - By default, we deploy VMs with 2 vCPUs and 2048MB memory. --kube-proxy-mode Which mode to use for kube-proxy (default is iptables). Setting to 'none' will skip deploying kube-proxy." } @@ -35,10 +33,6 @@ case $key in K8S_IP_FAMILY="$2" shift 2 ;; - -l|--large) - K8S_NODE_LARGE=true - shift 1 - ;; --kube-proxy-mode) KUBE_PROXY_MODE="$2" shift 2 @@ -57,7 +51,6 @@ THIS_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" pushd $THIS_DIR -export K8S_NODE_LARGE export K8S_IP_FAMILY export KUBE_PROXY_MODE @@ -86,6 +79,7 @@ time vagrant up --provision echo "Writing Vagrant ssh config to file" vagrant ssh-config > ssh-config +chmod 0600 "$THIS_DIR/playbook/kube/config" # TODO: use Kubeconfig contexts to add new cluster to existing Kubeconfig file echo "******************************" echo "Kubeconfig file written to $THIS_DIR/playbook/kube/config" diff --git a/test/e2e/infra/vagrant/push_antrea.sh b/test/e2e/infra/vagrant/push_antrea.sh index 8ac1965bfa5..80fe5b5b2b7 100755 --- a/test/e2e/infra/vagrant/push_antrea.sh +++ b/test/e2e/infra/vagrant/push_antrea.sh @@ -19,10 +19,12 @@ function usage() { Push the latest Antrea image to all vagrant nodes and restart the Antrea daemons --prometheus Deploy Prometheus service to scrape metrics from Antrea Agents and Controllers. - --flow-collector Provide either the external IPFIX collector - address or specify 'ELK' to deploy the ELK - flow collector. The address should be given - in the format IP:port:proto. Example: 192.168.1.100:4739:udp. + --flow-collector + Provide either the external IPFIX collector + address or specify 'Grafana' to deploy the + Grafana flow collector. + The address should be given in the format IP:port:proto. + Example: 192.168.1.100:4739:udp. Please note that with this option we deploy the Flow Aggregator Service. --flow-aggregator Upload Flow Aggregator image and manifests @@ -160,29 +162,56 @@ function copyManifestToNodes() { FLOW_AGG_YML="/tmp/flow-aggregator.yml" SAVED_FLOW_AGG_IMG=/tmp/flow-aggregator.tar FLOW_AGG_IMG_NAME=projects.registry.vmware.com/antrea/flow-aggregator:latest + +CH_OPERATOR_INSTALL_BUNDLE_YML=$THIS_DIR/../../../../build/yamls/clickhouse-operator-install-bundle.yml +FLOW_VIS_YML="/tmp/flow-visibility.yml" + +# If a flow collector address is also provided, we update the Antrea +# manifest to enable FlowExporter. +if [[ $FLOW_COLLECTOR != "" ]]; then + echo "Generating manifest with FlowExporter enabled" + $THIS_DIR/../../../../hack/generate-manifest.sh --mode dev --flow-exporter > "${ANTREA_YML}" +fi + +# Push Antrea image and related manifest. +pushImgToNodes "$ANTREA_IMG_NAME" "$SAVED_ANTREA_IMG" +copyManifestToNodes "$ANTREA_YML" +copyManifestToNodes "$ANTREA_IPSEC_YML" + +# To ensure that the most recent version of Antrea (that we just pushed) will be used. +echo "Restarting Antrea DaemonSet" +ssh -F ssh-config k8s-node-control-plane kubectl -n kube-system delete all -l app=antrea +ssh -F ssh-config k8s-node-control-plane kubectl apply -f antrea.yml + +rm "${ANTREA_YML}" + +# Update aggregator manifests (to set the collector address) accordingly. if [ "$FLOW_AGGREGATOR" == "true" ]; then pushImgToNodes "$FLOW_AGG_IMG_NAME" "$SAVED_FLOW_AGG_IMG" - - # If a flow collector address is also provided, we update the Antrea - # manifest (to enable all features) and Aggregator manifests (to set the - # collector address) accordingly. if [[ $FLOW_COLLECTOR != "" ]]; then - echo "Generating manifest with all features enabled along with FlowExporter feature" - $THIS_DIR/../../../../hack/generate-manifest.sh --mode dev --all-features > "${ANTREA_YML}" - if [[ $FLOW_COLLECTOR == "ELK" ]]; then - echo "Deploy ELK flow collector" - echo "Copying ELK flow collector folder" - scp -F ssh-config -r $THIS_DIR/../../../../build/yamls/elk-flow-collector k8s-node-control-plane:~/ - echo "Done copying" - # ELK flow collector needs a few minutes (2-4 mins.) to finish its deployment, - # so the Flow Aggregator service will not send any records till then. - ssh -F ssh-config k8s-node-control-plane kubectl create namespace elk-flow-collector - ssh -F ssh-config k8s-node-control-plane kubectl create configmap logstash-configmap -n elk-flow-collector --from-file=./elk-flow-collector/logstash/ - ssh -F ssh-config k8s-node-control-plane kubectl apply -f elk-flow-collector/elk-flow-collector.yml -n elk-flow-collector - LOGSTASH_CLUSTER_IP=$(ssh -F ssh-config k8s-node-control-plane kubectl get -n elk-flow-collector svc logstash -o jsonpath='{.spec.clusterIP}') - ELK_ADDR="${LOGSTASH_CLUSTER_IP}:4739:udp" - - $THIS_DIR/../../../../hack/generate-manifest-flow-aggregator.sh --mode dev -fc $ELK_ADDR > "${FLOW_AGG_YML}" + if [[ $FLOW_COLLECTOR == "Grafana" ]]; then + echo "Deploy ClickHouse flow collector" + # Generate manifest + $THIS_DIR/../../../../hack/generate-manifest-flow-visibility.sh --mode dev > "${FLOW_VIS_YML}" + $THIS_DIR/../../../../hack/generate-manifest-flow-aggregator.sh --mode dev -ch > "${FLOW_AGG_YML}" + + # Push ClickHouse Monitor image + SAVED_CH_MONITOR_IMG=/tmp/flow-visibility-clickhouse-monitor.tar + CH_MONITOR_IMG_NAME=projects.registry.vmware.com/antrea/flow-visibility-clickhouse-monitor:latest + pushImgToNodes "$CH_MONITOR_IMG_NAME" "$SAVED_CH_MONITOR_IMG" + + # Copy manifests to nodes + copyManifestToNodes "$FLOW_VIS_YML" + copyManifestToNodes "$CH_OPERATOR_INSTALL_BUNDLE_YML" + + # Apply needed yaml files + # Grafana flow collector needs a few minutes (2-5 mins.) to finish its deployment. It depends on the wait conditions below. + ssh -F ssh-config k8s-node-control-plane kubectl apply -f clickhouse-operator-install-bundle.yml + ssh -F ssh-config k8s-node-control-plane kubectl wait --for=condition=ready pod -l app=clickhouse-operator -n kube-system --timeout=180s + ssh -F ssh-config k8s-node-control-plane kubectl apply -f flow-visibility.yml + ssh -F ssh-config k8s-node-control-plane kubectl wait --for=condition=ready pod -l app=grafana -n flow-visibility --timeout=180s + ssh -F ssh-config k8s-node-control-plane kubectl wait --for=condition=ready pod -l app=clickhouse -n flow-visibility --timeout=180s + rm "${FLOW_VIS_YML}" else $THIS_DIR/../../../../hack/generate-manifest-flow-aggregator.sh --mode dev -fc $FLOW_COLLECTOR > "${FLOW_AGG_YML}" fi @@ -200,17 +229,4 @@ if [ "$FLOW_AGGREGATOR" == "true" ]; then rm "${FLOW_AGG_YML}" fi -# Push Antrea image and related manifest. -pushImgToNodes "$ANTREA_IMG_NAME" "$SAVED_ANTREA_IMG" -copyManifestToNodes "$ANTREA_YML" -copyManifestToNodes "$ANTREA_IPSEC_YML" - -# To ensure that the most recent version of Antrea (that we just pushed) will be -# used. -echo "Restarting Antrea DaemonSet" -ssh -F ssh-config k8s-node-control-plane kubectl -n kube-system delete all -l app=antrea -ssh -F ssh-config k8s-node-control-plane kubectl apply -f antrea.yml - -rm "${ANTREA_YML}" - echo "Done!" diff --git a/test/e2e/k8s_util.go b/test/e2e/k8s_util.go index 99afdcd60d6..8e4250af97a 100644 --- a/test/e2e/k8s_util.go +++ b/test/e2e/k8s_util.go @@ -32,6 +32,7 @@ import ( crdv1alpha1 "antrea.io/antrea/pkg/apis/crd/v1alpha1" crdv1alpha2 "antrea.io/antrea/pkg/apis/crd/v1alpha2" crdv1alpha3 "antrea.io/antrea/pkg/apis/crd/v1alpha3" + "antrea.io/antrea/test/e2e/utils" ) type KubernetesUtils struct { @@ -60,7 +61,7 @@ type TestStep struct { Reachability *Reachability TestResources []metav1.Object Ports []int32 - Protocol v1.Protocol + Protocol utils.AntreaPolicyProtocol Duration time.Duration CustomProbes []*CustomProbe } @@ -120,12 +121,12 @@ func (k *KubernetesUtils) probe( dstAddr string, dstName string, port int32, - protocol v1.Protocol, + protocol utils.AntreaPolicyProtocol, ) PodConnectivityMark { - protocolStr := map[v1.Protocol]string{ - v1.ProtocolTCP: "tcp", - v1.ProtocolUDP: "udp", - v1.ProtocolSCTP: "sctp", + protocolStr := map[utils.AntreaPolicyProtocol]string{ + utils.ProtocolTCP: "tcp", + utils.ProtocolUDP: "udp", + utils.ProtocolSCTP: "sctp", } // We try to connect 3 times. This dates back to when we were using the OVS netdev datapath // for Kind clusters, as the first packet sent on a tunnel was always dropped @@ -178,11 +179,86 @@ func DecideProbeResult(stderr string, probeNum int) PodConnectivityMark { return Error } +func (k *KubernetesUtils) pingProbe( + pod *v1.Pod, + podName string, + containerName string, + dstAddr string, + dstName string, +) PodConnectivityMark { + pingCmd := fmt.Sprintf("ping -4 -c 3 -W 1 %s", dstAddr) + if strings.Contains(dstAddr, ":") { + pingCmd = fmt.Sprintf("ping -6 -c 3 -W 1 %s", dstAddr) + } + cmd := []string{ + "/bin/sh", + "-c", + pingCmd, + } + log.Tracef("Running: kubectl exec %s -c %s -n %s -- %s", pod.Name, containerName, pod.Namespace, strings.Join(cmd, " ")) + stdout, stderr, err := k.RunCommandFromPod(pod.Namespace, pod.Name, containerName, cmd) + log.Tracef("%s -> %s: error when running command: err - %v /// stdout - %s /// stderr - %s", podName, dstName, err, stdout, stderr) + return DecidePingProbeResult(stdout, 3) +} + +// DecidePingProbeResult uses the pingProbe stdout to decide the connectivity. +func DecidePingProbeResult(stdout string, probeNum int) PodConnectivityMark { + // Provide stdout example for different connectivity: + // ================== Connected stdout ================== + // PING 10.10.1.2 (10.10.1.2) 56(84) bytes of data. + // 64 bytes from 10.10.1.2: icmp_seq=1 ttl=64 time=0.695 ms + // 64 bytes from 10.10.1.2: icmp_seq=2 ttl=64 time=0.250 ms + // 64 bytes from 10.10.1.2: icmp_seq=3 ttl=64 time=0.058 ms + // + // --- 10.10.1.2 ping statistics --- + // 3 packets transmitted, 3 received, 0% packet loss, time 2043ms + // rtt min/avg/max/mdev = 0.058/0.334/0.695/0.266 ms + // ====================================================== + // =================== Dropped stdout =================== + // PING 10.10.1.2 (10.10.1.2) 56(84) bytes of data. + // + // --- 10.10.1.2 ping statistics --- + // 3 packets transmitted, 0 received, 100% packet loss, time 2037ms + // ======================================================= + // =================== Rejected stdout =================== + // PING 10.10.1.2 (10.10.1.2) 56(84) bytes of data. + // From 10.10.1.2 icmp_seq=1 Destination Host Prohibited + // From 10.10.1.2 icmp_seq=2 Destination Host Prohibited + // From 10.10.1.2 icmp_seq=3 Destination Host Prohibited + // + // --- 10.10.1.2 ping statistics --- + // 3 packets transmitted, 0 received, +3 errors, 100% packet loss, time 2042ms + // ======================================================= + // =================== Rejected ICMPv6 stdout =================== + // PING fd02:0:0:f8::11(fd02:0:0:f8::11) 56 data bytes + // From fd02:0:0:f8::11 icmp_seq=1 Destination unreachable: Administratively prohibited + // From fd02:0:0:f8::11 icmp_seq=2 Destination unreachable: Administratively prohibited + // From fd02:0:0:f8::11 icmp_seq=3 Destination unreachable: Administratively prohibited + // + // --- fd02:0:0:f8::11 ping statistics --- + // 3 packets transmitted, 0 received, +3 errors, 100% packet loss, time 2047ms + // ======================================================= + countConnected := strings.Count(stdout, "bytes from") + countRejected := strings.Count(stdout, "Prohibited") + strings.Count(stdout, "prohibited") + countDropped := probeNum - strings.Count(stdout, "icmp_seq") + + if countRejected == 0 && countConnected > 0 { + return Connected + } + if countConnected == 0 && countRejected > 0 { + return Rejected + } + if countDropped == probeNum { + return Dropped + } + return Error +} + // Probe execs into a Pod and checks its connectivity to another Pod. Of course it // assumes that the target Pod is serving on the input port, and also that agnhost // is installed. The connectivity from source Pod to all IPs of the target Pod // should be consistent. Otherwise, Error PodConnectivityMark will be returned. -func (k *KubernetesUtils) Probe(ns1, pod1, ns2, pod2 string, port int32, protocol v1.Protocol) (PodConnectivityMark, error) { +func (k *KubernetesUtils) Probe(ns1, pod1, ns2, pod2 string, port int32, protocol utils.AntreaPolicyProtocol) (PodConnectivityMark, error) { fromPods, err := k.GetPodsByLabel(ns1, "pod", pod1) if err != nil { return Error, fmt.Errorf("unable to get Pods from Namespace %s: %v", ns1, err) @@ -223,7 +299,7 @@ func (k *KubernetesUtils) Probe(ns1, pod1, ns2, pod2 string, port int32, protoco // ProbeAddr execs into a Pod and checks its connectivity to an arbitrary destination // address. -func (k *KubernetesUtils) ProbeAddr(ns, podLabelKey, podLabelValue, dstAddr string, port int32, protocol v1.Protocol) (PodConnectivityMark, error) { +func (k *KubernetesUtils) ProbeAddr(ns, podLabelKey, podLabelValue, dstAddr string, port int32, protocol utils.AntreaPolicyProtocol) (PodConnectivityMark, error) { fromPods, err := k.GetPodsByLabel(ns, podLabelKey, podLabelValue) if err != nil { return Error, fmt.Errorf("unable to get Pods from Namespace %s: %v", ns, err) @@ -233,11 +309,16 @@ func (k *KubernetesUtils) ProbeAddr(ns, podLabelKey, podLabelValue, dstAddr stri } fromPod := fromPods[0] containerName := fromPod.Spec.Containers[0].Name - // If it's an IPv6 address, add "[]" around it. - if strings.Contains(dstAddr, ":") { - dstAddr = fmt.Sprintf("[%s]", dstAddr) + var connectivity PodConnectivityMark + if protocol == utils.ProtocolICMP { + connectivity = k.pingProbe(&fromPod, fmt.Sprintf("%s/%s", ns, podLabelValue), containerName, dstAddr, dstAddr) + } else { + // If it's an IPv6 address, add "[]" around it. + if strings.Contains(dstAddr, ":") { + dstAddr = fmt.Sprintf("[%s]", dstAddr) + } + connectivity = k.probe(&fromPod, fmt.Sprintf("%s/%s", ns, podLabelValue), containerName, dstAddr, dstAddr, port, protocol) } - connectivity := k.probe(&fromPod, fmt.Sprintf("%s/%s", ns, podLabelValue), containerName, dstAddr, dstAddr, port, protocol) return connectivity, nil } @@ -403,7 +484,7 @@ func (data *TestData) DeleteService(ns, name string) error { } // CleanServices is a convenience function for deleting Services in the cluster. -func (data *TestData) CleanServices(namespaces []string) error { +func (data *TestData) CleanServices(namespaces map[string]string) error { for _, ns := range namespaces { l, err := data.clientset.CoreV1().Services(ns).List(context.TODO(), metav1.ListOptions{}) if err != nil { @@ -496,7 +577,7 @@ func (data *TestData) DeleteNetworkPolicy(ns, name string) error { } // CleanNetworkPolicies is a convenience function for deleting NetworkPolicies in the provided namespaces. -func (data *TestData) CleanNetworkPolicies(namespaces []string) error { +func (data *TestData) CleanNetworkPolicies(namespaces map[string]string) error { for _, ns := range namespaces { l, err := data.clientset.NetworkingV1().NetworkPolicies(ns).List(context.TODO(), metav1.ListOptions{}) if err != nil { @@ -807,17 +888,17 @@ func (k *KubernetesUtils) waitForHTTPServers(allPods []Pod) error { serversAreReady := func() bool { reachability := NewReachability(allPods, Connected) - k.Validate(allPods, reachability, []int32{80, 81, 8080, 8081, 8082, 8083, 8084, 8085}, v1.ProtocolTCP) + k.Validate(allPods, reachability, []int32{80, 81, 8080, 8081, 8082, 8083, 8084, 8085}, utils.ProtocolTCP) if _, wrong, _ := reachability.Summary(); wrong != 0 { return false } - k.Validate(allPods, reachability, []int32{80, 81}, v1.ProtocolUDP) + k.Validate(allPods, reachability, []int32{80, 81}, utils.ProtocolUDP) if _, wrong, _ := reachability.Summary(); wrong != 0 { return false } - k.Validate(allPods, reachability, []int32{80, 81}, v1.ProtocolSCTP) + k.Validate(allPods, reachability, []int32{80, 81}, utils.ProtocolSCTP) if _, wrong, _ := reachability.Summary(); wrong != 0 { return false } @@ -834,7 +915,7 @@ func (k *KubernetesUtils) waitForHTTPServers(allPods []Pod) error { return errors.Errorf("after %d tries, HTTP servers are not ready", maxTries) } -func (k *KubernetesUtils) validateOnePort(allPods []Pod, reachability *Reachability, port int32, protocol v1.Protocol) { +func (k *KubernetesUtils) validateOnePort(allPods []Pod, reachability *Reachability, port int32, protocol utils.AntreaPolicyProtocol) { type probeResult struct { podFrom Pod podTo Pod @@ -884,7 +965,7 @@ func (k *KubernetesUtils) validateOnePort(allPods []Pod, reachability *Reachabil // list of ports and a protocol. The connectivity from a Pod to another Pod should // be consistent across all provided ports. Otherwise, this connectivity will be // treated as Error. -func (k *KubernetesUtils) Validate(allPods []Pod, reachability *Reachability, ports []int32, protocol v1.Protocol) { +func (k *KubernetesUtils) Validate(allPods []Pod, reachability *Reachability, ports []int32, protocol utils.AntreaPolicyProtocol) { for _, port := range ports { // we do not run all the probes in parallel as we have experienced that on some // machines, this can cause a fraction of the probes to always fail, despite the @@ -896,7 +977,7 @@ func (k *KubernetesUtils) Validate(allPods []Pod, reachability *Reachability, po } } -func (k *KubernetesUtils) Bootstrap(namespaces, pods []string) (*map[string][]string, error) { +func (k *KubernetesUtils) Bootstrap(namespaces map[string]string, pods []string) (*map[string][]string, error) { for _, ns := range namespaces { _, err := k.CreateOrUpdateNamespace(ns, map[string]string{"ns": ns}) if err != nil { @@ -935,7 +1016,7 @@ func (k *KubernetesUtils) Bootstrap(namespaces, pods []string) (*map[string][]st return &podIPs, nil } -func (k *KubernetesUtils) Cleanup(namespaces []string) { +func (k *KubernetesUtils) Cleanup(namespaces map[string]string) { // Cleanup any cluster-scoped resources. if err := k.CleanACNPs(); err != nil { log.Errorf("Error when cleaning up ACNPs: %v", err) diff --git a/test/e2e/main_test.go b/test/e2e/main_test.go index c43aa9adb93..cad7fc67f0b 100644 --- a/test/e2e/main_test.go +++ b/test/e2e/main_test.go @@ -81,6 +81,7 @@ func testMain(m *testing.M) int { flag.BoolVar(&testOptions.withBench, "benchtest", false, "Run tests include benchmark tests") flag.BoolVar(&testOptions.enableCoverage, "coverage", false, "Run tests and measure coverage") flag.BoolVar(&testOptions.enableAntreaIPAM, "antrea-ipam", false, "Run tests with AntreaIPAM") + flag.BoolVar(&testOptions.flowVisibility, "flow-visibility", false, "Run flow visibility tests") flag.StringVar(&testOptions.coverageDir, "coverage-dir", "", "Directory for coverage data files") flag.StringVar(&testOptions.skipCases, "skip", "", "Key words to skip cases") flag.Parse() diff --git a/test/e2e/multicast_test.go b/test/e2e/multicast_test.go index 31a49751bbe..0d04c7acbde 100644 --- a/test/e2e/multicast_test.go +++ b/test/e2e/multicast_test.go @@ -83,6 +83,7 @@ func TestMulticast(t *testing.T) { for _, mc := range testcases { mc := mc t.Run(mc.name, func(t *testing.T) { + t.Parallel() runTestMulticastBetweenPods(t, data, mc, nodeMulticastInterfaces) }) } @@ -122,6 +123,7 @@ func TestMulticast(t *testing.T) { for _, mc := range testcases { mc := mc t.Run(mc.name, func(t *testing.T) { + t.Parallel() runTestMulticastBetweenPods(t, data, mc, nodeMulticastInterfaces) }) } @@ -158,15 +160,15 @@ type multicastTestcase struct { func runTestMulticastForwardToMultipleInterfaces(t *testing.T, data *TestData, senderIdx int, senderPort int, senderGroup string, senderMulticastInterfaces []string) { mcjoinWaitTimeout := defaultTimeout / time.Second - senderName, _, cleanupFunc := createAndWaitForPod(t, data, data.createMcJoinPodOnNode, "test-sender-", nodeName(senderIdx), testNamespace, false) + senderName, _, cleanupFunc := createAndWaitForPod(t, data, data.createMcJoinPodOnNode, "test-sender-", nodeName(senderIdx), data.testNamespace, false) defer cleanupFunc() - tcpdumpName, _, cleanupFunc := createAndWaitForPod(t, data, data.createNetshootPodOnNode, "test-tcpdump-", nodeName(senderIdx), testNamespace, true) + tcpdumpName, _, cleanupFunc := createAndWaitForPod(t, data, data.createNetshootPodOnNode, "test-tcpdump-", nodeName(senderIdx), data.testNamespace, true) defer cleanupFunc() // Wait 2 seconds(-w 2) before sending multicast traffic. // It sends two multicast packets for every second(-f 500 means it takes 500 milliseconds for sending one packet). sendMulticastCommand := []string{"/bin/sh", "-c", fmt.Sprintf("timeout 90s mcjoin -f 500 -o -p %d -s -t 3 -w 2 -W %d %s", senderPort, mcjoinWaitTimeout, senderGroup)} go func() { - data.RunCommandFromPod(testNamespace, senderName, mcjoinContainerName, sendMulticastCommand) + data.RunCommandFromPod(data.testNamespace, senderName, mcjoinContainerName, sendMulticastCommand) }() if err := wait.Poll(5*time.Second, defaultTimeout, func() (bool, error) { @@ -175,7 +177,7 @@ func runTestMulticastForwardToMultipleInterfaces(t *testing.T, data *TestData, s // If multicast traffic is sent from non-HostNetwork pods, all multicast interfaces in senders should receive multicast traffic. for _, multicastInterface := range senderMulticastInterfaces { tcpdumpReceiveMulticastCommand := []string{"/bin/sh", "-c", fmt.Sprintf("timeout 5s tcpdump -q -i %s -c 1 -W 90 host %s", multicastInterface, senderGroup)} - _, stderr, err := data.RunCommandFromPod(testNamespace, tcpdumpName, tcpdumpContainerName, tcpdumpReceiveMulticastCommand) + _, stderr, err := data.RunCommandFromPod(data.testNamespace, tcpdumpName, tcpdumpContainerName, tcpdumpReceiveMulticastCommand) if err != nil { return false, err } @@ -189,15 +191,15 @@ func runTestMulticastForwardToMultipleInterfaces(t *testing.T, data *TestData, s } } -func runTestMulticastBetweenPods(t *testing.T, data *TestData, mc multicastTestcase, nodeMulticastInterfaces [][]string) { +func runTestMulticastBetweenPods(t *testing.T, data *TestData, mc multicastTestcase, nodeMulticastInterfaces map[int][]string) { mcjoinWaitTimeout := defaultTimeout / time.Second gatewayInterface, err := data.GetGatewayInterfaceName(antreaNamespace) failOnError(err, t) - senderName, _, cleanupFunc := createAndWaitForPod(t, data, data.createMcJoinPodOnNode, "test-sender-", nodeName(mc.senderConfig.nodeIdx), testNamespace, mc.senderConfig.isHostNetwork) + senderName, _, cleanupFunc := createAndWaitForPod(t, data, data.createMcJoinPodOnNode, "test-sender-", nodeName(mc.senderConfig.nodeIdx), data.testNamespace, mc.senderConfig.isHostNetwork) defer cleanupFunc() receiverNames := make([]string, 0) for _, receiver := range mc.receiverConfigs { - receiverName, _, cleanupFunc := createAndWaitForPod(t, data, data.createMcJoinPodOnNode, "test-receiver-", nodeName(receiver.nodeIdx), testNamespace, receiver.isHostNetwork) + receiverName, _, cleanupFunc := createAndWaitForPod(t, data, data.createMcJoinPodOnNode, "test-receiver-", nodeName(receiver.nodeIdx), data.testNamespace, receiver.isHostNetwork) receiverNames = append(receiverNames, receiverName) defer cleanupFunc() } @@ -209,36 +211,45 @@ func runTestMulticastBetweenPods(t *testing.T, data *TestData, mc multicastTestc defer wg.Done() // The following command joins a multicast group and sets the timeout to 100 seconds(-W 100) before exit. // The command will return after receiving 1 packet(-c 1). - receiveMulticastCommand := []string{"/bin/sh", "-c", fmt.Sprintf("mcjoin -c 1 -o -p %d -W %d %s", mc.port, mcjoinWaitTimeout, mc.group.String())} - res, _, err := data.RunCommandFromPod(testNamespace, r, mcjoinContainerName, receiveMulticastCommand) + receiveMulticastCommand := []string{"/bin/sh", "-c", fmt.Sprintf("mcjoin -c 10 -o -p %d -W %d %s", mc.port, mcjoinWaitTimeout, mc.group.String())} + res, _, err := data.RunCommandFromPod(data.testNamespace, r, mcjoinContainerName, receiveMulticastCommand) failOnError(err, t) - assert.Contains(t, res, "Total: 1 packets") + assert.Contains(t, res, "Total: 10 packets") }() } // Wait 2 seconds(-w 2) before sending multicast traffic. // It sends two multicast packets for every second(-f 500 means it takes 500 milliseconds for sending one packet). sendMulticastCommand := []string{"/bin/sh", "-c", fmt.Sprintf("mcjoin -f 500 -o -p %d -s -t 3 -w 2 -W %d %s", mc.port, mcjoinWaitTimeout, mc.group.String())} go func() { - data.RunCommandFromPod(testNamespace, senderName, mcjoinContainerName, sendMulticastCommand) + data.RunCommandFromPod(data.testNamespace, senderName, mcjoinContainerName, sendMulticastCommand) }() - if err := wait.Poll(5*time.Second, defaultTimeout, func() (bool, error) { - // Sender pods should add an outbound multicast route except running as HostNetwork. - _, mrouteResult, _, err := data.RunCommandOnNode(nodeName(mc.senderConfig.nodeIdx), fmt.Sprintf("ip mroute show to %s iif %s | grep '%s'", mc.group.String(), gatewayInterface, strings.Join(nodeMulticastInterfaces[mc.senderConfig.nodeIdx], " "))) - if err != nil { - return false, err - } - if !mc.senderConfig.isHostNetwork { - if len(mrouteResult) == 0 { - return false, nil + readyReceivers := sets.NewInt() + senderReady := false + if err := wait.Poll(3*time.Second, defaultTimeout, func() (bool, error) { + if !senderReady { + // Sender pods should add an outbound multicast route except running as HostNetwork. + _, mrouteResult, _, err := data.RunCommandOnNode(nodeName(mc.senderConfig.nodeIdx), fmt.Sprintf("ip mroute show to %s iif %s | grep '%s'", mc.group.String(), gatewayInterface, strings.Join(nodeMulticastInterfaces[mc.senderConfig.nodeIdx], " "))) + if err != nil { + return false, err } - } else { - if len(mrouteResult) != 0 { - return false, nil + if !mc.senderConfig.isHostNetwork { + if len(mrouteResult) == 0 { + return false, nil + } + } else { + if len(mrouteResult) != 0 { + return false, nil + } } + senderReady = true } + // Check inbound multicast route and whether multicast interfaces has joined the multicast group. for _, receiver := range mc.receiverConfigs { + if readyReceivers.Has(receiver.nodeIdx) { + continue + } for _, receiverMulticastInterface := range nodeMulticastInterfaces[receiver.nodeIdx] { _, mRouteResult, _, err := data.RunCommandOnNode(nodeName(receiver.nodeIdx), fmt.Sprintf("ip mroute show to %s iif %s ", mc.group.String(), receiverMulticastInterface)) if err != nil { @@ -272,6 +283,7 @@ func runTestMulticastBetweenPods(t *testing.T, data *TestData, mc multicastTestc } } } + readyReceivers = readyReceivers.Insert(receiver.nodeIdx) } return true, nil }); err != nil { @@ -282,7 +294,7 @@ func runTestMulticastBetweenPods(t *testing.T, data *TestData, mc multicastTestc // computeMulticastInterfaces computes multicastInterfaces for each node. // It returns [][]string with its index as node index and value as multicastInterfaces for this node. -func computeMulticastInterfaces(t *testing.T, data *TestData) ([][]string, error) { +func computeMulticastInterfaces(t *testing.T, data *TestData) (map[int][]string, error) { multicastInterfaces, err := data.GetMulticastInterfaces(antreaNamespace) if err != nil { return nil, err @@ -291,7 +303,7 @@ func computeMulticastInterfaces(t *testing.T, data *TestData) ([][]string, error if err != nil { t.Fatalf("Error getting transport interfaces: %v", err) } - nodeMulticastInterfaces := make([][]string, 0, len(clusterInfo.nodes)) + nodeMulticastInterfaces := make(map[int][]string) for nodeIdx := range clusterInfo.nodes { _, localInterfacesStr, _, err := data.RunCommandOnNode(nodeName(nodeIdx), "ls /sys/class/net") if err != nil { @@ -303,7 +315,7 @@ func computeMulticastInterfaces(t *testing.T, data *TestData) ([][]string, error externalMulticastInterfaces := localInterfacesSet.Intersection(multicastInterfaceSet) currNodeMulticastInterfaces := externalMulticastInterfaces.Insert(transportInterface).List() t.Logf("Multicast interfaces for node index %d is %+v", nodeIdx, currNodeMulticastInterfaces) - nodeMulticastInterfaces = append(nodeMulticastInterfaces, currNodeMulticastInterfaces) + nodeMulticastInterfaces[nodeIdx] = currNodeMulticastInterfaces } return nodeMulticastInterfaces, nil } diff --git a/test/e2e/networkpolicy_test.go b/test/e2e/networkpolicy_test.go index 313ad31b145..736acf65cca 100644 --- a/test/e2e/networkpolicy_test.go +++ b/test/e2e/networkpolicy_test.go @@ -84,10 +84,10 @@ func TestNetworkPolicy(t *testing.T) { } func testNetworkPolicyStats(t *testing.T, data *TestData) { - serverName, serverIPs, cleanupFunc := createAndWaitForPod(t, data, data.createNginxPodOnNode, "test-server-", "", testNamespace, false) + serverName, serverIPs, cleanupFunc := createAndWaitForPod(t, data, data.createNginxPodOnNode, "test-server-", "", data.testNamespace, false) defer cleanupFunc() - clientName, _, cleanupFunc := createAndWaitForPod(t, data, data.createBusyboxPodOnNode, "test-client-", "", testNamespace, false) + clientName, _, cleanupFunc := createAndWaitForPod(t, data, data.createBusyboxPodOnNode, "test-client-", "", data.testNamespace, false) defer cleanupFunc() // When using the userspace OVS datapath and tunneling, @@ -95,11 +95,11 @@ func testNetworkPolicyStats(t *testing.T, data *TestData) { // So we need to "warm-up" the tunnel. if clusterInfo.podV4NetworkCIDR != "" { cmd := []string{"/bin/sh", "-c", fmt.Sprintf("nc -vz -w 4 %s 80", serverIPs.ipv4.String())} - data.RunCommandFromPod(testNamespace, clientName, busyboxContainerName, cmd) + data.RunCommandFromPod(data.testNamespace, clientName, busyboxContainerName, cmd) } if clusterInfo.podV6NetworkCIDR != "" { cmd := []string{"/bin/sh", "-c", fmt.Sprintf("nc -vz -w 4 %s 80", serverIPs.ipv6.String())} - data.RunCommandFromPod(testNamespace, clientName, busyboxContainerName, cmd) + data.RunCommandFromPod(data.testNamespace, clientName, busyboxContainerName, cmd) } np1, err := data.createNetworkPolicy("test-networkpolicy-ingress", &networkingv1.NetworkPolicySpec{ @@ -155,11 +155,11 @@ func testNetworkPolicyStats(t *testing.T, data *TestData) { go func() { if clusterInfo.podV4NetworkCIDR != "" { cmd := []string{"/bin/sh", "-c", fmt.Sprintf("nc -vz -w 4 %s 80", serverIPs.ipv4.String())} - data.RunCommandFromPod(testNamespace, clientName, busyboxContainerName, cmd) + data.RunCommandFromPod(data.testNamespace, clientName, busyboxContainerName, cmd) } if clusterInfo.podV6NetworkCIDR != "" { cmd := []string{"/bin/sh", "-c", fmt.Sprintf("nc -vz -w 4 %s 80", serverIPs.ipv6.String())} - data.RunCommandFromPod(testNamespace, clientName, busyboxContainerName, cmd) + data.RunCommandFromPod(data.testNamespace, clientName, busyboxContainerName, cmd) } wg.Done() }() @@ -177,7 +177,7 @@ func testNetworkPolicyStats(t *testing.T, data *TestData) { if err := wait.Poll(5*time.Second, defaultTimeout, func() (bool, error) { var ingressStats *v1alpha1.NetworkPolicyStats for _, np := range []string{"test-networkpolicy-ingress", "test-networkpolicy-egress"} { - stats, err := data.crdClient.StatsV1alpha1().NetworkPolicyStats(testNamespace).Get(context.TODO(), np, metav1.GetOptions{}) + stats, err := data.crdClient.StatsV1alpha1().NetworkPolicyStats(data.testNamespace).Get(context.TODO(), np, metav1.GetOptions{}) if err != nil { return false, err } @@ -228,29 +228,29 @@ func (data *TestData) setupDifferentNamedPorts(t *testing.T) (checkFn func(), cl server0Port := int32(80) server0Name, server0IPs, cleanupFunc := createAndWaitForPod(t, data, func(name string, ns string, nodeName string, hostNetwork bool) error { - return data.createServerPod(name, testNamespace, "http", server0Port, false, false) - }, "test-server-", "", testNamespace, false) + return data.createServerPod(name, data.testNamespace, "http", server0Port, false, false) + }, "test-server-", "", data.testNamespace, false) cleanupFuncs = append(cleanupFuncs, cleanupFunc) server1Port := int32(8080) server1Name, server1IPs, cleanupFunc := createAndWaitForPod(t, data, func(name string, ns string, nodeName string, hostNetwork bool) error { - return data.createServerPod(name, testNamespace, "http", server1Port, false, false) - }, "test-server-", "", testNamespace, false) + return data.createServerPod(name, data.testNamespace, "http", server1Port, false, false) + }, "test-server-", "", data.testNamespace, false) cleanupFuncs = append(cleanupFuncs, cleanupFunc) - client0Name, _, cleanupFunc := createAndWaitForPod(t, data, data.createBusyboxPodOnNode, "test-client-", "", testNamespace, false) + client0Name, _, cleanupFunc := createAndWaitForPod(t, data, data.createBusyboxPodOnNode, "test-client-", "", data.testNamespace, false) cleanupFuncs = append(cleanupFuncs, cleanupFunc) - client1Name, _, cleanupFunc := createAndWaitForPod(t, data, data.createBusyboxPodOnNode, "test-client-", "", testNamespace, false) + client1Name, _, cleanupFunc := createAndWaitForPod(t, data, data.createBusyboxPodOnNode, "test-client-", "", data.testNamespace, false) cleanupFuncs = append(cleanupFuncs, cleanupFunc) preCheckFunc := func(server0IP, server1IP string) { // Both clients can connect to both servers. for _, clientName := range []string{client0Name, client1Name} { - if err := data.runNetcatCommandFromTestPod(clientName, testNamespace, server0IP, server0Port); err != nil { + if err := data.runNetcatCommandFromTestPod(clientName, data.testNamespace, server0IP, server0Port); err != nil { t.Fatalf("Pod %s should be able to connect %s, but was not able to connect", clientName, net.JoinHostPort(server0IP, fmt.Sprint(server0Port))) } - if err := data.runNetcatCommandFromTestPod(clientName, testNamespace, server1IP, server1Port); err != nil { + if err := data.runNetcatCommandFromTestPod(clientName, data.testNamespace, server1IP, server1Port); err != nil { t.Fatalf("Pod %s should be able to connect %s, but was not able to connect", clientName, net.JoinHostPort(server1IP, fmt.Sprint(server1Port))) } } @@ -302,17 +302,17 @@ func (data *TestData) setupDifferentNamedPorts(t *testing.T) (checkFn func(), cl server0Address := net.JoinHostPort(server0IP, fmt.Sprint(server0Port)) server1Address := net.JoinHostPort(server1IP, fmt.Sprint(server1Port)) // client0 can connect to both servers. - if err = data.runNetcatCommandFromTestPod(client0Name, testNamespace, server0IP, server0Port); err != nil { + if err = data.runNetcatCommandFromTestPod(client0Name, data.testNamespace, server0IP, server0Port); err != nil { t.Fatalf("Pod %s should be able to connect %s, but was not able to connect", client0Name, server0Address) } - if err = data.runNetcatCommandFromTestPod(client0Name, testNamespace, server1IP, server1Port); err != nil { + if err = data.runNetcatCommandFromTestPod(client0Name, data.testNamespace, server1IP, server1Port); err != nil { t.Fatalf("Pod %s should be able to connect %s, but was not able to connect", client0Name, server1Address) } // client1 cannot connect to both servers. - if err = data.runNetcatCommandFromTestPod(client1Name, testNamespace, server0IP, server0Port); err == nil { + if err = data.runNetcatCommandFromTestPod(client1Name, data.testNamespace, server0IP, server0Port); err == nil { t.Fatalf("Pod %s should not be able to connect %s, but was able to connect", client1Name, server0Address) } - if err = data.runNetcatCommandFromTestPod(client1Name, testNamespace, server1IP, server1Port); err == nil { + if err = data.runNetcatCommandFromTestPod(client1Name, data.testNamespace, server1IP, server1Port); err == nil { t.Fatalf("Pod %s should not be able to connect %s, but was able to connect", client1Name, server1Address) } } @@ -338,21 +338,21 @@ func testDefaultDenyIngressPolicy(t *testing.T, data *TestData) { serverNode := workerNodeName(1) serverNodeIP := workerNodeIP(1) serverPort := int32(80) - _, serverIPs, cleanupFunc := createAndWaitForPod(t, data, data.createNginxPodOnNode, "test-server-", serverNode, testNamespace, false) + _, serverIPs, cleanupFunc := createAndWaitForPod(t, data, data.createNginxPodOnNode, "test-server-", serverNode, data.testNamespace, false) defer cleanupFunc() - service, err := data.CreateService("nginx", testNamespace, serverPort, serverPort, map[string]string{"app": "nginx"}, false, false, corev1.ServiceTypeNodePort, nil) + service, err := data.CreateService("nginx", data.testNamespace, serverPort, serverPort, map[string]string{"app": "nginx"}, false, false, corev1.ServiceTypeNodePort, nil) if err != nil { t.Fatalf("Error when creating nginx NodePort service: %v", err) } defer data.deleteService(service.Namespace, service.Name) // client1 is a host network Pod and is on the same node as the server Pod, simulating kubelet probe traffic. - client1Name, _, cleanupFunc := createAndWaitForPod(t, data, data.createBusyboxPodOnNode, "test-hostnetwork-client-can-connect-", serverNode, testNamespace, true) + client1Name, _, cleanupFunc := createAndWaitForPod(t, data, data.createBusyboxPodOnNode, "test-hostnetwork-client-can-connect-", serverNode, data.testNamespace, true) defer cleanupFunc() // client2 is a host network Pod and is on a different node from the server Pod, accessing the server Pod via the NodePort service. - client2Name, _, cleanupFunc := createAndWaitForPod(t, data, data.createBusyboxPodOnNode, "test-hostnetwork-client-cannot-connect-", controlPlaneNodeName(), testNamespace, true) + client2Name, _, cleanupFunc := createAndWaitForPod(t, data, data.createBusyboxPodOnNode, "test-hostnetwork-client-cannot-connect-", controlPlaneNodeName(), data.testNamespace, true) defer cleanupFunc() spec := &networkingv1.NetworkPolicySpec{ @@ -371,7 +371,7 @@ func testDefaultDenyIngressPolicy(t *testing.T, data *TestData) { }() npCheck := func(clientName, serverIP string, serverPort int32, wantErr bool) { - if err = data.runNetcatCommandFromTestPod(clientName, testNamespace, serverIP, serverPort); wantErr && err == nil { + if err = data.runNetcatCommandFromTestPod(clientName, data.testNamespace, serverIP, serverPort); wantErr && err == nil { t.Fatalf("Pod %s should not be able to connect %s, but was able to connect", clientName, net.JoinHostPort(serverIP, fmt.Sprint(serverPort))) } else if !wantErr && err != nil { t.Fatalf("Pod %s should be able to connect %s, but was not able to connect", clientName, net.JoinHostPort(serverIP, fmt.Sprint(serverPort))) @@ -397,14 +397,14 @@ func testDefaultDenyIngressPolicy(t *testing.T, data *TestData) { func testDefaultDenyEgressPolicy(t *testing.T, data *TestData) { serverPort := int32(80) - _, serverIPs, cleanupFunc := createAndWaitForPod(t, data, data.createNginxPodOnNode, "test-server-", "", testNamespace, false) + _, serverIPs, cleanupFunc := createAndWaitForPod(t, data, data.createNginxPodOnNode, "test-server-", "", data.testNamespace, false) defer cleanupFunc() - clientName, _, cleanupFunc := createAndWaitForPod(t, data, data.createBusyboxPodOnNode, "test-client-", "", testNamespace, false) + clientName, _, cleanupFunc := createAndWaitForPod(t, data, data.createBusyboxPodOnNode, "test-client-", "", data.testNamespace, false) defer cleanupFunc() preCheckFunc := func(serverIP string) { - if err := data.runNetcatCommandFromTestPod(clientName, testNamespace, serverIP, serverPort); err != nil { + if err := data.runNetcatCommandFromTestPod(clientName, data.testNamespace, serverIP, serverPort); err != nil { t.Fatalf("Pod %s should be able to connect %s, but was not able to connect", clientName, net.JoinHostPort(serverIP, fmt.Sprint(serverPort))) } } @@ -431,7 +431,7 @@ func testDefaultDenyEgressPolicy(t *testing.T, data *TestData) { }() npCheck := func(serverIP string) { - if err = data.runNetcatCommandFromTestPod(clientName, testNamespace, serverIP, serverPort); err == nil { + if err = data.runNetcatCommandFromTestPod(clientName, data.testNamespace, serverIP, serverPort); err == nil { t.Fatalf("Pod %s should not be able to connect %s, but was able to connect", clientName, net.JoinHostPort(serverIP, fmt.Sprint(serverPort))) } } @@ -451,12 +451,12 @@ func testDefaultDenyEgressPolicy(t *testing.T, data *TestData) { // https://github.com/kubernetes/kubernetes/pull/93583 func testEgressToServerInCIDRBlock(t *testing.T, data *TestData) { workerNode := workerNodeName(1) - serverAName, serverAIPs, cleanupFunc := createAndWaitForPod(t, data, data.createNginxPodOnNode, "test-server-", workerNode, testNamespace, false) + serverAName, serverAIPs, cleanupFunc := createAndWaitForPod(t, data, data.createNginxPodOnNode, "test-server-", workerNode, data.testNamespace, false) defer cleanupFunc() - serverBName, serverBIPs, cleanupFunc := createAndWaitForPod(t, data, data.createNginxPodOnNode, "test-server-", workerNode, testNamespace, false) + serverBName, serverBIPs, cleanupFunc := createAndWaitForPod(t, data, data.createNginxPodOnNode, "test-server-", workerNode, data.testNamespace, false) defer cleanupFunc() - clientA, _, cleanupFunc := createAndWaitForPod(t, data, data.createBusyboxPodOnNode, "test-client-", workerNode, testNamespace, false) + clientA, _, cleanupFunc := createAndWaitForPod(t, data, data.createBusyboxPodOnNode, "test-client-", workerNode, data.testNamespace, false) defer cleanupFunc() var serverCIDR string var serverAIP, serverBIP string @@ -467,10 +467,10 @@ func testEgressToServerInCIDRBlock(t *testing.T, data *TestData) { serverAIP = serverAIPs.ipv6.String() serverBIP = serverBIPs.ipv6.String() - if err := data.runNetcatCommandFromTestPod(clientA, testNamespace, serverAIP, 80); err != nil { + if err := data.runNetcatCommandFromTestPod(clientA, data.testNamespace, serverAIP, 80); err != nil { t.Fatalf("%s should be able to netcat %s", clientA, serverAName) } - if err := data.runNetcatCommandFromTestPod(clientA, testNamespace, serverBIP, 80); err != nil { + if err := data.runNetcatCommandFromTestPod(clientA, data.testNamespace, serverBIP, 80); err != nil { t.Fatalf("%s should be able to netcat %s", clientA, serverBName) } @@ -503,10 +503,10 @@ func testEgressToServerInCIDRBlock(t *testing.T, data *TestData) { } defer cleanupNP() - if err := data.runNetcatCommandFromTestPod(clientA, testNamespace, serverAIP, 80); err != nil { + if err := data.runNetcatCommandFromTestPod(clientA, data.testNamespace, serverAIP, 80); err != nil { t.Fatalf("%s should be able to netcat %s", clientA, serverAName) } - if err := data.runNetcatCommandFromTestPod(clientA, testNamespace, serverBIP, 80); err == nil { + if err := data.runNetcatCommandFromTestPod(clientA, data.testNamespace, serverBIP, 80); err == nil { t.Fatalf("%s should not be able to netcat %s", clientA, serverBName) } } @@ -518,10 +518,10 @@ func testEgressToServerInCIDRBlock(t *testing.T, data *TestData) { // https://github.com/kubernetes/kubernetes/pull/93583 func testEgressToServerInCIDRBlockWithException(t *testing.T, data *TestData) { workerNode := workerNodeName(1) - serverAName, serverAIPs, cleanupFunc := createAndWaitForPod(t, data, data.createNginxPodOnNode, "test-server-", workerNode, testNamespace, false) + serverAName, serverAIPs, cleanupFunc := createAndWaitForPod(t, data, data.createNginxPodOnNode, "test-server-", workerNode, data.testNamespace, false) defer cleanupFunc() - clientA, _, cleanupFunc := createAndWaitForPod(t, data, data.createBusyboxPodOnNode, "test-client-", workerNode, testNamespace, false) + clientA, _, cleanupFunc := createAndWaitForPod(t, data, data.createBusyboxPodOnNode, "test-client-", workerNode, data.testNamespace, false) defer cleanupFunc() var serverAAllowCIDR string var serverAExceptList []string @@ -537,7 +537,7 @@ func testEgressToServerInCIDRBlockWithException(t *testing.T, data *TestData) { serverAExceptList = []string{fmt.Sprintf("%s/%d", serverAIPs.ipv6.String(), 128)} serverAIP = serverAIPs.ipv6.String() - if err := data.runNetcatCommandFromTestPod(clientA, testNamespace, serverAIP, 80); err != nil { + if err := data.runNetcatCommandFromTestPod(clientA, data.testNamespace, serverAIP, 80); err != nil { t.Fatalf("%s should be able to netcat %s", clientA, serverAName) } @@ -571,7 +571,7 @@ func testEgressToServerInCIDRBlockWithException(t *testing.T, data *TestData) { } defer cleanupNP() - if err := data.runNetcatCommandFromTestPod(clientA, testNamespace, serverAIP, 80); err == nil { + if err := data.runNetcatCommandFromTestPod(clientA, data.testNamespace, serverAIP, 80); err == nil { t.Fatalf("%s should not be able to netcat %s", clientA, serverAName) } } @@ -583,16 +583,16 @@ func testNetworkPolicyResyncAfterRestart(t *testing.T, data *TestData) { t.Fatalf("Error when getting antrea-agent pod name: %v", err) } - server0Name, server0IPs, cleanupFunc := createAndWaitForPod(t, data, data.createNginxPodOnNode, "test-server-", workerNode, testNamespace, false) + server0Name, server0IPs, cleanupFunc := createAndWaitForPod(t, data, data.createNginxPodOnNode, "test-server-", workerNode, data.testNamespace, false) defer cleanupFunc() - server1Name, server1IPs, cleanupFunc := createAndWaitForPod(t, data, data.createNginxPodOnNode, "test-server-", workerNode, testNamespace, false) + server1Name, server1IPs, cleanupFunc := createAndWaitForPod(t, data, data.createNginxPodOnNode, "test-server-", workerNode, data.testNamespace, false) defer cleanupFunc() - client0Name, _, cleanupFunc := createAndWaitForPod(t, data, data.createBusyboxPodOnNode, "test-client-", workerNode, testNamespace, false) + client0Name, _, cleanupFunc := createAndWaitForPod(t, data, data.createBusyboxPodOnNode, "test-client-", workerNode, data.testNamespace, false) defer cleanupFunc() - client1Name, _, cleanupFunc := createAndWaitForPod(t, data, data.createBusyboxPodOnNode, "test-client-", workerNode, testNamespace, false) + client1Name, _, cleanupFunc := createAndWaitForPod(t, data, data.createBusyboxPodOnNode, "test-client-", workerNode, data.testNamespace, false) defer cleanupFunc() netpol0, err := data.createNetworkPolicy("test-isolate-server0", &networkingv1.NetworkPolicySpec{ @@ -617,10 +617,10 @@ func testNetworkPolicyResyncAfterRestart(t *testing.T, data *TestData) { defer cleanupNetpol0() preCheckFunc := func(server0IP, server1IP string) { - if err = data.runNetcatCommandFromTestPod(client0Name, testNamespace, server0IP, 80); err == nil { + if err = data.runNetcatCommandFromTestPod(client0Name, data.testNamespace, server0IP, 80); err == nil { t.Fatalf("Pod %s should not be able to connect %s, but was able to connect", client0Name, server0Name) } - if err = data.runNetcatCommandFromTestPod(client1Name, testNamespace, server1IP, 80); err != nil { + if err = data.runNetcatCommandFromTestPod(client1Name, data.testNamespace, server1IP, 80); err != nil { t.Fatalf("Pod %s should be able to connect %s, but was not able to connect", client1Name, server1Name) } } @@ -673,10 +673,10 @@ func testNetworkPolicyResyncAfterRestart(t *testing.T, data *TestData) { waitForAgentCondition(t, data, antreaPod, v1beta1.ControllerConnectionUp, corev1.ConditionTrue) npCheck := func(server0IP, server1IP string) { - if err = data.runNetcatCommandFromTestPod(client0Name, testNamespace, server0IP, 80); err != nil { + if err = data.runNetcatCommandFromTestPod(client0Name, data.testNamespace, server0IP, 80); err != nil { t.Fatalf("Pod %s should be able to connect %s, but was not able to connect", client0Name, server0Name) } - if err = data.runNetcatCommandFromTestPod(client1Name, testNamespace, server1IP, 80); err == nil { + if err = data.runNetcatCommandFromTestPod(client1Name, data.testNamespace, server1IP, 80); err == nil { t.Fatalf("Pod %s should not be able to connect %s, but was able to connect", client1Name, server1Name) } } @@ -691,19 +691,19 @@ func testNetworkPolicyResyncAfterRestart(t *testing.T, data *TestData) { func testIngressPolicyWithoutPortNumber(t *testing.T, data *TestData) { serverPort := int32(80) - _, serverIPs, cleanupFunc := createAndWaitForPod(t, data, data.createNginxPodOnNode, "test-server-", "", testNamespace, false) + _, serverIPs, cleanupFunc := createAndWaitForPod(t, data, data.createNginxPodOnNode, "test-server-", "", data.testNamespace, false) defer cleanupFunc() - client0Name, _, cleanupFunc := createAndWaitForPod(t, data, data.createBusyboxPodOnNode, "test-client-", "", testNamespace, false) + client0Name, _, cleanupFunc := createAndWaitForPod(t, data, data.createBusyboxPodOnNode, "test-client-", "", data.testNamespace, false) defer cleanupFunc() - client1Name, _, cleanupFunc := createAndWaitForPod(t, data, data.createBusyboxPodOnNode, "test-client-", "", testNamespace, false) + client1Name, _, cleanupFunc := createAndWaitForPod(t, data, data.createBusyboxPodOnNode, "test-client-", "", data.testNamespace, false) defer cleanupFunc() preCheckFunc := func(serverIP string) { // Both clients can connect to server. for _, clientName := range []string{client0Name, client1Name} { - if err := data.runNetcatCommandFromTestPod(clientName, testNamespace, serverIP, serverPort); err != nil { + if err := data.runNetcatCommandFromTestPod(clientName, data.testNamespace, serverIP, serverPort); err != nil { t.Fatalf("Pod %s should be able to connect %s, but was not able to connect", clientName, net.JoinHostPort(serverIP, fmt.Sprint(serverPort))) } } @@ -750,11 +750,11 @@ func testIngressPolicyWithoutPortNumber(t *testing.T, data *TestData) { npCheck := func(serverIP string) { serverAddress := net.JoinHostPort(serverIP, fmt.Sprint(serverPort)) // Client0 can access server. - if err = data.runNetcatCommandFromTestPod(client0Name, testNamespace, serverIP, serverPort); err != nil { + if err = data.runNetcatCommandFromTestPod(client0Name, data.testNamespace, serverIP, serverPort); err != nil { t.Fatalf("Pod %s should be able to connect %s, but was not able to connect", client0Name, serverAddress) } // Client1 can't access server. - if err = data.runNetcatCommandFromTestPod(client1Name, testNamespace, serverIP, serverPort); err == nil { + if err = data.runNetcatCommandFromTestPod(client1Name, data.testNamespace, serverIP, serverPort); err == nil { t.Fatalf("Pod %s should not be able to connect %s, but was able to connect", client1Name, serverAddress) } } @@ -816,8 +816,7 @@ func testIngressPolicyWithEndPort(t *testing.T, data *TestData) { } if nodeName == controlPlaneNodeName() { // tolerate NoSchedule taint if we want Pod to run on control-plane Node - noScheduleToleration := controlPlaneNoScheduleToleration() - podSpec.Tolerations = []corev1.Toleration{noScheduleToleration} + podSpec.Tolerations = controlPlaneNoScheduleTolerations() } pod := &corev1.Pod{ ObjectMeta: metav1.ObjectMeta{ @@ -835,16 +834,16 @@ func testIngressPolicyWithEndPort(t *testing.T, data *TestData) { return nil } - serverName, serverIPs, cleanupFunc := createAndWaitForPod(t, data, createAgnhostPodOnNodeWithMultiPort, "test-server-", "", testNamespace, false) + serverName, serverIPs, cleanupFunc := createAndWaitForPod(t, data, createAgnhostPodOnNodeWithMultiPort, "test-server-", "", data.testNamespace, false) defer cleanupFunc() - clientName, _, cleanupFunc := createAndWaitForPod(t, data, data.createBusyboxPodOnNode, "test-client-", "", testNamespace, false) + clientName, _, cleanupFunc := createAndWaitForPod(t, data, data.createBusyboxPodOnNode, "test-client-", "", data.testNamespace, false) defer cleanupFunc() preCheck := func(serverIP string) { // The client can connect to server on all ports. for _, port := range serverPorts { - if err := data.runNetcatCommandFromTestPod(clientName, testNamespace, serverIP, port); err != nil { + if err := data.runNetcatCommandFromTestPod(clientName, data.testNamespace, serverIP, port); err != nil { t.Fatalf("Pod %s should be able to connect %s, but was not able to connect", clientName, net.JoinHostPort(serverIP, fmt.Sprint(port))) } } @@ -901,7 +900,7 @@ func testIngressPolicyWithEndPort(t *testing.T, data *TestData) { npCheck := func(serverIP string) { for _, port := range serverPorts { - err = data.runNetcatCommandFromTestPod(clientName, testNamespace, serverIP, port) + err = data.runNetcatCommandFromTestPod(clientName, data.testNamespace, serverIP, port) if port >= policyPort && port <= policyEndPort { if err != nil { t.Errorf("Pod %s should be able to connect %s, but was not able to connect", clientName, net.JoinHostPort(serverIP, fmt.Sprint(port))) @@ -942,7 +941,7 @@ func createAndWaitForPodWithServiceAccount(t *testing.T, data *TestData, createF t.Fatalf("Error when creating busybox test Pod: %v", err) } cleanupFunc := func() { - deletePodWrapper(t, data, testNamespace, name) + deletePodWrapper(t, data, data.testNamespace, name) } podIP, err := data.podWaitForIPs(defaultTimeout, name, ns) if err != nil { diff --git a/test/e2e/nodeportlocal_test.go b/test/e2e/nodeportlocal_test.go index fede7abbf32..725036cd6f8 100644 --- a/test/e2e/nodeportlocal_test.go +++ b/test/e2e/nodeportlocal_test.go @@ -18,9 +18,11 @@ package e2e import ( + "bufio" "encoding/json" "fmt" "regexp" + "strconv" "strings" "testing" "time" @@ -45,6 +47,7 @@ const ( ) type nplRuleData struct { + nodeIP string nodePort int podPort int podIP string @@ -103,7 +106,7 @@ func getNPLAnnotation(t *testing.T, data *TestData, r *require.Assertions, testP podTimeout = 18 * time.Second } for i := 0; i <= maxRetries; i++ { - _, err = data.PodWaitFor(podTimeout, testPodName, testNamespace, func(pod *corev1.Pod) (bool, error) { + _, err = data.PodWaitFor(podTimeout, testPodName, data.testNamespace, func(pod *corev1.Pod) (bool, error) { var err error if pod.Status.Phase != corev1.PodRunning { return false, nil @@ -144,11 +147,20 @@ func getNPLAnnotations(t *testing.T, data *TestData, r *require.Assertions, test return nplAnnotations, testPodIP } +func checkNPLRules(t *testing.T, data *TestData, r *require.Assertions, nplAnnotations []k8s.NPLAnnotation, antreaPod, podIP string, nodeName string, present bool) { + if clusterInfo.nodesOS[nodeName] == "windows" { + checkNPLRulesForWindowsPod(t, data, r, nplAnnotations, antreaPod, podIP, nodeName, present) + } else { + checkNPLRulesForPod(t, data, r, nplAnnotations, antreaPod, podIP, present) + } +} + func checkNPLRulesForPod(t *testing.T, data *TestData, r *require.Assertions, nplAnnotations []k8s.NPLAnnotation, antreaPod, podIP string, present bool) { var rules []nplRuleData for _, ann := range nplAnnotations { for _, protocol := range ann.Protocols { rule := nplRuleData{ + nodeIP: ann.NodeIP, nodePort: ann.NodePort, podIP: podIP, podPort: ann.PodPort, @@ -161,6 +173,23 @@ func checkNPLRulesForPod(t *testing.T, data *TestData, r *require.Assertions, np checkForNPLListeningSockets(t, data, r, antreaPod, rules, present) } +func checkNPLRulesForWindowsPod(t *testing.T, data *TestData, r *require.Assertions, nplAnnotations []k8s.NPLAnnotation, antreaPod, podIP string, nodeName string, present bool) { + var rules []nplRuleData + for _, ann := range nplAnnotations { + for _, protocol := range ann.Protocols { + rule := nplRuleData{ + nodeIP: ann.NodeIP, + nodePort: ann.NodePort, + podIP: podIP, + podPort: ann.PodPort, + protocol: protocol, + } + rules = append(rules, rule) + } + } + checkForNPLRuleInNetNat(t, data, r, antreaPod, nodeName, rules, present) +} + func buildRuleForPod(rule nplRuleData) []string { return []string{ "-p", rule.protocol, "-m", rule.protocol, "--dport", fmt.Sprint(rule.nodePort), @@ -202,6 +231,64 @@ func checkForNPLRuleInIPTables(t *testing.T, data *TestData, r *require.Assertio r.NoError(err, "Poll for iptables rules check failed") } +func parseGetNetCmdResult(result string, itemNum int) [][]string { + scanner := bufio.NewScanner(strings.NewReader(result)) + parsed := [][]string{} + for scanner.Scan() { + items := strings.Fields(scanner.Text()) + if len(items) < itemNum { + // Skip if an empty line or something similar + continue + } + parsed = append(parsed, items) + } + return parsed +} + +func checkForNPLRuleInNetNat(t *testing.T, data *TestData, r *require.Assertions, antreaPod string, nodeName string, rules []nplRuleData, present bool) { + defaultnodeIP := "0.0.0.0" + t.Logf("Verifying NetNat rules %v, present: %v", rules, present) + const timeout = 60 * time.Second + err := wait.Poll(time.Second, timeout, func() (bool, error) { + _, _, _, err := data.RunCommandOnNode(nodeName, "Get-NetNatStaticMapping") + if err != nil { + t.Logf("Error while checking NPL rules on Windows Node: %v", err) + // Retry, as sometimes error can occur due to concurrent operations on iptables. + return false, nil + } + for _, rule := range rules { + cmd := fmt.Sprintf("Get-NetNatStaticMapping -NatName antrea-nat") + + fmt.Sprintf("|? ExternalIPAddress -EQ %s", defaultnodeIP) + + fmt.Sprintf("|? ExternalPort -EQ %d", rule.nodePort) + + fmt.Sprintf("|? Protocol -EQ %s", rule.protocol) + + "| Format-Table -HideTableHeaders" + cmdpwsh := fmt.Sprintf(`powershell.exe -NoLogo -NoProfile -NonInteractive -Command `) + + fmt.Sprintf(`'$ErrorActionPreference="Stop";try {%s} catch {Write-Host $_;os.Exit(1)}'`, cmd) + _, stdout, _, err := data.RunCommandOnNode(nodeName, cmdpwsh) + if err != nil { + t.Logf("Error while checking NPL rule in NetNat:%s %v", rule.nodeIP, err) + // Retry, as sometimes error can occur due to concurrent operations on iptables. + return false, nil + } + parsed := parseGetNetCmdResult(stdout, 6) + if len(parsed) > 0 { + items := parsed[0] + if items[4] == rule.podIP && items[5] == strconv.Itoa(rule.podPort) { + if !present { + return false, nil + } + continue + } + } + if present { + return false, nil + } + } + return true, nil + }) + r.NoError(err, "Poll for NetNat rules check failed") +} + func checkForNPLListeningSockets(t *testing.T, data *TestData, r *require.Assertions, antreaPod string, rules []nplRuleData, present bool) { t.Logf("Verifying NPL listening sockets") const timeout = 30 * time.Second @@ -245,20 +332,26 @@ func deleteNPLRuleFromIPTables(t *testing.T, data *TestData, r *require.Assertio r.NoError(err, "Error when deleting iptables rule") } +func deleteNPLRuleFromNetNat(t *testing.T, data *TestData, r *require.Assertions, antreaPod string, rule nplRuleData) { + t.Logf("Deleting Netnat rule for %v", rule) + _, _, _, err := data.RunCommandOnNode(rule.nodeIP, "Remove-NetNatStaticMapping -NatName antrea-nat -StaticMappingID 1 -Confirm:$false") + r.NoError(err, "Error when deleting Netnat rule") +} + func checkTrafficForNPL(data *TestData, r *require.Assertions, nplAnnotations []k8s.NPLAnnotation, clientName string) { for i := range nplAnnotations { for j := range nplAnnotations[i].Protocols { - err := data.runNetcatCommandFromTestPodWithProtocol(clientName, testNamespace, nplAnnotations[i].NodeIP, int32(nplAnnotations[i].NodePort), nplAnnotations[i].Protocols[j]) + err := data.runNetcatCommandFromTestPodWithProtocol(clientName, data.testNamespace, "agnhost", nplAnnotations[i].NodeIP, int32(nplAnnotations[i].NodePort), nplAnnotations[i].Protocols[j]) r.NoError(err, "Traffic test failed for NodeIP: %s, NodePort: %d, Protocol: %s", nplAnnotations[i].NodeIP, nplAnnotations[i].NodePort, nplAnnotations[i].Protocols[j]) } } } func testNPLAddPod(t *testing.T, data *TestData) { - t.Run("NPLTestMultiplePods", NPLTestMultiplePods) - t.Run("NPLTestPodAddMultiPort", NPLTestPodAddMultiPort) - t.Run("NPLTestPodAddMultiProtocol", NPLTestPodAddMultiProtocol) - t.Run("NPLTestLocalAccess", NPLTestLocalAccess) + t.Run("NPLTestMultiplePods", func(t *testing.T) { NPLTestMultiplePods(t, data) }) + t.Run("NPLTestPodAddMultiPort", func(t *testing.T) { NPLTestPodAddMultiPort(t, data) }) + t.Run("NPLTestPodAddMultiProtocol", func(t *testing.T) { NPLTestPodAddMultiProtocol(t, data) }) + t.Run("NPLTestLocalAccess", func(t *testing.T) { NPLTestLocalAccess(t, data) }) } // NPLTestMultiplePods tests NodePortLocal functionalities after adding multiple Pods. @@ -267,7 +360,7 @@ func testNPLAddPod(t *testing.T, data *TestData) { // - Make sure iptables rules are correctly added in the Node from Antrea Agent Pod. // - Create a client Pod and test traffic through netcat. // - Delete the nginx test Pods and verify that the iptables rules are deleted. -func NPLTestMultiplePods(t *testing.T) { +func NPLTestMultiplePods(t *testing.T, data *TestData) { r := require.New(t) annotation := make(map[string]string) @@ -275,43 +368,51 @@ func NPLTestMultiplePods(t *testing.T) { ipFamily := corev1.IPv4Protocol testData.createNginxClusterIPServiceWithAnnotations(false, &ipFamily, annotation) node := nodeName(0) + workerNode := node + if len(clusterInfo.windowsNodes) != 0 { + workerNode = workerNodeName(clusterInfo.windowsNodes[0]) + } var testPods []string for i := 0; i < 4; i++ { testPodName := randName("test-pod-") testPods = append(testPods, testPodName) - err := testData.createNginxPodOnNode(testPodName, testNamespace, node, false) + err := testData.createNginxPodOnNode(testPodName, data.testNamespace, workerNode, false) r.NoError(err, "Error creating test Pod: %v", err) } clientName := randName("test-client-") - err := testData.createBusyboxPodOnNode(clientName, testNamespace, node, false) - r.NoError(err, "Error creating Pod %s: %v", clientName) + err := testData.createAgnhostPodOnNode(clientName, data.testNamespace, workerNode, false) + r.NoError(err, "Error creating AgnhostPod %s: %v", clientName) - err = testData.podWaitForRunning(defaultTimeout, clientName, testNamespace) + err = testData.podWaitForRunning(defaultTimeout, clientName, data.testNamespace) r.NoError(err, "Error when waiting for Pod %s to be running", clientName) - antreaPod, err := testData.getAntreaPodOnNode(node) - r.NoError(err, "Error when getting Antrea Agent Pod on Node '%s'", node) + antreaPod, err := testData.getAntreaPodOnNode(workerNode) + r.NoError(err, "Error when getting Antrea Agent Pod on Node '%s'", workerNode) expectedAnnotations := newExpectedNPLAnnotations(defaultStartPort, defaultEndPort).Add(nil, defaultTargetPort, "tcp") for _, testPodName := range testPods { nplAnnotations, testPodIP := getNPLAnnotations(t, testData, r, testPodName) - checkNPLRulesForPod(t, testData, r, nplAnnotations, antreaPod, testPodIP, true) + checkNPLRules(t, testData, r, nplAnnotations, antreaPod, testPodIP, workerNode, true) expectedAnnotations.Check(t, nplAnnotations) checkTrafficForNPL(testData, r, nplAnnotations, clientName) - testData.DeletePod(testNamespace, testPodName) - checkNPLRulesForPod(t, testData, r, nplAnnotations, antreaPod, testPodIP, false) + testData.DeletePod(data.testNamespace, testPodName) + checkNPLRules(t, testData, r, nplAnnotations, antreaPod, testPodIP, workerNode, false) } + testData.DeletePod(data.testNamespace, clientName) } // NPLTestPodAddMultiPort tests NodePortLocal functionalities for a Pod with multiple ports. -func NPLTestPodAddMultiPort(t *testing.T) { +func NPLTestPodAddMultiPort(t *testing.T, data *TestData) { r := require.New(t) node := nodeName(0) + if len(clusterInfo.windowsNodes) != 0 { + node = workerNodeName(clusterInfo.windowsNodes[0]) + } testPodName := randName("test-pod-") annotation := make(map[string]string) @@ -319,15 +420,15 @@ func NPLTestPodAddMultiPort(t *testing.T) { selector := make(map[string]string) selector["app"] = "agnhost" ipFamily := corev1.IPv4Protocol - testData.CreateServiceWithAnnotations("agnhost1", testNamespace, 80, 80, corev1.ProtocolTCP, selector, false, false, corev1.ServiceTypeClusterIP, &ipFamily, annotation) - testData.CreateServiceWithAnnotations("agnhost2", testNamespace, 80, 8080, corev1.ProtocolTCP, selector, false, false, corev1.ServiceTypeClusterIP, &ipFamily, annotation) + testData.CreateServiceWithAnnotations("agnhost1", data.testNamespace, 80, 80, corev1.ProtocolTCP, selector, false, false, corev1.ServiceTypeClusterIP, &ipFamily, annotation) + testData.CreateServiceWithAnnotations("agnhost2", data.testNamespace, 80, 8080, corev1.ProtocolTCP, selector, false, false, corev1.ServiceTypeClusterIP, &ipFamily, annotation) expectedAnnotations := newExpectedNPLAnnotations(defaultStartPort, defaultEndPort). Add(nil, 80, "tcp").Add(nil, 8080, "tcp") podcmd := "porter" // Creating a Pod using agnhost image to support multiple ports, instead of nginx. - err := testData.createPodOnNode(testPodName, testNamespace, node, agnhostImage, nil, []string{podcmd}, []corev1.EnvVar{ + err := testData.createPodOnNode(testPodName, data.testNamespace, node, agnhostImage, nil, []string{podcmd}, []corev1.EnvVar{ { Name: fmt.Sprintf("SERVE_PORT_%d", 80), Value: "foo", }, @@ -352,30 +453,34 @@ func NPLTestPodAddMultiPort(t *testing.T) { nplAnnotations, testPodIP := getNPLAnnotations(t, testData, r, testPodName) clientName := randName("test-client-") - err = testData.createBusyboxPodOnNode(clientName, testNamespace, node, false) - r.NoError(err, "Error when creating Pod %s", clientName) + err = testData.createAgnhostPodOnNode(clientName, data.testNamespace, node, false) + r.NoError(err, "Error when creating AgnhostPod %s", clientName) - err = testData.podWaitForRunning(defaultTimeout, clientName, testNamespace) + err = testData.podWaitForRunning(defaultTimeout, clientName, data.testNamespace) r.NoError(err, "Error when waiting for Pod %s to be running", clientName) antreaPod, err := testData.getAntreaPodOnNode(node) r.NoError(err, "Error when getting Antrea Agent Pod on Node '%s'", node) - checkNPLRulesForPod(t, testData, r, nplAnnotations, antreaPod, testPodIP, true) + checkNPLRules(t, testData, r, nplAnnotations, antreaPod, testPodIP, node, true) expectedAnnotations.Check(t, nplAnnotations) checkTrafficForNPL(testData, r, nplAnnotations, clientName) - testData.DeletePod(testNamespace, testPodName) - testData.DeleteService(testNamespace, "agnhost1") - testData.DeleteService(testNamespace, "agnhost2") - checkNPLRulesForPod(t, testData, r, nplAnnotations, antreaPod, testPodIP, false) + testData.DeletePod(data.testNamespace, clientName) + testData.DeletePod(data.testNamespace, testPodName) + testData.DeleteService(data.testNamespace, "agnhost1") + testData.DeleteService(data.testNamespace, "agnhost2") + checkNPLRules(t, testData, r, nplAnnotations, antreaPod, testPodIP, node, false) } // NPLTestPodAddMultiProtocol tests NodePortLocal functionalities for a Pod using a single port with multiple protocols. -func NPLTestPodAddMultiProtocol(t *testing.T) { +func NPLTestPodAddMultiProtocol(t *testing.T, data *TestData) { r := require.New(t) node := nodeName(0) + if len(clusterInfo.windowsNodes) != 0 { + node = workerNodeName(clusterInfo.windowsNodes[0]) + } testPodName := randName("test-pod-") annotation := make(map[string]string) @@ -383,8 +488,8 @@ func NPLTestPodAddMultiProtocol(t *testing.T) { selector := make(map[string]string) selector["app"] = "agnhost" ipFamily := corev1.IPv4Protocol - testData.CreateServiceWithAnnotations("agnhost1", testNamespace, 80, 8080, corev1.ProtocolTCP, selector, false, false, corev1.ServiceTypeClusterIP, &ipFamily, annotation) - testData.CreateServiceWithAnnotations("agnhost2", testNamespace, 80, 8080, corev1.ProtocolUDP, selector, false, false, corev1.ServiceTypeClusterIP, &ipFamily, annotation) + testData.CreateServiceWithAnnotations("agnhost1", data.testNamespace, 80, 8080, corev1.ProtocolTCP, selector, false, false, corev1.ServiceTypeClusterIP, &ipFamily, annotation) + testData.CreateServiceWithAnnotations("agnhost2", data.testNamespace, 80, 8080, corev1.ProtocolUDP, selector, false, false, corev1.ServiceTypeClusterIP, &ipFamily, annotation) expectedAnnotations := newExpectedNPLAnnotations(defaultStartPort, defaultEndPort). Add(nil, 8080, "tcp").Add(nil, 8080, "udp") @@ -400,36 +505,37 @@ func NPLTestPodAddMultiProtocol(t *testing.T) { pod.Labels[k] = v } } - err := testData.CreatePodOnNodeInNamespace(testPodName, testNamespace, node, containerName, agnhostImage, cmd, args, []corev1.EnvVar{}, []corev1.ContainerPort{port}, false, mutateLabels) + err := testData.CreatePodOnNodeInNamespace(testPodName, data.testNamespace, node, containerName, agnhostImage, cmd, args, []corev1.EnvVar{}, []corev1.ContainerPort{port}, false, mutateLabels) r.NoError(err, "Error creating test Pod: %v", err) nplAnnotations, testPodIP := getNPLAnnotations(t, testData, r, testPodName) clientName := randName("test-client-") - err = testData.createBusyboxPodOnNode(clientName, testNamespace, node, false) - r.NoError(err, "Error when creating Pod %s", clientName) + err = testData.createAgnhostPodOnNode(clientName, data.testNamespace, node, false) + r.NoError(err, "Error when creating AgnhostPod %s", clientName) - err = testData.podWaitForRunning(defaultTimeout, clientName, testNamespace) + err = testData.podWaitForRunning(defaultTimeout, clientName, data.testNamespace) r.NoError(err, "Error when waiting for Pod %s to be running", clientName) antreaPod, err := testData.getAntreaPodOnNode(node) r.NoError(err, "Error when getting Antrea Agent Pod on Node '%s'", node) - checkNPLRulesForPod(t, testData, r, nplAnnotations, antreaPod, testPodIP, true) + checkNPLRules(t, testData, r, nplAnnotations, antreaPod, testPodIP, node, true) expectedAnnotations.Check(t, nplAnnotations) checkTrafficForNPL(testData, r, nplAnnotations, clientName) - testData.DeletePod(testNamespace, testPodName) - testData.DeleteService(testNamespace, "agnhost1") - testData.DeleteService(testNamespace, "agnhost2") - checkNPLRulesForPod(t, testData, r, nplAnnotations, antreaPod, testPodIP, false) + testData.DeletePod(data.testNamespace, clientName) + testData.DeletePod(data.testNamespace, testPodName) + testData.DeleteService(data.testNamespace, "agnhost1") + testData.DeleteService(data.testNamespace, "agnhost2") + checkNPLRules(t, testData, r, nplAnnotations, antreaPod, testPodIP, node, false) } // NPLTestLocalAccess validates that a NodePortLocal Pod can be accessed locally // from the host network namespace. -func NPLTestLocalAccess(t *testing.T) { +func NPLTestLocalAccess(t *testing.T, data *TestData) { r := require.New(t) annotation := make(map[string]string) @@ -439,16 +545,19 @@ func NPLTestLocalAccess(t *testing.T) { expectedAnnotations := newExpectedNPLAnnotations(defaultStartPort, defaultEndPort).Add(nil, defaultTargetPort, "tcp") node := nodeName(0) + if len(clusterInfo.windowsNodes) != 0 { + node = workerNodeName(clusterInfo.windowsNodes[0]) + } testPodName := randName("test-pod-") - err := testData.createNginxPodOnNode(testPodName, testNamespace, node, false) + err := testData.createNginxPodOnNode(testPodName, data.testNamespace, node, false) r.NoError(err, "Error creating test Pod: %v", err) clientName := randName("test-client-") - err = testData.createBusyboxPodOnNode(clientName, testNamespace, node, true) - r.NoError(err, "Error creating hostNetwork Pod %s: %v", clientName) + err = testData.createAgnhostPodOnNode(clientName, data.testNamespace, node, false) + r.NoError(err, "Error when creating AgnhostPod %s", clientName) - err = testData.podWaitForRunning(defaultTimeout, clientName, testNamespace) + err = testData.podWaitForRunning(defaultTimeout, clientName, data.testNamespace) r.NoError(err, "Error when waiting for Pod %s to be running", clientName) antreaPod, err := testData.getAntreaPodOnNode(node) @@ -456,12 +565,13 @@ func NPLTestLocalAccess(t *testing.T) { nplAnnotations, testPodIP := getNPLAnnotations(t, testData, r, testPodName) - checkNPLRulesForPod(t, testData, r, nplAnnotations, antreaPod, testPodIP, true) + checkNPLRules(t, testData, r, nplAnnotations, antreaPod, testPodIP, node, true) expectedAnnotations.Check(t, nplAnnotations) checkTrafficForNPL(testData, r, nplAnnotations, clientName) - testData.DeletePod(testNamespace, testPodName) - checkNPLRulesForPod(t, testData, r, nplAnnotations, antreaPod, testPodIP, false) + testData.DeletePod(data.testNamespace, testPodName) + checkNPLRules(t, testData, r, nplAnnotations, antreaPod, testPodIP, node, false) + testData.DeletePod(data.testNamespace, clientName) } // testNPLMultiplePodsAndAgentRestart tests NodePortLocal functionalities after Antrea Agent restarts. @@ -478,20 +588,25 @@ func testNPLMultiplePodsAgentRestart(t *testing.T, data *TestData) { data.createNginxClusterIPServiceWithAnnotations(false, &ipFamily, annotation) node := nodeName(0) + winenv := false + if len(clusterInfo.windowsNodes) != 0 { + node = workerNodeName(clusterInfo.windowsNodes[0]) + winenv = true + } var testPods []string var err error for i := 0; i < 4; i++ { testPodName := randName("test-pod-") testPods = append(testPods, testPodName) - err = data.createNginxPodOnNode(testPodName, testNamespace, node, false) + err = data.createNginxPodOnNode(testPodName, data.testNamespace, node, false) r.NoError(err, "Error creating test Pod: %v", err) } clientName := randName("test-client-") - err = data.createBusyboxPodOnNode(clientName, testNamespace, node, false) - r.NoError(err, "Error when creating Pod %s", clientName) + err = data.createAgnhostPodOnNode(clientName, data.testNamespace, node, false) + r.NoError(err, "Error when creating AgnhostPod %s", clientName) - err = data.podWaitForRunning(defaultTimeout, clientName, testNamespace) + err = data.podWaitForRunning(defaultTimeout, clientName, data.testNamespace) r.NoError(err, "Error when waiting for Pod %s to be running", clientName) antreaPod, err := data.getAntreaPodOnNode(node) @@ -502,14 +617,20 @@ func testNPLMultiplePodsAgentRestart(t *testing.T, data *TestData) { r.Len(nplAnnotations, 1) // Make sure the rule is present first. It should always be the case if the Pod was already // annotated. - checkNPLRulesForPod(t, data, r, nplAnnotations, antreaPod, testPodIP, true) + + checkNPLRules(t, testData, r, nplAnnotations, antreaPod, testPodIP, node, true) ruleToDelete := nplRuleData{ + nodeIP: node, nodePort: nplAnnotations[0].NodePort, podIP: testPodIP, podPort: nplAnnotations[0].PodPort, protocol: protocolToString(corev1.ProtocolTCP), } - deleteNPLRuleFromIPTables(t, data, r, antreaPod, ruleToDelete) + if !winenv { + deleteNPLRuleFromIPTables(t, data, r, antreaPod, ruleToDelete) + } else { + deleteNPLRuleFromNetNat(t, data, r, antreaPod, ruleToDelete) + } err = data.restartAntreaAgentPods(defaultTimeout) r.NoError(err, "Error when restarting Antrea Agent Pods") @@ -521,11 +642,12 @@ func testNPLMultiplePodsAgentRestart(t *testing.T, data *TestData) { for _, testPodName := range testPods { nplAnnotations, testPodIP := getNPLAnnotations(t, data, r, testPodName) - checkNPLRulesForPod(t, data, r, nplAnnotations, antreaPod, testPodIP, true) + checkNPLRules(t, testData, r, nplAnnotations, antreaPod, testPodIP, node, true) expectedAnnotations.Check(t, nplAnnotations) checkTrafficForNPL(data, r, nplAnnotations, clientName) + testData.DeletePod(data.testNamespace, testPodName) } - + testData.DeletePod(data.testNamespace, clientName) } // testNPLChangePortRangeAgentRestart tests NodePortLocal functionalities after changing port range. @@ -542,20 +664,23 @@ func testNPLChangePortRangeAgentRestart(t *testing.T, data *TestData) { data.createNginxClusterIPServiceWithAnnotations(false, &ipFamily, annotation) node := nodeName(0) + if len(clusterInfo.windowsNodes) != 0 { + node = workerNodeName(clusterInfo.windowsNodes[0]) + } var testPods []string var err error for i := 0; i < 4; i++ { testPodName := randName("test-pod-") testPods = append(testPods, testPodName) - err = data.createNginxPodOnNode(testPodName, testNamespace, node, false) + err = data.createNginxPodOnNode(testPodName, data.testNamespace, node, false) r.NoError(err, "Error Creating test Pod: %v", err) } clientName := randName("test-client-") - err = data.createBusyboxPodOnNode(clientName, testNamespace, node, false) - r.NoError(err, "Error when creating Pod %s", clientName) + err = data.createAgnhostPodOnNode(clientName, data.testNamespace, node, false) + r.NoError(err, "Error when creating AgnhostPod %s", clientName) - err = data.podWaitForRunning(defaultTimeout, clientName, testNamespace) + err = data.podWaitForRunning(defaultTimeout, clientName, data.testNamespace) r.NoError(err, "Error when waiting for Pod %s to be running", clientName) var rules []nplRuleData @@ -580,14 +705,22 @@ func testNPLChangePortRangeAgentRestart(t *testing.T, data *TestData) { r.NoError(err, "Error when getting Antrea Agent Pod on Node '%s'", node) expectedAnnotations := newExpectedNPLAnnotations(updatedStartPort, updatedEndPort).Add(nil, defaultTargetPort, "tcp") + + if clusterInfo.nodesOS[node] == "windows" { + time.Sleep(10 * time.Second) + checkForNPLRuleInNetNat(t, data, r, antreaPod, node, rules, false) + } else { + checkForNPLRuleInIPTables(t, data, r, antreaPod, rules, false) + checkForNPLListeningSockets(t, data, r, antreaPod, rules, false) + } + for _, testPodName := range testPods { nplAnnotations, testPodIP := getNPLAnnotations(t, data, r, testPodName) - checkNPLRulesForPod(t, data, r, nplAnnotations, antreaPod, testPodIP, true) + checkNPLRules(t, data, r, nplAnnotations, antreaPod, testPodIP, node, true) expectedAnnotations.Check(t, nplAnnotations) checkTrafficForNPL(data, r, nplAnnotations, clientName) + testData.DeletePod(data.testNamespace, testPodName) } - - checkForNPLRuleInIPTables(t, data, r, antreaPod, rules, false) - checkForNPLListeningSockets(t, data, r, antreaPod, rules, false) + testData.DeletePod(data.testNamespace, clientName) } diff --git a/test/e2e/performance_test.go b/test/e2e/performance_test.go index 02b32f6664c..37aaf6e4930 100644 --- a/test/e2e/performance_test.go +++ b/test/e2e/performance_test.go @@ -50,8 +50,6 @@ var ( customizePolicyRules = flag.Int("perf.http.policy_rules", 0, "Number of CIDRs in the network policy") httpConcurrency = flag.Int("perf.http.concurrency", 1, "Number of multiple requests to make at a time") realizeTimeout = flag.Duration("perf.realize.timeout", 5*time.Minute, "Timeout of the realization of network policies") - // tolerate NoSchedule taint to let the Pod run on control-plane Node - noScheduleToleration = controlPlaneNoScheduleToleration() labelSelector = &metav1.LabelSelector{ MatchLabels: map[string]string{"app": perfTestAppLabel}, } @@ -118,7 +116,7 @@ func createPerfTestPodDefinition(name, containerName, image string) *corev1.Pod "kubernetes.io/hostname": controlPlaneNodeName(), } - podSpec.Tolerations = []corev1.Toleration{noScheduleToleration} + podSpec.Tolerations = controlPlaneNoScheduleTolerations() pod := &corev1.Pod{ ObjectMeta: metav1.ObjectMeta{ Name: name, @@ -144,7 +142,7 @@ func setupTestPodsConnection(data *TestData) error { ObjectMeta: metav1.ObjectMeta{Name: podsConnectionNetworkPolicyName}, Spec: npSpec, } - _, err := data.clientset.NetworkingV1().NetworkPolicies(testNamespace).Create(context.TODO(), np, metav1.CreateOptions{}) + _, err := data.clientset.NetworkingV1().NetworkPolicies(data.testNamespace).Create(context.TODO(), np, metav1.CreateOptions{}) return err } @@ -172,31 +170,31 @@ func generateWorkloadNetworkPolicy(policyRules int) *networkv1.NetworkPolicy { } func populateWorkloadNetworkPolicy(np *networkv1.NetworkPolicy, data *TestData) error { - _, err := data.clientset.NetworkingV1().NetworkPolicies(testNamespace).Create(context.TODO(), np, metav1.CreateOptions{}) + _, err := data.clientset.NetworkingV1().NetworkPolicies(data.testNamespace).Create(context.TODO(), np, metav1.CreateOptions{}) return err } func setupTestPods(data *TestData, b *testing.B) (nginxPodIP, perfPodIP *PodIPs) { b.Logf("Creating a nginx test Pod") nginxPod := createPerfTestPodDefinition(benchNginxPodName, nginxContainerName, nginxImage) - _, err := data.clientset.CoreV1().Pods(testNamespace).Create(context.TODO(), nginxPod, metav1.CreateOptions{}) + _, err := data.clientset.CoreV1().Pods(data.testNamespace).Create(context.TODO(), nginxPod, metav1.CreateOptions{}) if err != nil { b.Fatalf("Error when creating nginx test pod: %v", err) } b.Logf("Waiting IP assignment of the nginx test Pod") - nginxPodIP, err = data.podWaitForIPs(defaultTimeout, benchNginxPodName, testNamespace) + nginxPodIP, err = data.podWaitForIPs(defaultTimeout, benchNginxPodName, data.testNamespace) if err != nil { b.Fatalf("Error when waiting for IP assignment of nginx test Pod: %v", err) } b.Logf("Creating a perftool test Pod") perfPod := createPerfTestPodDefinition(perftoolPodName, perftoolContainerName, perftoolImage) - _, err = data.clientset.CoreV1().Pods(testNamespace).Create(context.TODO(), perfPod, metav1.CreateOptions{}) + _, err = data.clientset.CoreV1().Pods(data.testNamespace).Create(context.TODO(), perfPod, metav1.CreateOptions{}) if err != nil { b.Fatalf("Error when creating perftool test Pod: %v", err) } b.Logf("Waiting for IP assignment of the perftool test Pod") - perfPodIP, err = data.podWaitForIPs(defaultTimeout, perftoolPodName, testNamespace) + perfPodIP, err = data.podWaitForIPs(defaultTimeout, perftoolPodName, data.testNamespace) if err != nil { b.Fatalf("Error when waiting for IP assignment of perftool test Pod: %v", err) } @@ -237,7 +235,7 @@ func httpRequest(requests, policyRules int, data *TestData, b *testing.B) { for i := 0; i < b.N; i++ { b.Logf("Running http request bench %d/%d", i+1, b.N) cmd := []string{"ab", "-n", fmt.Sprint(requests), "-c", fmt.Sprint(*httpConcurrency), serverURL.String()} - stdout, stderr, err := data.RunCommandFromPod(testNamespace, perftoolPodName, perftoolContainerName, cmd) + stdout, stderr, err := data.RunCommandFromPod(data.testNamespace, perftoolPodName, perftoolContainerName, cmd) if err != nil { b.Errorf("Error when running http request %dx: %v, stdout: %s, stderr: %s\n", requests, err, stdout, stderr) } @@ -270,7 +268,7 @@ func networkPolicyRealize(policyRules int, data *TestData, b *testing.B) { b.StopTimer() b.Log("Network policy realized") - err = data.clientset.NetworkingV1().NetworkPolicies(testNamespace).Delete(context.TODO(), workloadNetworkPolicyName, metav1.DeleteOptions{}) + err = data.clientset.NetworkingV1().NetworkPolicies(data.testNamespace).Delete(context.TODO(), workloadNetworkPolicyName, metav1.DeleteOptions{}) if err != nil { b.Fatalf("Error when cleaning up network policies after running one bench iteration: %v", err) } diff --git a/test/e2e/prometheus_test.go b/test/e2e/prometheus_test.go index 08571fd3437..b3e1732b1df 100644 --- a/test/e2e/prometheus_test.go +++ b/test/e2e/prometheus_test.go @@ -109,20 +109,14 @@ func skipIfPrometheusDisabled(t *testing.T) { // getMonitoringAuthToken retrieves monitoring authorization token, required for access to Antrea apiserver/metrics // resource func getMonitoringAuthToken(t *testing.T, data *TestData) string { - secrets, err := data.clientset.CoreV1().Secrets(monitoringNamespace).List(context.TODO(), metav1.ListOptions{}) + const secretName = "prometheus-service-account-token" + secret, err := data.clientset.CoreV1().Secrets(monitoringNamespace).Get(context.TODO(), secretName, metav1.GetOptions{}) if err != nil { - t.Fatalf("Error fetching monitoring secrets: %v", err) + t.Fatalf("Error fetching monitoring secret '%s': %v", secretName, err) } - - var token string - for _, secret := range secrets.Items { - if secret.Annotations["kubernetes.io/service-account.name"] == "prometheus" { - token = string(secret.Data[v1.ServiceAccountTokenKey]) - } - } - + token := string(secret.Data[v1.ServiceAccountTokenKey]) if len(token) == 0 { - t.Fatal("Prometheus ServiceAccount secret not found") + t.Fatalf("Monitoring secret '%s' does not include token", secretName) } return token diff --git a/test/e2e/providers/exec/docker.go b/test/e2e/providers/exec/docker.go index 97b00790b12..5f5fc59193c 100644 --- a/test/e2e/providers/exec/docker.go +++ b/test/e2e/providers/exec/docker.go @@ -16,9 +16,11 @@ package exec import ( "fmt" + "io" "io/ioutil" "os/exec" "strings" + "sync" ) // TODO: we could use the Docker Go SDK for this, but it seems like a big dependency to pull in just @@ -27,11 +29,20 @@ import ( // RunDockerExecCommand runs the provided command on the specified host using "docker exec". Returns // the exit code of the command, along with the contents of stdout and stderr as strings. Note that // if the command returns a non-zero error code, this function does not report it as an error. -func RunDockerExecCommand(container string, cmd string, workdir string) ( +func RunDockerExecCommand(container, cmd, workdir string, envs map[string]string, stdin string) ( code int, stdout string, stderr string, err error, ) { - args := make([]string, 0) - args = append(args, "exec", "-w", workdir, "-t", container) + args := []string{"exec"} + // Set environment variables. + for e, v := range envs { + args = append(args, "-e", e+"="+v) + } + if stdin != "" { + // Interactive mode to get input from stdin. + args = append(args, "-i") + } + args = append(args, "-w", workdir, container) + if strings.Contains(cmd, "/bin/sh") { // Just split in to "/bin/sh" "-c" and "actual_cmd" // This is useful for passing piped commands in to os/exec interface. @@ -39,7 +50,9 @@ func RunDockerExecCommand(container string, cmd string, workdir string) ( } else { args = append(args, strings.Fields(cmd)...) } + dockerCmd := exec.Command("docker", args...) + stdoutPipe, err := dockerCmd.StdoutPipe() if err != nil { return 0, "", "", fmt.Errorf("error when connecting to stdout: %v", err) @@ -48,12 +61,33 @@ func RunDockerExecCommand(container string, cmd string, workdir string) ( if err != nil { return 0, "", "", fmt.Errorf("error when connecting to stderr: %v", err) } + if stdin != "" { + stdinPipe, err := dockerCmd.StdinPipe() + if err != nil { + return 0, "", "", fmt.Errorf("error when connecting to stdin: %v", err) + } + _, err = io.WriteString(stdinPipe, stdin) + stdinPipe.Close() + if err != nil { + return 0, "", "", fmt.Errorf("error when writing to stdin: %v", err) + } + } + if err := dockerCmd.Start(); err != nil { return 0, "", "", fmt.Errorf("error when starting command: %v", err) } - - stdoutBytes, _ := ioutil.ReadAll(stdoutPipe) - stderrBytes, _ := ioutil.ReadAll(stderrPipe) + var stdoutBytes, stderrBytes []byte + var wg sync.WaitGroup + wg.Add(2) + go func() { + defer wg.Done() + stdoutBytes, _ = ioutil.ReadAll(stdoutPipe) + }() + go func() { + defer wg.Done() + stderrBytes, _ = ioutil.ReadAll(stderrPipe) + }() + wg.Wait() if err := dockerCmd.Wait(); err != nil { if e, ok := err.(*exec.ExitError); ok { diff --git a/test/e2e/providers/exec/ssh.go b/test/e2e/providers/exec/ssh.go index d6b128a4ab4..6701c1f29f1 100644 --- a/test/e2e/providers/exec/ssh.go +++ b/test/e2e/providers/exec/ssh.go @@ -17,6 +17,7 @@ package exec import ( "bytes" "fmt" + "strings" "golang.org/x/crypto/ssh" ) @@ -24,7 +25,8 @@ import ( // RunSSHCommand runs the provided SSH command on the specified host. Returns the exit code of the // command, along with the contents of stdout and stderr as strings. Note that if the command // returns a non-zero error code, this function does not report it as an error. -func RunSSHCommand(host string, config *ssh.ClientConfig, cmd string) (code int, stdout string, stderr string, err error) { +func RunSSHCommand(host string, config *ssh.ClientConfig, cmd string, envs map[string]string, stdin string, sudo bool) ( + code int, stdout, stderr string, err error) { client, err := ssh.Dial("tcp", host, config) if err != nil { return 0, "", "", fmt.Errorf("cannot establish SSH connection to host: %v", err) @@ -35,9 +37,24 @@ func RunSSHCommand(host string, config *ssh.ClientConfig, cmd string) (code int, } defer session.Close() + // Set environment variables. + for e, v := range envs { + // Session.Setenv() requires that the remote host's sshd configuration accepts + // environment variables set by clients. So, just pre-appending environment + // variables to the command. + cmd = e + "='" + v + "' " + cmd + } + if sudo { + cmd = "sudo " + cmd + } + var stdoutB, stderrB bytes.Buffer session.Stdout = &stdoutB session.Stderr = &stderrB + if stdin != "" { + session.Stdin = strings.NewReader(stdin) + } + if err := session.Run(cmd); err != nil { switch e := err.(type) { case *ssh.ExitMissingError: diff --git a/test/e2e/providers/interface.go b/test/e2e/providers/interface.go index 7ca4224dd8f..4ddcbdd551e 100644 --- a/test/e2e/providers/interface.go +++ b/test/e2e/providers/interface.go @@ -18,5 +18,7 @@ package providers // run on a variety of providers. type ProviderInterface interface { RunCommandOnNode(nodeName string, cmd string) (code int, stdout string, stderr string, err error) + // RunCommandOnNodeExt supports passing environment variables and writing the input to stdin. + RunCommandOnNodeExt(nodeName, cmd string, envs map[string]string, stdin string, sudo bool) (code int, stdout string, stderr string, err error) GetKubeconfigPath() (string, error) } diff --git a/test/e2e/providers/kind.go b/test/e2e/providers/kind.go index df4caaaf7a6..e5bab149cbe 100644 --- a/test/e2e/providers/kind.go +++ b/test/e2e/providers/kind.go @@ -30,13 +30,20 @@ type KindProvider struct { func (provider *KindProvider) RunCommandOnControlPlaneNode(cmd string) ( code int, stdout string, stderr string, err error, ) { - return exec.RunDockerExecCommand(provider.controlPlaneNodeName, cmd, "/root") + return exec.RunDockerExecCommand(provider.controlPlaneNodeName, cmd, "/root", nil, "") } func (provider *KindProvider) RunCommandOnNode(nodeName string, cmd string) ( code int, stdout string, stderr string, err error, ) { - return exec.RunDockerExecCommand(nodeName, cmd, "/root") + return exec.RunDockerExecCommand(nodeName, cmd, "/root", nil, "") +} + +func (provider *KindProvider) RunCommandOnNodeExt(nodeName, cmd string, envs map[string]string, stdin string, sudo bool) ( + code int, stdout string, stderr string, err error, +) { + // sudo is not needed for Docker exec, so ignore the argument. + return exec.RunDockerExecCommand(nodeName, cmd, "/root", envs, stdin) } func (provider *KindProvider) GetKubeconfigPath() (string, error) { diff --git a/test/e2e/providers/remote.go b/test/e2e/providers/remote.go index 7158e7823e3..615fd6ded75 100644 --- a/test/e2e/providers/remote.go +++ b/test/e2e/providers/remote.go @@ -56,7 +56,16 @@ func (p *RemoteProvider) RunCommandOnNode(nodeName string, cmd string) (code int if err != nil { return 0, "", "", err } - return exec.RunSSHCommand(host, clientCfg, cmd) + return exec.RunSSHCommand(host, clientCfg, cmd, nil, "", false) +} + +func (p *RemoteProvider) RunCommandOnNodeExt(nodeName, cmd string, envs map[string]string, stdin string, sudo bool) ( + code int, stdout, stderr string, err error) { + host, clientCfg, err := convertConfig(p.sshConfig, nodeName) + if err != nil { + return 0, "", "", err + } + return exec.RunSSHCommand(host, clientCfg, cmd, envs, stdin, sudo) } func (p *RemoteProvider) GetKubeconfigPath() (string, error) { diff --git a/test/e2e/providers/vagrant.go b/test/e2e/providers/vagrant.go index 1ce53a26ddd..118812873f0 100644 --- a/test/e2e/providers/vagrant.go +++ b/test/e2e/providers/vagrant.go @@ -121,7 +121,16 @@ func (provider *VagrantProvider) RunCommandOnNode(nodeName string, cmd string) ( if err != nil { return 0, "", "", fmt.Errorf("error when retrieving SSH config for node '%s': %v", nodeName, err) } - return exec.RunSSHCommand(host, config, cmd) + return exec.RunSSHCommand(host, config, cmd, nil, "", false) +} + +func (provider *VagrantProvider) RunCommandOnNodeExt(nodeName, cmd string, envs map[string]string, stdin string, sudo bool) ( + code int, stdout, stderr string, err error) { + host, config, err := GetSSHConfig(nodeName) + if err != nil { + return 0, "", "", fmt.Errorf("error when retrieving SSH config for node '%s': %v", nodeName, err) + } + return exec.RunSSHCommand(host, config, cmd, envs, stdin, sudo) } func (provider *VagrantProvider) GetKubeconfigPath() (string, error) { diff --git a/test/e2e/proxy_test.go b/test/e2e/proxy_test.go index 1739afa6eac..4289b1558a5 100644 --- a/test/e2e/proxy_test.go +++ b/test/e2e/proxy_test.go @@ -28,8 +28,6 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "antrea.io/antrea/pkg/agent/config" - agentconfig "antrea.io/antrea/pkg/config/agent" - controllerconfig "antrea.io/antrea/pkg/config/controller" ) type expectTableFlows struct { @@ -112,9 +110,9 @@ func probeClientIPFromNode(node string, baseUrl string, data *TestData) (string, func probeFromPod(data *TestData, pod, container string, url string) error { var err error if container == busyboxContainerName { - _, _, err = data.runWgetCommandOnBusyboxWithRetry(pod, testNamespace, url, 5) + _, _, err = data.runWgetCommandOnBusyboxWithRetry(pod, data.testNamespace, url, 5) } else { - _, _, err = data.RunCommandFromPod(testNamespace, pod, container, []string{"wget", "-O", "-", url, "-T", "5"}) + _, _, err = data.RunCommandFromPod(data.testNamespace, pod, container, []string{"wget", "-O", "-", url, "-T", "5"}) } return err } @@ -124,9 +122,9 @@ func probeHostnameFromPod(data *TestData, pod, container string, baseUrl string) var err error var hostname string if container == busyboxContainerName { - hostname, _, err = data.runWgetCommandOnBusyboxWithRetry(pod, testNamespace, url, 5) + hostname, _, err = data.runWgetCommandOnBusyboxWithRetry(pod, data.testNamespace, url, 5) } else { - hostname, _, err = data.RunCommandFromPod(testNamespace, pod, container, []string{"wget", "-O", "-", url, "-T", "5"}) + hostname, _, err = data.RunCommandFromPod(data.testNamespace, pod, container, []string{"wget", "-O", "-", url, "-T", "5"}) } return hostname, err } @@ -136,9 +134,9 @@ func probeClientIPFromPod(data *TestData, pod, container string, baseUrl string) var err error var hostPort string if container == busyboxContainerName { - hostPort, _, err = data.runWgetCommandOnBusyboxWithRetry(pod, testNamespace, url, 5) + hostPort, _, err = data.runWgetCommandOnBusyboxWithRetry(pod, data.testNamespace, url, 5) } else { - hostPort, _, err = data.RunCommandFromPod(testNamespace, pod, container, []string{"wget", "-O", "-", url, "-T", "5"}) + hostPort, _, err = data.RunCommandFromPod(data.testNamespace, pod, container, []string{"wget", "-O", "-", url, "-T", "5"}) } if err != nil { return "", err @@ -169,6 +167,7 @@ func testProxyLoadBalancerService(t *testing.T, isIPv6 bool) { skipIfProxyDisabled(t) skipIfHasWindowsNodes(t) skipIfNumNodesLessThan(t, 2) + data, err := setupTest(t) if err != nil { t.Fatalf("Error when setting up test: %v", err) @@ -180,7 +179,7 @@ func testProxyLoadBalancerService(t *testing.T, isIPv6 bool) { nodes := []string{nodeName(0), nodeName(1)} var busyboxes, busyboxIPs []string for idx, node := range nodes { - podName, ips, _ := createAndWaitForPod(t, data, data.createBusyboxPodOnNode, fmt.Sprintf("busybox-%d-", idx), node, testNamespace, false) + podName, ips, _ := createAndWaitForPod(t, data, data.createBusyboxPodOnNode, fmt.Sprintf("busybox-%d-", idx), node, data.testNamespace, false) busyboxes = append(busyboxes, podName) if !isIPv6 { busyboxIPs = append(busyboxIPs, ips.ipv4.String()) @@ -221,7 +220,7 @@ func testProxyLoadBalancerService(t *testing.T, isIPv6 bool) { // Delete agnhost Pods which are not on host network and create new agnhost Pods which are on host network. hostAgnhosts := []string{"agnhost-host-0", "agnhost-host-1"} for idx, node := range nodes { - require.NoError(t, data.DeletePod(testNamespace, agnhosts[idx])) + require.NoError(t, data.DeletePod(data.testNamespace, agnhosts[idx])) createAgnhostPod(t, data, hostAgnhosts[idx], node, true) } t.Run("HostNetwork Endpoints", func(t *testing.T) { @@ -293,6 +292,7 @@ func testProxyNodePortService(t *testing.T, isIPv6 bool) { skipIfHasWindowsNodes(t) skipIfNumNodesLessThan(t, 2) skipIfProxyDisabled(t) + data, err := setupTest(t) if err != nil { t.Fatalf("Error when setting up test: %v", err) @@ -311,7 +311,7 @@ func testProxyNodePortService(t *testing.T, isIPv6 bool) { // Create a busybox Pod on every Node. The busybox Pod is used as a client. var busyboxes, busyboxIPs []string for idx, node := range nodes { - podName, ips, _ := createAndWaitForPod(t, data, data.createBusyboxPodOnNode, fmt.Sprintf("busybox-%d-", idx), node, testNamespace, false) + podName, ips, _ := createAndWaitForPod(t, data, data.createBusyboxPodOnNode, fmt.Sprintf("busybox-%d-", idx), node, data.testNamespace, false) busyboxes = append(busyboxes, podName) if !isIPv6 { busyboxIPs = append(busyboxIPs, ips.ipv4.String()) @@ -354,7 +354,7 @@ func testProxyNodePortService(t *testing.T, isIPv6 bool) { // Delete agnhost Pods which are not on host network and create new agnhost Pods which are on host network. hostAgnhosts := []string{"agnhost-host-0", "agnhost-host-1"} for idx, node := range nodes { - require.NoError(t, data.DeletePod(testNamespace, agnhosts[idx])) + require.NoError(t, data.DeletePod(data.testNamespace, agnhosts[idx])) createAgnhostPod(t, data, hostAgnhosts[idx], node, true) } t.Run("HostNetwork Endpoints", func(t *testing.T) { @@ -396,7 +396,9 @@ func TestNodePortAndEgressWithTheSameBackendPod(t *testing.T) { skipIfHasWindowsNodes(t) skipIfNotIPv4Cluster(t) skipIfNumNodesLessThan(t, 2) + skipIfAntreaIPAMTest(t) skipIfProxyDisabled(t) + skipIfEgressDisabled(t) data, err := setupTest(t) if err != nil { @@ -406,17 +408,6 @@ func TestNodePortAndEgressWithTheSameBackendPod(t *testing.T) { skipIfProxyAllDisabled(t, data) skipIfEncapModeIsNot(t, data, config.TrafficEncapModeEncap) // Egress works for encap mode only. - cc := func(config *controllerconfig.ControllerConfig) { - config.FeatureGates["Egress"] = true - } - ac := func(config *agentconfig.AgentConfig) { - config.FeatureGates["Egress"] = true - } - - if err := data.mutateAntreaConfigMap(cc, ac, true, true); err != nil { - t.Fatalf("Failed to enable Egress feature: %v", err) - } - // Create a NodePort Service. nodePortIP := controlPlaneNodeIPv4() ipProtocol := corev1.IPv4Protocol @@ -438,9 +429,9 @@ func TestNodePortAndEgressWithTheSameBackendPod(t *testing.T) { // Create the backend Pod on control plane Node. backendPodName := "test-nodeport-egress-backend-pod" - require.NoError(t, data.createNginxPodOnNode(backendPodName, testNamespace, controlPlaneNodeName(), false)) - defer deletePodWrapper(t, data, testNamespace, backendPodName) - if err := data.podWaitForRunning(defaultTimeout, backendPodName, testNamespace); err != nil { + require.NoError(t, data.createNginxPodOnNode(backendPodName, data.testNamespace, controlPlaneNodeName(), false)) + defer deletePodWrapper(t, data, data.testNamespace, backendPodName) + if err := data.podWaitForRunning(defaultTimeout, backendPodName, data.testNamespace); err != nil { t.Fatalf("Error when waiting for Pod '%s' to be in the Running state", backendPodName) } @@ -457,19 +448,19 @@ ip netns exec %[1]s ip link set dev %[1]s-a up && \ ip netns exec %[1]s ip route replace default via %[3]s && \ sleep 3600 `, testNetns, "1.1.1.1", "1.1.1.254", 24) - if err := data.createPodOnNode(testPod, testNamespace, controlPlaneNodeName(), agnhostImage, []string{"sh", "-c", cmd}, nil, nil, nil, true, func(pod *corev1.Pod) { + if err := data.createPodOnNode(testPod, data.testNamespace, controlPlaneNodeName(), agnhostImage, []string{"sh", "-c", cmd}, nil, nil, nil, true, func(pod *corev1.Pod) { privileged := true pod.Spec.Containers[0].SecurityContext = &corev1.SecurityContext{Privileged: &privileged} }); err != nil { t.Fatalf("Failed to create client Pod: %v", err) } - defer deletePodWrapper(t, data, testNamespace, testPod) - if err := data.podWaitForRunning(defaultTimeout, testPod, testNamespace); err != nil { + defer deletePodWrapper(t, data, data.testNamespace, testPod) + if err := data.podWaitForRunning(defaultTimeout, testPod, data.testNamespace); err != nil { t.Fatalf("Error when waiting for Pod '%s' to be in the Running state", testPod) } // Connect to NodePort on control plane Node in the fake external network. cmd = fmt.Sprintf("ip netns exec %s curl --connect-timeout 1 --retry 5 --retry-connrefused %s", testNetns, testNodePortURL) - _, _, err = data.RunCommandFromPod(testNamespace, testPod, agnhostContainerName, []string{"sh", "-c", cmd}) + _, _, err = data.RunCommandFromPod(data.testNamespace, testPod, agnhostContainerName, []string{"sh", "-c", cmd}) require.NoError(t, err, "Service NodePort should be able to be connected from external network when Egress is enabled") } @@ -483,10 +474,10 @@ func createAgnhostPod(t *testing.T, data *TestData, podName string, node string, }, } - require.NoError(t, data.createPodOnNode(podName, testNamespace, node, agnhostImage, []string{}, args, nil, ports, hostNetwork, nil)) - _, err := data.podWaitForIPs(defaultTimeout, podName, testNamespace) + require.NoError(t, data.createPodOnNode(podName, data.testNamespace, node, agnhostImage, []string{}, args, nil, ports, hostNetwork, nil)) + _, err := data.podWaitForIPs(defaultTimeout, podName, data.testNamespace) require.NoError(t, err) - require.NoError(t, data.podWaitForRunning(defaultTimeout, podName, testNamespace)) + require.NoError(t, data.podWaitForRunning(defaultTimeout, podName, data.testNamespace)) } func testNodePortClusterFromRemote(t *testing.T, data *TestData, nodes, urls []string) { @@ -550,6 +541,7 @@ func testNodePortLocalFromPod(t *testing.T, data *TestData, pods, urls, expected func TestProxyServiceSessionAffinity(t *testing.T) { skipIfHasWindowsNodes(t) skipIfProxyDisabled(t) + data, err := setupTest(t) if err != nil { t.Fatalf("Error when setting up test: %v", err) @@ -580,6 +572,7 @@ func testProxyExternalTrafficPolicy(t *testing.T, isIPv6 bool) { skipIfHasWindowsNodes(t) skipIfNumNodesLessThan(t, 2) skipIfProxyDisabled(t) + data, err := setupTest(t) if err != nil { t.Fatalf("Error when setting up test: %v", err) @@ -639,26 +632,26 @@ func testProxyServiceSessionAffinity(ipFamily *corev1.IPFamily, ingressIPs []str nodeName := nodeName(1) nginx := randName("nginx-") - require.NoError(t, data.createNginxPodOnNode(nginx, testNamespace, nodeName, false)) - nginxIP, err := data.podWaitForIPs(defaultTimeout, nginx, testNamespace) - defer data.deletePodAndWait(defaultTimeout, nginx, testNamespace) + require.NoError(t, data.createNginxPodOnNode(nginx, data.testNamespace, nodeName, false)) + nginxIP, err := data.podWaitForIPs(defaultTimeout, nginx, data.testNamespace) + defer data.deletePodAndWait(defaultTimeout, nginx, data.testNamespace) require.NoError(t, err) - require.NoError(t, data.podWaitForRunning(defaultTimeout, nginx, testNamespace)) - svc, err := data.createNginxClusterIPService(nginx, testNamespace, true, ipFamily) - defer data.deleteServiceAndWait(defaultTimeout, nginx, testNamespace) + require.NoError(t, data.podWaitForRunning(defaultTimeout, nginx, data.testNamespace)) + svc, err := data.createNginxClusterIPService(nginx, data.testNamespace, true, ipFamily) + defer data.deleteServiceAndWait(defaultTimeout, nginx, data.testNamespace) require.NoError(t, err) _, err = data.createNginxLoadBalancerService(true, ingressIPs, ipFamily) - defer data.deleteServiceAndWait(defaultTimeout, nginxLBService, testNamespace) + defer data.deleteServiceAndWait(defaultTimeout, nginxLBService, data.testNamespace) require.NoError(t, err) busyboxPod := randName("busybox-") - require.NoError(t, data.createBusyboxPodOnNode(busyboxPod, testNamespace, nodeName, false)) - defer data.deletePodAndWait(defaultTimeout, busyboxPod, testNamespace) - require.NoError(t, data.podWaitForRunning(defaultTimeout, busyboxPod, testNamespace)) - stdout, stderr, err := data.runWgetCommandOnBusyboxWithRetry(busyboxPod, testNamespace, svc.Spec.ClusterIP, 5) + require.NoError(t, data.createBusyboxPodOnNode(busyboxPod, data.testNamespace, nodeName, false)) + defer data.deletePodAndWait(defaultTimeout, busyboxPod, data.testNamespace) + require.NoError(t, data.podWaitForRunning(defaultTimeout, busyboxPod, data.testNamespace)) + stdout, stderr, err := data.runWgetCommandOnBusyboxWithRetry(busyboxPod, data.testNamespace, svc.Spec.ClusterIP, 5) require.NoError(t, err, fmt.Sprintf("ipFamily: %v\nstdout: %s\nstderr: %s\n", *ipFamily, stdout, stderr)) for _, ingressIP := range ingressIPs { - stdout, stderr, err := data.runWgetCommandOnBusyboxWithRetry(busyboxPod, testNamespace, ingressIP, 5) + stdout, stderr, err := data.runWgetCommandOnBusyboxWithRetry(busyboxPod, data.testNamespace, ingressIP, 5) require.NoError(t, err, fmt.Sprintf("ipFamily: %v\nstdout: %s\nstderr: %s\n", *ipFamily, stdout, stderr)) } @@ -724,7 +717,7 @@ func testProxyHairpin(t *testing.T, isIPv6 bool) { // Create a ClusterIP Service. serviceClusterIP := fmt.Sprintf("clusterip-%v", isIPv6) clusterIPSvc, err := data.createAgnhostClusterIPService(serviceClusterIP, true, &ipProtocol) - defer data.deleteServiceAndWait(defaultTimeout, serviceClusterIP, testNamespace) + defer data.deleteServiceAndWait(defaultTimeout, serviceClusterIP, data.testNamespace) require.NoError(t, err) // Create two NodePort Services. The externalTrafficPolicy of one Service is Cluster, and the externalTrafficPolicy @@ -733,7 +726,7 @@ func testProxyHairpin(t *testing.T, isIPv6 bool) { serviceNodePortCluster := fmt.Sprintf("nodeport-cluster-%v", isIPv6) serviceNodePortLocal := fmt.Sprintf("nodeport-local-%v", isIPv6) nodePortSvc, err := data.createAgnhostNodePortService(serviceNodePortCluster, true, false, &ipProtocol) - defer data.deleteServiceAndWait(defaultTimeout, serviceNodePortCluster, testNamespace) + defer data.deleteServiceAndWait(defaultTimeout, serviceNodePortCluster, data.testNamespace) require.NoError(t, err) for _, port := range nodePortSvc.Spec.Ports { if port.NodePort != 0 { @@ -744,7 +737,7 @@ func testProxyHairpin(t *testing.T, isIPv6 bool) { require.NotEqual(t, "", nodePortCluster, "NodePort port number should not be empty") nodePortSvc, err = data.createAgnhostNodePortService(serviceNodePortLocal, true, true, &ipProtocol) require.NoError(t, err) - defer data.deleteServiceAndWait(defaultTimeout, serviceNodePortLocal, testNamespace) + defer data.deleteServiceAndWait(defaultTimeout, serviceNodePortLocal, data.testNamespace) for _, port := range nodePortSvc.Spec.Ports { if port.NodePort != 0 { nodePortLocal = fmt.Sprint(port.NodePort) @@ -786,7 +779,7 @@ func testProxyHairpin(t *testing.T, isIPv6 bool) { testProxyIntraNodeHairpinCases(data, t, expectedGatewayIP, agnhost, clusterIPUrl, workerNodePortClusterUrl, workerNodePortLocalUrl, lbClusterUrl, lbLocalUrl) testProxyInterNodeHairpinCases(data, t, false, expectedControllerIP, nodeName(0), clusterIPUrl, controllerNodePortClusterUrl, lbClusterUrl) }) - require.NoError(t, data.DeletePod(testNamespace, agnhost)) + require.NoError(t, data.DeletePod(data.testNamespace, agnhost)) agnhostHost := fmt.Sprintf("agnhost-host-%v", isIPv6) createAgnhostPod(t, data, agnhostHost, node, true) @@ -907,6 +900,7 @@ func testProxyEndpointLifeCycleCase(t *testing.T, data *TestData) { func TestProxyEndpointLifeCycle(t *testing.T) { skipIfHasWindowsNodes(t) skipIfProxyDisabled(t) + data, err := setupTest(t) if err != nil { t.Fatalf("Error when setting up test: %v", err) @@ -926,11 +920,11 @@ func TestProxyEndpointLifeCycle(t *testing.T) { func testProxyEndpointLifeCycle(ipFamily *corev1.IPFamily, data *TestData, t *testing.T) { nodeName := nodeName(1) nginx := randName("nginx-") - require.NoError(t, data.createNginxPodOnNode(nginx, testNamespace, nodeName, false)) - nginxIPs, err := data.podWaitForIPs(defaultTimeout, nginx, testNamespace) + require.NoError(t, data.createNginxPodOnNode(nginx, data.testNamespace, nodeName, false)) + nginxIPs, err := data.podWaitForIPs(defaultTimeout, nginx, data.testNamespace) require.NoError(t, err) - _, err = data.createNginxClusterIPService(nginx, testNamespace, false, ipFamily) - defer data.deleteServiceAndWait(defaultTimeout, nginx, testNamespace) + _, err = data.createNginxClusterIPService(nginx, data.testNamespace, false, ipFamily) + defer data.deleteServiceAndWait(defaultTimeout, nginx, data.testNamespace) require.NoError(t, err) // Hold on to make sure that the Service is realized. @@ -967,7 +961,7 @@ func testProxyEndpointLifeCycle(ipFamily *corev1.IPFamily, data *TestData, t *te require.Contains(t, groupOutput, k) } - require.NoError(t, data.deletePodAndWait(defaultTimeout, nginx, testNamespace)) + require.NoError(t, data.deletePodAndWait(defaultTimeout, nginx, data.testNamespace)) // Wait for one second to make sure the pipeline to be updated. time.Sleep(time.Second) @@ -999,6 +993,7 @@ func testProxyServiceLifeCycleCase(t *testing.T, data *TestData) { func TestProxyServiceLifeCycle(t *testing.T) { skipIfHasWindowsNodes(t) skipIfProxyDisabled(t) + data, err := setupTest(t) if err != nil { t.Fatalf("Error when setting up test: %v", err) @@ -1019,9 +1014,9 @@ func testProxyServiceLifeCycle(ipFamily *corev1.IPFamily, ingressIPs []string, d nodeName := nodeName(1) nginx := randName("nginx-") - require.NoError(t, data.createNginxPodOnNode(nginx, testNamespace, nodeName, false)) - defer data.deletePodAndWait(defaultTimeout, nginx, testNamespace) - nginxIPs, err := data.podWaitForIPs(defaultTimeout, nginx, testNamespace) + require.NoError(t, data.createNginxPodOnNode(nginx, data.testNamespace, nodeName, false)) + defer data.deletePodAndWait(defaultTimeout, nginx, data.testNamespace) + nginxIPs, err := data.podWaitForIPs(defaultTimeout, nginx, data.testNamespace) require.NoError(t, err) var nginxIP string if *ipFamily == corev1.IPv6Protocol { @@ -1029,11 +1024,11 @@ func testProxyServiceLifeCycle(ipFamily *corev1.IPFamily, ingressIPs []string, d } else { nginxIP = nginxIPs.ipv4.String() } - svc, err := data.createNginxClusterIPService(nginx, testNamespace, false, ipFamily) - defer data.deleteServiceAndWait(defaultTimeout, nginx, testNamespace) + svc, err := data.createNginxClusterIPService(nginx, data.testNamespace, false, ipFamily) + defer data.deleteServiceAndWait(defaultTimeout, nginx, data.testNamespace) require.NoError(t, err) _, err = data.createNginxLoadBalancerService(false, ingressIPs, ipFamily) - defer data.deleteServiceAndWait(defaultTimeout, nginxLBService, testNamespace) + defer data.deleteServiceAndWait(defaultTimeout, nginxLBService, data.testNamespace) require.NoError(t, err) agentName, err := data.getAntreaPodOnNode(nodeName) require.NoError(t, err) @@ -1086,8 +1081,8 @@ func testProxyServiceLifeCycle(ipFamily *corev1.IPFamily, ingressIPs []string, d } } - require.NoError(t, data.deleteService(testNamespace, nginx)) - require.NoError(t, data.deleteService(testNamespace, nginxLBService)) + require.NoError(t, data.deleteService(data.testNamespace, nginx)) + require.NoError(t, data.deleteService(data.testNamespace, nginxLBService)) // Hold on to make sure that the Service is realized. time.Sleep(3 * time.Second) diff --git a/test/e2e/secondary_network_ipam_test.go b/test/e2e/secondary_network_ipam_test.go new file mode 100644 index 00000000000..6bb634a3688 --- /dev/null +++ b/test/e2e/secondary_network_ipam_test.go @@ -0,0 +1,286 @@ +// Copyright 2021 Antrea Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package e2e + +import ( + "context" + "testing" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "antrea.io/antrea/pkg/agent/config" + crdv1alpha2 "antrea.io/antrea/pkg/apis/crd/v1alpha2" + agentconfig "antrea.io/antrea/pkg/config/agent" + controllerconfig "antrea.io/antrea/pkg/config/controller" +) + +var ( + testIPPoolv4 = &crdv1alpha2.IPPool{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-ippool-ipv4", + }, + Spec: crdv1alpha2.IPPoolSpec{ + IPVersion: crdv1alpha2.IPv4, + IPRanges: []crdv1alpha2.SubnetIPRange{{IPRange: crdv1alpha2.IPRange{ + CIDR: "10.123.1.0/24", + }, + SubnetInfo: crdv1alpha2.SubnetInfo{ + Gateway: "10.123.1.254", + PrefixLength: 24, + }}}, + }, + } + + testIPPoolv6 = &crdv1alpha2.IPPool{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-ippool-ipv6", + }, + Spec: crdv1alpha2.IPPoolSpec{ + IPVersion: crdv1alpha2.IPv6, + IPRanges: []crdv1alpha2.SubnetIPRange{{IPRange: crdv1alpha2.IPRange{ + Start: "3ffe:ffff:1:01ff::0101", + End: "3ffe:ffff:1:01ff::0200", + }, + SubnetInfo: crdv1alpha2.SubnetInfo{ + Gateway: "3ffe:ffff:1:01ff::1", + PrefixLength: 64, + }}}, + }, + } + + cniCmd = "/opt/cni/bin/antrea" + + cniEnvs = map[string]string{ + "CNI_CONTAINERID": "test-container-id", + "CNI_NETNS": "/var/run/netns/test-netns", + "CNI_PATH": "/opt/cni/bin", + "CNI_ARGS": "K8S_POD_NAMESPACE=test-namespace;K8S_POD_NAME=test-pod", + } + + cniNetworkConfig = `{ + "cniVersion": "0.3.0", + "name": "test", + "type": "test-cni", + "keyA": ["some more", "plugin specific", "configuration"], + "ipam": { + "type": "antrea", + "ippools": [ "test-ippool-ipv4", "test-ippool-ipv6" ], + "addresses": [ + { + "address": "10.123.10.111/24", + "gateway": "10.123.10.1" + }, + { + "address": "3ffe:ffff:10:01ff::111/64", + "gateway": "3ffe:ffff:10::1" + } + ], + "routes": [ + { "dst": "0.0.0.0/0" }, + { "dst": "192.168.0.0/16", "gw": "10.10.5.1" }, + { "dst": "3ffe:ffff:0:01ff::1/64" } + ], + "dns": { + "nameservers" : ["8.8.8.8"], + "domain": "example.com", + "search": [ "example.com" ] + } + } +}` + + testOutput1 = `{ + "ips": [ + { + "version": "4", + "address": "10.123.1.1/24", + "gateway": "10.123.1.254" + }, + { + "version": "6", + "address": "3ffe:ffff:1:1ff::101/64", + "gateway": "3ffe:ffff:1:1ff::1" + }, + { + "version": "4", + "address": "10.123.10.111/24", + "gateway": "10.123.10.1" + }, + { + "version": "6", + "address": "3ffe:ffff:10:1ff::111/64", + "gateway": "3ffe:ffff:10::1" + } + ], + "routes": [ + { + "dst": "0.0.0.0/0" + }, + { + "dst": "192.168.0.0/16", + "gw": "10.10.5.1" + }, + { + "dst": "3ffe:ffff:0:1ff::1/64" + } + ], + "dns": { + "nameservers": [ + "8.8.8.8" + ], + "domain": "example.com", + "search": [ + "example.com" + ] + } +}` + + testOutput2 = `{ + "ips": [ + { + "version": "4", + "address": "10.123.1.2/24", + "gateway": "10.123.1.254" + }, + { + "version": "6", + "address": "3ffe:ffff:1:1ff::102/64", + "gateway": "3ffe:ffff:1:1ff::1" + }, + { + "version": "4", + "address": "10.123.10.111/24", + "gateway": "10.123.10.1" + }, + { + "version": "6", + "address": "3ffe:ffff:10:1ff::111/64", + "gateway": "3ffe:ffff:10::1" + } + ], + "routes": [ + { + "dst": "0.0.0.0/0" + }, + { + "dst": "192.168.0.0/16", + "gw": "10.10.5.1" + }, + { + "dst": "3ffe:ffff:0:1ff::1/64" + } + ], + "dns": { + "nameservers": [ + "8.8.8.8" + ], + "domain": "example.com", + "search": [ + "example.com" + ] + } +}` +) + +func executeCNI(t *testing.T, data *TestData, add, del bool, ifName string, expectedExitCode int, expectedOutput string) { + var code int + var stdout, stderr string + var err error + + t.Logf("Execute CNI for interface %s, ADD %v, DEL %v", ifName, add, del) + cniEnvs["CNI_IFNAME"] = ifName + defer delete(cniEnvs, "CNI_IFNAME") + + if add { + cniEnvs["CNI_COMMAND"] = "ADD" + defer delete(cniEnvs, "ADD") + // antrea CNI needs to be executed as root to connect to the antrea-agent CNI + // socket, so set sudo. + code, stdout, stderr, err = data.RunCommandOnNodeExt(nodeName(0), cniCmd, cniEnvs, cniNetworkConfig, true) + if err != nil { + t.Fatalf("Failed to execute CNI ADD: %v", err) + } + if code != expectedExitCode { + t.Fatalf("CNI ADD exits with code %d, expected %d, stdout:\n%s\nstderr: %s", code, expectedExitCode, stdout, stderr) + } + if expectedExitCode == 0 && stdout != expectedOutput { + t.Fatalf("CNI ADD output:\n%s\nexpected:\n%s", stdout, expectedOutput) + } + } + if del { + cniEnvs["CNI_COMMAND"] = "DEL" + defer delete(cniEnvs, "DEL") + code, stdout, stderr, err = data.RunCommandOnNodeExt(nodeName(0), cniCmd, cniEnvs, cniNetworkConfig, true) + if err != nil { + t.Fatalf("Failed to execute CNI DEL: %v", err) + } + if code != 0 { + t.Fatalf("CNI DEL exits with code %d, stdout:\n%s\nstderr: %s", code, stdout, stderr) + } + } +} + +// Test secondary network IPAM by executing Antrea CNI with forged CNI arguments +// and network configuration, and validating the CNI command output. Do not +// really install Multus and create secondary networks. +func TestSecondaryNetworkIPAM(t *testing.T) { + skipIfHasWindowsNodes(t) + // The test is about IPAM for secondary network, which should not be + // impacted by other modes and configurations, such as encap mode, + // AntreaProxy, IPv6, etc., so we skip those cases. + skipIfProxyDisabled(t) + skipIfNotIPv4Cluster(t) + skipIfAntreaIPAMTest(t) + + data, err := setupTest(t) + if err != nil { + t.Fatalf("Error when setting up test: %v", err) + } + defer teardownTest(t, data) + skipIfEncapModeIsNot(t, data, config.TrafficEncapModeEncap) + + cc := func(config *controllerconfig.ControllerConfig) { + config.FeatureGates["AntreaIPAM"] = true + } + ac := func(config *agentconfig.AgentConfig) { + config.FeatureGates["AntreaIPAM"] = true + } + if err = data.mutateAntreaConfigMap(cc, ac, true, true); err != nil { + t.Fatalf("Failed to enable AntreaIPAM feature: %v", err) + } + + _, err = data.crdClient.CrdV1alpha2().IPPools().Create(context.TODO(), testIPPoolv4, metav1.CreateOptions{}) + defer deleteIPPoolWrapper(t, data, testIPPoolv4.Name) + if err != nil { + t.Fatalf("Failed to create v4 IPPool CR: %v", err) + } + _, err = data.crdClient.CrdV1alpha2().IPPools().Create(context.TODO(), testIPPoolv6, metav1.CreateOptions{}) + defer deleteIPPoolWrapper(t, data, testIPPoolv6.Name) + if err != nil { + t.Fatalf("Failed to create v6 IPPool CR: %v", err) + } + + // DEL non-existing network. Should return no error. + executeCNI(t, data, false, true, "net1", 0, "") + // Allocate the first IP. + executeCNI(t, data, true, false, "net1", 0, testOutput1) + // CNI ADD retry should return the same result. + executeCNI(t, data, true, false, "net1", 0, testOutput1) + // Allocate the second IP, and then DEL. + executeCNI(t, data, true, true, "net2", 0, testOutput2) + // The second IP should be re-allocated, as it was releaed with the previous CNI DEL. + executeCNI(t, data, true, true, "net3", 0, testOutput2) + // Release the first IP. + executeCNI(t, data, false, true, "net1", 0, "") +} diff --git a/test/e2e/service_externalip_test.go b/test/e2e/service_externalip_test.go index 635c9425a68..9d1bc4f0391 100644 --- a/test/e2e/service_externalip_test.go +++ b/test/e2e/service_externalip_test.go @@ -16,6 +16,7 @@ package e2e import ( "context" + "encoding/json" "fmt" "net" "strconv" @@ -38,6 +39,7 @@ import ( "antrea.io/antrea/pkg/apis/crd/v1alpha2" agentconfig "antrea.io/antrea/pkg/config/agent" controllerconfig "antrea.io/antrea/pkg/config/controller" + "antrea.io/antrea/pkg/querier" ) func TestServiceExternalIP(t *testing.T) { @@ -224,7 +226,7 @@ func testServiceExternalTrafficPolicyLocal(t *testing.T, data *TestData) { antreaagenttypes.ServiceExternalIPPoolAnnotationKey: ipPool.Name, } service, err = data.CreateServiceWithAnnotations(fmt.Sprintf("test-svc-local-%d", idx), - testNamespace, 80, 80, corev1.ProtocolTCP, nil, false, true, v1.ServiceTypeLoadBalancer, nil, annotation) + data.testNamespace, 80, 80, corev1.ProtocolTCP, nil, false, true, v1.ServiceTypeLoadBalancer, nil, annotation) require.NoError(t, err) defer data.clientset.CoreV1().Services(service.Namespace).Delete(context.TODO(), service.Name, metav1.DeleteOptions{}) @@ -243,18 +245,16 @@ func testServiceExternalTrafficPolicyLocal(t *testing.T, data *TestData) { require.NoError(t, err) defer data.clientset.CoreV1().Endpoints(eps.Namespace).Delete(context.TODO(), eps.Name, metav1.DeleteOptions{}) - service, err = data.waitForServiceConfigured(service, tt.expectedExternalIP, tt.expectedNodeOrigin != "", tt.expectedNodeOrigin) + service, node, err := data.waitForServiceConfigured(service, tt.expectedExternalIP, tt.expectedNodeOrigin) require.NoError(t, err) - _, node := getServiceExternalIPAndHost(service) assert.Equal(t, tt.expectedNodeOrigin, node) epsToUpdate := eps.DeepCopy() epsToUpdate.Subsets = tt.updatedEndpointSubsets _, err = data.clientset.CoreV1().Endpoints(eps.Namespace).Update(context.TODO(), epsToUpdate, metav1.UpdateOptions{}) require.NoError(t, err) - service, err = data.waitForServiceConfigured(service, tt.expectedExternalIP, tt.expectedNodeUpdated != "", tt.expectedNodeUpdated) + _, node, err = data.waitForServiceConfigured(service, tt.expectedExternalIP, tt.expectedNodeUpdated) require.NoError(t, err) - _, node = getServiceExternalIPAndHost(service) assert.Equal(t, tt.expectedNodeUpdated, node) assert.NoError(t, err) }) @@ -343,16 +343,14 @@ func testServiceWithExternalIPCRUD(t *testing.T, data *TestData) { antreaagenttypes.ServiceExternalIPPoolAnnotationKey: ipPool.Name, } service, err = data.CreateServiceWithAnnotations(fmt.Sprintf("test-svc-eip-%d", idx), - testNamespace, 80, 80, corev1.ProtocolTCP, nil, false, false, v1.ServiceTypeLoadBalancer, nil, annotation) + data.testNamespace, 80, 80, corev1.ProtocolTCP, nil, false, false, v1.ServiceTypeLoadBalancer, nil, annotation) require.NoError(t, err) defer data.clientset.CoreV1().Services(service.Namespace).Delete(context.TODO(), service.Name, metav1.DeleteOptions{}) - waitForNodeConfigured := len(tt.expectedNodes) != 0 - service, err = data.waitForServiceConfigured(service, tt.expectedExternalIP, waitForNodeConfigured, "") + service, assignedNode, err := data.waitForServiceConfigured(service, tt.expectedExternalIP, "") require.NoError(t, err) if len(tt.expectedNodes) > 0 { - _, assignedNode := getServiceExternalIPAndHost(service) assert.True(t, tt.expectedNodes.Has(assignedNode), "expected assigned Node in %s, got %s", tt.expectedNodes, assignedNode) } @@ -437,11 +435,11 @@ func testServiceUpdateExternalIP(t *testing.T, data *TestData) { antreaagenttypes.ServiceExternalIPPoolAnnotationKey: originalPool.Name, } service, err := data.CreateServiceWithAnnotations(fmt.Sprintf("test-update-eip-%d", idx), - testNamespace, 80, 80, corev1.ProtocolTCP, nil, false, false, v1.ServiceTypeLoadBalancer, nil, annotation) + data.testNamespace, 80, 80, corev1.ProtocolTCP, nil, false, false, v1.ServiceTypeLoadBalancer, nil, annotation) require.NoError(t, err) defer data.clientset.CoreV1().Services(service.Namespace).Delete(context.TODO(), service.Name, metav1.DeleteOptions{}) - service, err = data.waitForServiceConfigured(service, tt.originalExternalIP, true, tt.originalNode) + service, _, err = data.waitForServiceConfigured(service, tt.originalExternalIP, tt.originalNode) require.NoError(t, err) toUpdate := service.DeepCopy() @@ -455,7 +453,7 @@ func testServiceUpdateExternalIP(t *testing.T, data *TestData) { }) require.NoError(t, err, "Failed to update Service") - _, err = data.waitForServiceConfigured(service, tt.newExternalIP, true, tt.newNode) + _, _, err = data.waitForServiceConfigured(service, tt.newExternalIP, tt.newNode) assert.NoError(t, err) }) } @@ -518,14 +516,13 @@ func testServiceNodeFailure(t *testing.T, data *TestData) { annotation := map[string]string{ antreaagenttypes.ServiceExternalIPPoolAnnotationKey: externalIPPoolTwoNodes.Name, } - service, err := data.CreateServiceWithAnnotations("test-service-node-failure", testNamespace, 80, 80, + service, err := data.CreateServiceWithAnnotations("test-service-node-failure", data.testNamespace, 80, 80, corev1.ProtocolTCP, nil, false, false, v1.ServiceTypeLoadBalancer, nil, annotation) require.NoError(t, err) defer data.clientset.CoreV1().Services(service.Namespace).Delete(context.TODO(), service.Name, metav1.DeleteOptions{}) - service, err = data.waitForServiceConfigured(service, tt.expectedIP, true, "") + service, originalNode, err := data.waitForServiceConfigured(service, tt.expectedIP, "") assert.NoError(t, err) - _, originalNode := getServiceExternalIPAndHost(service) pauseAgent(originalNode) defer restoreAgent(originalNode) @@ -535,10 +532,17 @@ func testServiceNodeFailure(t *testing.T, data *TestData) { } else { expectedMigratedNode = nodeName(0) } - service, err = data.waitForServiceConfigured(service, tt.expectedIP, true, expectedMigratedNode) + // The Agent on the original Node is paused. Run antctl from the expected migrated Node instead. + err = wait.PollImmediate(200*time.Millisecond, 15*time.Second, func() (done bool, err error) { + assigndNode, err := data.getServiceAssignedNode(expectedMigratedNode, service) + if err != nil { + return false, nil + } + return assigndNode == expectedMigratedNode, nil + }) assert.NoError(t, err) restoreAgent(originalNode) - _, err = data.waitForServiceConfigured(service, tt.expectedIP, true, originalNode) + _, _, err = data.waitForServiceConfigured(service, tt.expectedIP, originalNode) assert.NoError(t, err) }) } @@ -587,7 +591,7 @@ func testExternalIPAccess(t *testing.T, data *TestData) { // Create agnhost Pods on each Node. for idx, node := range nodes { createAgnhostPod(t, data, agnhosts[idx], node, false) - defer data.deletePodAndWait(defaultTimeout, agnhosts[idx], testNamespace) + defer data.deletePodAndWait(defaultTimeout, agnhosts[idx], data.testNamespace) } var port int32 = 8080 externalIPTestCases := []struct { @@ -608,27 +612,30 @@ func testExternalIPAccess(t *testing.T, data *TestData) { } waitExternalIPConfigured := func(service *v1.Service) (string, string, error) { var ip string - var host string + var assigndNode string err := wait.PollImmediate(200*time.Millisecond, 5*time.Second, func() (done bool, err error) { service, err = data.clientset.CoreV1().Services(service.Namespace).Get(context.TODO(), service.Name, metav1.GetOptions{}) if err != nil { return false, err } - if len(service.Status.LoadBalancer.Ingress) == 0 || service.Status.LoadBalancer.Ingress[0].IP == "" || service.Status.LoadBalancer.Ingress[0].Hostname == "" { + if len(service.Status.LoadBalancer.Ingress) == 0 || service.Status.LoadBalancer.Ingress[0].IP == "" { + return false, nil + } + assigndNode, err = data.getServiceAssignedNode("", service) + if err != nil { return false, nil } ip = service.Status.LoadBalancer.Ingress[0].IP - host = service.Status.LoadBalancer.Ingress[0].Hostname return true, nil }) - return ip, host, err + return ip, assigndNode, err } for _, et := range externalIPTestCases { t.Run(et.name, func(t *testing.T) { annotations := map[string]string{ antreaagenttypes.ServiceExternalIPPoolAnnotationKey: ipPool.Name, } - service, err := data.CreateServiceWithAnnotations(et.serviceName, testNamespace, port, port, corev1.ProtocolTCP, map[string]string{"app": "agnhost"}, false, et.externalTrafficPolicyLocal, corev1.ServiceTypeLoadBalancer, &ipFamily, annotations) + service, err := data.CreateServiceWithAnnotations(et.serviceName, data.testNamespace, port, port, corev1.ProtocolTCP, map[string]string{"app": "agnhost"}, false, et.externalTrafficPolicyLocal, corev1.ServiceTypeLoadBalancer, &ipFamily, annotations) require.NoError(t, err) defer data.deleteService(service.Namespace, service.Name) @@ -649,7 +656,7 @@ sleep 3600`, tt.clientName, tt.clientIP, tt.localIP, tt.clientIPMaskLen) baseUrl := net.JoinHostPort(externalIP, strconv.FormatInt(int64(port), 10)) - require.NoError(t, data.createPodOnNode(tt.clientName, testNamespace, host, agnhostImage, []string{"sh", "-c", cmd}, nil, nil, nil, true, func(pod *v1.Pod) { + require.NoError(t, data.createPodOnNode(tt.clientName, data.testNamespace, host, agnhostImage, []string{"sh", "-c", cmd}, nil, nil, nil, true, func(pod *v1.Pod) { privileged := true pod.Spec.Containers[0].SecurityContext = &v1.SecurityContext{Privileged: &privileged} delete(pod.Labels, "app") @@ -658,7 +665,7 @@ sleep 3600`, tt.clientName, tt.clientIP, tt.localIP, tt.clientIPMaskLen) // Refer to https://github.com/curl/curl/issues/1603. probeCmd := strings.Split(fmt.Sprintf("ip netns exec %s curl -s %s", tt.clientName, baseUrl), " ") pod.Spec.Containers[0].ReadinessProbe = &v1.Probe{ - Handler: v1.Handler{ + ProbeHandler: v1.ProbeHandler{ Exec: &v1.ExecAction{ Command: probeCmd, }, @@ -668,7 +675,7 @@ sleep 3600`, tt.clientName, tt.clientIP, tt.localIP, tt.clientIPMaskLen) } })) - _, err = data.PodWaitFor(defaultTimeout, tt.clientName, testNamespace, func(p *v1.Pod) (bool, error) { + _, err = data.PodWaitFor(defaultTimeout, tt.clientName, data.testNamespace, func(p *v1.Pod) (bool, error) { for _, condition := range p.Status.Conditions { if condition.Type == corev1.PodReady { return condition.Status == corev1.ConditionTrue, nil @@ -677,11 +684,11 @@ sleep 3600`, tt.clientName, tt.clientIP, tt.localIP, tt.clientIPMaskLen) return false, nil }) require.NoError(t, err) - defer data.deletePodAndWait(defaultTimeout, tt.clientName, testNamespace) + defer data.deletePodAndWait(defaultTimeout, tt.clientName, data.testNamespace) hostNameUrl := fmt.Sprintf("%s/%s", baseUrl, "hostname") probeCmd := fmt.Sprintf("ip netns exec %s curl --connect-timeout 1 --retry 5 --retry-connrefused %s", tt.clientName, hostNameUrl) - hostname, stderr, err := data.RunCommandFromPod(testNamespace, tt.clientName, "", []string{"sh", "-c", probeCmd}) + hostname, stderr, err := data.RunCommandFromPod(data.testNamespace, tt.clientName, "", []string{"sh", "-c", probeCmd}) assert.NoError(t, err, "External IP should be able to be connected from remote: %s", stderr) if et.externalTrafficPolicyLocal { @@ -692,7 +699,7 @@ sleep 3600`, tt.clientName, tt.clientIP, tt.localIP, tt.clientIPMaskLen) } clientIPUrl := fmt.Sprintf("%s/clientip", baseUrl) probeClientIPCmd := fmt.Sprintf("ip netns exec %s curl --connect-timeout 1 --retry 5 --retry-connrefused %s", tt.clientName, clientIPUrl) - clientIPPort, stderr, err := data.RunCommandFromPod(testNamespace, tt.clientName, "", []string{"sh", "-c", probeClientIPCmd}) + clientIPPort, stderr, err := data.RunCommandFromPod(data.testNamespace, tt.clientName, "", []string{"sh", "-c", probeClientIPCmd}) assert.NoError(t, err, "External IP should be able to be connected from remote: %s", stderr) clientIP, _, err := net.SplitHostPort(clientIPPort) assert.NoError(t, err) @@ -704,14 +711,32 @@ sleep 3600`, tt.clientName, tt.clientIP, tt.localIP, tt.clientIPMaskLen) } } -func getServiceExternalIPAndHost(service *v1.Service) (string, string) { - if service == nil || len(service.Status.LoadBalancer.Ingress) == 0 { - return "", "" +func (data *TestData) getServiceAssignedNode(node string, service *v1.Service) (string, error) { + if node == "" { + node = nodeName(0) + } + agentPodName, err := data.getAntreaPodOnNode(node) + if err != nil { + return "", err } - return service.Status.LoadBalancer.Ingress[0].IP, service.Status.LoadBalancer.Ingress[0].Hostname + cmd := []string{"antctl", "get", "serviceexternalip", service.Name, "-n", service.Namespace, "-o", "json"} + + stdout, _, err := runAntctl(agentPodName, cmd, data) + if err != nil { + return "", err + } + var serviceExternalIPInfo []querier.ServiceExternalIPInfo + if err := json.Unmarshal([]byte(stdout), &serviceExternalIPInfo); err != nil { + return "", err + } + if len(serviceExternalIPInfo) != 1 { + return "", fmt.Errorf("expected exactly one entry, got %#v", serviceExternalIPInfo) + } + return serviceExternalIPInfo[0].AssignedNode, nil } -func (data *TestData) waitForServiceConfigured(service *v1.Service, expectedExternalIP string, waitForNodeConfigured bool, expectedNodeName string) (*corev1.Service, error) { +func (data *TestData) waitForServiceConfigured(service *v1.Service, expectedExternalIP string, expectedNodeName string) (*corev1.Service, string, error) { + var assignedNode string err := wait.PollImmediate(200*time.Millisecond, 15*time.Second, func() (done bool, err error) { service, err = data.clientset.CoreV1().Services(service.Namespace).Get(context.TODO(), service.Name, metav1.GetOptions{}) if err != nil { @@ -720,19 +745,18 @@ func (data *TestData) waitForServiceConfigured(service *v1.Service, expectedExte if len(service.Status.LoadBalancer.Ingress) == 0 || service.Status.LoadBalancer.Ingress[0].IP != expectedExternalIP { return false, nil } - if waitForNodeConfigured || expectedNodeName != "" { - if service.Status.LoadBalancer.Ingress[0].Hostname == "" { - return false, nil - } + assignedNode, err = data.getServiceAssignedNode("", service) + if err != nil { + return false, nil } - if expectedNodeName != "" && service.Status.LoadBalancer.Ingress[0].Hostname != expectedNodeName { + if expectedNodeName != "" && assignedNode != expectedNodeName { return false, nil } return true, nil }) if err != nil { - return service, fmt.Errorf("wait for Service %q configured failed: %v. Expected external IP %s on Node %s, actual status %#v", - service.Name, err, expectedExternalIP, expectedNodeName, service.Status) + return service, assignedNode, fmt.Errorf("wait for Service %q configured failed: %v. Expected external IP %s on Node %s, actual status %#v, assigned Node: %s"+ + service.Name, err, expectedExternalIP, expectedNodeName, service.Status, assignedNode) } - return service, nil + return service, assignedNode, nil } diff --git a/test/e2e/service_test.go b/test/e2e/service_test.go index 128909d7ac1..267a6d732be 100644 --- a/test/e2e/service_test.go +++ b/test/e2e/service_test.go @@ -38,13 +38,14 @@ func TestClusterIPv6(t *testing.T) { func testClusterIP(t *testing.T, isIPv6 bool) { skipIfNumNodesLessThan(t, 2) + data, err := setupTest(t) if err != nil { t.Fatalf("Error when setting up test: %v", err) } defer teardownTest(t, data) - data.testClusterIP(t, isIPv6, testNamespace, testNamespace) + data.testClusterIP(t, isIPv6, data.testNamespace, data.testNamespace) } func (data *TestData) testClusterIP(t *testing.T, isIPv6 bool, clientNamespace, serverNamespace string) { @@ -84,7 +85,7 @@ func (data *TestData) testClusterIP(t *testing.T, isIPv6 bool, clientNamespace, _, _, cleanupFunc = createAndWaitForPod(t, data, data.createNginxPodOnNode, hostNginx, nodeName(0), serverNamespace, true) defer cleanupFunc() t.Run("HostNetwork Endpoints", func(t *testing.T) { - skipIfNamespaceIsNotEqual(t, serverNamespace, testNamespace) + skipIfNamespaceIsNotEqual(t, serverNamespace, data.testNamespace) testClusterIPCases(t, data, url, clients, hostNetworkClients, clientNamespace) }) } @@ -93,7 +94,7 @@ func testClusterIPCases(t *testing.T, data *TestData, url string, clients, hostN t.Run("All Nodes can access Service ClusterIP", func(t *testing.T) { skipIfProxyAllDisabled(t, data) skipIfKubeProxyEnabled(t, data) - skipIfNamespaceIsNotEqual(t, namespace, testNamespace) + skipIfNamespaceIsNotEqual(t, namespace, data.testNamespace) for node, pod := range hostNetworkClients { testClusterIPFromPod(t, data, url, node, pod, true, namespace) } @@ -136,7 +137,7 @@ func TestNodePortWindows(t *testing.T) { } defer teardownTest(t, data) - data.testNodePort(t, true, testNamespace, testNamespace) + data.testNodePort(t, true, data.testNamespace, data.testNamespace) } func (data *TestData) testNodePort(t *testing.T, isWindows bool, clientNamespace, serverNamespace string) { @@ -175,7 +176,7 @@ func (data *TestData) testNodePort(t *testing.T, isWindows bool, clientNamespace } func (data *TestData) createAgnhostServiceAndBackendPods(t *testing.T, name, namespace string, node string, svcType corev1.ServiceType) (*corev1.Service, func()) { - ipv4Protocol := corev1.IPv4Protocol + ipProtocol := corev1.IPv4Protocol args := []string{"netexec", "--http-port=80", "--udp-port=80"} require.NoError(t, data.createPodOnNode(name, namespace, node, agnhostImage, []string{}, args, nil, []corev1.ContainerPort{ { @@ -187,8 +188,13 @@ func (data *TestData) createAgnhostServiceAndBackendPods(t *testing.T, name, nam podIPs, err := data.podWaitForIPs(defaultTimeout, name, namespace) require.NoError(t, err) t.Logf("Created service Pod IPs %v", podIPs.ipStrings) + if podIPs.ipv4 == nil { + // "IPv4" is invalid in IPv6 only cluster with K8s>=1.21 + // error: Service "s1" is invalid: spec.ipFamilies[0]: Invalid value: "IPv4": not configured on this cluster + ipProtocol = corev1.IPv6Protocol + } require.NoError(t, data.podWaitForRunning(defaultTimeout, name, namespace)) - svc, err := data.CreateService(name, namespace, 80, 80, map[string]string{"app": "agnhost"}, false, false, svcType, &ipv4Protocol) + svc, err := data.CreateService(name, namespace, 80, 80, map[string]string{"app": "agnhost"}, false, false, svcType, &ipProtocol) require.NoError(t, err) cleanup := func() { diff --git a/test/e2e/traceflow_test.go b/test/e2e/traceflow_test.go index d1892c43db3..2531dc946c6 100644 --- a/test/e2e/traceflow_test.go +++ b/test/e2e/traceflow_test.go @@ -19,6 +19,7 @@ import ( "fmt" "net" "reflect" + "strconv" "strings" "testing" "time" @@ -53,7 +54,6 @@ type testcase struct { // TestTraceflow is the top-level test which contains all subtests for // Traceflow related test cases so they can share setup, teardown. func TestTraceflow(t *testing.T) { - skipIfHasWindowsNodes(t) skipIfTraceflowDisabled(t) data, err := setupTest(t) @@ -97,8 +97,12 @@ func testTraceflowIntraNodeANP(t *testing.T, data *TestData) { k8sUtils, err = NewKubernetesUtils(data) failOnError(err, t) - node1 := nodeName(0) - node1Pods, _, node1CleanupFn := createTestBusyboxPods(t, data, 3, testNamespace, node1) + nodeIdx := 0 + if len(clusterInfo.windowsNodes) != 0 { + nodeIdx = clusterInfo.windowsNodes[0] + } + node1 := nodeName(nodeIdx) + node1Pods, _, node1CleanupFn := createTestAgnhostPods(t, data, 3, data.testNamespace, node1) defer node1CleanupFn() var denyIngress *v1alpha1.NetworkPolicy @@ -111,6 +115,9 @@ func testTraceflowIntraNodeANP(t *testing.T, data *TestData) { t.Errorf("Error when deleting Antrea NetworkPolicy: %v", err) } }() + if err = data.waitForANPRealized(t, data.testNamespace, denyIngressName); err != nil { + t.Fatal(err) + } var rejectIngress *v1alpha1.NetworkPolicy rejectIngressName := "test-anp-reject-ingress" if rejectIngress, err = data.createANPDenyIngress("antrea-e2e", node1Pods[2], rejectIngressName, true); err != nil { @@ -121,8 +128,7 @@ func testTraceflowIntraNodeANP(t *testing.T, data *TestData) { t.Errorf("Error when deleting Antrea NetworkPolicy: %v", err) } }() - antreaPod, err := data.getAntreaPodOnNode(node1) - if err = data.waitForNetworkpolicyRealized(antreaPod, denyIngressName, v1beta2.AntreaNetworkPolicy); err != nil { + if err = data.waitForANPRealized(t, data.testNamespace, rejectIngressName); err != nil { t.Fatal(err) } @@ -132,15 +138,15 @@ func testTraceflowIntraNodeANP(t *testing.T, data *TestData) { ipVersion: 4, tf: &v1alpha1.Traceflow{ ObjectMeta: metav1.ObjectMeta{ - Name: randName(fmt.Sprintf("%s-%s-to-%s-%s-", testNamespace, node1Pods[0], testNamespace, node1Pods[1])), + Name: randName(fmt.Sprintf("%s-%s-to-%s-%s-", data.testNamespace, node1Pods[0], data.testNamespace, node1Pods[1])), }, Spec: v1alpha1.TraceflowSpec{ Source: v1alpha1.Source{ - Namespace: testNamespace, + Namespace: data.testNamespace, Pod: node1Pods[0], }, Destination: v1alpha1.Destination{ - Namespace: testNamespace, + Namespace: data.testNamespace, Pod: node1Pods[1], }, Packet: v1alpha1.Packet{ @@ -150,6 +156,7 @@ func testTraceflowIntraNodeANP(t *testing.T, data *TestData) { TransportHeader: v1alpha1.TransportHeader{ TCP: &v1alpha1.TCPHeader{ DstPort: 80, + SrcPort: 10000, Flags: 2, }, }, @@ -179,15 +186,15 @@ func testTraceflowIntraNodeANP(t *testing.T, data *TestData) { ipVersion: 4, tf: &v1alpha1.Traceflow{ ObjectMeta: metav1.ObjectMeta{ - Name: randName(fmt.Sprintf("%s-%s-to-%s-%s-", testNamespace, node1Pods[0], testNamespace, node1Pods[2])), + Name: randName(fmt.Sprintf("%s-%s-to-%s-%s-", data.testNamespace, node1Pods[0], data.testNamespace, node1Pods[2])), }, Spec: v1alpha1.TraceflowSpec{ Source: v1alpha1.Source{ - Namespace: testNamespace, + Namespace: data.testNamespace, Pod: node1Pods[0], }, Destination: v1alpha1.Destination{ - Namespace: testNamespace, + Namespace: data.testNamespace, Pod: node1Pods[2], }, Packet: v1alpha1.Packet{ @@ -197,6 +204,7 @@ func testTraceflowIntraNodeANP(t *testing.T, data *TestData) { TransportHeader: v1alpha1.TransportHeader{ TCP: &v1alpha1.TCPHeader{ DstPort: 80, + SrcPort: 10001, Flags: 2, }, }, @@ -226,15 +234,15 @@ func testTraceflowIntraNodeANP(t *testing.T, data *TestData) { ipVersion: 6, tf: &v1alpha1.Traceflow{ ObjectMeta: metav1.ObjectMeta{ - Name: randName(fmt.Sprintf("%s-%s-to-%s-%s-", testNamespace, node1Pods[0], testNamespace, node1Pods[1])), + Name: randName(fmt.Sprintf("%s-%s-to-%s-%s-", data.testNamespace, node1Pods[0], data.testNamespace, node1Pods[1])), }, Spec: v1alpha1.TraceflowSpec{ Source: v1alpha1.Source{ - Namespace: testNamespace, + Namespace: data.testNamespace, Pod: node1Pods[0], }, Destination: v1alpha1.Destination{ - Namespace: testNamespace, + Namespace: data.testNamespace, Pod: node1Pods[1], }, Packet: v1alpha1.Packet{ @@ -244,6 +252,7 @@ func testTraceflowIntraNodeANP(t *testing.T, data *TestData) { TransportHeader: v1alpha1.TransportHeader{ TCP: &v1alpha1.TCPHeader{ DstPort: 80, + SrcPort: 10002, Flags: 2, }, }, @@ -282,10 +291,15 @@ func testTraceflowIntraNodeANP(t *testing.T, data *TestData) { // testTraceflowIntraNode verifies if traceflow can trace intra node traffic with some NetworkPolicies set. func testTraceflowIntraNode(t *testing.T, data *TestData) { - node1 := nodeName(0) + nodeIdx := 0 + isWindows := len(clusterInfo.windowsNodes) != 0 + if isWindows { + nodeIdx = clusterInfo.windowsNodes[0] + } + node1 := nodeName(nodeIdx) agentPod, _ := data.getAntreaPodOnNode(node1) - node1Pods, node1IPs, node1CleanupFn := createTestBusyboxPods(t, data, 3, testNamespace, node1) + node1Pods, node1IPs, node1CleanupFn := createTestAgnhostPods(t, data, 3, data.testNamespace, node1) defer node1CleanupFn() var pod0IPv4Str, pod1IPv4Str, dstPodIPv4Str, dstPodIPv6Str string if node1IPs[0].ipv4 != nil { @@ -300,7 +314,7 @@ func testTraceflowIntraNode(t *testing.T, data *TestData) { if node1IPs[2].ipv6 != nil { dstPodIPv6Str = node1IPs[2].ipv6.String() } - gwIPv4Str, gwIPv6Str := nodeGatewayIPs(0) + gwIPv4Str, gwIPv6Str := nodeGatewayIPs(nodeIdx) // Setup 2 NetworkPolicies: // 1. Allow all egress traffic. @@ -329,29 +343,38 @@ func testTraceflowIntraNode(t *testing.T, data *TestData) { }() antreaPod, err := data.getAntreaPodOnNode(node1) - if err = data.waitForNetworkpolicyRealized(antreaPod, allowAllEgressName, v1beta2.K8sNetworkPolicy); err != nil { + if err = data.waitForNetworkpolicyRealized(antreaPod, node1, isWindows, allowAllEgressName, v1beta2.K8sNetworkPolicy); err != nil { t.Fatal(err) } - if err = data.waitForNetworkpolicyRealized(antreaPod, denyAllIngressName, v1beta2.K8sNetworkPolicy); err != nil { + if err = data.waitForNetworkpolicyRealized(antreaPod, node1, isWindows, denyAllIngressName, v1beta2.K8sNetworkPolicy); err != nil { t.Fatal(err) } + // default Ubuntu ping packet properties. + expectedLength := uint16(84) expectedTTL := int32(64) + expectedFlags := int32(2) + if len(clusterInfo.windowsNodes) != 0 { + // default Windows ping packet properties. + expectedLength = 60 + expectedTTL = 128 + expectedFlags = 0 + } testcases := []testcase{ { name: "intraNodeTraceflowIPv4", ipVersion: 4, tf: &v1alpha1.Traceflow{ ObjectMeta: metav1.ObjectMeta{ - Name: randName(fmt.Sprintf("%s-%s-to-%s-%s-", testNamespace, node1Pods[0], testNamespace, node1Pods[1])), + Name: randName(fmt.Sprintf("%s-%s-to-%s-%s-", data.testNamespace, node1Pods[0], data.testNamespace, node1Pods[1])), }, Spec: v1alpha1.TraceflowSpec{ Source: v1alpha1.Source{ - Namespace: testNamespace, + Namespace: data.testNamespace, Pod: node1Pods[0], }, Destination: v1alpha1.Destination{ - Namespace: testNamespace, + Namespace: data.testNamespace, Pod: node1Pods[1], }, Packet: v1alpha1.Packet{ @@ -361,6 +384,7 @@ func testTraceflowIntraNode(t *testing.T, data *TestData) { TransportHeader: v1alpha1.TransportHeader{ TCP: &v1alpha1.TCPHeader{ DstPort: 80, + SrcPort: 10003, Flags: 2, }, }, @@ -395,15 +419,15 @@ func testTraceflowIntraNode(t *testing.T, data *TestData) { ipVersion: 4, tf: &v1alpha1.Traceflow{ ObjectMeta: metav1.ObjectMeta{ - Name: randName(fmt.Sprintf("%s-%s-to-%s-", testNamespace, node1Pods[0], node1Pods[2])), + Name: randName(fmt.Sprintf("%s-%s-to-%s-", data.testNamespace, node1Pods[0], node1Pods[2])), }, Spec: v1alpha1.TraceflowSpec{ Source: v1alpha1.Source{ - Namespace: testNamespace, + Namespace: data.testNamespace, Pod: node1Pods[0], }, Destination: v1alpha1.Destination{ - Namespace: testNamespace, + Namespace: data.testNamespace, Pod: node1Pods[2], }, Packet: v1alpha1.Packet{ @@ -413,6 +437,7 @@ func testTraceflowIntraNode(t *testing.T, data *TestData) { TransportHeader: v1alpha1.TransportHeader{ UDP: &v1alpha1.UDPHeader{ DstPort: 321, + SrcPort: 10004, }, }, }, @@ -446,11 +471,11 @@ func testTraceflowIntraNode(t *testing.T, data *TestData) { ipVersion: 4, tf: &v1alpha1.Traceflow{ ObjectMeta: metav1.ObjectMeta{ - Name: randName(fmt.Sprintf("%s-%s-to-%s-", testNamespace, node1Pods[0], dstPodIPv4Str)), + Name: randName(fmt.Sprintf("%s-%s-to-%s-", data.testNamespace, node1Pods[0], dstPodIPv4Str)), }, Spec: v1alpha1.TraceflowSpec{ Source: v1alpha1.Source{ - Namespace: testNamespace, + Namespace: data.testNamespace, Pod: node1Pods[0], }, Destination: v1alpha1.Destination{ @@ -463,6 +488,7 @@ func testTraceflowIntraNode(t *testing.T, data *TestData) { TransportHeader: v1alpha1.TransportHeader{ UDP: &v1alpha1.UDPHeader{ DstPort: 321, + SrcPort: 10005, }, }, }, @@ -496,11 +522,11 @@ func testTraceflowIntraNode(t *testing.T, data *TestData) { ipVersion: 4, tf: &v1alpha1.Traceflow{ ObjectMeta: metav1.ObjectMeta{ - Name: randName(fmt.Sprintf("%s-%s-to-%s-", testNamespace, node1Pods[0], dstPodIPv4Str)), + Name: randName(fmt.Sprintf("%s-%s-to-%s-", data.testNamespace, node1Pods[0], dstPodIPv4Str)), }, Spec: v1alpha1.TraceflowSpec{ Source: v1alpha1.Source{ - Namespace: testNamespace, + Namespace: data.testNamespace, Pod: node1Pods[0], }, Destination: v1alpha1.Destination{ @@ -541,15 +567,15 @@ func testTraceflowIntraNode(t *testing.T, data *TestData) { ipVersion: 4, tf: &v1alpha1.Traceflow{ ObjectMeta: metav1.ObjectMeta{ - Name: randName(fmt.Sprintf("%s-%s-to-%s-%s-", testNamespace, node1Pods[0], testNamespace, "non-existing-pod")), + Name: randName(fmt.Sprintf("%s-%s-to-%s-%s-", data.testNamespace, node1Pods[0], data.testNamespace, "non-existing-pod")), }, Spec: v1alpha1.TraceflowSpec{ Source: v1alpha1.Source{ - Namespace: testNamespace, + Namespace: data.testNamespace, Pod: node1Pods[0], }, Destination: v1alpha1.Destination{ - Namespace: testNamespace, + Namespace: data.testNamespace, Pod: "non-existing-pod", }, }, @@ -562,28 +588,28 @@ func testTraceflowIntraNode(t *testing.T, data *TestData) { ipVersion: 4, tf: &v1alpha1.Traceflow{ ObjectMeta: metav1.ObjectMeta{ - Name: randName(fmt.Sprintf("%s-%s-to-%s-%s-", testNamespace, "non-existing-pod", testNamespace, node1Pods[1])), + Name: randName(fmt.Sprintf("%s-%s-to-%s-%s-", data.testNamespace, "non-existing-pod", data.testNamespace, node1Pods[1])), }, Spec: v1alpha1.TraceflowSpec{ Source: v1alpha1.Source{ - Namespace: testNamespace, + Namespace: data.testNamespace, Pod: "non-existing-pod", }, Destination: v1alpha1.Destination{ - Namespace: testNamespace, + Namespace: data.testNamespace, Pod: node1Pods[1], }, }, }, expectedPhase: v1alpha1.Failed, - expectedReasons: []string{fmt.Sprintf("Invalid Traceflow request, err: %+v", fmt.Errorf("requested source Pod %s not found", k8s.NamespacedName(testNamespace, "non-existing-pod")))}, + expectedReasons: []string{fmt.Sprintf("Invalid Traceflow request, err: %+v", fmt.Errorf("requested source Pod %s not found", k8s.NamespacedName(data.testNamespace, "non-existing-pod")))}, }, { name: "hostNetworkSrcPodIPv4", ipVersion: 4, tf: &v1alpha1.Traceflow{ ObjectMeta: metav1.ObjectMeta{ - Name: randName(fmt.Sprintf("%s-%s-to-%s-%s-", antreaNamespace, agentPod, testNamespace, node1Pods[1])), + Name: randName(fmt.Sprintf("%s-%s-to-%s-%s-", antreaNamespace, agentPod, data.testNamespace, node1Pods[1])), }, Spec: v1alpha1.TraceflowSpec{ Source: v1alpha1.Source{ @@ -591,7 +617,7 @@ func testTraceflowIntraNode(t *testing.T, data *TestData) { Pod: agentPod, }, Destination: v1alpha1.Destination{ - Namespace: testNamespace, + Namespace: data.testNamespace, Pod: node1Pods[1], }, }, @@ -604,11 +630,11 @@ func testTraceflowIntraNode(t *testing.T, data *TestData) { ipVersion: 4, tf: &v1alpha1.Traceflow{ ObjectMeta: metav1.ObjectMeta{ - Name: randName(fmt.Sprintf("%s-%s-to-%s-", testNamespace, node1Pods[0], dstPodIPv4Str)), + Name: randName(fmt.Sprintf("%s-%s-to-%s-", data.testNamespace, node1Pods[0], dstPodIPv4Str)), }, Spec: v1alpha1.TraceflowSpec{ Source: v1alpha1.Source{ - Namespace: testNamespace, + Namespace: data.testNamespace, Pod: node1Pods[0], }, Destination: v1alpha1.Destination{ @@ -643,8 +669,8 @@ func testTraceflowIntraNode(t *testing.T, data *TestData) { expectedPktCap: &v1alpha1.Packet{ SrcIP: pod0IPv4Str, DstIP: dstPodIPv4Str, - Length: 84, // default ping packet length. - IPHeader: v1alpha1.IPHeader{Protocol: 1, TTL: expectedTTL, Flags: 2}, + Length: expectedLength, + IPHeader: v1alpha1.IPHeader{Protocol: 1, TTL: expectedTTL, Flags: expectedFlags}, TransportHeader: v1alpha1.TransportHeader{ ICMP: &v1alpha1.ICMPEchoRequestHeader{}, }, @@ -655,14 +681,14 @@ func testTraceflowIntraNode(t *testing.T, data *TestData) { ipVersion: 4, tf: &v1alpha1.Traceflow{ ObjectMeta: metav1.ObjectMeta{ - Name: randName(fmt.Sprintf("%s-%s-to-%s-", testNamespace, node1Pods[0], dstPodIPv4Str)), + Name: randName(fmt.Sprintf("%s-%s-to-%s-", data.testNamespace, pod0IPv4Str, node1Pods[1])), }, Spec: v1alpha1.TraceflowSpec{ Source: v1alpha1.Source{ IP: pod0IPv4Str, }, Destination: v1alpha1.Destination{ - Namespace: testNamespace, + Namespace: data.testNamespace, Pod: node1Pods[1], }, Packet: v1alpha1.Packet{ @@ -695,8 +721,8 @@ func testTraceflowIntraNode(t *testing.T, data *TestData) { expectedPktCap: &v1alpha1.Packet{ SrcIP: pod0IPv4Str, DstIP: pod1IPv4Str, - Length: 84, // default ping packet length. - IPHeader: v1alpha1.IPHeader{Protocol: 1, TTL: expectedTTL, Flags: 2}, + Length: expectedLength, + IPHeader: v1alpha1.IPHeader{Protocol: 1, TTL: expectedTTL, Flags: expectedFlags}, TransportHeader: v1alpha1.TransportHeader{ ICMP: &v1alpha1.ICMPEchoRequestHeader{}, }, @@ -707,15 +733,15 @@ func testTraceflowIntraNode(t *testing.T, data *TestData) { ipVersion: 6, tf: &v1alpha1.Traceflow{ ObjectMeta: metav1.ObjectMeta{ - Name: randName(fmt.Sprintf("%s-%s-to-%s-%s-", testNamespace, node1Pods[0], testNamespace, node1Pods[1])), + Name: randName(fmt.Sprintf("%s-%s-to-%s-%s-", data.testNamespace, node1Pods[0], data.testNamespace, node1Pods[1])), }, Spec: v1alpha1.TraceflowSpec{ Source: v1alpha1.Source{ - Namespace: testNamespace, + Namespace: data.testNamespace, Pod: node1Pods[0], }, Destination: v1alpha1.Destination{ - Namespace: testNamespace, + Namespace: data.testNamespace, Pod: node1Pods[1], }, Packet: v1alpha1.Packet{ @@ -725,6 +751,7 @@ func testTraceflowIntraNode(t *testing.T, data *TestData) { TransportHeader: v1alpha1.TransportHeader{ TCP: &v1alpha1.TCPHeader{ DstPort: 80, + SrcPort: 10006, Flags: 2, }, }, @@ -759,15 +786,15 @@ func testTraceflowIntraNode(t *testing.T, data *TestData) { ipVersion: 6, tf: &v1alpha1.Traceflow{ ObjectMeta: metav1.ObjectMeta{ - Name: randName(fmt.Sprintf("%s-%s-to-%s-", testNamespace, node1Pods[0], node1Pods[2])), + Name: randName(fmt.Sprintf("%s-%s-to-%s-", data.testNamespace, node1Pods[0], node1Pods[2])), }, Spec: v1alpha1.TraceflowSpec{ Source: v1alpha1.Source{ - Namespace: testNamespace, + Namespace: data.testNamespace, Pod: node1Pods[0], }, Destination: v1alpha1.Destination{ - Namespace: testNamespace, + Namespace: data.testNamespace, Pod: node1Pods[2], }, Packet: v1alpha1.Packet{ @@ -777,6 +804,7 @@ func testTraceflowIntraNode(t *testing.T, data *TestData) { TransportHeader: v1alpha1.TransportHeader{ UDP: &v1alpha1.UDPHeader{ DstPort: 321, + SrcPort: 10007, }, }, }, @@ -810,11 +838,11 @@ func testTraceflowIntraNode(t *testing.T, data *TestData) { ipVersion: 6, tf: &v1alpha1.Traceflow{ ObjectMeta: metav1.ObjectMeta{ - Name: randName(fmt.Sprintf("%s-%s-to-%s-", testNamespace, node1Pods[0], strings.ReplaceAll(dstPodIPv6Str, ":", "--"))), + Name: randName(fmt.Sprintf("%s-%s-to-%s-", data.testNamespace, node1Pods[0], strings.ReplaceAll(dstPodIPv6Str, ":", "--"))), }, Spec: v1alpha1.TraceflowSpec{ Source: v1alpha1.Source{ - Namespace: testNamespace, + Namespace: data.testNamespace, Pod: node1Pods[0], }, Destination: v1alpha1.Destination{ @@ -827,6 +855,7 @@ func testTraceflowIntraNode(t *testing.T, data *TestData) { TransportHeader: v1alpha1.TransportHeader{ UDP: &v1alpha1.UDPHeader{ DstPort: 321, + SrcPort: 10008, }, }, }, @@ -860,11 +889,11 @@ func testTraceflowIntraNode(t *testing.T, data *TestData) { ipVersion: 6, tf: &v1alpha1.Traceflow{ ObjectMeta: metav1.ObjectMeta{ - Name: randName(fmt.Sprintf("%s-%s-to-%s-", testNamespace, node1Pods[0], strings.ReplaceAll(dstPodIPv6Str, ":", "--"))), + Name: randName(fmt.Sprintf("%s-%s-to-%s-", data.testNamespace, node1Pods[0], strings.ReplaceAll(dstPodIPv6Str, ":", "--"))), }, Spec: v1alpha1.TraceflowSpec{ Source: v1alpha1.Source{ - Namespace: testNamespace, + Namespace: data.testNamespace, Pod: node1Pods[0], }, Destination: v1alpha1.Destination{ @@ -905,15 +934,15 @@ func testTraceflowIntraNode(t *testing.T, data *TestData) { ipVersion: 6, tf: &v1alpha1.Traceflow{ ObjectMeta: metav1.ObjectMeta{ - Name: randName(fmt.Sprintf("%s-%s-to-%s-%s-", testNamespace, node1Pods[0], testNamespace, "non-existing-pod")), + Name: randName(fmt.Sprintf("%s-%s-to-%s-%s-", data.testNamespace, node1Pods[0], data.testNamespace, "non-existing-pod")), }, Spec: v1alpha1.TraceflowSpec{ Source: v1alpha1.Source{ - Namespace: testNamespace, + Namespace: data.testNamespace, Pod: node1Pods[0], }, Destination: v1alpha1.Destination{ - Namespace: testNamespace, + Namespace: data.testNamespace, Pod: "non-existing-pod", }, Packet: v1alpha1.Packet{ @@ -931,11 +960,11 @@ func testTraceflowIntraNode(t *testing.T, data *TestData) { ipVersion: 6, tf: &v1alpha1.Traceflow{ ObjectMeta: metav1.ObjectMeta{ - Name: randName(fmt.Sprintf("%s-%s-to-%s-", testNamespace, node1Pods[0], strings.ReplaceAll(dstPodIPv6Str, ":", "--"))), + Name: randName(fmt.Sprintf("%s-%s-to-%s-", data.testNamespace, node1Pods[0], strings.ReplaceAll(dstPodIPv6Str, ":", "--"))), }, Spec: v1alpha1.TraceflowSpec{ Source: v1alpha1.Source{ - Namespace: testNamespace, + Namespace: data.testNamespace, Pod: node1Pods[0], }, Destination: v1alpha1.Destination{ @@ -981,11 +1010,11 @@ func testTraceflowIntraNode(t *testing.T, data *TestData) { ipVersion: 4, tf: &v1alpha1.Traceflow{ ObjectMeta: metav1.ObjectMeta{ - Name: randName(fmt.Sprintf("%s-%s-to-%s-", testNamespace, node1Pods[0], gwIPv4Str)), + Name: randName(fmt.Sprintf("%s-%s-to-%s-", data.testNamespace, node1Pods[0], gwIPv4Str)), }, Spec: v1alpha1.TraceflowSpec{ Source: v1alpha1.Source{ - Namespace: testNamespace, + Namespace: data.testNamespace, Pod: node1Pods[0], }, Destination: v1alpha1.Destination{ @@ -1029,11 +1058,11 @@ func testTraceflowIntraNode(t *testing.T, data *TestData) { ipVersion: 6, tf: &v1alpha1.Traceflow{ ObjectMeta: metav1.ObjectMeta{ - Name: randName(fmt.Sprintf("%s-%s-to-%s-", testNamespace, node1Pods[0], strings.ReplaceAll(gwIPv6Str, ":", "--"))), + Name: randName(fmt.Sprintf("%s-%s-to-%s-", data.testNamespace, node1Pods[0], strings.ReplaceAll(gwIPv6Str, ":", "--"))), }, Spec: v1alpha1.TraceflowSpec{ Source: v1alpha1.Source{ - Namespace: testNamespace, + Namespace: data.testNamespace, Pod: node1Pods[0], }, Destination: v1alpha1.Destination{ @@ -1084,11 +1113,19 @@ func testTraceflowIntraNode(t *testing.T, data *TestData) { // testTraceflowInterNode verifies if traceflow can trace inter nodes traffic with some NetworkPolicies set. func testTraceflowInterNode(t *testing.T, data *TestData) { - node1 := nodeName(0) - node2 := nodeName(1) + nodeIdx0 := 0 + nodeIdx1 := 1 + if len(clusterInfo.windowsNodes) > 1 { + nodeIdx0 = clusterInfo.windowsNodes[0] + nodeIdx1 = clusterInfo.windowsNodes[1] + } else { + skipIfHasWindowsNodes(t) + } + node1 := nodeName(nodeIdx0) + node2 := nodeName(nodeIdx1) - node1Pods, _, node1CleanupFn := createTestBusyboxPods(t, data, 1, testNamespace, node1) - node2Pods, node2IPs, node2CleanupFn := createTestBusyboxPods(t, data, 2, testNamespace, node2) + node1Pods, _, node1CleanupFn := createTestAgnhostPods(t, data, 1, data.testNamespace, node1) + node2Pods, node2IPs, node2CleanupFn := createTestAgnhostPods(t, data, 3, data.testNamespace, node2) gatewayIPv4, gatewayIPv6 := nodeGatewayIPs(1) defer node1CleanupFn() defer node2CleanupFn() @@ -1102,27 +1139,45 @@ func testTraceflowInterNode(t *testing.T, data *TestData) { // Create Service backend Pod. The "hairpin" testcases require the Service to have a single backend Pod, // and no more, in order to be deterministic. - nginxPodName := "nginx" - require.NoError(t, data.createNginxPodOnNode(nginxPodName, testNamespace, node2, false)) - nginxIP, err := data.podWaitForIPs(defaultTimeout, nginxPodName, testNamespace) + agnhostPodName := "agnhost" + mutateFunc := func(pod *corev1.Pod) { + pod.Labels["app"] = "agnhost-server" + } + require.NoError(t, data.createPodOnNode(agnhostPodName, data.testNamespace, node2, agnhostImage, []string{"sleep", strconv.Itoa(3600)}, nil, nil, nil, false, mutateFunc)) + agnhostIP, err := data.podWaitForIPs(defaultTimeout, agnhostPodName, data.testNamespace) require.NoError(t, err) - var nginxIPv4Str, nginxIPv6Str, svcIPv4Name, svcIPv6Name string - if nginxIP.ipv4 != nil { - nginxIPv4Str = nginxIP.ipv4.String() + var agnhostIPv4Str, agnhostIPv6Str, svcIPv4Name, svcIPv6Name string + if agnhostIP.ipv4 != nil { + agnhostIPv4Str = agnhostIP.ipv4.String() ipv4Protocol := corev1.IPv4Protocol - svcIPv4, err := data.createNginxClusterIPService("nginx-ipv4", testNamespace, false, &ipv4Protocol) + svcIPv4, err := data.CreateService("agnhost-ipv4", data.testNamespace, 80, 8080, map[string]string{"app": "agnhost-server"}, false, false, corev1.ServiceTypeClusterIP, &ipv4Protocol) require.NoError(t, err) svcIPv4Name = svcIPv4.Name } - if nginxIP.ipv6 != nil { - nginxIPv6Str = nginxIP.ipv6.String() + if agnhostIP.ipv6 != nil { + agnhostIPv6Str = agnhostIP.ipv6.String() ipv6Protocol := corev1.IPv6Protocol - svcIPv6, err := data.createNginxClusterIPService("nginx-ipv6", testNamespace, false, &ipv6Protocol) + svcIPv6, err := data.CreateService("agnhost-ipv6", data.testNamespace, 80, 8080, map[string]string{"app": "agnhost-server"}, false, false, corev1.ServiceTypeClusterIP, &ipv6Protocol) require.NoError(t, err) svcIPv6Name = svcIPv6.Name } + // Mesh ping to activate tunnel on Windows Node + // TODO: Remove this after Windows OVS fixes the issue (openvswitch/ovs-issues#253) that first packet is possibly + // dropped on tunnel because the ARP entry doesn't exist in host cache. + isWindows := len(clusterInfo.windowsNodes) != 0 + if isWindows { + podInfos := make([]podInfo, 2) + podInfos[0].name = node1Pods[0] + podInfos[0].namespace = data.testNamespace + podInfos[0].os = "windows" + podInfos[1].name = node2Pods[2] + podInfos[1].namespace = data.testNamespace + podInfos[1].os = "windows" + data.runPingMesh(t, podInfos, agnhostContainerName) + } + // Setup 2 NetworkPolicies: // 1. Allow all egress traffic. // 2. Deny ingress traffic on pod with label antrea-e2e = node1Pods[1]. So flow node1Pods[0] -> node1Pods[1] will be dropped. @@ -1149,10 +1204,10 @@ func testTraceflowInterNode(t *testing.T, data *TestData) { }() antreaPod, err := data.getAntreaPodOnNode(node2) - if err = data.waitForNetworkpolicyRealized(antreaPod, allowAllEgressName, v1beta2.K8sNetworkPolicy); err != nil { + if err = data.waitForNetworkpolicyRealized(antreaPod, node2, isWindows, allowAllEgressName, v1beta2.K8sNetworkPolicy); err != nil { t.Fatal(err) } - if err = data.waitForNetworkpolicyRealized(antreaPod, denyAllIngressName, v1beta2.K8sNetworkPolicy); err != nil { + if err = data.waitForNetworkpolicyRealized(antreaPod, node2, isWindows, denyAllIngressName, v1beta2.K8sNetworkPolicy); err != nil { t.Fatal(err) } @@ -1162,15 +1217,15 @@ func testTraceflowInterNode(t *testing.T, data *TestData) { ipVersion: 4, tf: &v1alpha1.Traceflow{ ObjectMeta: metav1.ObjectMeta{ - Name: randName(fmt.Sprintf("%s-%s-to-%s-%s-", testNamespace, node1Pods[0], testNamespace, node2Pods[0])), + Name: randName(fmt.Sprintf("%s-%s-to-%s-%s-", data.testNamespace, node1Pods[0], data.testNamespace, node2Pods[0])), }, Spec: v1alpha1.TraceflowSpec{ Source: v1alpha1.Source{ - Namespace: testNamespace, + Namespace: data.testNamespace, Pod: node1Pods[0], }, Destination: v1alpha1.Destination{ - Namespace: testNamespace, + Namespace: data.testNamespace, Pod: node2Pods[0], }, Packet: v1alpha1.Packet{ @@ -1180,6 +1235,7 @@ func testTraceflowInterNode(t *testing.T, data *TestData) { TransportHeader: v1alpha1.TransportHeader{ TCP: &v1alpha1.TCPHeader{ DstPort: 80, + SrcPort: 10009, Flags: 2, }, }, @@ -1228,11 +1284,11 @@ func testTraceflowInterNode(t *testing.T, data *TestData) { ipVersion: 4, tf: &v1alpha1.Traceflow{ ObjectMeta: metav1.ObjectMeta{ - Name: randName(fmt.Sprintf("%s-%s-to-%s-", testNamespace, node1Pods[0], dstPodIPv4Str)), + Name: randName(fmt.Sprintf("%s-%s-to-%s-", data.testNamespace, node1Pods[0], dstPodIPv4Str)), }, Spec: v1alpha1.TraceflowSpec{ Source: v1alpha1.Source{ - Namespace: testNamespace, + Namespace: data.testNamespace, Pod: node1Pods[0], }, Destination: v1alpha1.Destination{ @@ -1245,6 +1301,7 @@ func testTraceflowInterNode(t *testing.T, data *TestData) { TransportHeader: v1alpha1.TransportHeader{ UDP: &v1alpha1.UDPHeader{ DstPort: 321, + SrcPort: 10010, }, }, }, @@ -1288,19 +1345,20 @@ func testTraceflowInterNode(t *testing.T, data *TestData) { }, }, { - name: "interNodeICMPDstIPTraceflowIPv4", + name: "interNodeICMPDstPodDroppedTraceflowIPv4", ipVersion: 4, tf: &v1alpha1.Traceflow{ ObjectMeta: metav1.ObjectMeta{ - Name: randName(fmt.Sprintf("%s-%s-to-%s-", testNamespace, node1Pods[0], dstPodIPv4Str)), + Name: randName(fmt.Sprintf("%s-%s-to-%s-", data.testNamespace, node1Pods[0], node2Pods[1])), }, Spec: v1alpha1.TraceflowSpec{ Source: v1alpha1.Source{ - Namespace: testNamespace, + Namespace: data.testNamespace, Pod: node1Pods[0], }, Destination: v1alpha1.Destination{ - IP: dstPodIPv4Str, + Namespace: data.testNamespace, + Pod: node2Pods[1], }, Packet: v1alpha1.Packet{ IPHeader: v1alpha1.IPHeader{ @@ -1338,9 +1396,9 @@ func testTraceflowInterNode(t *testing.T, data *TestData) { Action: v1alpha1.ActionReceived, }, { - Component: v1alpha1.ComponentForwarding, - ComponentInfo: "Output", - Action: v1alpha1.ActionDelivered, + Component: v1alpha1.ComponentNetworkPolicy, + ComponentInfo: "IngressDefaultRule", + Action: v1alpha1.ActionDropped, }, }, }, @@ -1354,15 +1412,15 @@ func testTraceflowInterNode(t *testing.T, data *TestData) { ipVersion: 4, tf: &v1alpha1.Traceflow{ ObjectMeta: metav1.ObjectMeta{ - Name: randName(fmt.Sprintf("%s-%s-to-svc-%s-", testNamespace, node1Pods[0], svcIPv4Name)), + Name: randName(fmt.Sprintf("%s-%s-to-svc-%s-", data.testNamespace, node1Pods[0], svcIPv4Name)), }, Spec: v1alpha1.TraceflowSpec{ Source: v1alpha1.Source{ - Namespace: testNamespace, + Namespace: data.testNamespace, Pod: node1Pods[0], }, Destination: v1alpha1.Destination{ - Namespace: testNamespace, + Namespace: data.testNamespace, Service: svcIPv4Name, }, Packet: v1alpha1.Packet{ @@ -1372,6 +1430,7 @@ func testTraceflowInterNode(t *testing.T, data *TestData) { TransportHeader: v1alpha1.TransportHeader{ TCP: &v1alpha1.TCPHeader{ DstPort: 80, + SrcPort: 10011, Flags: 2, }, }, @@ -1389,8 +1448,8 @@ func testTraceflowInterNode(t *testing.T, data *TestData) { }, { Component: v1alpha1.ComponentLB, - Pod: fmt.Sprintf("%s/%s", testNamespace, nginxPodName), - TranslatedDstIP: nginxIPv4Str, + Pod: fmt.Sprintf("%s/%s", data.testNamespace, agnhostPodName), + TranslatedDstIP: agnhostIPv4Str, Action: v1alpha1.ActionForwarded, }, { @@ -1429,15 +1488,15 @@ func testTraceflowInterNode(t *testing.T, data *TestData) { ipVersion: 4, tf: &v1alpha1.Traceflow{ ObjectMeta: metav1.ObjectMeta{ - Name: randName(fmt.Sprintf("%s-%s-to-svc-%s-", testNamespace, nginxPodName, svcIPv4Name)), + Name: randName(fmt.Sprintf("%s-%s-to-svc-%s-", data.testNamespace, agnhostPodName, svcIPv4Name)), }, Spec: v1alpha1.TraceflowSpec{ Source: v1alpha1.Source{ - Namespace: testNamespace, - Pod: nginxPodName, + Namespace: data.testNamespace, + Pod: agnhostPodName, }, Destination: v1alpha1.Destination{ - Namespace: testNamespace, + Namespace: data.testNamespace, Service: svcIPv4Name, }, Packet: v1alpha1.Packet{ @@ -1447,6 +1506,7 @@ func testTraceflowInterNode(t *testing.T, data *TestData) { TransportHeader: v1alpha1.TransportHeader{ TCP: &v1alpha1.TCPHeader{ DstPort: 80, + SrcPort: 10012, Flags: 2, }, }, @@ -1464,9 +1524,9 @@ func testTraceflowInterNode(t *testing.T, data *TestData) { }, { Component: v1alpha1.ComponentLB, - Pod: fmt.Sprintf("%s/%s", testNamespace, nginxPodName), + Pod: fmt.Sprintf("%s/%s", data.testNamespace, agnhostPodName), TranslatedSrcIP: gatewayIPv4, - TranslatedDstIP: nginxIPv4Str, + TranslatedDstIP: agnhostIPv4Str, Action: v1alpha1.ActionForwarded, }, { @@ -1488,15 +1548,15 @@ func testTraceflowInterNode(t *testing.T, data *TestData) { ipVersion: 4, tf: &v1alpha1.Traceflow{ ObjectMeta: metav1.ObjectMeta{ - Name: randName(fmt.Sprintf("%s-%s-to-%s-", testNamespace, node1Pods[0], node2Pods[0])), + Name: randName(fmt.Sprintf("%s-%s-to-%s-", data.testNamespace, node1Pods[0], node2Pods[0])), }, Spec: v1alpha1.TraceflowSpec{ Source: v1alpha1.Source{ - Namespace: testNamespace, + Namespace: data.testNamespace, Pod: node1Pods[0], }, Destination: v1alpha1.Destination{ - Namespace: testNamespace, + Namespace: data.testNamespace, Pod: node2Pods[0], }, LiveTraffic: true, @@ -1545,15 +1605,15 @@ func testTraceflowInterNode(t *testing.T, data *TestData) { ipVersion: 6, tf: &v1alpha1.Traceflow{ ObjectMeta: metav1.ObjectMeta{ - Name: randName(fmt.Sprintf("%s-%s-to-%s-%s-", testNamespace, node1Pods[0], testNamespace, node2Pods[0])), + Name: randName(fmt.Sprintf("%s-%s-to-%s-%s-", data.testNamespace, node1Pods[0], data.testNamespace, node2Pods[0])), }, Spec: v1alpha1.TraceflowSpec{ Source: v1alpha1.Source{ - Namespace: testNamespace, + Namespace: data.testNamespace, Pod: node1Pods[0], }, Destination: v1alpha1.Destination{ - Namespace: testNamespace, + Namespace: data.testNamespace, Pod: node2Pods[0], }, Packet: v1alpha1.Packet{ @@ -1563,6 +1623,7 @@ func testTraceflowInterNode(t *testing.T, data *TestData) { TransportHeader: v1alpha1.TransportHeader{ TCP: &v1alpha1.TCPHeader{ DstPort: 80, + SrcPort: 10013, Flags: 2, }, }, @@ -1614,11 +1675,11 @@ func testTraceflowInterNode(t *testing.T, data *TestData) { ipVersion: 6, tf: &v1alpha1.Traceflow{ ObjectMeta: metav1.ObjectMeta{ - Name: randName(fmt.Sprintf("%s-%s-to-%s-", testNamespace, node1Pods[0], strings.ReplaceAll(dstPodIPv6Str, ":", "--"))), + Name: randName(fmt.Sprintf("%s-%s-to-%s-", data.testNamespace, node1Pods[0], strings.ReplaceAll(dstPodIPv6Str, ":", "--"))), }, Spec: v1alpha1.TraceflowSpec{ Source: v1alpha1.Source{ - Namespace: testNamespace, + Namespace: data.testNamespace, Pod: node1Pods[0], }, Destination: v1alpha1.Destination{ @@ -1631,6 +1692,7 @@ func testTraceflowInterNode(t *testing.T, data *TestData) { TransportHeader: v1alpha1.TransportHeader{ UDP: &v1alpha1.UDPHeader{ DstPort: 321, + SrcPort: 10014, }, }, }, @@ -1678,11 +1740,11 @@ func testTraceflowInterNode(t *testing.T, data *TestData) { ipVersion: 6, tf: &v1alpha1.Traceflow{ ObjectMeta: metav1.ObjectMeta{ - Name: randName(fmt.Sprintf("%s-%s-to-%s-", testNamespace, node1Pods[0], strings.ReplaceAll(dstPodIPv6Str, ":", "--"))), + Name: randName(fmt.Sprintf("%s-%s-to-%s-", data.testNamespace, node1Pods[0], strings.ReplaceAll(dstPodIPv6Str, ":", "--"))), }, Spec: v1alpha1.TraceflowSpec{ Source: v1alpha1.Source{ - Namespace: testNamespace, + Namespace: data.testNamespace, Pod: node1Pods[0], }, Destination: v1alpha1.Destination{ @@ -1737,15 +1799,15 @@ func testTraceflowInterNode(t *testing.T, data *TestData) { ipVersion: 6, tf: &v1alpha1.Traceflow{ ObjectMeta: metav1.ObjectMeta{ - Name: randName(fmt.Sprintf("%s-%s-to-svc-%s-", testNamespace, node1Pods[0], svcIPv6Name)), + Name: randName(fmt.Sprintf("%s-%s-to-svc-%s-", data.testNamespace, node1Pods[0], svcIPv6Name)), }, Spec: v1alpha1.TraceflowSpec{ Source: v1alpha1.Source{ - Namespace: testNamespace, + Namespace: data.testNamespace, Pod: node1Pods[0], }, Destination: v1alpha1.Destination{ - Namespace: testNamespace, + Namespace: data.testNamespace, Service: svcIPv6Name, }, Packet: v1alpha1.Packet{ @@ -1755,6 +1817,7 @@ func testTraceflowInterNode(t *testing.T, data *TestData) { TransportHeader: v1alpha1.TransportHeader{ TCP: &v1alpha1.TCPHeader{ DstPort: 80, + SrcPort: 10015, Flags: 2, }, }, @@ -1772,8 +1835,8 @@ func testTraceflowInterNode(t *testing.T, data *TestData) { }, { Component: v1alpha1.ComponentLB, - Pod: fmt.Sprintf("%s/%s", testNamespace, nginxPodName), - TranslatedDstIP: nginxIPv6Str, + Pod: fmt.Sprintf("%s/%s", data.testNamespace, agnhostPodName), + TranslatedDstIP: agnhostIPv6Str, Action: v1alpha1.ActionForwarded, }, { @@ -1809,15 +1872,15 @@ func testTraceflowInterNode(t *testing.T, data *TestData) { ipVersion: 6, tf: &v1alpha1.Traceflow{ ObjectMeta: metav1.ObjectMeta{ - Name: randName(fmt.Sprintf("%s-%s-to-svc-%s-", testNamespace, nginxPodName, svcIPv6Name)), + Name: randName(fmt.Sprintf("%s-%s-to-svc-%s-", data.testNamespace, agnhostPodName, svcIPv6Name)), }, Spec: v1alpha1.TraceflowSpec{ Source: v1alpha1.Source{ - Namespace: testNamespace, - Pod: nginxPodName, + Namespace: data.testNamespace, + Pod: agnhostPodName, }, Destination: v1alpha1.Destination{ - Namespace: testNamespace, + Namespace: data.testNamespace, Service: svcIPv6Name, }, Packet: v1alpha1.Packet{ @@ -1827,6 +1890,7 @@ func testTraceflowInterNode(t *testing.T, data *TestData) { TransportHeader: v1alpha1.TransportHeader{ TCP: &v1alpha1.TCPHeader{ DstPort: 80, + SrcPort: 10016, Flags: 2, }, }, @@ -1844,9 +1908,9 @@ func testTraceflowInterNode(t *testing.T, data *TestData) { }, { Component: v1alpha1.ComponentLB, - Pod: fmt.Sprintf("%s/%s", testNamespace, nginxPodName), + Pod: fmt.Sprintf("%s/%s", data.testNamespace, agnhostPodName), TranslatedSrcIP: gatewayIPv6, - TranslatedDstIP: nginxIPv6Str, + TranslatedDstIP: agnhostIPv6Str, Action: v1alpha1.ActionForwarded, }, { @@ -1868,15 +1932,15 @@ func testTraceflowInterNode(t *testing.T, data *TestData) { ipVersion: 6, tf: &v1alpha1.Traceflow{ ObjectMeta: metav1.ObjectMeta{ - Name: randName(fmt.Sprintf("%s-%s-to-%s-", testNamespace, node1Pods[0], node2Pods[0])), + Name: randName(fmt.Sprintf("%s-%s-to-%s-", data.testNamespace, node1Pods[0], node2Pods[0])), }, Spec: v1alpha1.TraceflowSpec{ Source: v1alpha1.Source{ - Namespace: testNamespace, + Namespace: data.testNamespace, Pod: node1Pods[0], }, Destination: v1alpha1.Destination{ - Namespace: testNamespace, + Namespace: data.testNamespace, Pod: node2Pods[0], }, Packet: v1alpha1.Packet{ @@ -1931,7 +1995,12 @@ func testTraceflowInterNode(t *testing.T, data *TestData) { for _, tc := range testcases { tc := tc t.Run(tc.name, func(t *testing.T) { - t.Parallel() + // Run test cases in sequential on Windows environment to verify the first packet issue is worked around. + // TODO: Run test cases in parallel after Windows OVS fixes the issue (openvswitch/ovs-issues#253) that + // first packet is possibly dropped on tunnel because the ARP entry doesn't exist in host cache. + if len(clusterInfo.windowsNodes) == 0 { + t.Parallel() + } runTestTraceflow(t, data, tc) }) } @@ -1939,9 +2008,13 @@ func testTraceflowInterNode(t *testing.T, data *TestData) { } func testTraceflowExternalIP(t *testing.T, data *TestData) { - node := nodeName(0) - nodeIP := nodeIP(0) - podNames, _, cleanupFn := createTestBusyboxPods(t, data, 1, testNamespace, node) + nodeIdx := 0 + if len(clusterInfo.windowsNodes) != 0 { + nodeIdx = clusterInfo.windowsNodes[0] + } + node := nodeName(nodeIdx) + nodeIP := nodeIP(nodeIdx) + podNames, _, cleanupFn := createTestAgnhostPods(t, data, 1, data.testNamespace, node) defer cleanupFn() testcase := testcase{ @@ -1949,11 +2022,11 @@ func testTraceflowExternalIP(t *testing.T, data *TestData) { ipVersion: 4, tf: &v1alpha1.Traceflow{ ObjectMeta: metav1.ObjectMeta{ - Name: randName(fmt.Sprintf("%s-%s-to-%s-%s-", testNamespace, podNames[0], testNamespace, strings.ReplaceAll(nodeIP, ":", "--"))), + Name: randName(fmt.Sprintf("%s-%s-to-%s-%s-", data.testNamespace, podNames[0], data.testNamespace, strings.ReplaceAll(nodeIP, ":", "--"))), }, Spec: v1alpha1.TraceflowSpec{ Source: v1alpha1.Source{ - Namespace: testNamespace, + Namespace: data.testNamespace, Pod: podNames[0], }, Destination: v1alpha1.Destination{ @@ -2065,7 +2138,7 @@ func (data *TestData) createANPDenyIngress(key string, value string, name string Egress: []v1alpha1.Rule{}, }, } - anpCreated, err := k8sUtils.crdClient.CrdV1alpha1().NetworkPolicies(testNamespace).Create(context.TODO(), &anp, metav1.CreateOptions{}) + anpCreated, err := k8sUtils.crdClient.CrdV1alpha1().NetworkPolicies(data.testNamespace).Create(context.TODO(), &anp, metav1.CreateOptions{}) if err != nil { return nil, err } @@ -2074,7 +2147,7 @@ func (data *TestData) createANPDenyIngress(key string, value string, name string // deleteAntreaNetworkpolicy deletes an Antrea NetworkPolicy. func (data *TestData) deleteAntreaNetworkpolicy(policy *v1alpha1.NetworkPolicy) error { - if err := k8sUtils.crdClient.CrdV1alpha1().NetworkPolicies(testNamespace).Delete(context.TODO(), policy.Name, metav1.DeleteOptions{}); err != nil { + if err := k8sUtils.crdClient.CrdV1alpha1().NetworkPolicies(data.testNamespace).Delete(context.TODO(), policy.Name, metav1.DeleteOptions{}); err != nil { return fmt.Errorf("unable to cleanup policy %v: %v", policy.Name, err) } return nil @@ -2106,18 +2179,27 @@ func (data *TestData) createNPAllowAllEgress(name string) (*networkingv1.Network } // waitForNetworkpolicyRealized waits for the NetworkPolicy to be realized by the antrea-agent Pod. -func (data *TestData) waitForNetworkpolicyRealized(pod string, networkpolicy string, npType v1beta2.NetworkPolicyType) error { +func (data *TestData) waitForNetworkpolicyRealized(pod string, node string, isWindows bool, networkpolicy string, npType v1beta2.NetworkPolicyType) error { npOption := "K8sNP" if npType == v1beta2.AntreaNetworkPolicy { npOption = "ANP" } if err := wait.Poll(200*time.Millisecond, 5*time.Second, func() (bool, error) { - cmds := []string{"antctl", "get", "networkpolicy", "-S", networkpolicy, "-n", testNamespace, "-T", npOption} - stdout, stderr, err := runAntctl(pod, cmds, data) + var stdout, stderr string + var err error + if isWindows { + antctlCmd := fmt.Sprintf("C:/k/antrea/bin/antctl.exe get networkpolicy -S %s -n %s -T %s", networkpolicy, data.testNamespace, npOption) + envCmd := fmt.Sprintf("export POD_NAME=antrea-agent;export KUBERNETES_SERVICE_HOST=%s;export KUBERNETES_SERVICE_PORT=%d", clusterInfo.k8sServiceHost, clusterInfo.k8sServicePort) + cmd := fmt.Sprintf("%s && %s", envCmd, antctlCmd) + _, stdout, stderr, err = data.RunCommandOnNode(node, cmd) + } else { + cmds := []string{"antctl", "get", "networkpolicy", "-S", networkpolicy, "-n", data.testNamespace, "-T", npOption} + stdout, stderr, err = runAntctl(pod, cmds, data) + } if err != nil { return false, fmt.Errorf("Error when executing antctl get NetworkPolicy, stdout: %s, stderr: %s, err: %v", stdout, stderr, err) } - return strings.Contains(stdout, fmt.Sprintf("%s:%s/%s", npType, testNamespace, networkpolicy)), nil + return strings.Contains(stdout, fmt.Sprintf("%s:%s/%s", npType, data.testNamespace, networkpolicy)), nil }); err == wait.ErrWaitTimeout { return fmt.Errorf("NetworkPolicy %s isn't realized in time", networkpolicy) } else if err != nil { @@ -2148,6 +2230,10 @@ func runTestTraceflow(t *testing.T, data *TestData, tc testcase) { if tc.tf.Spec.LiveTraffic { // LiveTraffic Traceflow test supports only ICMP traffic from // the source Pod to an IP or another Pod. + osString := "linux" + if len(clusterInfo.windowsNodes) != 0 { + osString = "windows" + } var dstPodIPs *PodIPs srcPod := tc.srcPod if dstIP := tc.tf.Spec.Destination.IP; dstIP != "" { @@ -2159,13 +2245,13 @@ func runTestTraceflow(t *testing.T, data *TestData, tc testcase) { } } else { dstPod := tc.tf.Spec.Destination.Pod - podIPs := waitForPodIPs(t, data, []podInfo{{dstPod, "linux", "", ""}}) + podIPs := waitForPodIPs(t, data, []podInfo{{dstPod, osString, "", ""}}) dstPodIPs = podIPs[dstPod] } // Give a little time for Nodes to install OVS flows. time.Sleep(time.Second * 2) // Send an ICMP echo packet from the source Pod to the destination. - if err := data.runPingCommandFromTestPod(podInfo{srcPod, "linux", "", ""}, testNamespace, dstPodIPs, busyboxContainerName, 2, 0); err != nil { + if err := data.runPingCommandFromTestPod(podInfo{srcPod, osString, "", ""}, data.testNamespace, dstPodIPs, agnhostContainerName, 2, 0); err != nil { t.Logf("Ping '%s' -> '%v' failed: ERROR (%v)", srcPod, *dstPodIPs, err) } } diff --git a/test/e2e/upgrade_test.go b/test/e2e/upgrade_test.go index d03b162de5c..4a6fbd63099 100644 --- a/test/e2e/upgrade_test.go +++ b/test/e2e/upgrade_test.go @@ -54,10 +54,10 @@ func TestUpgrade(t *testing.T) { podName := randName("test-pod-") t.Logf("Creating a busybox test Pod on '%s'", nodeName) - if err := data.createBusyboxPodOnNode(podName, testNamespace, nodeName, false); err != nil { + if err := data.createBusyboxPodOnNode(podName, data.testNamespace, nodeName, false); err != nil { t.Fatalf("Error when creating busybox test Pod: %v", err) } - if err := data.podWaitForRunning(defaultTimeout, podName, testNamespace); err != nil { + if err := data.podWaitForRunning(defaultTimeout, podName, data.testNamespace); err != nil { t.Fatalf("Error when waiting for Pod '%s' to be in the Running state", podName) } @@ -113,5 +113,5 @@ func TestUpgrade(t *testing.T) { t.Errorf("Namespace deletion failed: %v", err) } - data.testDeletePod(t, podName, nodeName, testNamespace, false) + data.testDeletePod(t, podName, nodeName, data.testNamespace, false) } diff --git a/test/e2e/utils/anpspecbuilder.go b/test/e2e/utils/anpspecbuilder.go index af6279237ea..7e8350e8b9b 100644 --- a/test/e2e/utils/anpspecbuilder.go +++ b/test/e2e/utils/anpspecbuilder.go @@ -15,9 +15,7 @@ package utils import ( - v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/util/intstr" crdv1alpha1 "antrea.io/antrea/pkg/apis/crd/v1alpha1" ) @@ -87,8 +85,8 @@ func (b *AntreaNetworkPolicySpecBuilder) GetAppliedToPeer(podSelector map[string } } -func (b *AntreaNetworkPolicySpecBuilder) AddIngress(protoc v1.Protocol, - port *int32, portName *string, endPort *int32, cidr *string, +func (b *AntreaNetworkPolicySpecBuilder) AddIngress(protoc AntreaPolicyProtocol, + port *int32, portName *string, endPort, icmpType, icmpCode *int32, cidr *string, podSelector map[string]string, nsSelector map[string]string, podSelectorMatchExp []metav1.LabelSelectorRequirement, nsSelectorMatchExp []metav1.LabelSelectorRequirement, ruleAppliedToSpecs []ANPAppliedToSpec, action crdv1alpha1.RuleAction, name string) *AntreaNetworkPolicySpecBuilder { @@ -129,36 +127,11 @@ func (b *AntreaNetworkPolicySpecBuilder) AddIngress(protoc v1.Protocol, IPBlock: ipBlock, }} } - - var ports []crdv1alpha1.NetworkPolicyPort - if port != nil && portName != nil { - panic("specify portname or port, not both") - } - if portName != nil { - ports = []crdv1alpha1.NetworkPolicyPort{ - { - Port: &intstr.IntOrString{Type: intstr.String, StrVal: *portName}, - Protocol: &protoc, - }, - } - } - if port != nil || endPort != nil { - var pVal *intstr.IntOrString - if port != nil { - pVal = &intstr.IntOrString{IntVal: *port} - } - ports = []crdv1alpha1.NetworkPolicyPort{ - { - Port: pVal, - EndPort: endPort, - Protocol: &protoc, - }, - } - } - + ports, protocols := GenPortsOrProtocols(protoc, port, portName, endPort, icmpType, icmpCode) newRule := crdv1alpha1.Rule{ From: policyPeer, Ports: ports, + Protocols: protocols, Action: &action, Name: name, AppliedTo: appliedTos, @@ -167,8 +140,8 @@ func (b *AntreaNetworkPolicySpecBuilder) AddIngress(protoc v1.Protocol, return b } -func (b *AntreaNetworkPolicySpecBuilder) AddEgress(protoc v1.Protocol, - port *int32, portName *string, endPort *int32, cidr *string, +func (b *AntreaNetworkPolicySpecBuilder) AddEgress(protoc AntreaPolicyProtocol, + port *int32, portName *string, endPort, icmpType, icmpCode *int32, cidr *string, podSelector map[string]string, nsSelector map[string]string, podSelectorMatchExp []metav1.LabelSelectorRequirement, nsSelectorMatchExp []metav1.LabelSelectorRequirement, ruleAppliedToSpecs []ANPAppliedToSpec, action crdv1alpha1.RuleAction, name string) *AntreaNetworkPolicySpecBuilder { @@ -176,7 +149,7 @@ func (b *AntreaNetworkPolicySpecBuilder) AddEgress(protoc v1.Protocol, // For simplicity, we just reuse the Ingress code here. The underlying data model for ingress/egress is identical // With the exception of calling the rule `To` vs. `From`. c := &AntreaNetworkPolicySpecBuilder{} - c.AddIngress(protoc, port, portName, endPort, cidr, podSelector, nsSelector, + c.AddIngress(protoc, port, portName, endPort, icmpType, icmpCode, cidr, podSelector, nsSelector, podSelectorMatchExp, nsSelectorMatchExp, ruleAppliedToSpecs, action, name) theRule := c.Get().Spec.Ingress[0] diff --git a/test/e2e/utils/cnpspecbuilder.go b/test/e2e/utils/cnpspecbuilder.go index 0a1d89ff69a..76f068b5acb 100644 --- a/test/e2e/utils/cnpspecbuilder.go +++ b/test/e2e/utils/cnpspecbuilder.go @@ -15,7 +15,6 @@ package utils import ( - v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/intstr" @@ -104,8 +103,8 @@ func (b *ClusterNetworkPolicySpecBuilder) GetAppliedToPeer(podSelector map[strin return peer } -func (b *ClusterNetworkPolicySpecBuilder) AddIngress(protoc v1.Protocol, - port *int32, portName *string, endPort *int32, cidr *string, +func (b *ClusterNetworkPolicySpecBuilder) AddIngress(protoc AntreaPolicyProtocol, + port *int32, portName *string, endPort, icmpType, icmpCode *int32, cidr *string, podSelector map[string]string, nsSelector map[string]string, podSelectorMatchExp []metav1.LabelSelectorRequirement, nsSelectorMatchExp []metav1.LabelSelectorRequirement, selfNS bool, ruleAppliedToSpecs []ACNPAppliedToSpec, action crdv1alpha1.RuleAction, ruleClusterGroup, name string, serviceAccount *crdv1alpha1.NamespacedName) *ClusterNetworkPolicySpecBuilder { @@ -158,35 +157,11 @@ func (b *ClusterNetworkPolicySpecBuilder) AddIngress(protoc v1.Protocol, ServiceAccount: serviceAccount, }} } - - var ports []crdv1alpha1.NetworkPolicyPort - if port != nil && portName != nil { - panic("specify portname or port, not both") - } - if portName != nil { - ports = []crdv1alpha1.NetworkPolicyPort{ - { - Port: &intstr.IntOrString{Type: intstr.String, StrVal: *portName}, - Protocol: &protoc, - }, - } - } - if port != nil || endPort != nil { - var pVal *intstr.IntOrString - if port != nil { - pVal = &intstr.IntOrString{IntVal: *port} - } - ports = []crdv1alpha1.NetworkPolicyPort{ - { - Port: pVal, - EndPort: endPort, - Protocol: &protoc, - }, - } - } + ports, protocols := GenPortsOrProtocols(protoc, port, portName, endPort, icmpType, icmpCode) newRule := crdv1alpha1.Rule{ From: policyPeer, Ports: ports, + Protocols: protocols, Action: &action, Name: name, AppliedTo: appliedTos, @@ -195,8 +170,8 @@ func (b *ClusterNetworkPolicySpecBuilder) AddIngress(protoc v1.Protocol, return b } -func (b *ClusterNetworkPolicySpecBuilder) AddEgress(protoc v1.Protocol, - port *int32, portName *string, endPort *int32, cidr *string, +func (b *ClusterNetworkPolicySpecBuilder) AddEgress(protoc AntreaPolicyProtocol, + port *int32, portName *string, endPort, icmpType, icmpCode *int32, cidr *string, podSelector map[string]string, nsSelector map[string]string, podSelectorMatchExp []metav1.LabelSelectorRequirement, nsSelectorMatchExp []metav1.LabelSelectorRequirement, selfNS bool, ruleAppliedToSpecs []ACNPAppliedToSpec, action crdv1alpha1.RuleAction, ruleClusterGroup, name string, serviceAccount *crdv1alpha1.NamespacedName) *ClusterNetworkPolicySpecBuilder { @@ -204,7 +179,7 @@ func (b *ClusterNetworkPolicySpecBuilder) AddEgress(protoc v1.Protocol, // For simplicity, we just reuse the Ingress code here. The underlying data model for ingress/egress is identical // With the exception of calling the rule `To` vs. `From`. c := &ClusterNetworkPolicySpecBuilder{} - c.AddIngress(protoc, port, portName, endPort, cidr, podSelector, nsSelector, + c.AddIngress(protoc, port, portName, endPort, icmpType, icmpCode, cidr, podSelector, nsSelector, podSelectorMatchExp, nsSelectorMatchExp, selfNS, ruleAppliedToSpecs, action, ruleClusterGroup, name, serviceAccount) theRule := c.Get().Spec.Ingress[0] @@ -218,17 +193,17 @@ func (b *ClusterNetworkPolicySpecBuilder) AddEgress(protoc v1.Protocol, return b } -func (b *ClusterNetworkPolicySpecBuilder) AddNodeSelectorRule(nodeSelector *metav1.LabelSelector, protoc v1.Protocol, port *int32, name string, +func (b *ClusterNetworkPolicySpecBuilder) AddNodeSelectorRule(nodeSelector *metav1.LabelSelector, protoc AntreaPolicyProtocol, port *int32, name string, ruleAppliedToSpecs []ACNPAppliedToSpec, action crdv1alpha1.RuleAction, isEgress bool) *ClusterNetworkPolicySpecBuilder { var appliedTos []crdv1alpha1.NetworkPolicyPeer for _, at := range ruleAppliedToSpecs { appliedTos = append(appliedTos, b.GetAppliedToPeer(at.PodSelector, at.NSSelector, at.PodSelectorMatchExp, at.NSSelectorMatchExp, at.Group)) } policyPeer := []crdv1alpha1.NetworkPolicyPeer{{NodeSelector: nodeSelector}} - + k8sProtocol, _ := AntreaPolicyProtocolToK8sProtocol(protoc) newRule := crdv1alpha1.Rule{ Ports: []crdv1alpha1.NetworkPolicyPort{ - {Protocol: &protoc, Port: &intstr.IntOrString{IntVal: *port}}, + {Protocol: &k8sProtocol, Port: &intstr.IntOrString{IntVal: *port}}, }, Action: &action, Name: name, @@ -245,35 +220,14 @@ func (b *ClusterNetworkPolicySpecBuilder) AddNodeSelectorRule(nodeSelector *meta } func (b *ClusterNetworkPolicySpecBuilder) AddFQDNRule(fqdn string, - protoc v1.Protocol, port *int32, portName *string, endPort *int32, name string, + protoc AntreaPolicyProtocol, port *int32, portName *string, endPort *int32, name string, ruleAppliedToSpecs []ACNPAppliedToSpec, action crdv1alpha1.RuleAction) *ClusterNetworkPolicySpecBuilder { var appliedTos []crdv1alpha1.NetworkPolicyPeer for _, at := range ruleAppliedToSpecs { appliedTos = append(appliedTos, b.GetAppliedToPeer(at.PodSelector, at.NSSelector, at.PodSelectorMatchExp, at.NSSelectorMatchExp, at.Group)) } policyPeer := []crdv1alpha1.NetworkPolicyPeer{{FQDN: fqdn}} - var ports []crdv1alpha1.NetworkPolicyPort - if portName != nil { - ports = []crdv1alpha1.NetworkPolicyPort{ - { - Port: &intstr.IntOrString{Type: intstr.String, StrVal: *portName}, - Protocol: &protoc, - }, - } - } - if port != nil || endPort != nil { - var pVal *intstr.IntOrString - if port != nil { - pVal = &intstr.IntOrString{IntVal: *port} - } - ports = []crdv1alpha1.NetworkPolicyPort{ - { - Port: pVal, - EndPort: endPort, - Protocol: &protoc, - }, - } - } + ports, _ := GenPortsOrProtocols(protoc, port, portName, endPort, nil, nil) newRule := crdv1alpha1.Rule{ To: policyPeer, Ports: ports, @@ -304,7 +258,7 @@ func (b *ClusterNetworkPolicySpecBuilder) AddToServicesRule(svcRefs []crdv1alpha // AddEgressDNS mutates the nth policy rule to allow DNS, convenience method func (b *ClusterNetworkPolicySpecBuilder) WithEgressDNS() *ClusterNetworkPolicySpecBuilder { - protocolUDP := v1.ProtocolUDP + protocolUDP, _ := AntreaPolicyProtocolToK8sProtocol(ProtocolUDP) route53 := crdv1alpha1.NetworkPolicyPort{ Protocol: &protocolUDP, Port: &intstr.IntOrString{Type: intstr.Int, IntVal: 53}, diff --git a/test/e2e/utils/helper.go b/test/e2e/utils/helper.go new file mode 100644 index 00000000000..48694ebde8b --- /dev/null +++ b/test/e2e/utils/helper.go @@ -0,0 +1,86 @@ +// Copyright 2022 Antrea Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package utils + +import ( + "fmt" + + v1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/util/intstr" + + crdv1alpha1 "antrea.io/antrea/pkg/apis/crd/v1alpha1" +) + +type AntreaPolicyProtocol string + +const ( + ProtocolTCP AntreaPolicyProtocol = "TCP" + ProtocolUDP AntreaPolicyProtocol = "UDP" + ProtocolSCTP AntreaPolicyProtocol = "SCTP" + ProtocolICMP AntreaPolicyProtocol = "ICMP" +) + +func AntreaPolicyProtocolToK8sProtocol(antreaProtocol AntreaPolicyProtocol) (v1.Protocol, error) { + switch antreaProtocol { + case ProtocolTCP: + return v1.ProtocolTCP, nil + case ProtocolUDP: + return v1.ProtocolUDP, nil + case ProtocolSCTP: + return v1.ProtocolSCTP, nil + default: + return "", fmt.Errorf("k8s doesn't support protocol %s", antreaProtocol) + } +} + +func GenPortsOrProtocols(protoc AntreaPolicyProtocol, port *int32, portName *string, endPort, icmpType, icmpCode *int32) ([]crdv1alpha1.NetworkPolicyPort, []crdv1alpha1.NetworkPolicyProtocol) { + if protoc == ProtocolICMP { + return nil, []crdv1alpha1.NetworkPolicyProtocol{ + { + ICMP: &crdv1alpha1.ICMPProtocol{ + ICMPType: icmpType, + ICMPCode: icmpCode, + }, + }, + } + } + var ports []crdv1alpha1.NetworkPolicyPort + k8sProtocol, _ := AntreaPolicyProtocolToK8sProtocol(protoc) + if port != nil && portName != nil { + panic("specify portname or port, not both") + } + if portName != nil { + ports = []crdv1alpha1.NetworkPolicyPort{ + { + Port: &intstr.IntOrString{Type: intstr.String, StrVal: *portName}, + Protocol: &k8sProtocol, + }, + } + } + if port != nil || endPort != nil { + var pVal *intstr.IntOrString + if port != nil { + pVal = &intstr.IntOrString{IntVal: *port} + } + ports = []crdv1alpha1.NetworkPolicyPort{ + { + Port: pVal, + EndPort: endPort, + Protocol: &k8sProtocol, + }, + } + } + return ports, nil +} diff --git a/test/e2e/wireguard_test.go b/test/e2e/wireguard_test.go index 3199f4e8a35..b6667ab7d81 100644 --- a/test/e2e/wireguard_test.go +++ b/test/e2e/wireguard_test.go @@ -99,7 +99,7 @@ func (data *TestData) getWireGuardPeerEndpointsWithHandshake(nodeName string) ([ } func testPodConnectivity(t *testing.T, data *TestData) { - podInfos, deletePods := createPodsOnDifferentNodes(t, data, testNamespace, "differentnodes") + podInfos, deletePods := createPodsOnDifferentNodes(t, data, data.testNamespace, "differentnodes") defer deletePods() numPods := 2 data.runPingMesh(t, podInfos[:numPods], agnhostContainerName) @@ -113,17 +113,17 @@ func testServiceConnectivity(t *testing.T, data *TestData) { // nodeIP() returns IPv6 address if this is a IPv6 cluster. clientPodNodeIP := nodeIP(0) serverPodNode := nodeName(1) - svc, cleanup := data.createAgnhostServiceAndBackendPods(t, svcName, testNamespace, serverPodNode, corev1.ServiceTypeNodePort) + svc, cleanup := data.createAgnhostServiceAndBackendPods(t, svcName, data.testNamespace, serverPodNode, corev1.ServiceTypeNodePort) defer cleanup() // Create the a hostNetwork Pod on a Node different from the service's backend Pod, so the service traffic will be transferred across the tunnel. - require.NoError(t, data.createPodOnNode(clientPodName, testNamespace, clientPodNode, busyboxImage, []string{"sleep", strconv.Itoa(3600)}, nil, nil, nil, true, nil)) - defer data.deletePodAndWait(defaultTimeout, clientPodName, testNamespace) - require.NoError(t, data.podWaitForRunning(defaultTimeout, clientPodName, testNamespace)) + require.NoError(t, data.createPodOnNode(clientPodName, data.testNamespace, clientPodNode, busyboxImage, []string{"sleep", strconv.Itoa(3600)}, nil, nil, nil, true, nil)) + defer data.deletePodAndWait(defaultTimeout, clientPodName, data.testNamespace) + require.NoError(t, data.podWaitForRunning(defaultTimeout, clientPodName, data.testNamespace)) - err := data.runNetcatCommandFromTestPod(clientPodName, testNamespace, svc.Spec.ClusterIP, 80) + err := data.runNetcatCommandFromTestPod(clientPodName, data.testNamespace, svc.Spec.ClusterIP, 80) require.NoError(t, err, "Pod %s should be able to connect the service's ClusterIP %s, but was not able to connect", clientPodName, net.JoinHostPort(svc.Spec.ClusterIP, fmt.Sprint(80))) - err = data.runNetcatCommandFromTestPod(clientPodName, testNamespace, clientPodNodeIP, svc.Spec.Ports[0].NodePort) + err = data.runNetcatCommandFromTestPod(clientPodName, data.testNamespace, clientPodNodeIP, svc.Spec.Ports[0].NodePort) require.NoError(t, err, "Pod %s should be able to connect the service's NodePort %s:%d, but was not able to connect", clientPodName, clientPodNodeIP, svc.Spec.Ports[0].NodePort) } diff --git a/test/integration/agent/cniserver_test.go b/test/integration/agent/cniserver_test.go index c5e5efa4546..2e6c503a80c 100644 --- a/test/integration/agent/cniserver_test.go +++ b/test/integration/agent/cniserver_test.go @@ -142,7 +142,9 @@ const ( chainCNIConfStr = `{ "cniVersion":"%s", "name":"azure", -"prevResult":%s +"type":"antrea", +"prevResult":%s, +"ipam":{"type":"unknown"} }` ) @@ -571,9 +573,8 @@ func newTester() *cmdAddDelTester { "", testNodeConfig, k8sFake.NewSimpleClientset(), - false, - false, routeMock, + false, false, false, false, tester.networkReadyCh) tester.server.Initialize(ovsServiceMock, ofServiceMock, ifaceStore, channel.NewSubscribableChannel("PodUpdate", 100), nil) ctx := context.Background() @@ -651,7 +652,7 @@ func TestAntreaServerFunc(t *testing.T) { controller := mock.NewController(t) defer controller.Finish() ipamMock = ipamtest.NewMockIPAMDriver(controller) - _ = ipam.RegisterIPAMDriver("mock", ipamMock) + ipam.RegisterIPAMDriver("mock", ipamMock) ovsServiceMock = ovsconfigtest.NewMockOVSBridgeClient(controller) ofServiceMock = openflowtest.NewMockClient(controller) routeMock = routetest.NewMockInterface(controller) @@ -736,9 +737,8 @@ func setupChainTest( "", testNodeConfig, k8sFake.NewSimpleClientset(), - true, - false, routeMock, + true, false, false, false, networkReadyCh) } else { server = inServer diff --git a/test/integration/agent/openflow_test.go b/test/integration/agent/openflow_test.go index 834af6536fd..9a571cb08f0 100644 --- a/test/integration/agent/openflow_test.go +++ b/test/integration/agent/openflow_test.go @@ -41,6 +41,7 @@ import ( "antrea.io/antrea/pkg/agent/util" "antrea.io/antrea/pkg/apis/controlplane/v1beta2" crdv1alpha1 "antrea.io/antrea/pkg/apis/crd/v1alpha1" + "antrea.io/antrea/pkg/apis/crd/v1alpha2" ofconfig "antrea.io/antrea/pkg/ovs/openflow" "antrea.io/antrea/pkg/ovs/ovsconfig" "antrea.io/antrea/pkg/ovs/ovsctl" @@ -116,7 +117,7 @@ func TestConnectivityFlows(t *testing.T) { antrearuntime.WindowsOS = runtime.GOOS } - c = ofClient.NewClient(br, bridgeMgmtAddr, ovsconfig.OVSDatapathNetdev, true, false, true, false, false, false, false) + c = ofClient.NewClient(br, bridgeMgmtAddr, true, false, true, false, false, false, false, false) err := ofTestUtils.PrepareOVSBridge(br) require.Nil(t, err, fmt.Sprintf("Failed to prepare OVS bridge: %v", err)) defer func() { @@ -164,7 +165,7 @@ func TestAntreaFlexibleIPAMConnectivityFlows(t *testing.T) { legacyregistry.Reset() metrics.InitializeOVSMetrics() - c = ofClient.NewClient(br, bridgeMgmtAddr, ovsconfig.OVSDatapathNetdev, true, false, true, false, false, true, false) + c = ofClient.NewClient(br, bridgeMgmtAddr, true, false, true, false, false, true, false, false) err := ofTestUtils.PrepareOVSBridge(br) require.Nil(t, err, fmt.Sprintf("Failed to prepare OVS bridge: %v", err)) defer func() { @@ -223,7 +224,7 @@ func TestReplayFlowsConnectivityFlows(t *testing.T) { legacyregistry.Reset() metrics.InitializeOVSMetrics() - c = ofClient.NewClient(br, bridgeMgmtAddr, ovsconfig.OVSDatapathNetdev, true, false, true, false, false, false, false) + c = ofClient.NewClient(br, bridgeMgmtAddr, true, false, true, false, false, false, false, false) err := ofTestUtils.PrepareOVSBridge(br) require.Nil(t, err, fmt.Sprintf("Failed to prepare OVS bridge: %v", err)) @@ -265,12 +266,12 @@ func TestReplayFlowsNetworkPolicyFlows(t *testing.T) { legacyregistry.Reset() metrics.InitializeOVSMetrics() - c = ofClient.NewClient(br, bridgeMgmtAddr, ovsconfig.OVSDatapathNetdev, true, false, false, false, false, false, false) + c = ofClient.NewClient(br, bridgeMgmtAddr, true, false, false, false, false, false, false, false) err := ofTestUtils.PrepareOVSBridge(br) require.Nil(t, err, fmt.Sprintf("Failed to prepare OVS bridge: %v", err)) config := prepareConfiguration(true, false) - _, err = c.Initialize(roundInfo, config.nodeConfig, &config1.NetworkConfig{TrafficEncapMode: config1.TrafficEncapModeEncap}) + _, err = c.Initialize(roundInfo, config.nodeConfig, &config1.NetworkConfig{TrafficEncapMode: config1.TrafficEncapModeEncap, IPv4Enabled: true}, &config1.EgressConfig{}, &config1.ServiceConfig{}) require.Nil(t, err, "Failed to initialize OFClient") defer func() { @@ -320,11 +321,6 @@ func TestReplayFlowsNetworkPolicyFlows(t *testing.T) { } func testExternalFlows(t *testing.T, config *testConfig) { - exceptCIDRs := []net.IPNet{} - if err := c.InstallExternalFlows(exceptCIDRs); err != nil { - t.Errorf("Failed to install OpenFlow entries to allow Pod to communicate to the external addresses: %v", err) - } - gwMACStr := config.nodeConfig.GatewayConfig.MAC.String() if config.enableIPv4 { for _, tableFlow := range expectedExternalFlows("ip", gwMACStr) { @@ -360,7 +356,7 @@ func testReplayFlows(t *testing.T) { } func testInitialize(t *testing.T, config *testConfig) { - if _, err := c.Initialize(roundInfo, config.nodeConfig, &config1.NetworkConfig{TrafficEncapMode: config1.TrafficEncapModeEncap, IPv4Enabled: config.enableIPv4, IPv6Enabled: config.enableIPv6}); err != nil { + if _, err := c.Initialize(roundInfo, config.nodeConfig, &config1.NetworkConfig{TrafficEncapMode: config1.TrafficEncapModeEncap, IPv4Enabled: config.enableIPv4, IPv6Enabled: config.enableIPv6}, &config1.EgressConfig{}, &config1.ServiceConfig{}); err != nil { t.Errorf("Failed to initialize openflow client: %v", err) } for _, tableFlow := range prepareDefaultFlows(config) { @@ -370,20 +366,12 @@ func testInitialize(t *testing.T, config *testConfig) { } func testInstallTunnelFlows(t *testing.T, config *testConfig) { - err := c.InstallDefaultTunnelFlows() - if err != nil { - t.Fatalf("Failed to install Openflow entries for tunnel port: %v", err) - } for _, tableFlow := range prepareTunnelFlows(config1.DefaultTunOFPort, config.globalMAC) { ofTestUtils.CheckFlowExists(t, ovsCtlClient, tableFlow.tableName, 0, true, tableFlow.flows) } } func testInstallServiceFlows(t *testing.T, config *testConfig) { - err := c.InstallDefaultServiceFlows(nil, nil) - if err != nil { - t.Fatalf("Failed to install Openflow entries to skip service CIDR from egress table: %v", err) - } for _, tableFlow := range prepareServiceHelperFlows() { ofTestUtils.CheckFlowExists(t, ovsCtlClient, tableFlow.tableName, 0, true, tableFlow.flows) } @@ -455,12 +443,12 @@ func TestNetworkPolicyFlows(t *testing.T) { legacyregistry.Reset() metrics.InitializeOVSMetrics() - c = ofClient.NewClient(br, bridgeMgmtAddr, ovsconfig.OVSDatapathNetdev, true, false, false, false, false, false, false) + c = ofClient.NewClient(br, bridgeMgmtAddr, true, false, false, false, false, false, false, false) err := ofTestUtils.PrepareOVSBridge(br) require.Nil(t, err, fmt.Sprintf("Failed to prepare OVS bridge %s", br)) config := prepareConfiguration(true, true) - _, err = c.Initialize(roundInfo, config.nodeConfig, &config1.NetworkConfig{TrafficEncapMode: config1.TrafficEncapModeEncap, IPv4Enabled: true, IPv6Enabled: true}) + _, err = c.Initialize(roundInfo, config.nodeConfig, &config1.NetworkConfig{TrafficEncapMode: config1.TrafficEncapModeEncap, IPv4Enabled: true, IPv6Enabled: true}, &config1.EgressConfig{}, &config1.ServiceConfig{}) require.Nil(t, err, "Failed to initialize OFClient") defer func() { @@ -569,7 +557,7 @@ func TestIPv6ConnectivityFlows(t *testing.T) { legacyregistry.Reset() metrics.InitializeOVSMetrics() - c = ofClient.NewClient(br, bridgeMgmtAddr, ovsconfig.OVSDatapathNetdev, true, false, true, false, false, false, false) + c = ofClient.NewClient(br, bridgeMgmtAddr, true, false, true, false, false, false, false, false) err := ofTestUtils.PrepareOVSBridge(br) require.Nil(t, err, fmt.Sprintf("Failed to prepare OVS bridge: %v", err)) @@ -617,12 +605,12 @@ func TestProxyServiceFlows(t *testing.T) { legacyregistry.Reset() metrics.InitializeOVSMetrics() - c = ofClient.NewClient(br, bridgeMgmtAddr, ovsconfig.OVSDatapathNetdev, true, false, false, false, false, false, false) + c = ofClient.NewClient(br, bridgeMgmtAddr, true, false, false, false, false, false, false, false) err := ofTestUtils.PrepareOVSBridge(br) require.Nil(t, err, fmt.Sprintf("Failed to prepare OVS bridge %s", br)) config := prepareConfiguration(true, false) - _, err = c.Initialize(roundInfo, config.nodeConfig, &config1.NetworkConfig{TrafficEncapMode: config1.TrafficEncapModeEncap, IPv4Enabled: true}) + _, err = c.Initialize(roundInfo, config.nodeConfig, &config1.NetworkConfig{TrafficEncapMode: config1.TrafficEncapModeEncap, IPv4Enabled: true}, &config1.EgressConfig{}, &config1.ServiceConfig{}) require.Nil(t, err, "Failed to initialize OFClient") defer func() { @@ -716,7 +704,7 @@ func uninstallServiceFlowsFunc(t *testing.T, gid uint32, svc svcConfig, endpoint groupID := ofconfig.GroupIDType(gid) err := c.UninstallServiceFlows(svc.ip, svc.port, svc.protocol) assert.Nil(t, err) - err = c.UninstallServiceGroup(groupID) + err = c.UninstallGroup(groupID) assert.Nil(t, err) for _, ep := range endpointList { err := c.UninstallEndpointFlows(svc.protocol, ep) @@ -961,10 +949,6 @@ func checkOVSFlowMetrics(t *testing.T, client ofClient.Client) { func testInstallGatewayFlows(t *testing.T, config *testConfig) { gatewayConfig := config.nodeConfig.GatewayConfig - err := c.InstallGatewayFlows() - if err != nil { - t.Fatalf("Failed to install Openflow entries for gateway: %v", err) - } var ips []net.IP if config.enableIPv4 { ips = append(ips, gatewayConfig.IPv4) @@ -980,6 +964,7 @@ func testInstallGatewayFlows(t *testing.T, config *testConfig) { func prepareConfiguration(enableIPv4, enableIPv6 bool) *testConfig { podMAC, _ := net.ParseMAC("aa:aa:aa:aa:aa:13") gwMAC, _ := net.ParseMAC("aa:aa:aa:aa:aa:11") + uplinkMAC, _ := net.ParseMAC("aa:aa:aa:aa:aa:12") peerNodeMAC, _ := net.ParseMAC("aa:aa:aa:aa:ab:00") nodeIPv4, nodeIPv4Subnet, _ := net.ParseCIDR("10.10.10.1/24") @@ -990,7 +975,8 @@ func prepareConfiguration(enableIPv4, enableIPv6 bool) *testConfig { _, peerIPv6Subnet, _ := net.ParseCIDR("fd74:ca9b:172:20::/64") gatewayConfig := &config1.GatewayConfig{MAC: gwMAC} - nodeConfig := &config1.NodeConfig{GatewayConfig: gatewayConfig} + uplinkConfig := &config1.AdapterNetConfig{MAC: uplinkMAC} + nodeConfig := &config1.NodeConfig{GatewayConfig: gatewayConfig, UplinkNetConfig: uplinkConfig} podCfg := &testLocalPodConfig{ name: "container-1", testPortConfig: &testPortConfig{ @@ -1082,7 +1068,7 @@ func preparePodFlows(podIPs []net.IP, podMAC net.HardwareAddr, podOFPort uint32, []*ofTestUtils.ExpectFlow{ { MatchStr: fmt.Sprintf("priority=210,ip,in_port=%d%s,dl_dst=%s", 3, matchVlanVIDString, podMAC.String()), - ActStr: fmt.Sprintf("load:0x1->NXM_NX_REG8[12..15],load:%s->NXM_NX_REG8[0..11],load:0x4->NXM_NX_REG0[0..3],goto_table:SNATConntrackZone", vlanVIDString), + ActStr: fmt.Sprintf("load:0x1->NXM_NX_REG8[12..15],load:0x4->NXM_NX_REG0[0..3],load:%s->NXM_NX_REG8[0..11],goto_table:SNATConntrackZone", vlanVIDString), }, }, }}...) @@ -1237,7 +1223,7 @@ func prepareGatewayFlows(gwIPs []net.IP, gwMAC net.HardwareAddr, vMAC net.Hardwa tableName: "IngressSecurityClassifier", flows: []*ofTestUtils.ExpectFlow{ { - MatchStr: fmt.Sprintf("priority=210,%s,%s=%s", ipProtoStr, nwSrcStr, gwIP.String()), + MatchStr: fmt.Sprintf("priority=210,ct_state=-rpl+trk,%s,%s=%s", ipProtoStr, nwSrcStr, gwIP.String()), ActStr: "goto_table:ConntrackCommit", }, }, @@ -1318,7 +1304,7 @@ func prepareNodeFlows(peerSubnet net.IPNet, peerGwIP, peerNodeIP net.IP, vMAC, l []*ofTestUtils.ExpectFlow{ { MatchStr: fmt.Sprintf("priority=200,%s,reg4=0x100000/0x100000,reg8=0/0xfff,%s=%s", ipProtoStr, nwDstFieldName, peerSubnet.String()), - ActStr: fmt.Sprintf("set_field:%s->eth_dst,goto_table:L3DecTTL", peerNodeMAC.String()), + ActStr: fmt.Sprintf("set_field:%s->eth_dst,load:0x4->NXM_NX_REG0[4..7],goto_table:L3DecTTL", peerNodeMAC.String()), }, }, }) @@ -1401,11 +1387,10 @@ func prepareDefaultFlows(config *testConfig) []expectTableFlows { &ofTestUtils.ExpectFlow{MatchStr: "priority=200,ip", ActStr: fmt.Sprintf("ct(table=ConntrackState,zone=%s,nat)", ctZone)}, ) tableConntrackStateFlows.flows = append(tableConntrackStateFlows.flows, - &ofTestUtils.ExpectFlow{MatchStr: "priority=190,ct_state=+inv+trk,ip", ActStr: "drop"}, + &ofTestUtils.ExpectFlow{MatchStr: "priority=210,ct_state=+inv+trk,ip", ActStr: "drop"}, ) tableConntrackCommitFlows.flows = append(tableConntrackCommitFlows.flows, - &ofTestUtils.ExpectFlow{MatchStr: "priority=210,ct_mark=0x10/0x10,ip", ActStr: fmt.Sprintf("goto_table:%s", outputStageTable)}, - &ofTestUtils.ExpectFlow{MatchStr: "priority=200,ct_state=+new+trk,ip", ActStr: fmt.Sprintf("ct(commit,table=%s,zone=%s,exec(move:NXM_NX_REG0[0..3]->NXM_NX_CT_MARK[0..3]))", outputStageTable, ctZone)}, + &ofTestUtils.ExpectFlow{MatchStr: "priority=200,ct_state=+new+trk,ct_mark=0/0x10,ip", ActStr: fmt.Sprintf("ct(commit,table=%s,zone=%s,exec(move:NXM_NX_REG0[0..3]->NXM_NX_CT_MARK[0..3]))", outputStageTable, ctZone)}, ) tableSNATConntrackCommitFlows.flows = append(tableSNATConntrackCommitFlows.flows, &ofTestUtils.ExpectFlow{ @@ -1431,7 +1416,7 @@ func prepareDefaultFlows(config *testConfig) []expectTableFlows { ) tableServiceMarkFlows.flows = append(tableServiceMarkFlows.flows, &ofTestUtils.ExpectFlow{MatchStr: "priority=200,ct_state=+new+trk,ip,reg0=0x22/0xff", ActStr: fmt.Sprintf("ct(commit,table=SNATConntrackCommit,zone=%s,exec(load:0x1->NXM_NX_CT_MARK[5],load:0x1->NXM_NX_CT_MARK[6]))", ctZone)}, - &ofTestUtils.ExpectFlow{MatchStr: "priority=190,ct_state=+new+trk,ip,reg0=0x2/0xf,reg4=0x200000/0x200000", ActStr: fmt.Sprintf("ct(commit,table=SNATConntrackCommit,zone=%s,exec(load:0x1->NXM_NX_CT_MARK[5]))", ctZone)}, + &ofTestUtils.ExpectFlow{MatchStr: "priority=200,ct_state=+new+trk,ip,reg0=0x12/0xff,reg4=0x200000/0x200000", ActStr: fmt.Sprintf("ct(commit,table=SNATConntrackCommit,zone=%s,exec(load:0x1->NXM_NX_CT_MARK[5]))", ctZone)}, ) tableL3DecTTLFlows.flows = append(tableL3DecTTLFlows.flows, &ofTestUtils.ExpectFlow{MatchStr: "priority=210,ip,reg0=0x2/0xf", ActStr: "goto_table:ServiceMark"}, @@ -1446,11 +1431,10 @@ func prepareDefaultFlows(config *testConfig) []expectTableFlows { &ofTestUtils.ExpectFlow{MatchStr: "priority=200,ipv6", ActStr: fmt.Sprintf("ct(table=ConntrackState,zone=%s,nat)", ctZoneV6)}, ) tableConntrackStateFlows.flows = append(tableConntrackStateFlows.flows, - &ofTestUtils.ExpectFlow{MatchStr: "priority=190,ct_state=+inv+trk,ipv6", ActStr: "drop"}, + &ofTestUtils.ExpectFlow{MatchStr: "priority=210,ct_state=+inv+trk,ipv6", ActStr: "drop"}, ) tableConntrackCommitFlows.flows = append(tableConntrackCommitFlows.flows, - &ofTestUtils.ExpectFlow{MatchStr: "priority=210,ct_mark=0x10/0x10,ipv6", ActStr: "goto_table:Output"}, - &ofTestUtils.ExpectFlow{MatchStr: "priority=200,ct_state=+new+trk,ipv6", ActStr: fmt.Sprintf("ct(commit,table=Output,zone=%s,exec(move:NXM_NX_REG0[0..3]->NXM_NX_CT_MARK[0..3]))", ctZoneV6)}, + &ofTestUtils.ExpectFlow{MatchStr: "priority=200,ct_state=+new+trk,ct_mark=0/0x10,ipv6", ActStr: fmt.Sprintf("ct(commit,table=Output,zone=%s,exec(move:NXM_NX_REG0[0..3]->NXM_NX_CT_MARK[0..3]))", ctZoneV6)}, ) tableSNATConntrackCommitFlows.flows = append(tableSNATConntrackCommitFlows.flows, &ofTestUtils.ExpectFlow{ @@ -1476,7 +1460,7 @@ func prepareDefaultFlows(config *testConfig) []expectTableFlows { ) tableServiceMarkFlows.flows = append(tableServiceMarkFlows.flows, &ofTestUtils.ExpectFlow{MatchStr: "priority=200,ct_state=+new+trk,ipv6,reg0=0x22/0xff", ActStr: "ct(commit,table=SNATConntrackCommit,zone=65510,exec(load:0x1->NXM_NX_CT_MARK[5],load:0x1->NXM_NX_CT_MARK[6]))"}, - &ofTestUtils.ExpectFlow{MatchStr: "priority=190,ct_state=+new+trk,ipv6,reg0=0x2/0xf,reg4=0x200000/0x200000", ActStr: "ct(commit,table=SNATConntrackCommit,zone=65510,exec(load:0x1->NXM_NX_CT_MARK[5]))"}, + &ofTestUtils.ExpectFlow{MatchStr: "priority=200,ct_state=+new+trk,ipv6,reg0=0x12/0xff,reg4=0x200000/0x200000", ActStr: "ct(commit,table=SNATConntrackCommit,zone=65510,exec(load:0x1->NXM_NX_CT_MARK[5]))"}, ) tableL3DecTTLFlows.flows = append(tableL3DecTTLFlows.flows, &ofTestUtils.ExpectFlow{MatchStr: "priority=210,ipv6,reg0=0x2/0xf", ActStr: "goto_table:ServiceMark"}, @@ -1642,17 +1626,67 @@ func prepareEgressMarkFlows(snatIP net.IP, mark, podOFPort, podOFPortRemote uint } } +func prepareTrafficControlFlows(sourceOFPorts []uint32, targetOFPort, returnOFPort uint32) []expectTableFlows { + expectedFlows := []expectTableFlows{ + { + "Classifier", + []*ofTestUtils.ExpectFlow{ + { + MatchStr: fmt.Sprintf("priority=200,in_port=%d", returnOFPort), + ActStr: "load:0x6->NXM_NX_REG0[0..3],goto_table:L3Forwarding", + }, + }, + }, + { + "Output", + []*ofTestUtils.ExpectFlow{ + { + MatchStr: "priority=211,reg0=0x100/0x100,reg4=0x400000/0xc00000", + ActStr: "output:NXM_NX_REG1[],output:NXM_NX_REG9[]", + }, + { + MatchStr: "priority=211,reg0=0x100/0x100,reg4=0x800000/0xc00000", + ActStr: "output:NXM_NX_REG9[]", + }, + }, + }, + } + trafficControlTableFlows := expectTableFlows{ + "TrafficControl", + []*ofTestUtils.ExpectFlow{ + { + MatchStr: "priority=210,reg0=0x106/0x10f", + ActStr: "goto_table:Output", + }, + }, + } + for _, port := range sourceOFPorts { + trafficControlTableFlows.flows = append(trafficControlTableFlows.flows, + &ofTestUtils.ExpectFlow{ + MatchStr: fmt.Sprintf("priority=200,reg1=0x%x", port), + ActStr: fmt.Sprintf("load:0x%x->NXM_NX_REG9[],load:0x2->NXM_NX_REG4[22..23],goto_table:IngressSecurityClassifier", targetOFPort), + }, + &ofTestUtils.ExpectFlow{ + MatchStr: fmt.Sprintf("priority=200,in_port=%d", port), + ActStr: fmt.Sprintf("load:0x%x->NXM_NX_REG9[],load:0x2->NXM_NX_REG4[22..23],goto_table:IngressSecurityClassifier", targetOFPort), + }, + ) + } + expectedFlows = append(expectedFlows, trafficControlTableFlows) + return expectedFlows +} + func TestEgressMarkFlows(t *testing.T) { // Reset OVS metrics (Prometheus) and reinitialize them to test. legacyregistry.Reset() metrics.InitializeOVSMetrics() - c = ofClient.NewClient(br, bridgeMgmtAddr, ovsconfig.OVSDatapathNetdev, false, false, true, false, false, false, false) + c = ofClient.NewClient(br, bridgeMgmtAddr, false, false, true, false, false, false, false, false) err := ofTestUtils.PrepareOVSBridge(br) require.Nil(t, err, fmt.Sprintf("Failed to prepare OVS bridge %s", br)) config := prepareConfiguration(true, true) - _, err = c.Initialize(roundInfo, config.nodeConfig, &config1.NetworkConfig{TrafficEncapMode: config1.TrafficEncapModeEncap}) + _, err = c.Initialize(roundInfo, config.nodeConfig, &config1.NetworkConfig{TrafficEncapMode: config1.TrafficEncapModeEncap}, &config1.EgressConfig{}, &config1.ServiceConfig{}) require.Nil(t, err, "Failed to initialize OFClient") defer func() { @@ -1698,3 +1732,36 @@ func TestEgressMarkFlows(t *testing.T) { ofTestUtils.CheckFlowExists(t, ovsCtlClient, tableFlow.tableName, 0, false, tableFlow.flows) } } + +func TestTrafficControlFlows(t *testing.T) { + // Reset OVS metrics (Prometheus) and reinitialize them to test. + legacyregistry.Reset() + metrics.InitializeOVSMetrics() + + c = ofClient.NewClient(br, bridgeMgmtAddr, false, false, false, false, false, false, false, true) + err := ofTestUtils.PrepareOVSBridge(br) + require.Nil(t, err, fmt.Sprintf("Failed to prepare OVS bridge %s", br)) + + config := prepareConfiguration(true, false) + _, err = c.Initialize(roundInfo, config.nodeConfig, &config1.NetworkConfig{TrafficEncapMode: config1.TrafficEncapModeEncap, IPv4Enabled: config.enableIPv4}, &config1.EgressConfig{}, &config1.ServiceConfig{}) + require.Nil(t, err, "Failed to initialize OFClient") + + defer func() { + err = c.Disconnect() + assert.Nil(t, err, fmt.Sprintf("Error while disconnecting from OVS bridge: %v", err)) + err = ofTestUtils.DeleteOVSBridge(br) + assert.Nil(t, err, fmt.Sprintf("Error while deleting OVS bridge: %v", err)) + ofClient.CleanOFTableCache() + ofClient.ResetOFTable() + }() + + sourceOFPorts := []uint32{100, 101, 102} + targetOFPort := uint32(200) + returnOFPort := uint32(201) + expectedFlows := prepareTrafficControlFlows(sourceOFPorts, targetOFPort, returnOFPort) + c.InstallTrafficControlReturnPortFlow(returnOFPort) + c.InstallTrafficControlMarkFlows("tc", sourceOFPorts, targetOFPort, v1alpha2.DirectionBoth, v1alpha2.ActionRedirect) + for _, tableFlow := range expectedFlows { + ofTestUtils.CheckFlowExists(t, ovsCtlClient, tableFlow.tableName, 0, true, tableFlow.flows) + } +} diff --git a/test/integration/ovs/ofctrl_test.go b/test/integration/ovs/ofctrl_test.go index b646cceeb39..73769a10e58 100644 --- a/test/integration/ovs/ofctrl_test.go +++ b/test/integration/ovs/ofctrl_test.go @@ -269,6 +269,8 @@ func TestOFctrlGroup(t *testing.T) { ovsCtlClient := ovsctl.NewClient(brName) + id := 1 + for name, buckets := range map[string][]struct { weight uint16 // Must have non-zero value. reg2reg [][4]uint32 // regNum, data, startIndex, endIndex @@ -278,12 +280,25 @@ func TestOFctrlGroup(t *testing.T) { {weight: 100, reg2reg: [][4]uint32{{0, 1, 0, 31}, {1, 2, 15, 31}}, resubmitTable: 31}, {weight: 110, resubmitTable: 42}, }, + "TypeAll": { + {weight: 100, reg2reg: [][4]uint32{{0, 1, 0, 31}, {1, 2, 15, 31}}, resubmitTable: 31}, + {weight: 110, resubmitTable: 42}, + }, } { t.Run(name, func(t *testing.T) { - group := br.CreateGroup(1) + var group binding.Group + gid := binding.GroupIDType(id) + if name == "TypeAll" { + group = br.CreateGroupTypeAll(gid) + } else { + group = br.CreateGroup(gid) + } for _, bucket := range buckets { require.NotZero(t, bucket.weight, "Weight value of a bucket must be specified") - bucketBuilder := group.Bucket().Weight(bucket.weight) + bucketBuilder := group.Bucket() + if name == "Normal" { + bucketBuilder = bucketBuilder.Weight(bucket.weight) + } if bucket.resubmitTable != 0 { bucketBuilder = bucketBuilder.ResubmitToTable(bucket.resubmitTable) } @@ -303,8 +318,10 @@ func TestOFctrlGroup(t *testing.T) { }), "Failed to install group") dumpedGroup := groups[0] for i, bucket := range buckets { - // Must have weight - assert.True(t, strings.Contains(dumpedGroup[i+1], fmt.Sprintf("weight:%d", bucket.weight))) + if name == "Normal" { + // Must have weight + assert.True(t, strings.Contains(dumpedGroup[i+1], fmt.Sprintf("weight:%d", bucket.weight))) + } for _, loading := range bucket.reg2reg { rngStr := "[]" if !(loading[2] == 0 && loading[3] == 31) { @@ -326,6 +343,7 @@ func TestOFctrlGroup(t *testing.T) { return len(groups) == 0, nil }), "Failed to delete group") }) + id++ } } diff --git a/third_party/proxy/service.go b/third_party/proxy/service.go index d0a7ac178e7..f951986b506 100644 --- a/third_party/proxy/service.go +++ b/third_party/proxy/service.go @@ -70,7 +70,6 @@ type BaseServiceInfo struct { nodeLocalExternal bool nodeLocalInternal bool internalTrafficPolicy *v1.ServiceInternalTrafficPolicyType - topologyKeys []string hintsAnnotation string } @@ -150,11 +149,6 @@ func (info *BaseServiceInfo) InternalTrafficPolicy() *v1.ServiceInternalTrafficP return info.internalTrafficPolicy } -// TopologyKeys is part of ServicePort interface. -func (info *BaseServiceInfo) TopologyKeys() []string { - return info.topologyKeys -} - // HintsAnnotation is part of ServicePort interface. func (info *BaseServiceInfo) HintsAnnotation() string { return info.hintsAnnotation @@ -183,7 +177,6 @@ func (sct *ServiceChangeTracker) newBaseServiceInfo(port *v1.ServicePort, servic nodeLocalExternal: nodeLocalExternal, nodeLocalInternal: nodeLocalInternal, internalTrafficPolicy: service.Spec.InternalTrafficPolicy, - topologyKeys: service.Spec.TopologyKeys, hintsAnnotation: service.Annotations[v1.AnnotationTopologyAwareHints], } diff --git a/third_party/proxy/types.go b/third_party/proxy/types.go index 200faf6203e..f224470bd63 100644 --- a/third_party/proxy/types.go +++ b/third_party/proxy/types.go @@ -105,8 +105,6 @@ type ServicePort interface { NodeLocalInternal() bool // InternalTrafficPolicy returns service InternalTrafficPolicy InternalTrafficPolicy() *v1.ServiceInternalTrafficPolicyType - // TopologyKeys returns service TopologyKeys as a string array. - TopologyKeys() []string // HintsAnnotation returns the value of the v1.AnnotationTopologyAwareHints annotation. HintsAnnotation() string }